@mui/x-data-grid 9.12.0 → 9.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +301 -0
  2. package/DataGrid/DataGrid.js +1 -1
  3. package/DataGrid/DataGrid.mjs +1 -1
  4. package/components/GridPagination.js +1 -1
  5. package/components/GridPagination.mjs +1 -1
  6. package/components/GridRow.d.mts +1 -0
  7. package/components/GridRow.d.ts +1 -0
  8. package/components/GridRow.js +41 -6
  9. package/components/GridRow.mjs +41 -6
  10. package/components/GridScrollArea.js +20 -7
  11. package/components/GridScrollArea.mjs +21 -8
  12. package/components/base/GridOverlays.js +6 -5
  13. package/components/base/GridOverlays.mjs +6 -5
  14. package/components/cell/GridActionsCell.js +53 -50
  15. package/components/cell/GridActionsCell.mjs +53 -50
  16. package/components/cell/GridActionsCellItem.js +0 -1
  17. package/components/cell/GridActionsCellItem.mjs +0 -1
  18. package/components/cell/GridCell.js +15 -4
  19. package/components/cell/GridCell.mjs +15 -4
  20. package/components/cell/GridEditBooleanCell.d.mts +1 -1
  21. package/components/cell/GridEditBooleanCell.d.ts +1 -1
  22. package/components/cell/GridEditBooleanCell.js +4 -4
  23. package/components/cell/GridEditBooleanCell.mjs +4 -4
  24. package/components/cell/GridEditDateCell.d.mts +1 -1
  25. package/components/cell/GridEditDateCell.d.ts +1 -1
  26. package/components/cell/GridEditDateCell.js +5 -5
  27. package/components/cell/GridEditDateCell.mjs +5 -5
  28. package/components/cell/GridEditInputCell.d.mts +1 -1
  29. package/components/cell/GridEditInputCell.d.ts +1 -1
  30. package/components/cell/GridEditInputCell.js +1 -1
  31. package/components/cell/GridEditInputCell.mjs +1 -1
  32. package/components/cell/GridEditLongTextCell.d.mts +1 -1
  33. package/components/cell/GridEditLongTextCell.d.ts +1 -1
  34. package/components/cell/GridEditLongTextCell.js +2 -2
  35. package/components/cell/GridEditLongTextCell.mjs +2 -2
  36. package/components/cell/GridEditSingleSelectCell.d.mts +1 -1
  37. package/components/cell/GridEditSingleSelectCell.d.ts +1 -1
  38. package/components/cell/GridEditSingleSelectCell.js +4 -4
  39. package/components/cell/GridEditSingleSelectCell.mjs +4 -4
  40. package/components/quickFilter/QuickFilter.js +7 -2
  41. package/components/quickFilter/QuickFilter.mjs +7 -2
  42. package/components/toolbarV8/Toolbar.d.mts +5 -1
  43. package/components/toolbarV8/Toolbar.d.ts +5 -1
  44. package/components/toolbarV8/Toolbar.js +34 -12
  45. package/components/toolbarV8/Toolbar.mjs +33 -11
  46. package/components/virtualization/GridVirtualScroller.js +3 -0
  47. package/components/virtualization/GridVirtualScroller.mjs +3 -0
  48. package/hooks/core/useGridVirtualizer.js +14 -1
  49. package/hooks/core/useGridVirtualizer.mjs +14 -1
  50. package/hooks/features/columnResize/useGridColumnResize.js +4 -1
  51. package/hooks/features/columnResize/useGridColumnResize.mjs +4 -1
  52. package/hooks/features/dataSource/models.d.mts +2 -2
  53. package/hooks/features/dataSource/models.d.ts +2 -2
  54. package/hooks/features/dataSource/useGridDataSourceBase.js +12 -8
  55. package/hooks/features/dataSource/useGridDataSourceBase.mjs +13 -9
  56. package/hooks/features/pivoting/gridPivotingInterfaces.d.mts +2 -2
  57. package/hooks/features/pivoting/gridPivotingInterfaces.d.ts +2 -2
  58. package/hooks/features/rowSelection/useGridRowSelection.d.mts +1 -1
  59. package/hooks/features/rowSelection/useGridRowSelection.d.ts +1 -1
  60. package/hooks/features/rowSelection/useGridRowSelection.js +51 -10
  61. package/hooks/features/rowSelection/useGridRowSelection.mjs +53 -12
  62. package/hooks/features/rowSelection/utils.js +5 -0
  63. package/hooks/features/rowSelection/utils.mjs +5 -0
  64. package/hooks/features/rows/gridRowsUtils.d.mts +37 -3
  65. package/hooks/features/rows/gridRowsUtils.d.ts +37 -3
  66. package/hooks/features/rows/gridRowsUtils.js +120 -23
  67. package/hooks/features/rows/gridRowsUtils.mjs +115 -22
  68. package/hooks/features/rows/useGridRows.js +10 -1
  69. package/hooks/features/rows/useGridRows.mjs +10 -1
  70. package/index.js +1 -1
  71. package/index.mjs +1 -1
  72. package/internals/index.d.mts +2 -2
  73. package/internals/index.d.ts +2 -2
  74. package/internals/index.js +28 -0
  75. package/internals/index.mjs +2 -2
  76. package/material/variables.d.mts +6 -1
  77. package/material/variables.d.ts +6 -1
  78. package/material/variables.js +17 -3
  79. package/material/variables.mjs +14 -4
  80. package/models/api/gridRowApi.d.mts +7 -7
  81. package/models/api/gridRowApi.d.ts +7 -7
  82. package/models/gridDataSource.d.mts +3 -0
  83. package/models/gridDataSource.d.ts +3 -0
  84. package/models/gridRows.d.mts +28 -1
  85. package/models/gridRows.d.ts +28 -1
  86. package/models/props/DataGridProps.d.mts +3 -3
  87. package/models/props/DataGridProps.d.ts +3 -3
  88. package/package.json +6 -6
  89. package/utils/keyboardUtils.d.mts +1 -0
  90. package/utils/keyboardUtils.d.ts +1 -0
  91. package/utils/keyboardUtils.js +6 -0
  92. package/utils/keyboardUtils.mjs +5 -0
