@mui/x-data-grid 9.0.0-alpha.0 → 9.0.0-alpha.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/DataGrid/DataGrid.js +7 -0
  3. package/components/panel/filterPanel/GridFilterInputMultipleValue.js +12 -9
  4. package/constants/dataGridPropsDefaultValues.js +1 -0
  5. package/esm/DataGrid/DataGrid.js +7 -0
  6. package/esm/components/panel/filterPanel/GridFilterInputMultipleValue.js +11 -8
  7. package/esm/constants/dataGridPropsDefaultValues.js +1 -0
  8. package/esm/hooks/features/columns/gridColumnsSelector.js +5 -14
  9. package/esm/hooks/features/dataSource/models.d.ts +4 -1
  10. package/esm/hooks/features/dataSource/useGridDataSourceBase.d.ts +5 -2
  11. package/esm/hooks/features/dataSource/useGridDataSourceBase.js +92 -6
  12. package/esm/hooks/features/editing/useGridRowEditing.js +14 -4
  13. package/esm/index.js +1 -1
  14. package/esm/locales/csCZ.js +2 -2
  15. package/esm/locales/ukUA.js +13 -13
  16. package/esm/models/api/gridEditingApi.d.ts +0 -1
  17. package/esm/models/params/gridRowParams.d.ts +0 -1
  18. package/esm/models/props/DataGridProps.d.ts +7 -0
  19. package/esm/utils/utils.d.ts +2 -2
  20. package/esm/utils/utils.js +2 -2
  21. package/hooks/features/columns/gridColumnsSelector.js +5 -14
  22. package/hooks/features/dataSource/models.d.ts +4 -1
  23. package/hooks/features/dataSource/useGridDataSourceBase.d.ts +5 -2
  24. package/hooks/features/dataSource/useGridDataSourceBase.js +91 -5
  25. package/hooks/features/editing/useGridRowEditing.js +14 -4
  26. package/index.js +1 -1
  27. package/locales/csCZ.js +2 -2
  28. package/locales/ukUA.js +13 -13
  29. package/models/api/gridEditingApi.d.ts +0 -1
  30. package/models/params/gridRowParams.d.ts +0 -1
  31. package/models/props/DataGridProps.d.ts +7 -0
  32. package/package.json +12 -4
  33. package/utils/utils.d.ts +2 -2
  34. package/utils/utils.js +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,123 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.0.0-alpha.1