@@ -7,7 +7,7 @@ export interface GridEditLongTextCellProps extends GridRenderEditCellParams<any,
7
7
  * Callback called when the value is changed by the user.
8
8
  * @param {React.ChangeEvent<HTMLTextAreaElement>} event The event source of the callback.
9
9
  * @param {string} newValue The value that is going to be passed to `apiRef.current.setEditCellValue`.
10
- * @returns {Promise<void> | void} A promise to be awaited before calling `apiRef.current.setEditCellValue`
10
+ * @returns {Promise<void> | void} A promise to be awaited after `apiRef.current.setEditCellValue` is called
11
11
  */
12
12
  onValueChange?: (event: React.ChangeEvent<HTMLTextAreaElement>, newValue: string) => Promise<void> | void;
13
13
  /**
@@ -7,7 +7,7 @@ export interface GridEditLongTextCellProps extends GridRenderEditCellParams<any,
7
7
  * Callback called when the value is changed by the user.
8
8
  * @param {React.ChangeEvent<HTMLTextAreaElement>} event The event source of the callback.
9
9
  * @param {string} newValue The value that is going to be passed to `apiRef.current.setEditCellValue`.
10
- * @returns {Promise<void> | void} A promise to be awaited before calling `apiRef.current.setEditCellValue`
10
+ * @returns {Promise<void> | void} A promise to be awaited after `apiRef.current.setEditCellValue` is called
11
11
  */
12
12
  onValueChange?: (event: React.ChangeEvent<HTMLTextAreaElement>, newValue: string) => Promise<void> | void;
13
13
  /**
@@ -217,7 +217,7 @@ process.env.NODE_ENV !== "production" ? GridEditLongTextCell.propTypes /* remove
217
217
  * Callback called when the value is changed by the user.
218
218
  * @param {React.ChangeEvent<HTMLTextAreaElement>} event The event source of the callback.
219
219
  * @param {string} newValue The value that is going to be passed to `apiRef.current.setEditCellValue`.
220
- * @returns {Promise<void> | void} A promise to be awaited before calling `apiRef.current.setEditCellValue`
220
+ * @returns {Promise<void> | void} A promise to be awaited after `apiRef.current.setEditCellValue` is called
221
221
  */
222
222
  onValueChange: _propTypes.default.func,
223
223
  /**
@@ -359,7 +359,7 @@ process.env.NODE_ENV !== "production" ? GridEditLongTextarea.propTypes /* remove
359
359
  * Callback called when the value is changed by the user.
360
360
  * @param {React.ChangeEvent<HTMLTextAreaElement>} event The event source of the callback.
361
361
  * @param {string} newValue The value that is going to be passed to `apiRef.current.setEditCellValue`.
362
- * @returns {Promise<void> | void} A promise to be awaited before calling `apiRef.current.setEditCellValue`
362
+ * @returns {Promise<void> | void} A promise to be awaited after `apiRef.current.setEditCellValue` is called
363
363
  */
364
364
  onValueChange: _propTypes.default.func,
365
365
  /**
@@ -209,7 +209,7 @@ process.env.NODE_ENV !== "production" ? GridEditLongTextCell.propTypes /* remove
209
209
  * Callback called when the value is changed by the user.
210
210
  * @param {React.ChangeEvent<HTMLTextAreaElement>} event The event source of the callback.
211
211
  * @param {string} newValue The value that is going to be passed to `apiRef.current.setEditCellValue`.
212
- * @returns {Promise<void> | void} A promise to be awaited before calling `apiRef.current.setEditCellValue`
212
+ * @returns {Promise<void> | void} A promise to be awaited after `apiRef.current.setEditCellValue` is called
213
213
  */
214
214
  onValueChange: PropTypes.func,
215
215
  /**
@@ -351,7 +351,7 @@ process.env.NODE_ENV !== "production" ? GridEditLongTextarea.propTypes /* remove
351
351
  * Callback called when the value is changed by the user.
352
352
  * @param {React.ChangeEvent<HTMLTextAreaElement>} event The event source of the callback.
353
353
  * @param {string} newValue The value that is going to be passed to `apiRef.current.setEditCellValue`.
354
- * @returns {Promise<void> | void} A promise to be awaited before calling `apiRef.current.setEditCellValue`
354
+ * @returns {Promise<void> | void} A promise to be awaited after `apiRef.current.setEditCellValue` is called
355
355
  */
356
356
  onValueChange: PropTypes.func,
357
357
  /**
@@ -6,7 +6,7 @@ export interface GridEditSingleSelectCellProps extends GridRenderEditCellParams
6
6
  * Callback called when the value is changed by the user.
7
7
  * @param {Event<any>} event The event source of the callback.
8
8
  * @param {any} newValue The value that is going to be passed to `apiRef.current.setEditCellValue`.
9
- * @returns {Promise<void> | void} A promise to be awaited before calling `apiRef.current.setEditCellValue`
9
+ * @returns {Promise<void> | void} A promise to be awaited after `apiRef.current.setEditCellValue` is called
10
10
  */
11
11
  onValueChange?: (event: Parameters<NonNullable<GridSlotProps['baseSelect']['onOpen']>>[0], newValue: any) => Promise<void> | void;
12
12
  /**
@@ -6,7 +6,7 @@ export interface GridEditSingleSelectCellProps extends GridRenderEditCellParams
6
6
  * Callback called when the value is changed by the user.
7
7
  * @param {Event<any>} event The event source of the callback.
8
8
  * @param {any} newValue The value that is going to be passed to `apiRef.current.setEditCellValue`.
9
- * @returns {Promise<void> | void} A promise to be awaited before calling `apiRef.current.setEditCellValue`
9
+ * @returns {Promise<void> | void} A promise to be awaited after `apiRef.current.setEditCellValue` is called
10
10
  */
11
11
  onValueChange?: (event: Parameters<NonNullable<GridSlotProps['baseSelect']['onOpen']>>[0], newValue: any) => Promise<void> | void;
12
12
  /**
@@ -70,14 +70,14 @@ function GridEditSingleSelectCell(props) {
70
70
  const target = event.target;
71
71
  // NativeSelect casts the value to a string.
72
72
  const formattedTargetValue = (0, _filterPanelUtils.getValueFromValueOptions)(target.value, valueOptions, getOptionValue);
73
- if (onValueChange) {
74
- await onValueChange(event, formattedTargetValue);
75
- }
76
73
  await apiRef.current.setEditCellValue({
77
74
  id,
78
75
  field,
79
76
  value: formattedTargetValue
80
77
  }, event);
78
+ if (onValueChange) {
79
+ await onValueChange(event, formattedTargetValue);
80
+ }
81
81
  };
82
82
  const handleClose = (event, reason) => {
83
83
  if (rootProps.editMode === _gridEditRowModel.GridEditModes.Row) {
@@ -174,7 +174,7 @@ process.env.NODE_ENV !== "production" ? GridEditSingleSelectCell.propTypes /* re
174
174
  * Callback called when the value is changed by the user.
175
175
  * @param {Event<any>} event The event source of the callback.
176
176
  * @param {any} newValue The value that is going to be passed to `apiRef.current.setEditCellValue`.
177
- * @returns {Promise<void> | void} A promise to be awaited before calling `apiRef.current.setEditCellValue`
177
+ * @returns {Promise<void> | void} A promise to be awaited after `apiRef.current.setEditCellValue` is called
178
178
  */
179
179
  onValueChange: _propTypes.default.func,
180
180
  /**
@@ -62,14 +62,14 @@ function GridEditSingleSelectCell(props) {
62
62
  const target = event.target;
63
63
  // NativeSelect casts the value to a string.
64
64
  const formattedTargetValue = getValueFromValueOptions(target.value, valueOptions, getOptionValue);
65
- if (onValueChange) {
66
- await onValueChange(event, formattedTargetValue);
67
- }
68
65
  await apiRef.current.setEditCellValue({
69
66
  id,
70
67
  field,
71
68
  value: formattedTargetValue
72
69
  }, event);
70
+ if (onValueChange) {
71
+ await onValueChange(event, formattedTargetValue);
72
+ }
73
73
  };
74
74
  const handleClose = (event, reason) => {
75
75
  if (rootProps.editMode === GridEditModes.Row) {
@@ -166,7 +166,7 @@ process.env.NODE_ENV !== "production" ? GridEditSingleSelectCell.propTypes /* re
166
166
  * Callback called when the value is changed by the user.
167
167
  * @param {Event<any>} event The event source of the callback.
168
168
  * @param {any} newValue The value that is going to be passed to `apiRef.current.setEditCellValue`.
169
- * @returns {Promise<void> | void} A promise to be awaited before calling `apiRef.current.setEditCellValue`
169
+ * @returns {Promise<void> | void} A promise to be awaited after `apiRef.current.setEditCellValue` is called
170
170
  */
171
171
  onValueChange: PropTypes.func,
172
172
  /**
@@ -13,6 +13,7 @@ var React = _interopRequireWildcard(require("react"));
13
13
  var _propTypes = _interopRequireDefault(require("prop-types"));
14
14
  var _debounce = _interopRequireDefault(require("@mui/utils/debounce"));
15
15
  var _useEnhancedEffect = _interopRequireDefault(require("@mui/utils/useEnhancedEffect"));
16
+ var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
16
17
  var _useId = _interopRequireDefault(require("@mui/utils/useId"));
17
18
  var _isDeepEqual = require("@mui/x-internals/isDeepEqual");
18
19
  var _useComponentRenderer = require("@mui/x-internals/useComponentRenderer");
@@ -108,11 +109,15 @@ function QuickFilter(props) {
108
109
  previousExpandedValue.current = expandedValue;
109
110
  }
110
111
  }, [expandedValue]);
111
- const setQuickFilterValueDebounced = React.useMemo(() => (0, _debounce.default)(newValue => {
112
+
113
+ // Identity-stable, so that a re-render with a new `parser` does not recreate the debounced
114
+ // function below and clear a pending commit. See https://github.com/mui/mui-x/issues/23572.
115
+ const commitQuickFilterValue = (0, _useEventCallback.default)(newValue => {
112
116
  const newQuickFilterValues = parser(newValue);
113
117
  prevQuickFilterValuesRef.current = newQuickFilterValues;
114
118
  apiRef.current.setQuickFilterValues(newQuickFilterValues);
115
- }, debounceMs), [apiRef, debounceMs, parser]);
119
+ });
120
+ const setQuickFilterValueDebounced = React.useMemo(() => (0, _debounce.default)(commitQuickFilterValue, debounceMs), [commitQuickFilterValue, debounceMs]);
116
121
  React.useEffect(() => setQuickFilterValueDebounced.clear, [setQuickFilterValueDebounced]);
117
122
  const handleValueChange = React.useCallback(event => {
118
123
  const newValue = event.target.value;
@@ -7,6 +7,7 @@ import * as React from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import debounce from '@mui/utils/debounce';
9
9
  import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
10
+ import useEventCallback from '@mui/utils/useEventCallback';
10
11
  import useId from '@mui/utils/useId';
11
12
  import { isDeepEqual } from '@mui/x-internals/isDeepEqual';
12
13
  import { useComponentRenderer } from '@mui/x-internals/useComponentRenderer';
@@ -101,11 +102,15 @@ function QuickFilter(props) {
101
102
  previousExpandedValue.current = expandedValue;
102
103
  }
103
104
  }, [expandedValue]);
104
- const setQuickFilterValueDebounced = React.useMemo(() => debounce(newValue => {
105
+
106
+ // Identity-stable, so that a re-render with a new `parser` does not recreate the debounced
107
+ // function below and clear a pending commit. See https://github.com/mui/mui-x/issues/23572.
108
+ const commitQuickFilterValue = useEventCallback(newValue => {
105
109
  const newQuickFilterValues = parser(newValue);
106
110
  prevQuickFilterValuesRef.current = newQuickFilterValues;
107
111
  apiRef.current.setQuickFilterValues(newQuickFilterValues);
108
- }, debounceMs), [apiRef, debounceMs, parser]);
112
+ });
113
+ const setQuickFilterValueDebounced = React.useMemo(() => debounce(commitQuickFilterValue, debounceMs), [commitQuickFilterValue, debounceMs]);
109
114
  React.useEffect(() => setQuickFilterValueDebounced.clear, [setQuickFilterValueDebounced]);
110
115
  const handleValueChange = React.useCallback(event => {
111
116
  const newValue = event.target.value;
@@ -6,6 +6,10 @@ export type ToolbarProps = React.HTMLAttributes<HTMLDivElement> & {
6
6
  */