4
+
5
+ _Feb 26, 2026_
6
+
7
+ We'd like to extend a big thank you to the 18 contributors who made this release possible. Here are some highlights ✨:
8
+
9
+ - ⚡️ Improved dynamic data support and cache invalidation in lazy loading for Data Grid Pro
10
+ - ⌨️ Keyboard support for selecting day, month, and year in Date Pickers
11
+ - 📊 Axis tooltip sorting and control improvements in Charts
12
+ - 🐞 Bugfixes and internal improvements
13
+
14
+ Special thanks go out to these community members for their valuable contributions:
15
+ @EllGree, @lion1963
16
+
17
+ The following team members contributed to this release:
18
+ @alexfauquette, @arminmeh, @brijeshb42, @cherniavskii, @dav-is, @flaviendelangle, @Janpot, @JCQuintas, @mapache-salvaje, @MBilalShafi, @michelengelen, @noraleonte, @rita-codes, @sai6855, @siriwatknp, @ZeeshanTamboli
19
+
20
+ ### Data Grid
21
+
22
+ #### `@mui/x-data-grid@9.0.0-alpha.1`
23
+
24
+ - [DataGrid] Forward rest props in `GridFilterInputMultipleValue` (#21407) @siriwatknp
25
+ - [DataGrid] Preserve key input during row edit when using `rowModesModel` (#20759) @michelengelen
26
+ - [DataGrid] Remove double rtl inversion logic for columns pinning (#21371) @siriwatknp
27
+
28
+ #### `@mui/x-data-grid-pro@9.0.0-alpha.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
29
+
30
+ Same changes as in `@mui/x-data-grid@9.0.0-alpha.1`, plus:
31
+
32
+ - [DataGridPro] Fix number input visibility in header filters (#21328) @michelengelen
33
+ - [DataGridPro] Improve dynamic data support and cache invalidation in lazy loading (#21282) @MBilalShafi
34
+
35
+ #### `@mui/x-data-grid-premium@9.0.0-alpha.1` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
36
+
37
+ Same changes as in `@mui/x-data-grid-pro@9.0.0-alpha.1`.
38
+
39
+ ### Date and Time Pickers
40
+
41
+ #### `@mui/x-date-pickers@9.0.0-alpha.1`
42
+
43
+ - [DatePicker] Add keyboard support for selecting day, month, and year (#20859) @michelengelen
44
+
45
+ #### `@mui/x-date-pickers-pro@9.0.0-alpha.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
46
+
47
+ Same changes as in `@mui/x-date-pickers@9.0.0-alpha.1`, plus:
48
+
49
+ - [DateRangePicker] Fix timezone update issue leading to `invalidRange` error (#20863) @michelengelen
50
+
51
+ ### Charts
52
+
53
+ #### `@mui/x-charts@9.0.0-alpha.1`
54
+
55
+ - [charts] Add `sort` props to the axis tooltip (#21293) @alexfauquette
56
+ - [charts] Controll axis tooltip (#21351) @alexfauquette
57
+ - [charts] De duplicate keyboard focus handler function (#21267) @sai6855
58
+ - [charts] Make `type` optional in identifiers (#21311) @alexfauquette
59
+ - [charts] Move ref to the root component (#21396) @alexfauquette
60
+ - [charts] Refactor loading and no data overlays to use a shared OverlayText component (#21414) @sai6855
61
+ - [charts] Require series ids to be unique (#21330) @alexfauquette
62
+ - [charts] Set `showMark` as `false` by default (#21373) @alexfauquette
63
+ - [charts] Use `createGetNextIndexFocusedItem()` util in Funnel and RangeBar charts (#21390) @sai6855
64
+ - [charts] Remove unnecessary string concatenation (#21418) @sai6855
65
+
66
+ #### `@mui/x-charts-pro@9.0.0-alpha.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
67
+
68
+ Same changes as in `@mui/x-charts@9.0.0-alpha.1`.
69
+
70
+ #### `@mui/x-charts-premium@9.0.0-alpha.1` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
71
+
72
+ Same changes as in `@mui/x-charts-pro@9.0.0-alpha.1`.
73
+
74
+ ### Tree View
75
+
76
+ #### `@mui/x-tree-view@9.0.0-alpha.1`
77
+
78
+ - [tree view] Focus item sibling on unmount instead of the 1st item (#21254) @flaviendelangle
79
+
80
+ #### `@mui/x-tree-view-pro@9.0.0-alpha.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
81
+
82
+ Same changes as in `@mui/x-tree-view@9.0.0-alpha.1`.
83
+
84
+ ### Codemod
85
+
86
+ #### `@mui/x-codemod@9.0.0-alpha.1`
87
+
88
+ Internal changes.
89
+
90
+ ### Docs
91
+
92
+ - [docs] Fix external 301s (#21377) @Janpot
93
+ - [docs] Show premium in the overview (#21343) @alexfauquette
94
+ - [docs][charts] Revise the useLegend hook doc (#21352) @mapache-salvaje
95
+ - [docs][charts] Revise the axis hooks doc (#21317) @mapache-salvaje
96
+ - [docs][charts] Revise the scale hooks doc (#21316) @mapache-salvaje
97
+ - [docs][charts] Revise the series hooks doc (#21353) @mapache-salvaje
98
+ - [docs][charts] Revise the useDataset doc (#21336) @mapache-salvaje
99
+ - [docs][charts] Revise the useDrawingArea doc (#21333) @mapache-salvaje
100
+
101
+ ### Core
102
+
103
+ - [core] Update docs deploy script to the `docs-next` branch (#21341) @siriwatknp
104
+ - [code-infra] Cleanup unused babel plugins (#21453) @brijeshb42
105
+ - [code-infra] Do not append `x` to the last version for the compare API (#21408) @arminmeh
106
+ - [code-infra] Upgrade react-docgen to v8 X (#21155) @JCQuintas
107
+ - [code-infra] Modernize codemod (#21096) @JCQuintas
108
+ - [docs-infra] Fix current version detection logic (#21417) @cherniavskii
109
+ - [docs-infra] Reapply Cookie Banner (#21281) @dav-is
110
+ - [internal] Headless filtering plugin (#21302) @arminmeh
111
+ - [internal] Headless pagination plugin (#21183) @arminmeh
112
+ - [internal] Headless virtualization followups (#21327) @cherniavskii
113
+ - [internal] Keep cached data for disabled pipe processors (#21348) @arminmeh
114
+ - [internal] Remove autoprefixer package (#21440) @ZeeshanTamboli
115
+
116
+ ### Miscellaneous
117
+
118
+ - [l10n] Fix Czech (csCZ) locale: sort/filter labels are swapped (#21400) @EllGree
119
+ - [l10n] Improve Ukrainian (uk-UA) locale (#21366) @lion1963
120
+
3
121
  ## 9.0.0-alpha.0
4
122
 
5
123
  _Feb 16, 2026_
@@ -180,6 +180,13 @@ DataGridRaw.propTypes = {
180
180
  get: _propTypes.default.func.isRequired,
181
181
  set: _propTypes.default.func.isRequired
182
182
  }),
183
+ /**
184
+ * If positive, the Data Grid will periodically revalidate data source rows by
185
+ * re-fetching them from the server when the cache entry has expired.
186
+ * Set to `0` to disable polling.
187
+ * @default 0
188
+ */
189
+ dataSourceRevalidateMs: _propTypes.default.number,
183
190
  /**
184
191
  * Set the density of the Data Grid.
185
192
  * @default "standard"
@@ -1,27 +1,30 @@
1
1
  "use strict";
2
2
  'use client';
3
3
 
4
- var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
4
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
5
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
6
6
  Object.defineProperty(exports, "__esModule", {
7
7
  value: true
8
8
  });
9
9
  exports.GridFilterInputMultipleValue = GridFilterInputMultipleValue;
10
10
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
+ var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
11
12
  var React = _interopRequireWildcard(require("react"));
12
13
  var _propTypes = _interopRequireDefault(require("prop-types"));
13
14
  var _useId = _interopRequireDefault(require("@mui/utils/useId"));
14
15
  var _useGridRootProps = require("../../../hooks/utils/useGridRootProps");
15
16
  var _jsxRuntime = require("react/jsx-runtime");
17
+ const _excluded = ["item", "applyValue", "type", "apiRef", "focusElementRef", "slotProps"];
16
18
  function GridFilterInputMultipleValue(props) {
17
19
  const {
18
- item,
19
- applyValue,
20
- type,
21
- apiRef,
22
- focusElementRef,
23
- slotProps
24
- } = props;
20
+ item,
21
+ applyValue,
22
+ type,
23
+ apiRef,
24
+ focusElementRef,
25
+ slotProps
26
+ } = props,
27
+ other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
25
28
  const id = (0, _useId.default)();
26
29
  const [options, setOptions] = React.useState([]);
27
30
  const [filterValueState, setFilterValueState] = React.useState(item.value || []);
@@ -60,7 +63,7 @@ function GridFilterInputMultipleValue(props) {
60
63
  inputRef: focusElementRef
61
64
  }
62
65
  }
63
- }, slotProps?.root));
66
+ }, other, slotProps?.root));
64
67
  }
65
68
  process.env.NODE_ENV !== "production" ? GridFilterInputMultipleValue.propTypes = {
66
69
  // ----------------------------- Warning --------------------------------
@@ -30,6 +30,7 @@ const DATA_GRID_PROPS_DEFAULT_VALUES = exports.DATA_GRID_PROPS_DEFAULT_VALUES =
30
30
  disableMultipleColumnsFiltering: false,
31
31
  disableMultipleColumnsSorting: false,
32
32
  disableMultipleRowSelection: false,
33
+ dataSourceRevalidateMs: 0,
33
34
  disableRowSelectionOnClick: false,
34
35
  disableRowSelectionExcludeModel: false,
35
36
  disableVirtualization: false,
@@ -173,6 +173,13 @@ DataGridRaw.propTypes = {
173
173
  get: PropTypes.func.isRequired,
174
174
  set: PropTypes.func.isRequired
175
175
  }),
176
+ /**
177
+ * If positive, the Data Grid will periodically revalidate data source rows by
178
+ * re-fetching them from the server when the cache entry has expired.
179
+ * Set to `0` to disable polling.
180
+ * @default 0
181
+ */
182
+ dataSourceRevalidateMs: PropTypes.number,
176
183
  /**
177
184
  * Set the density of the Data Grid.
178
185
  * @default "standard"
@@ -1,6 +1,8 @@
1
1
  'use client';
2
2
 
3
3
  import _extends from "@babel/runtime/helpers/esm/extends";
4
+ import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
5
+ const _excluded = ["item", "applyValue", "type", "apiRef", "focusElementRef", "slotProps"];
4
6
  import * as React from 'react';
5
7
  import PropTypes from 'prop-types';
6
8
  import useId from '@mui/utils/useId';
@@ -8,13 +10,14 @@ import { useGridRootProps } from "../../../hooks/utils/useGridRootProps.js";
8
10
  import { jsx as _jsx } from "react/jsx-runtime";
9
11
  function GridFilterInputMultipleValue(props) {
10
12
  const {
11
- item,
12
- applyValue,
13
- type,
14
- apiRef,
15
- focusElementRef,
16
- slotProps
17
- } = props;
13
+ item,
14
+ applyValue,
15
+ type,
16
+ apiRef,
17
+ focusElementRef,
18
+ slotProps
19
+ } = props,
20
+ other = _objectWithoutPropertiesLoose(props, _excluded);
18
21
  const id = useId();
19
22
  const [options, setOptions] = React.useState([]);
20
23
  const [filterValueState, setFilterValueState] = React.useState(item.value || []);
@@ -53,7 +56,7 @@ function GridFilterInputMultipleValue(props) {
53
56
  inputRef: focusElementRef
54
57
  }
55
58
  }
56
- }, slotProps?.root));
59
+ }, other, slotProps?.root));
57
60
  }
58
61
  process.env.NODE_ENV !== "production" ? GridFilterInputMultipleValue.propTypes = {
59
62
  // ----------------------------- Warning --------------------------------
@@ -24,6 +24,7 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES = {
24
24
  disableMultipleColumnsFiltering: false,
25
25
  disableMultipleColumnsSorting: false,
26
26
  disableMultipleRowSelection: false,
27
+ dataSourceRevalidateMs: 0,
27
28
  disableRowSelectionOnClick: false,
28
29
  disableRowSelectionExcludeModel: false,
29
30
  disableVirtualization: false,
@@ -1,6 +1,5 @@
1
1
  import { createSelector, createSelectorMemoized, createRootSelector } from "../../../utils/createSelector.js";
2
2
  import { EMPTY_PINNED_COLUMN_FIELDS } from "./gridColumnsInterfaces.js";
3
- import { gridIsRtlSelector } from "../../core/gridCoreSelector.js";
4
3
  import { gridListColumnSelector, gridListViewSelector } from "../listView/index.js";
5
4
 
6
5
  /**
@@ -65,24 +64,24 @@ export const gridPinnedColumnsSelector = createRootSelector(state => state.pinne
65
64
  * @category Pinned Columns
66
65
  * @ignore - Do not document
67
66
  */
68
- export const gridExistingPinnedColumnSelector = createSelectorMemoized(gridPinnedColumnsSelector, gridColumnFieldsSelector, gridIsRtlSelector, (model, orderedFields, isRtl) => filterMissingColumns(model, orderedFields, isRtl));
67
+ export const gridExistingPinnedColumnSelector = createSelectorMemoized(gridPinnedColumnsSelector, gridColumnFieldsSelector, (model, orderedFields) => filterMissingColumns(model, orderedFields));
69
68
 
70
69
  /**
71
70
  * Get the visible pinned columns.
72
71
  * @category Visible Columns
73
72
  */
74
- export const gridVisiblePinnedColumnDefinitionsSelector = createSelectorMemoized(gridColumnsStateSelector, gridPinnedColumnsSelector, gridVisibleColumnFieldsSelector, gridIsRtlSelector, gridListViewSelector, (columnsState, model, visibleColumnFields, isRtl, listView) => {
73
+ export const gridVisiblePinnedColumnDefinitionsSelector = createSelectorMemoized(gridColumnsStateSelector, gridPinnedColumnsSelector, gridVisibleColumnFieldsSelector, gridListViewSelector, (columnsState, model, visibleColumnFields, listView) => {
75
74
  if (listView) {
76
75
  return EMPTY_PINNED_COLUMN_FIELDS;
77
76
  }
78
- const visiblePinnedFields = filterMissingColumns(model, visibleColumnFields, isRtl);
77
+ const visiblePinnedFields = filterMissingColumns(model, visibleColumnFields);
79
78
  const visiblePinnedColumns = {
80
79
  left: visiblePinnedFields.left.map(field => columnsState.lookup[field]),
81
80
  right: visiblePinnedFields.right.map(field => columnsState.lookup[field])
82
81
  };
83
82
  return visiblePinnedColumns;
84
83
  });
85
- function filterMissingColumns(pinnedColumns, columns, invert) {
84
+ function filterMissingColumns(pinnedColumns, columns) {
86
85
  if (!Array.isArray(pinnedColumns.left) && !Array.isArray(pinnedColumns.right)) {
87
86
  return EMPTY_PINNED_COLUMN_FIELDS;
88
87
  }
@@ -96,16 +95,8 @@ function filterMissingColumns(pinnedColumns, columns, invert) {
96
95
  return newPinnedColumns.filter(field => remainingColumns.includes(field));
97
96
  };
98
97
  const leftPinnedColumns = filter(pinnedColumns.left, columns);
99
- const columnsWithoutLeftPinnedColumns = columns.filter(
100
- // Filter out from the remaining columns those columns already pinned to the left
101
- field => !leftPinnedColumns.includes(field));
98
+ const columnsWithoutLeftPinnedColumns = columns.filter(field => !leftPinnedColumns.includes(field));
102
99
  const rightPinnedColumns = filter(pinnedColumns.right, columnsWithoutLeftPinnedColumns);
103
- if (invert) {
104
- return {
105
- left: rightPinnedColumns,
106
- right: leftPinnedColumns
107
- };
108
- }
109
100
  return {
110
101
  left: leftPinnedColumns,
111
102
  right: rightPinnedColumns
@@ -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: {
@@ -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,7 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
203
286
  return undefined;
204
287
  }
205
288
  if (props.dataSource) {
289
+ stopPolling();
206
290
  apiRef.current.setRows([]);
207
291
  apiRef.current.dataSource.cache.clear();
208
292
  apiRef.current.dataSource.fetchRows();
@@ -211,7 +295,7 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
211
295
  // ignore the current request on unmount
212
296
  lastRequestId.current += 1;
213
297
  };
214
- }, [apiRef, props.dataSource, currentStrategy]);
298
+ }, [apiRef, props.dataSource, currentStrategy, stopPolling]);
215
299
  return {
216
300
  api: {
217
301
  public: dataSourceApi
@@ -223,13 +307,15 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
223
307
  processor: handleDataUpdate
224
308
  },
225
309
  setStrategyAvailability,
310
+ startPolling,
311
+ stopPolling,
226
312
  cacheChunkManager,
227
313
  cache,
228
314
  events: {
229
315
  strategyAvailabilityChange: handleStrategyActivityChange,
230
- sortModelChange: runIf(standardRowsUpdateStrategyActive, () => debouncedFetchRows()),
231
- filterModelChange: runIf(standardRowsUpdateStrategyActive, () => debouncedFetchRows()),
232
- paginationModelChange: runIf(standardRowsUpdateStrategyActive, () => debouncedFetchRows())
316
+ sortModelChange: runIf(standardRowsUpdateStrategyActive, handleFetchRowsOnParamsChange),
317
+ filterModelChange: runIf(standardRowsUpdateStrategyActive, handleFetchRowsOnParamsChange),
318
+ paginationModelChange: runIf(standardRowsUpdateStrategyActive, handleFetchRowsOnParamsChange)
233
319
  }
234
320
  };
235
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 v9.0.0-alpha.0
2
+ * @mui/x-data-grid v9.0.0-alpha.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -125,7 +125,7 @@ const csCZGrid = {
125
125
  columnMenuManageColumns: 'Spravovat sloupce',
126
126
  columnMenuFilter: 'Filtr',
127
127
  columnMenuHideColumn: 'Skrýt',
128
- columnMenuUnsort: 'Zrušit filtry',
128
+ columnMenuUnsort: 'Zrušit řazení',
129
129
  columnMenuSortAsc: 'Seřadit vzestupně',
130
130
  columnMenuSortDesc: 'Seřadit sestupně',
131
131
  // columnMenuManagePivot: 'Manage pivot',
@@ -142,7 +142,7 @@ const csCZGrid = {
142
142
  return `${count} ${pluralForm}`;
143
143
  },
144
144
  columnHeaderFiltersLabel: 'Zobrazit filtry',
145
- columnHeaderSortIconLabel: 'Filtrovat',
145
+ columnHeaderSortIconLabel: 'Řadit',
146
146
  // Rows selected footer text
147
147
  footerRowSelected: count => {
148
148
  let pluralForm = 'vybraných záznamů';
@@ -188,19 +188,19 @@ const ukUAGrid = {
188
188
  collapseDetailPanel: 'Приховати',
189
189
  // Pagination
190
190
  paginationRowsPerPage: 'Рядків на сторінці:',
191
- // paginationDisplayedRows: ({
192
- // from,
193
- // to,
194
- // count,
195
- // estimated
196
- // }) => {
197
- // const unknownRowCount = count == null || count === -1;
198
- // if (!estimated) {
199
- // return `${from}–${to} of ${!unknownRowCount ? count : `more than ${to}`}`;
200
- // }
201
- // const estimatedLabel = estimated && estimated > to ? `around ${estimated}` : `more than ${to}`;
202
- // return `${from}–${to} of ${!unknownRowCount ? count : estimatedLabel}`;
203
- // },
191
+ paginationDisplayedRows: ({
192
+ from,
193
+ to,
194
+ count,
195
+ estimated
196
+ }) => {
197
+ const unknownRowCount = count == null || count === -1;
198
+ if (!estimated) {
199
+ return `${from}–${to} з ${!unknownRowCount ? count : `більше ніж ${to}`}`;
200
+ }
201
+ const estimatedLabel = estimated && estimated > to ? `близько ${estimated}` : `більше ніж ${to}`;
202
+ return `${from}–${to} з ${!unknownRowCount ? count : estimatedLabel}`;
203
+ },
204
204
  paginationItemAriaLabel: type => {
205
205
  if (type === 'first') {
206
206
  return 'Перейти на першу сторінку';
@@ -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
@@ -4,8 +4,8 @@ export declare function isObject<TObject = Record<PropertyKey, any>>(value: unkn
4
4
  export declare function localStorageAvailable(): boolean;
5
5
  export declare function escapeRegExp(value: string): string;
6
6
  /**
7
- * Follows the CSS specification behavior for min and max
8
- * If min > max, then the min have priority
7
+ * Follows the CSS specification behavior for min and max.
8
+ * If min > max, then min has priority.
9
9
  */
10
10
  export declare const clamp: (value: number, min: number, max: number) => number;
11
11
  /**
@@ -25,8 +25,8 @@ export function escapeRegExp(value) {
25
25
  }
26
26
 
27
27
  /**
28
- * Follows the CSS specification behavior for min and max
29
- * If min > max, then the min have priority
28
+ * Follows the CSS specification behavior for min and max.
29
+ * If min > max, then min has priority.
30
30
  */
31
31
  export const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
32
32
 
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.gridVisiblePinnedColumnDefinitionsSelector = exports.gridVisibleColumnFieldsSelector = exports.gridVisibleColumnDefinitionsSelector = exports.gridPinnedColumnsSelector = exports.gridInitialColumnVisibilityModelSelector = exports.gridHasColSpanSelector = exports.gridFilterableColumnLookupSelector = exports.gridFilterableColumnDefinitionsSelector = exports.gridExistingPinnedColumnSelector = exports.gridColumnsStateSelector = exports.gridColumnVisibilityModelSelector = exports.gridColumnPositionsSelector = exports.gridColumnLookupSelector = exports.gridColumnFieldsSelector = exports.gridColumnDefinitionsSelector = void 0;
7
7
  var _createSelector = require("../../../utils/createSelector");
8
8
  var _gridColumnsInterfaces = require("./gridColumnsInterfaces");
9
- var _gridCoreSelector = require("../../core/gridCoreSelector");
10
9
  var _listView = require("../listView");
11
10
  /**
12
11
  * Get the columns state
@@ -70,24 +69,24 @@ const gridPinnedColumnsSelector = exports.gridPinnedColumnsSelector = (0, _creat
70
69
  * @category Pinned Columns
71
70
  * @ignore - Do not document
72
71
  */
73
- const gridExistingPinnedColumnSelector = exports.gridExistingPinnedColumnSelector = (0, _createSelector.createSelectorMemoized)(gridPinnedColumnsSelector, gridColumnFieldsSelector, _gridCoreSelector.gridIsRtlSelector, (model, orderedFields, isRtl) => filterMissingColumns(model, orderedFields, isRtl));
72
+ const gridExistingPinnedColumnSelector = exports.gridExistingPinnedColumnSelector = (0, _createSelector.createSelectorMemoized)(gridPinnedColumnsSelector, gridColumnFieldsSelector, (model, orderedFields) => filterMissingColumns(model, orderedFields));
74
73
 
75
74
  /**
76
75
  * Get the visible pinned columns.
77
76
  * @category Visible Columns
78
77
  */
79
- const gridVisiblePinnedColumnDefinitionsSelector = exports.gridVisiblePinnedColumnDefinitionsSelector = (0, _createSelector.createSelectorMemoized)(gridColumnsStateSelector, gridPinnedColumnsSelector, gridVisibleColumnFieldsSelector, _gridCoreSelector.gridIsRtlSelector, _listView.gridListViewSelector, (columnsState, model, visibleColumnFields, isRtl, listView) => {
78
+ const gridVisiblePinnedColumnDefinitionsSelector = exports.gridVisiblePinnedColumnDefinitionsSelector = (0, _createSelector.createSelectorMemoized)(gridColumnsStateSelector, gridPinnedColumnsSelector, gridVisibleColumnFieldsSelector, _listView.gridListViewSelector, (columnsState, model, visibleColumnFields, listView) => {
80
79
  if (listView) {
81
80
  return _gridColumnsInterfaces.EMPTY_PINNED_COLUMN_FIELDS;
82
81
  }
83
- const visiblePinnedFields = filterMissingColumns(model, visibleColumnFields, isRtl);
82
+ const visiblePinnedFields = filterMissingColumns(model, visibleColumnFields);
84
83
  const visiblePinnedColumns = {
85
84
  left: visiblePinnedFields.left.map(field => columnsState.lookup[field]),
86
85
  right: visiblePinnedFields.right.map(field => columnsState.lookup[field])
87
86
  };
88
87
  return visiblePinnedColumns;
89
88
  });
90
- function filterMissingColumns(pinnedColumns, columns, invert) {
89
+ function filterMissingColumns(pinnedColumns, columns) {
91
90
  if (!Array.isArray(pinnedColumns.left) && !Array.isArray(pinnedColumns.right)) {
92
91
  return _gridColumnsInterfaces.EMPTY_PINNED_COLUMN_FIELDS;
93
92
  }
@@ -101,16 +100,8 @@ function filterMissingColumns(pinnedColumns, columns, invert) {
101
100
  return newPinnedColumns.filter(field => remainingColumns.includes(field));
102
101
  };
103
102
  const leftPinnedColumns = filter(pinnedColumns.left, columns);
104
- const columnsWithoutLeftPinnedColumns = columns.filter(
105
- // Filter out from the remaining columns those columns already pinned to the left
106
- field => !leftPinnedColumns.includes(field));
103
+ const columnsWithoutLeftPinnedColumns = columns.filter(field => !leftPinnedColumns.includes(field));
107
104
  const rightPinnedColumns = filter(pinnedColumns.right, columnsWithoutLeftPinnedColumns);
108
- if (invert) {
109
- return {
110
- left: rightPinnedColumns,
111
- right: leftPinnedColumns
112
- };
113
- }
114
105
  return {
115
106
  left: leftPinnedColumns,
116
107
  right: rightPinnedColumns
@@ -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,7 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
210
293
  return undefined;
211
294
  }
212
295
  if (props.dataSource) {
296
+ stopPolling();
213
297
  apiRef.current.setRows([]);
214
298
  apiRef.current.dataSource.cache.clear();
215
299
  apiRef.current.dataSource.fetchRows();
@@ -218,7 +302,7 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
218
302
  // ignore the current request on unmount
219
303
  lastRequestId.current += 1;
220
304
  };
221
- }, [apiRef, props.dataSource, currentStrategy]);
305
+ }, [apiRef, props.dataSource, currentStrategy, stopPolling]);
222
306
  return {
223
307
  api: {
224
308
  public: dataSourceApi
@@ -230,13 +314,15 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
230
314
  processor: handleDataUpdate
231
315
  },
232
316
  setStrategyAvailability,
317
+ startPolling,
318
+ stopPolling,
233
319
  cacheChunkManager,
234
320
  cache,
235
321
  events: {
236
322
  strategyAvailabilityChange: handleStrategyActivityChange,
237
- sortModelChange: (0, _utils.runIf)(standardRowsUpdateStrategyActive, () => debouncedFetchRows()),
238
- filterModelChange: (0, _utils.runIf)(standardRowsUpdateStrategyActive, () => debouncedFetchRows()),
239
- 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)
240
326
  }
241
327
  };
242
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 v9.0.0-alpha.0
2
+ * @mui/x-data-grid v9.0.0-alpha.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
package/locales/csCZ.js CHANGED
@@ -131,7 +131,7 @@ const csCZGrid = {
131
131
  columnMenuManageColumns: 'Spravovat sloupce',
132
132
  columnMenuFilter: 'Filtr',
133
133
  columnMenuHideColumn: 'Skrýt',
134
- columnMenuUnsort: 'Zrušit filtry',
134
+ columnMenuUnsort: 'Zrušit řazení',
135
135
  columnMenuSortAsc: 'Seřadit vzestupně',
136
136
  columnMenuSortDesc: 'Seřadit sestupně',
137
137
  // columnMenuManagePivot: 'Manage pivot',
@@ -148,7 +148,7 @@ const csCZGrid = {
148
148
  return `${count} ${pluralForm}`;
149
149
  },
150
150
  columnHeaderFiltersLabel: 'Zobrazit filtry',
151
- columnHeaderSortIconLabel: 'Filtrovat',
151
+ columnHeaderSortIconLabel: 'Řadit',
152
152
  // Rows selected footer text
153
153
  footerRowSelected: count => {
154
154
  let pluralForm = 'vybraných záznamů';
package/locales/ukUA.js CHANGED
@@ -194,19 +194,19 @@ const ukUAGrid = {
194
194
  collapseDetailPanel: 'Приховати',
195
195
  // Pagination
196
196
  paginationRowsPerPage: 'Рядків на сторінці:',
197
- // paginationDisplayedRows: ({
198
- // from,
199
- // to,
200
- // count,
201
- // estimated
202
- // }) => {
203
- // const unknownRowCount = count == null || count === -1;
204
- // if (!estimated) {
205
- // return `${from}–${to} of ${!unknownRowCount ? count : `more than ${to}`}`;
206
- // }
207
- // const estimatedLabel = estimated && estimated > to ? `around ${estimated}` : `more than ${to}`;
208
- // return `${from}–${to} of ${!unknownRowCount ? count : estimatedLabel}`;
209
- // },
197
+ paginationDisplayedRows: ({
198
+ from,
199
+ to,
200
+ count,
201
+ estimated
202
+ }) => {
203
+ const unknownRowCount = count == null || count === -1;
204
+ if (!estimated) {
205
+ return `${from}–${to} з ${!unknownRowCount ? count : `більше ніж ${to}`}`;
206
+ }
207
+ const estimatedLabel = estimated && estimated > to ? `близько ${estimated}` : `більше ніж ${to}`;
208
+ return `${from}–${to} з ${!unknownRowCount ? count : estimatedLabel}`;
209
+ },
210
210
  paginationItemAriaLabel: type => {
211
211
  if (type === 'first') {
212
212
  return 'Перейти на першу сторінку';
@@ -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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-data-grid",
3
- "version": "9.0.0-alpha.0",
3
+ "version": "9.0.0-alpha.1",
4
4
  "author": "MUI Team",
5
5
  "description": "The Community plan edition of the MUI X Data Grid components.",
6
6
  "license": "MIT",
@@ -65,11 +65,13 @@
65
65
  "node": ">=14.0.0"
66
66
  },
67
67
  "type": "commonjs",
68
- "main": "./index.js",
69
- "types": "./index.d.ts",
70
68
  "exports": {
71
69
  "./package.json": "./package.json",
72
70
  ".": {
71
+ "import": {
72
+ "types": "./esm/index.d.ts",
73
+ "default": "./esm/index.js"
74
+ },
73
75
  "require": {
74
76
  "types": "./index.d.ts",
75
77
  "default": "./index.js"
@@ -80,6 +82,10 @@
80
82
  }
81
83
  },
82
84
  "./*": {
85
+ "import": {
86
+ "types": "./esm/*/index.d.ts",
87
+ "default": "./esm/*/index.js"
88
+ },
83
89
  "require": {
84
90
  "types": "./*/index.d.ts",
85
91
  "default": "./*/index.js"
@@ -90,5 +96,7 @@
90
96
  }
91
97
  },
92
98
  "./esm": null
93
- }
99
+ },
100
+ "main": "./index.js",
101
+ "types": "./index.d.ts"
94
102
  }
package/utils/utils.d.ts CHANGED
@@ -4,8 +4,8 @@ export declare function isObject<TObject = Record<PropertyKey, any>>(value: unkn
4
4
  export declare function localStorageAvailable(): boolean;
5
5
  export declare function escapeRegExp(value: string): string;
6
6
  /**
7
- * Follows the CSS specification behavior for min and max
8
- * If min > max, then the min have priority
7
+ * Follows the CSS specification behavior for min and max.
8
+ * If min > max, then min has priority.
9
9
  */
10
10
  export declare const clamp: (value: number, min: number, max: number) => number;
11
11
  /**
package/utils/utils.js CHANGED
@@ -41,8 +41,8 @@ function escapeRegExp(value) {
41
41
  }
42
42
 
43
43
  /**
44
- * Follows the CSS specification behavior for min and max
45
- * If min > max, then the min have priority
44
+ * Follows the CSS specification behavior for min and max.
45
+ * If min > max, then min has priority.
46
46
  */
47
47
  const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
48
48