7
7
  render?: RenderProp<React.ComponentProps<typeof ToolbarRoot>>;
8
8
  };
9
+ /**
10
+ * The styled `<div />` element rendered by the `<Toolbar />` component.
11
+ * Use it to apply the toolbar styles to other elements, inside or outside of a Data Grid.
12
+ */
9
13
  declare const ToolbarRoot: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme>, Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof React.ClassAttributes<HTMLDivElement> | keyof React.HTMLAttributes<HTMLDivElement>>, {}>;
10
14
  /**
11
15
  * The top level Toolbar component that provides context to child components.
@@ -25,4 +29,4 @@ declare const Toolbar: React.ForwardRefExoticComponent<ToolbarProps> | React.For
25
29
  */
26
30
  render?: RenderProp<React.ComponentProps<typeof ToolbarRoot>>;
27
31
  } & React.RefAttributes<HTMLDivElement>>;
28
- export { Toolbar };
32
+ export { Toolbar, ToolbarRoot };
@@ -6,6 +6,10 @@ export type ToolbarProps = React.HTMLAttributes<HTMLDivElement> & {
6
6
  */
7
7
  render?: RenderProp<React.ComponentProps<typeof ToolbarRoot>>;
8
8
  };
9
+ /**
10
+ * The styled `<div />` element rendered by the `<Toolbar />` component.
11
+ * Use it to apply the toolbar styles to other elements, inside or outside of a Data Grid.
12
+ */
9
13
  declare const ToolbarRoot: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme>, Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof React.ClassAttributes<HTMLDivElement> | keyof React.HTMLAttributes<HTMLDivElement>>, {}>;
10
14
  /**
11
15
  * The top level Toolbar component that provides context to child components.
@@ -25,4 +29,4 @@ declare const Toolbar: React.ForwardRefExoticComponent<ToolbarProps> | React.For
25
29
  */
26
30
  render?: RenderProp<React.ComponentProps<typeof ToolbarRoot>>;
27
31
  } & React.RefAttributes<HTMLDivElement>>;
28
- export { Toolbar };
32
+ export { Toolbar, ToolbarRoot };
@@ -6,7 +6,7 @@ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWild
6
6
  Object.defineProperty(exports, "__esModule", {
7
7
  value: true
8
8
  });
9
- exports.Toolbar = void 0;
9
+ exports.ToolbarRoot = exports.Toolbar = void 0;
10
10
  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"));
@@ -18,6 +18,7 @@ var _forwardRef = require("@mui/x-internals/forwardRef");
18
18
  var _useComponentRenderer = require("@mui/x-internals/useComponentRenderer");
19
19
  var _ToolbarContext = require("@mui/x-internals/ToolbarContext");
20
20
  var _cssVariables = require("../../constants/cssVariables");
21
+ var _variables = require("../../material/variables");
21
22
  var _gridClasses = require("../../constants/gridClasses");
22
23
  var _useGridRootProps = require("../../hooks/utils/useGridRootProps");
23
24
  var _jsxRuntime = require("react/jsx-runtime");
@@ -31,19 +32,40 @@ const useUtilityClasses = ownerState => {
31
32
  };
32
33
  return (0, _composeClasses.default)(slots, _gridClasses.getDataGridUtilityClass, classes);
33
34
  };
34
- const ToolbarRoot = (0, _styles.styled)('div', {
35
+
36
+ /**
37
+ * The styled `<div />` element rendered by the `<Toolbar />` component.
38
+ * Use it to apply the toolbar styles to other elements, inside or outside of a Data Grid.
39
+ */
40
+ const ToolbarRoot = exports.ToolbarRoot = (0, _styles.styled)('div', {
35
41
  name: 'MuiDataGrid',
36
42
  slot: 'Toolbar'
37
- })({
38
- flex: '0 1 1px',
39
- display: 'flex',
40
- alignItems: 'center',
41
- justifyContent: 'end',
42
- gap: _cssVariables.vars.spacing(0.25),
43
- padding: _cssVariables.vars.spacing(0.75),
44
- minHeight: 52,
45
- boxSizing: 'border-box',
46
- borderBottom: `1px solid ${_cssVariables.vars.colors.border.base}`
43
+ })(({
44
+ theme
45
+ }) => {
46
+ // The Data Grid CSS variables are only defined on the Data Grid root element, so they are
47
+ // declared with a fallback to keep the styles working when rendered outside of a Data Grid.
48
+ const spacingUnit = `var(${_cssVariables.vars.keys.spacingUnit}, ${(0, _variables.getSpacingUnit)(theme)})`;
49
+ const borderColor = `var(${_cssVariables.vars.keys.colors.border.base}, ${(0, _variables.getBorderColor)(theme)})`;
50
+ const background = `var(${_cssVariables.vars.keys.colors.background.base}, ${(0, _variables.getBackgroundBase)(theme)})`;
51
+ const foreground = `var(${_cssVariables.vars.keys.colors.foreground.base}, ${(theme.vars || theme).palette.text.primary})`;
52
+ const fontBody = (0, _variables.getFontBody)(theme);
53
+ return {
54
+ flex: '0 1 1px',
55
+ display: 'flex',
56
+ alignItems: 'center',
57
+ justifyContent: 'end',
58
+ gap: `calc(${spacingUnit} * 0.25)`,
59
+ padding: `calc(${spacingUnit} * 0.75)`,
60
+ minHeight: 52,
61
+ boxSizing: 'border-box',
62
+ borderBottom: `1px solid ${borderColor}`,
63
+ // Inherited from the Data Grid root inside a grid, declared here so the component keeps
64
+ // matching it when rendered on its own.
65
+ backgroundColor: background,
66
+ color: foreground,
67
+ font: fontBody ? `var(${_cssVariables.vars.keys.typography.font.body}, ${fontBody})` : undefined
68
+ };
47
69
  });
48
70
 
49
71
  /**
@@ -12,6 +12,7 @@ import { forwardRef } from '@mui/x-internals/forwardRef';
12
12
  import { useComponentRenderer } from '@mui/x-internals/useComponentRenderer';
13
13
  import { ToolbarContextProvider } from '@mui/x-internals/ToolbarContext';
14
14
  import { vars } from "../../constants/cssVariables.mjs";
15
+ import { getBackgroundBase, getBorderColor, getFontBody, getSpacingUnit } from "../../material/variables.mjs";
15
16
  import { getDataGridUtilityClass } from "../../constants/gridClasses.mjs";
16
17
  import { useGridRootProps } from "../../hooks/utils/useGridRootProps.mjs";
17
18
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -24,19 +25,40 @@ const useUtilityClasses = ownerState => {
24
25
  };
25
26
  return composeClasses(slots, getDataGridUtilityClass, classes);
26
27
  };
28
+
29
+ /**
30
+ * The styled `<div />` element rendered by the `<Toolbar />` component.
31
+ * Use it to apply the toolbar styles to other elements, inside or outside of a Data Grid.
32
+ */
27
33
  const ToolbarRoot = styled('div', {
28
34
  name: 'MuiDataGrid',
29
35
  slot: 'Toolbar'
30
- })({
31
- flex: '0 1 1px',
32
- display: 'flex',
33
- alignItems: 'center',
34
- justifyContent: 'end',
35
- gap: vars.spacing(0.25),
36
- padding: vars.spacing(0.75),
37
- minHeight: 52,
38
- boxSizing: 'border-box',
39
- borderBottom: `1px solid ${vars.colors.border.base}`
36
+ })(({
37
+ theme
38
+ }) => {
39
+ // The Data Grid CSS variables are only defined on the Data Grid root element, so they are
40
+ // declared with a fallback to keep the styles working when rendered outside of a Data Grid.
41
+ const spacingUnit = `var(${vars.keys.spacingUnit}, ${getSpacingUnit(theme)})`;
42
+ const borderColor = `var(${vars.keys.colors.border.base}, ${getBorderColor(theme)})`;
43
+ const background = `var(${vars.keys.colors.background.base}, ${getBackgroundBase(theme)})`;
44
+ const foreground = `var(${vars.keys.colors.foreground.base}, ${(theme.vars || theme).palette.text.primary})`;
45
+ const fontBody = getFontBody(theme);
46
+ return {
47
+ flex: '0 1 1px',
48
+ display: 'flex',
49
+ alignItems: 'center',
50
+ justifyContent: 'end',
51
+ gap: `calc(${spacingUnit} * 0.25)`,
52
+ padding: `calc(${spacingUnit} * 0.75)`,
53
+ minHeight: 52,
54
+ boxSizing: 'border-box',
55
+ borderBottom: `1px solid ${borderColor}`,
56
+ // Inherited from the Data Grid root inside a grid, declared here so the component keeps
57
+ // matching it when rendered on its own.
58
+ backgroundColor: background,
59
+ color: foreground,
60
+ font: fontBody ? `var(${vars.keys.typography.font.body}, ${fontBody})` : undefined
61
+ };
40
62
  });
41
63
 
42
64
  /**
@@ -82,4 +104,4 @@ process.env.NODE_ENV !== "production" ? Toolbar.propTypes /* remove-proptypes */
82
104
  */
83
105
  render: PropTypes.oneOfType([PropTypes.element, PropTypes.func])
84
106
  } : void 0;
85
- export { Toolbar };
107
+ export { Toolbar, ToolbarRoot };
@@ -93,7 +93,10 @@ const Viewport = (0, _styles.styled)('div', {
93
93
  display: 'inline-block',
94
94
  position: 'sticky',
95
95
  top: 0,
96
+ // The viewport spans the scrollport exactly, so both 0-insets resolve to the same
97
+ // offset and it stays pinned in LTR and RTL alike.
96
98
  left: 0,
99
+ right: 0,
97
100
  overflow: 'hidden'
98
101
  }
99
102
  });
@@ -85,7 +85,10 @@ const Viewport = styled('div', {
85
85
  display: 'inline-block',
86
86
  position: 'sticky',
87
87
  top: 0,
88
+ // The viewport spans the scrollport exactly, so both 0-insets resolve to the same
89
+ // offset and it stays pinned in LTR and RTL alike.
88
90
  left: 0,
91
+ right: 0,
89
92
  overflow: 'hidden'
90
93
  }
91
94
  });
@@ -67,6 +67,18 @@ function useGridVirtualizer() {
67
67
  listView
68
68
  } = rootProps;
69
69
  const visibleColumns = (0, _useGridSelector.useGridSelector)(apiRef, _gridColumnsSelector.gridVisibleColumnDefinitionsSelector);
70
+ // Convert visible row-header columns to their indexes once per column-model change. Each GridRow
71
+ // uses this ordered list to render those cells even when they fall outside its horizontal render
72
+ // context. This keeps the row-identifying cells available to assistive technology while scrolling.
73
+ const retainedColumnIndexes = React.useMemo(() => {
74
+ const indexes = [];
75
+ visibleColumns.forEach((column, index) => {
76
+ if (column.rowHeader) {
77
+ indexes.push(index);
78
+ }
79
+ });
80
+ return indexes;
81
+ }, [visibleColumns]);
70
82
  const pinnedRows = (0, _useGridSelector.useGridSelector)(apiRef, _gridRowsSelector.gridPinnedRowsSelector);
71
83
  const pinnedColumns = (0, _gridColumnsSelector.gridVisiblePinnedColumnDefinitionsSelector)(apiRef);
72
84
  const rowSelectionManager = (0, _useGridSelector.useGridSelector)(apiRef, _rowSelection.gridRowSelectionManagerSelector);
@@ -219,6 +231,7 @@ function useGridVirtualizer() {
219
231
  rowHeight: params.baseRowHeight,
220
232
  pinnedColumns: pinnedColumns,
221
233
  visibleColumns: visibleColumns,
234
+ retainedColumnIndexes: retainedColumnIndexes,
222
235
  firstColumnIndex: params.firstColumnIndex,
223
236
  lastColumnIndex: params.lastColumnIndex,
224
237
  focusedColumnIndex: params.focusedColumnIndex,
@@ -228,7 +241,7 @@ function useGridVirtualizer() {
228
241
  showBottomBorder: params.showBottomBorder,
229
242
  scrollbarWidth: verticalScrollbarWidth,
230
243
  gridHasFiller: hasFiller
231
- }, rowSlotProps), params.id), [columnsTotalWidth, hasFiller, isRowSelected, pinnedColumns, RowSlot, rowSlotProps, verticalScrollbarWidth, visibleColumns]),
244
+ }, rowSlotProps), params.id), [columnsTotalWidth, hasFiller, isRowSelected, pinnedColumns, retainedColumnIndexes, RowSlot, rowSlotProps, verticalScrollbarWidth, visibleColumns]),
232
245
  renderInfiniteLoadingTrigger: React.useCallback(id => apiRef.current.getInfiniteLoadingTriggerElement?.({
233
246
  lastRowId: id
234
247
  }), [apiRef])
@@ -59,6 +59,18 @@ export function useGridVirtualizer() {
59
59
  listView
60
60
  } = rootProps;
61
61
  const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector);
62
+ // Convert visible row-header columns to their indexes once per column-model change. Each GridRow
63
+ // uses this ordered list to render those cells even when they fall outside its horizontal render
64
+ // context. This keeps the row-identifying cells available to assistive technology while scrolling.
65
+ const retainedColumnIndexes = React.useMemo(() => {
66
+ const indexes = [];
67
+ visibleColumns.forEach((column, index) => {
68
+ if (column.rowHeader) {
69
+ indexes.push(index);
70
+ }
71
+ });
72
+ return indexes;
73
+ }, [visibleColumns]);
62
74
  const pinnedRows = useGridSelector(apiRef, gridPinnedRowsSelector);
63
75
  const pinnedColumns = gridVisiblePinnedColumnDefinitionsSelector(apiRef);
64
76
  const rowSelectionManager = useGridSelector(apiRef, gridRowSelectionManagerSelector);
@@ -211,6 +223,7 @@ export function useGridVirtualizer() {
211
223
  rowHeight: params.baseRowHeight,
212
224
  pinnedColumns: pinnedColumns,
213
225
  visibleColumns: visibleColumns,
226
+ retainedColumnIndexes: retainedColumnIndexes,
214
227
  firstColumnIndex: params.firstColumnIndex,
215
228
  lastColumnIndex: params.lastColumnIndex,
216
229
  focusedColumnIndex: params.focusedColumnIndex,
@@ -220,7 +233,7 @@ export function useGridVirtualizer() {
220
233
  showBottomBorder: params.showBottomBorder,
221
234
  scrollbarWidth: verticalScrollbarWidth,
222
235
  gridHasFiller: hasFiller
223
- }, rowSlotProps), params.id), [columnsTotalWidth, hasFiller, isRowSelected, pinnedColumns, RowSlot, rowSlotProps, verticalScrollbarWidth, visibleColumns]),
236
+ }, rowSlotProps), params.id), [columnsTotalWidth, hasFiller, isRowSelected, pinnedColumns, retainedColumnIndexes, RowSlot, rowSlotProps, verticalScrollbarWidth, visibleColumns]),
224
237
  renderInfiniteLoadingTrigger: React.useCallback(id => apiRef.current.getInfiniteLoadingTriggerElement?.({
225
238
  lastRowId: id
226
239
  }), [apiRef])
@@ -464,7 +464,10 @@ const useGridColumnResize = (apiRef, props) => {
464
464
  });
465
465
  const stopListening = React.useCallback(() => {
466
466
  const doc = (0, _ownerDocument.default)(apiRef.current.rootElementRef.current);
467
- doc.body.style.removeProperty('cursor');
467
+ // Also runs as this effect's unmount cleanup, which can execute against a
468
+ // document that no longer has a body. The cursor is only ever set while a
469
+ // resize is in progress, so there is nothing to clear in that case.
470
+ doc.body?.style.removeProperty('cursor');
468
471
  doc.removeEventListener('mousemove', handleResizeMouseMove);
469
472
  doc.removeEventListener('mouseup', handleResizeMouseUp);
470
473
  doc.removeEventListener('touchmove', handleTouchMove);
@@ -456,7 +456,10 @@ export const useGridColumnResize = (apiRef, props) => {
456
456
  });
457
457
  const stopListening = React.useCallback(() => {
458
458
  const doc = ownerDocument(apiRef.current.rootElementRef.current);
459
- doc.body.style.removeProperty('cursor');
459
+ // Also runs as this effect's unmount cleanup, which can execute against a
460
+ // document that no longer has a body. The cursor is only ever set while a
461
+ // resize is in progress, so there is nothing to clear in that case.
462
+ doc.body?.style.removeProperty('cursor');
460
463
  doc.removeEventListener('mousemove', handleResizeMouseMove);
461
464
  doc.removeEventListener('mouseup', handleResizeMouseUp);
462
465
  doc.removeEventListener('touchmove', handleTouchMove);
@@ -1,5 +1,5 @@
1
1
  import type { GridDataSourceCache, GridGetRowsParams, GridUpdateRowParams, GridGetRowsOptions } from "../../../models/gridDataSource.mjs";
2
- import type { GridRowId, GridRowModel } from "../../../models/gridRows.mjs";
2
+ import type { GridRowId, GridRowModel, GridRowModelReplace, GridRowModelUpdate } from "../../../models/gridRows.mjs";
3
3
  import type { GridDataSourceCacheDefaultConfig } from "./cache.mjs";
4
4
  /**
5
5
  * The parameters for the `fetchRows` method.
@@ -43,5 +43,5 @@ export interface GridDataSourceBaseOptions {
43
43
  cacheOptions?: GridDataSourceCacheDefaultConfig;
44
44
  fetchRowChildren?: (parents: GridRowId[], fetchParams: GridGetRowsParams[], showChildrenLoading?: boolean) => void;
45
45
  clearDataSourceState?: () => void;
46
- handleEditRow?: (params: GridUpdateRowParams, updatedRow: GridRowModel) => void;
46
+ handleEditRow?: (params: GridUpdateRowParams, rowUpdate: GridRowModelUpdate | GridRowModelReplace) => void;
47
47
  }
@@ -1,5 +1,5 @@
1
1
  import type { GridDataSourceCache, GridGetRowsParams, GridUpdateRowParams, GridGetRowsOptions } from "../../../models/gridDataSource.js";
2
- import type { GridRowId, GridRowModel } from "../../../models/gridRows.js";
2
+ import type { GridRowId, GridRowModel, GridRowModelReplace, GridRowModelUpdate } from "../../../models/gridRows.js";
3
3
  import type { GridDataSourceCacheDefaultConfig } from "./cache.js";
4
4
  /**
5
5
  * The parameters for the `fetchRows` method.
@@ -43,5 +43,5 @@ export interface GridDataSourceBaseOptions {
43
43
  cacheOptions?: GridDataSourceCacheDefaultConfig;
44
44
  fetchRowChildren?: (parents: GridRowId[], fetchParams: GridGetRowsParams[], showChildrenLoading?: boolean) => void;
45
45
  clearDataSourceState?: () => void;
46
- handleEditRow?: (params: GridUpdateRowParams, updatedRow: GridRowModel) => void;
46
+ handleEditRow?: (params: GridUpdateRowParams, rowUpdate: GridRowModelUpdate | GridRowModelReplace) => void;
47
47
  }
@@ -83,7 +83,7 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
83
83
  // The selector prunes the incomplete items, but a caller passing its own `filterModel`
84
84
  // overrides it, so prune again on the merged params.
85
85
  fetchParams.filterModel = (0, _gridFilterUtils.removeIncompleteFilterItems)(fetchParams.filterModel, (0, _columns.gridColumnLookupSelector)(apiRef));
86
- if (parentId && parentId !== _gridRowsUtils.GRID_ROOT_GROUP_ID && props.signature !== 'DataGrid') {
86
+ if (parentId != null && parentId !== _gridRowsUtils.GRID_ROOT_GROUP_ID && props.signature !== 'DataGrid') {
87
87
  options.fetchRowChildren?.([parentId], [fetchParams], showChildrenLoading);
88
88
  return;
89
89
  }
@@ -254,16 +254,20 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
254
254
  }
255
255
  try {
256
256
  const finalRowUpdate = await dataSourceUpdateRow(params);
257
- if (typeof handleEditRowOption === 'function') {
258
- handleEditRowOption(params, finalRowUpdate);
259
- return finalRowUpdate;
260
- }
261
- if (finalRowUpdate && !(0, _isDeepEqual.isDeepEqual)(finalRowUpdate, params.previousRow)) {
257
+ // `dataSource.updateRow()` can resolve with a `{ _action: 'replace', row }` update.
258
+ // The row update methods unwrap it themselves, everything else works with the row it
259
+ // holds: comparing the envelope with the previous row would never match.
260
+ const updatedRow = finalRowUpdate && (0, _gridRowsUtils.isReplaceUpdate)(finalRowUpdate) ? (0, _gridRowsUtils.getReplaceRow)(finalRowUpdate) : finalRowUpdate;
261
+ if (updatedRow && !(0, _isDeepEqual.isDeepEqual)(updatedRow, params.previousRow)) {
262
262
  // Reset the outdated cache, only if the row is _actually_ updated
263
263
  apiRef.current.dataSource.cache.clear();
264
264
  }
265
- apiRef.current.updateNestedRows([finalRowUpdate], []);
266
- return finalRowUpdate;
265
+ if (typeof handleEditRowOption === 'function') {
266
+ handleEditRowOption(params, finalRowUpdate);
267
+ } else {
268
+ apiRef.current.updateNestedRows([finalRowUpdate], []);
269
+ }
270
+ return updatedRow;
267
271
  } catch (errorThrown) {
268
272
  if (typeof onDataSourceErrorProp === 'function') {
269
273
  onDataSourceErrorProp(new _gridDataSourceError.GridUpdateRowError({
@@ -9,7 +9,7 @@ import useEventCallback from '@mui/utils/useEventCallback';
9
9
  import debounce from '@mui/utils/debounce';
10
10
  import { warnOnce } from '@mui/x-internals/warning';
11
11
  import { isDeepEqual } from '@mui/x-internals/isDeepEqual';
12
- import { GRID_ROOT_GROUP_ID } from "../rows/gridRowsUtils.mjs";
12
+ import { GRID_ROOT_GROUP_ID, getReplaceRow, isReplaceUpdate } from "../rows/gridRowsUtils.mjs";
13
13
  import { runIf } from "../../../utils/utils.mjs";
14
14
  import { GridStrategyGroup } from "../../core/strategyProcessing/index.mjs";
15
15
  import { useGridSelector } from "../../utils/useGridSelector.mjs";
@@ -76,7 +76,7 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
76
76
  // The selector prunes the incomplete items, but a caller passing its own `filterModel`
77
77
  // overrides it, so prune again on the merged params.
78
78
  fetchParams.filterModel = removeIncompleteFilterItems(fetchParams.filterModel, gridColumnLookupSelector(apiRef));
79
- if (parentId && parentId !== GRID_ROOT_GROUP_ID && props.signature !== 'DataGrid') {
79
+ if (parentId != null && parentId !== GRID_ROOT_GROUP_ID && props.signature !== 'DataGrid') {
80
80
  options.fetchRowChildren?.([parentId], [fetchParams], showChildrenLoading);
81
81
  return;
82
82
  }
@@ -247,16 +247,20 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
247
247
  }
248
248
  try {
249
249
  const finalRowUpdate = await dataSourceUpdateRow(params);
250
- if (typeof handleEditRowOption === 'function') {
251
- handleEditRowOption(params, finalRowUpdate);
252
- return finalRowUpdate;
253
- }
254
- if (finalRowUpdate && !isDeepEqual(finalRowUpdate, params.previousRow)) {
250
+ // `dataSource.updateRow()` can resolve with a `{ _action: 'replace', row }` update.
251
+ // The row update methods unwrap it themselves, everything else works with the row it
252
+ // holds: comparing the envelope with the previous row would never match.
253
+ const updatedRow = finalRowUpdate && isReplaceUpdate(finalRowUpdate) ? getReplaceRow(finalRowUpdate) : finalRowUpdate;
254
+ if (updatedRow && !isDeepEqual(updatedRow, params.previousRow)) {
255
255
  // Reset the outdated cache, only if the row is _actually_ updated
256
256
  apiRef.current.dataSource.cache.clear();
257
257
  }
258
- apiRef.current.updateNestedRows([finalRowUpdate], []);
259
- return finalRowUpdate;
258
+ if (typeof handleEditRowOption === 'function') {
259
+ handleEditRowOption(params, finalRowUpdate);
260
+ } else {
261
+ apiRef.current.updateNestedRows([finalRowUpdate], []);
262
+ }
263
+ return updatedRow;
260
264
  } catch (errorThrown) {
261
265
  if (typeof onDataSourceErrorProp === 'function') {
262
266
  onDataSourceErrorProp(new GridUpdateRowError({
@@ -1,10 +1,10 @@
1
- import type { GridRowModelUpdate } from '@mui/x-data-grid';
1
+ import type { GridRowModelUpdate, GridRowModelReplace } from '@mui/x-data-grid';
2
2
  import type { GridColDef } from "../../../models/colDef/index.mjs";
3
3
  export interface GridPivotingStatePartial {
4
4
  active: boolean;
5
5
  initialColumns: Map<string, GridColDef> | undefined;
6
6
  }
7
7
  export interface GridPivotingPrivateApiCommunity {
8
- updateNonPivotRows: (rows: readonly GridRowModelUpdate[], keepPreviousRows?: boolean) => void;
8
+ updateNonPivotRows: (rows: ReadonlyArray<GridRowModelUpdate | GridRowModelReplace>, keepPreviousRows?: boolean) => void;
9
9
  updateNonPivotColumns: (columns: readonly GridColDef[], keepPreviousColumns?: boolean) => void;
10
10
  }
@@ -1,10 +1,10 @@
1
- import type { GridRowModelUpdate } from '@mui/x-data-grid';
1
+ import type { GridRowModelUpdate, GridRowModelReplace } from '@mui/x-data-grid';
2
2
  import type { GridColDef } from "../../../models/colDef/index.js";
3
3
  export interface GridPivotingStatePartial {
4
4
  active: boolean;
5
5
  initialColumns: Map<string, GridColDef> | undefined;
6
6
  }
7
7
  export interface GridPivotingPrivateApiCommunity {
8
- updateNonPivotRows: (rows: readonly GridRowModelUpdate[], keepPreviousRows?: boolean) => void;
8
+ updateNonPivotRows: (rows: ReadonlyArray<GridRowModelUpdate | GridRowModelReplace>, keepPreviousRows?: boolean) => void;
9
9
  updateNonPivotColumns: (columns: readonly GridColDef[], keepPreviousColumns?: boolean) => void;
10
10
  }