@mui/x-data-grid 7.0.0 → 7.1.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 (32) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/DataGrid/DataGrid.js +5 -0
  3. package/DataGrid/useDataGridProps.js +1 -0
  4. package/components/columnHeaders/GridColumnHeaderItem.js +3 -1
  5. package/components/columnHeaders/GridGenericColumnHeaderItem.js +3 -1
  6. package/components/toolbar/GridToolbarQuickFilter.js +17 -2
  7. package/hooks/features/dimensions/useGridDimensions.d.ts +1 -1
  8. package/hooks/features/dimensions/useGridDimensions.js +3 -2
  9. package/hooks/features/editing/useGridRowEditing.js +13 -4
  10. package/index.js +1 -1
  11. package/models/props/DataGridProps.d.ts +5 -0
  12. package/modern/DataGrid/DataGrid.js +5 -0
  13. package/modern/DataGrid/useDataGridProps.js +1 -0
  14. package/modern/components/columnHeaders/GridColumnHeaderItem.js +3 -1
  15. package/modern/components/columnHeaders/GridGenericColumnHeaderItem.js +3 -1
  16. package/modern/components/toolbar/GridToolbarQuickFilter.js +17 -2
  17. package/modern/hooks/features/dimensions/useGridDimensions.js +3 -2
  18. package/modern/hooks/features/editing/useGridRowEditing.js +13 -4
  19. package/modern/index.js +1 -1
  20. package/modern/utils/throttle.js +19 -0
  21. package/node/DataGrid/DataGrid.js +5 -0
  22. package/node/DataGrid/useDataGridProps.js +1 -0
  23. package/node/components/columnHeaders/GridColumnHeaderItem.js +3 -1
  24. package/node/components/columnHeaders/GridGenericColumnHeaderItem.js +3 -1
  25. package/node/components/toolbar/GridToolbarQuickFilter.js +17 -2
  26. package/node/hooks/features/dimensions/useGridDimensions.js +2 -1
  27. package/node/hooks/features/editing/useGridRowEditing.js +13 -4
  28. package/node/index.js +1 -1
  29. package/node/utils/throttle.js +25 -0
  30. package/package.json +1 -1
  31. package/utils/throttle.d.ts +4 -0
  32. package/utils/throttle.js +19 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,77 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## 7.1.0
7
+
8
+ _Mar 28, 2024_
9
+
10
+ We'd like to offer a big thanks to the 10 contributors who made this release possible. Here are some highlights ✨:
11
+
12
+ - 🚀 Add `resizeThrottleMs` prop (#12556) @romgrk
13
+ - 🌍 Improve Chinese (Hong Kong) (zh-HK) and Italian (it-IT) locale on the Pickers
14
+ - 🐞 Bugfixes
15
+ - 📚 Documentation improvements
16
+
17
+ ### Data Grid
18
+
19
+ #### `@mui/x-data-grid@7.1.0`
20
+
21
+ - [DataGrid] Add `resizeThrottleMs` prop (#12556) @romgrk
22
+ - [DataGrid] Do not publish `rowEditStop` event if row has fields with errors (#11383) @cherniavskii
23
+ - [DataGrid] Fix bug in suspense (#12553) @romgrk
24
+ - [DataGrid] Fix missing class name in the `GridToolbarQuickFilter` component (#12484) @jhawkins11
25
+
26
+ #### `@mui/x-data-grid-pro@7.1.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
27
+
28
+ Same changes as in `@mui/x-data-grid@7.1.0`.
29
+
30
+ #### `@mui/x-data-grid-premium@7.1.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
31
+
32
+ Same changes as in `@mui/x-data-grid-pro@7.1.0`.
33
+
34
+ ### Date and Time Pickers
35
+
36
+ #### `@mui/x-date-pickers@7.1.0`
37
+
38
+ - [fields] Fix placeholder override (#12589) @flaviendelangle
39
+ - [l10n] Improve Chinese (Hong Kong) (zh-HK) locale (#12547) @samchiu90
40
+ - [l10n] Improve Italian (it-IT) locale (#12549) @antomanc
41
+ - [pickers] Prepare compatibility with `@mui/zero-runtime` (stop using `ownerState` in `styled`) (#12003) @flaviendelangle
42
+
43
+ #### `@mui/x-date-pickers-pro@7.1.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
44
+
45
+ Same changes as in `@mui/x-date-pickers@7.1.0`, plus:
46
+
47
+ - [DateRangePicker] Fix selection behavior with single input field when `readOnly` (#12593) @LukasTy
48
+
49
+ ### Charts
50
+
51
+ #### `@mui/x-charts@7.1.0`
52
+
53
+ - [charts] Fix tooltip causing crash on data change (#12571) @Rishi556
54
+
55
+ ### Tree View
56
+
57
+ #### `@mui/x-tree-view@7.1.0`
58
+
59
+ - [TreeView] Do not use outdated version of the state to compute new label first char in `RichTreeView` (#12512) @flaviendelangle
60
+
61
+ ### Docs
62
+
63
+ - [docs] Add example to add a second icon next to the field's opening button (#12524) @flaviendelangle
64
+ - [docs] Add missing note to Data Grid migration guide (#12557) @romgrk
65
+ - [docs] Fix Charts title for SEO (#12545) @oliviertassinari
66
+ - [docs] Fix small typo (#12558) @diogoparente
67
+ - [docs] Improve codemod related documentation (#12582) @MBilalShafi
68
+ - [docs] Reduce noise in migration docs side navigation (#12552) @cherniavskii
69
+ - [docs] Sync static images from core repository (#12525) @LukasTy
70
+
71
+ ### Core
72
+
73
+ - [core] Fix `l10n` script on Windows (#12550) @LukasTy
74
+ - [core] Include `DateTimeRangePicker` tag in `releaseChangelog` (#12526) @LukasTy
75
+ - [core] Upgrade monorepo (#12536) @cherniavskii
76
+
6
77
  ## v7.0.0
7
78
 
8
79
  _Mar 22, 2024_
@@ -608,6 +608,11 @@ DataGridRaw.propTypes = {
608
608
  * @returns {Promise<R> | R} The final values to update the row.
609
609
  */
610
610
  processRowUpdate: PropTypes.func,
611
+ /**
612
+ * The milliseconds throttle delay for resizing the grid.
613
+ * @default 60
614
+ */
615
+ resizeThrottleMs: PropTypes.number,
611
616
  /**
612
617
  * Row region in pixels to render before/after the viewport
613
618
  * @default 150
@@ -54,6 +54,7 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES = {
54
54
  pagination: false,
55
55
  paginationMode: 'client',
56
56
  rowHeight: 52,
57
+ resizeThrottleMs: 60,
57
58
  pageSizeOptions: [25, 50, 100],
58
59
  rowSpacingType: 'margin',
59
60
  showCellVerticalBorder: false,
@@ -153,7 +153,9 @@ function GridColumnHeaderItem(props) {
153
153
  const focusableElement = headerCellRef.current.querySelector('[tabindex="0"]');
154
154
  const elementToFocus = focusableElement || headerCellRef.current;
155
155
  elementToFocus?.focus();
156
- apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
156
+ if (apiRef.current.columnHeadersContainerRef?.current) {
157
+ apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
158
+ }
157
159
  }
158
160
  }, [apiRef, hasFocus]);
159
161
  const headerClassName = typeof colDef.headerClassName === 'function' ? colDef.headerClassName({
@@ -56,7 +56,9 @@ const GridGenericColumnHeaderItem = /*#__PURE__*/React.forwardRef(function GridG
56
56
  const focusableElement = headerCellRef.current.querySelector('[tabindex="0"]');
57
57
  const elementToFocus = focusableElement || headerCellRef.current;
58
58
  elementToFocus?.focus();
59
- apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
59
+ if (apiRef.current.columnHeadersContainerRef?.current) {
60
+ apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
61
+ }
60
62
  }
61
63
  }, [apiRef, hasFocus]);
62
64
  return /*#__PURE__*/_jsxs("div", _extends({
@@ -1,17 +1,29 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
- const _excluded = ["quickFilterParser", "quickFilterFormatter", "debounceMs"];
3
+ const _excluded = ["quickFilterParser", "quickFilterFormatter", "debounceMs", "className"];
4
4
  import * as React from 'react';
5
+ import clsx from 'clsx';
5
6
  import PropTypes from 'prop-types';
6
7
  import TextField from '@mui/material/TextField';
7
8
  import { styled } from '@mui/material/styles';
8
9
  import { unstable_debounce as debounce } from '@mui/utils';
10
+ import composeClasses from '@mui/utils/composeClasses';
11
+ import { getDataGridUtilityClass } from '../../constants';
9
12
  import { useGridApiContext } from '../../hooks/utils/useGridApiContext';
10
13
  import { useGridRootProps } from '../../hooks/utils/useGridRootProps';
11
14
  import { useGridSelector } from '../../hooks/utils/useGridSelector';
12
15
  import { gridQuickFilterValuesSelector } from '../../hooks/features/filter';
13
16
  import { isDeepEqual } from '../../utils/utils';
14
17
  import { jsx as _jsx } from "react/jsx-runtime";
18
+ const useUtilityClasses = ownerState => {
19
+ const {
20
+ classes
21
+ } = ownerState;
22
+ const slots = {
23
+ root: ['toolbarQuickFilter']
24
+ };
25
+ return composeClasses(slots, getDataGridUtilityClass, classes);
26
+ };
15
27
  const GridToolbarQuickFilterRoot = styled(TextField, {
16
28
  name: 'MuiDataGrid',
17
29
  slot: 'ToolbarQuickFilter',
@@ -47,11 +59,13 @@ const defaultSearchValueFormatter = values => values.join(' ');
47
59
  function GridToolbarQuickFilter(props) {
48
60
  const apiRef = useGridApiContext();
49
61
  const rootProps = useGridRootProps();
62
+ const classes = useUtilityClasses(rootProps);
50
63
  const quickFilterValues = useGridSelector(apiRef, gridQuickFilterValuesSelector);
51
64
  const {
52
65
  quickFilterParser = defaultSearchValueParser,
53
66
  quickFilterFormatter = defaultSearchValueFormatter,
54
- debounceMs = rootProps.filterDebounceMs
67
+ debounceMs = rootProps.filterDebounceMs,
68
+ className
55
69
  } = props,
56
70
  other = _objectWithoutPropertiesLoose(props, _excluded);
57
71
  const [searchValue, setSearchValue] = React.useState(() => quickFilterFormatter(quickFilterValues ?? []));
@@ -86,6 +100,7 @@ function GridToolbarQuickFilter(props) {
86
100
  variant: "standard",
87
101
  value: searchValue,
88
102
  onChange: handleSearchValueChange,
103
+ className: clsx(className, classes.root),
89
104
  placeholder: apiRef.current.getLocaleText('toolbarQuickFilterPlaceholder'),
90
105
  "aria-label": apiRef.current.getLocaleText('toolbarQuickFilterLabel'),
91
106
  type: "search"
@@ -3,7 +3,7 @@ import { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity';
3
3
  import { DataGridProcessedProps } from '../../../models/props/DataGridProps';
4
4
  import { GridDimensions } from './gridDimensionsApi';
5
5
  import { GridStateInitializer } from '../../utils/useGridInitializeState';
6
- type RootProps = Pick<DataGridProcessedProps, 'onResize' | 'scrollbarSize' | 'pagination' | 'paginationMode' | 'autoHeight' | 'getRowHeight' | 'rowHeight' | 'columnHeaderHeight'>;
6
+ type RootProps = Pick<DataGridProcessedProps, 'onResize' | 'scrollbarSize' | 'pagination' | 'paginationMode' | 'autoHeight' | 'getRowHeight' | 'rowHeight' | 'resizeThrottleMs' | 'columnHeaderHeight'>;
7
7
  export type GridDimensionsState = GridDimensions;
8
8
  export declare const dimensionsStateInitializer: GridStateInitializer<RootProps>;
9
9
  export declare function useGridDimensions(apiRef: React.MutableRefObject<GridPrivateApiCommunity>, props: RootProps): void;
@@ -1,8 +1,9 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
- import { unstable_debounce as debounce, unstable_ownerDocument as ownerDocument, unstable_useEnhancedEffect as useEnhancedEffect, unstable_useEventCallback as useEventCallback, unstable_ownerWindow as ownerWindow } from '@mui/utils';
3
+ import { unstable_ownerDocument as ownerDocument, unstable_useEnhancedEffect as useEnhancedEffect, unstable_useEventCallback as useEventCallback, unstable_ownerWindow as ownerWindow } from '@mui/utils';
4
4
  import { useGridApiEventHandler, useGridApiOptionHandler } from '../../utils/useGridApiEventHandler';
5
5
  import { useGridApiMethod } from '../../utils/useGridApiMethod';
6
+ import { throttle } from '../../../utils/throttle';
6
7
  import { useGridLogger } from '../../utils/useGridLogger';
7
8
  import { gridColumnsTotalWidthSelector, gridVisiblePinnedColumnDefinitionsSelector } from '../columns';
8
9
  import { gridDimensionsSelector } from './gridDimensionsSelectors';
@@ -57,7 +58,7 @@ export function useGridDimensions(apiRef, props) {
57
58
  const leftPinnedWidth = pinnedColumns.left.reduce((w, col) => w + col.computedWidth, 0);
58
59
  const rightPinnedWidth = pinnedColumns.right.reduce((w, col) => w + col.computedWidth, 0);
59
60
  const [savedSize, setSavedSize] = React.useState();
60
- const debouncedSetSavedSize = React.useMemo(() => debounce(setSavedSize, 60), []);
61
+ const debouncedSetSavedSize = React.useMemo(() => throttle(setSavedSize, props.resizeThrottleMs), [props.resizeThrottleMs]);
61
62
  const previousSize = React.useRef();
62
63
  const getRootDimensions = () => apiRef.current.state.dimensions;
63
64
  const setDimensions = useEventCallback(dimensions => {
@@ -45,6 +45,10 @@ export const useGridRowEditing = (apiRef, props) => {
45
45
  throw new Error(`MUI X: The row with id=${id} is not in ${mode} mode.`);
46
46
  }
47
47
  }, [apiRef]);
48
+ const hasFieldsWithErrors = React.useCallback(rowId => {
49
+ const editingState = gridEditRowsStateSelector(apiRef.current.state);
50
+ return Object.values(editingState[rowId]).some(fieldProps => fieldProps.error);
51
+ }, [apiRef]);
48
52
  const handleCellDoubleClick = React.useCallback((params, event) => {
49
53
  if (!params.isEditable) {
50
54
  return;
@@ -86,6 +90,9 @@ export const useGridRowEditing = (apiRef, props) => {
86
90
  if (apiRef.current.getRowMode(params.id) === GridRowModes.View) {
87
91
  return;
88
92
  }
93
+ if (hasFieldsWithErrors(params.id)) {
94
+ return;
95
+ }
89
96
  const rowParams = apiRef.current.getRowParams(params.id);
90
97
  const newParams = _extends({}, rowParams, {
91
98
  field: params.field,
@@ -94,7 +101,7 @@ export const useGridRowEditing = (apiRef, props) => {
94
101
  apiRef.current.publishEvent('rowEditStop', newParams, event);
95
102
  }
96
103
  });
97
- }, [apiRef]);
104
+ }, [apiRef, hasFieldsWithErrors]);
98
105
  React.useEffect(() => {
99
106
  return () => {
100
107
  clearTimeout(focusTimeout.current);
@@ -140,6 +147,9 @@ export const useGridRowEditing = (apiRef, props) => {
140
147
  }
141
148
  }
142
149
  if (reason) {
150
+ if (reason !== GridRowEditStopReasons.escapeKeyDown && hasFieldsWithErrors(params.id)) {
151
+ return;
152
+ }
143
153
  const newParams = _extends({}, apiRef.current.getRowParams(params.id), {
144
154
  reason,
145
155
  field: params.field
@@ -174,7 +184,7 @@ export const useGridRowEditing = (apiRef, props) => {
174
184
  apiRef.current.publishEvent('rowEditStart', newParams, event);
175
185
  }
176
186
  }
177
- }, [apiRef]);
187
+ }, [apiRef, hasFieldsWithErrors]);
178
188
  const handleRowEditStart = React.useCallback(params => {
179
189
  const {
180
190
  id,
@@ -358,8 +368,7 @@ export const useGridRowEditing = (apiRef, props) => {
358
368
  prevRowModesModel.current[id].mode = GridRowModes.Edit;
359
369
  return;
360
370
  }
361
- const hasSomeFieldWithError = Object.values(editingState[id]).some(fieldProps => fieldProps.error);
362
- if (hasSomeFieldWithError) {
371
+ if (hasFieldsWithErrors(id)) {
363
372
  prevRowModesModel.current[id].mode = GridRowModes.Edit;
364
373
  // Revert the mode in the rowModesModel prop back to "edit"
365
374
  updateRowInRowModesModel(id, {
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v7.0.0
2
+ * @mui/x-data-grid v7.1.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -112,6 +112,11 @@ export interface DataGridPropsWithDefaultValues<R extends GridValidRowModel = an
112
112
  * @default true
113
113
  */
114
114
  rowSelection: boolean;
115
+ /**
116
+ * The milliseconds throttle delay for resizing the grid.
117
+ * @default 60
118
+ */
119
+ resizeThrottleMs: number;
115
120
  /**
116
121
  * If `true`, column filters are disabled.
117
122
  * @default false
@@ -608,6 +608,11 @@ DataGridRaw.propTypes = {
608
608
  * @returns {Promise<R> | R} The final values to update the row.
609
609
  */
610
610
  processRowUpdate: PropTypes.func,
611
+ /**
612
+ * The milliseconds throttle delay for resizing the grid.
613
+ * @default 60
614
+ */
615
+ resizeThrottleMs: PropTypes.number,
611
616
  /**
612
617
  * Row region in pixels to render before/after the viewport
613
618
  * @default 150
@@ -54,6 +54,7 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES = {
54
54
  pagination: false,
55
55
  paginationMode: 'client',
56
56
  rowHeight: 52,
57
+ resizeThrottleMs: 60,
57
58
  pageSizeOptions: [25, 50, 100],
58
59
  rowSpacingType: 'margin',
59
60
  showCellVerticalBorder: false,
@@ -153,7 +153,9 @@ function GridColumnHeaderItem(props) {
153
153
  const focusableElement = headerCellRef.current.querySelector('[tabindex="0"]');
154
154
  const elementToFocus = focusableElement || headerCellRef.current;
155
155
  elementToFocus?.focus();
156
- apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
156
+ if (apiRef.current.columnHeadersContainerRef?.current) {
157
+ apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
158
+ }
157
159
  }
158
160
  }, [apiRef, hasFocus]);
159
161
  const headerClassName = typeof colDef.headerClassName === 'function' ? colDef.headerClassName({
@@ -56,7 +56,9 @@ const GridGenericColumnHeaderItem = /*#__PURE__*/React.forwardRef(function GridG
56
56
  const focusableElement = headerCellRef.current.querySelector('[tabindex="0"]');
57
57
  const elementToFocus = focusableElement || headerCellRef.current;
58
58
  elementToFocus?.focus();
59
- apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
59
+ if (apiRef.current.columnHeadersContainerRef?.current) {
60
+ apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
61
+ }
60
62
  }
61
63
  }, [apiRef, hasFocus]);
62
64
  return /*#__PURE__*/_jsxs("div", _extends({
@@ -1,17 +1,29 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
- const _excluded = ["quickFilterParser", "quickFilterFormatter", "debounceMs"];
3
+ const _excluded = ["quickFilterParser", "quickFilterFormatter", "debounceMs", "className"];
4
4
  import * as React from 'react';
5
+ import clsx from 'clsx';
5
6
  import PropTypes from 'prop-types';
6
7
  import TextField from '@mui/material/TextField';
7
8
  import { styled } from '@mui/material/styles';
8
9
  import { unstable_debounce as debounce } from '@mui/utils';
10
+ import composeClasses from '@mui/utils/composeClasses';
11
+ import { getDataGridUtilityClass } from '../../constants';
9
12
  import { useGridApiContext } from '../../hooks/utils/useGridApiContext';
10
13
  import { useGridRootProps } from '../../hooks/utils/useGridRootProps';
11
14
  import { useGridSelector } from '../../hooks/utils/useGridSelector';
12
15
  import { gridQuickFilterValuesSelector } from '../../hooks/features/filter';
13
16
  import { isDeepEqual } from '../../utils/utils';
14
17
  import { jsx as _jsx } from "react/jsx-runtime";
18
+ const useUtilityClasses = ownerState => {
19
+ const {
20
+ classes
21
+ } = ownerState;
22
+ const slots = {
23
+ root: ['toolbarQuickFilter']
24
+ };
25
+ return composeClasses(slots, getDataGridUtilityClass, classes);
26
+ };
15
27
  const GridToolbarQuickFilterRoot = styled(TextField, {
16
28
  name: 'MuiDataGrid',
17
29
  slot: 'ToolbarQuickFilter',
@@ -47,11 +59,13 @@ const defaultSearchValueFormatter = values => values.join(' ');
47
59
  function GridToolbarQuickFilter(props) {
48
60
  const apiRef = useGridApiContext();
49
61
  const rootProps = useGridRootProps();
62
+ const classes = useUtilityClasses(rootProps);
50
63
  const quickFilterValues = useGridSelector(apiRef, gridQuickFilterValuesSelector);
51
64
  const {
52
65
  quickFilterParser = defaultSearchValueParser,
53
66
  quickFilterFormatter = defaultSearchValueFormatter,
54
- debounceMs = rootProps.filterDebounceMs
67
+ debounceMs = rootProps.filterDebounceMs,
68
+ className
55
69
  } = props,
56
70
  other = _objectWithoutPropertiesLoose(props, _excluded);
57
71
  const [searchValue, setSearchValue] = React.useState(() => quickFilterFormatter(quickFilterValues ?? []));
@@ -86,6 +100,7 @@ function GridToolbarQuickFilter(props) {
86
100
  variant: "standard",
87
101
  value: searchValue,
88
102
  onChange: handleSearchValueChange,
103
+ className: clsx(className, classes.root),
89
104
  placeholder: apiRef.current.getLocaleText('toolbarQuickFilterPlaceholder'),
90
105
  "aria-label": apiRef.current.getLocaleText('toolbarQuickFilterLabel'),
91
106
  type: "search"
@@ -1,8 +1,9 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
- import { unstable_debounce as debounce, unstable_ownerDocument as ownerDocument, unstable_useEnhancedEffect as useEnhancedEffect, unstable_useEventCallback as useEventCallback, unstable_ownerWindow as ownerWindow } from '@mui/utils';
3
+ import { unstable_ownerDocument as ownerDocument, unstable_useEnhancedEffect as useEnhancedEffect, unstable_useEventCallback as useEventCallback, unstable_ownerWindow as ownerWindow } from '@mui/utils';
4
4
  import { useGridApiEventHandler, useGridApiOptionHandler } from '../../utils/useGridApiEventHandler';
5
5
  import { useGridApiMethod } from '../../utils/useGridApiMethod';
6
+ import { throttle } from '../../../utils/throttle';
6
7
  import { useGridLogger } from '../../utils/useGridLogger';
7
8
  import { gridColumnsTotalWidthSelector, gridVisiblePinnedColumnDefinitionsSelector } from '../columns';
8
9
  import { gridDimensionsSelector } from './gridDimensionsSelectors';
@@ -57,7 +58,7 @@ export function useGridDimensions(apiRef, props) {
57
58
  const leftPinnedWidth = pinnedColumns.left.reduce((w, col) => w + col.computedWidth, 0);
58
59
  const rightPinnedWidth = pinnedColumns.right.reduce((w, col) => w + col.computedWidth, 0);
59
60
  const [savedSize, setSavedSize] = React.useState();
60
- const debouncedSetSavedSize = React.useMemo(() => debounce(setSavedSize, 60), []);
61
+ const debouncedSetSavedSize = React.useMemo(() => throttle(setSavedSize, props.resizeThrottleMs), [props.resizeThrottleMs]);
61
62
  const previousSize = React.useRef();
62
63
  const getRootDimensions = () => apiRef.current.state.dimensions;
63
64
  const setDimensions = useEventCallback(dimensions => {
@@ -45,6 +45,10 @@ export const useGridRowEditing = (apiRef, props) => {
45
45
  throw new Error(`MUI X: The row with id=${id} is not in ${mode} mode.`);
46
46
  }
47
47
  }, [apiRef]);
48
+ const hasFieldsWithErrors = React.useCallback(rowId => {
49
+ const editingState = gridEditRowsStateSelector(apiRef.current.state);
50
+ return Object.values(editingState[rowId]).some(fieldProps => fieldProps.error);
51
+ }, [apiRef]);
48
52
  const handleCellDoubleClick = React.useCallback((params, event) => {
49
53
  if (!params.isEditable) {
50
54
  return;
@@ -86,6 +90,9 @@ export const useGridRowEditing = (apiRef, props) => {
86
90
  if (apiRef.current.getRowMode(params.id) === GridRowModes.View) {
87
91
  return;
88
92
  }
93
+ if (hasFieldsWithErrors(params.id)) {
94
+ return;
95
+ }
89
96
  const rowParams = apiRef.current.getRowParams(params.id);
90
97
  const newParams = _extends({}, rowParams, {
91
98
  field: params.field,
@@ -94,7 +101,7 @@ export const useGridRowEditing = (apiRef, props) => {
94
101
  apiRef.current.publishEvent('rowEditStop', newParams, event);
95
102
  }
96
103
  });
97
- }, [apiRef]);
104
+ }, [apiRef, hasFieldsWithErrors]);
98
105
  React.useEffect(() => {
99
106
  return () => {
100
107
  clearTimeout(focusTimeout.current);
@@ -140,6 +147,9 @@ export const useGridRowEditing = (apiRef, props) => {
140
147
  }
141
148
  }
142
149
  if (reason) {
150
+ if (reason !== GridRowEditStopReasons.escapeKeyDown && hasFieldsWithErrors(params.id)) {
151
+ return;
152
+ }
143
153
  const newParams = _extends({}, apiRef.current.getRowParams(params.id), {
144
154
  reason,
145
155
  field: params.field
@@ -174,7 +184,7 @@ export const useGridRowEditing = (apiRef, props) => {
174
184
  apiRef.current.publishEvent('rowEditStart', newParams, event);
175
185
  }
176
186
  }
177
- }, [apiRef]);
187
+ }, [apiRef, hasFieldsWithErrors]);
178
188
  const handleRowEditStart = React.useCallback(params => {
179
189
  const {
180
190
  id,
@@ -358,8 +368,7 @@ export const useGridRowEditing = (apiRef, props) => {
358
368
  prevRowModesModel.current[id].mode = GridRowModes.Edit;
359
369
  return;
360
370
  }
361
- const hasSomeFieldWithError = Object.values(editingState[id]).some(fieldProps => fieldProps.error);
362
- if (hasSomeFieldWithError) {
371
+ if (hasFieldsWithErrors(id)) {
363
372
  prevRowModesModel.current[id].mode = GridRowModes.Edit;
364
373
  // Revert the mode in the rowModesModel prop back to "edit"
365
374
  updateRowInRowModesModel(id, {
package/modern/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v7.0.0
2
+ * @mui/x-data-grid v7.1.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -0,0 +1,19 @@
1
+ export function throttle(func, wait = 166) {
2
+ let timeout;
3
+ let lastArgs;
4
+ const later = () => {
5
+ timeout = undefined;
6
+ func(...lastArgs);
7
+ };
8
+ function throttled(...args) {
9
+ lastArgs = args;
10
+ if (timeout === undefined) {
11
+ timeout = setTimeout(later, wait);
12
+ }
13
+ }
14
+ throttled.clear = () => {
15
+ clearTimeout(timeout);
16
+ timeout = undefined;
17
+ };
18
+ return throttled;
19
+ }
@@ -615,6 +615,11 @@ DataGridRaw.propTypes = {
615
615
  * @returns {Promise<R> | R} The final values to update the row.
616
616
  */
617
617
  processRowUpdate: _propTypes.default.func,
618
+ /**
619
+ * The milliseconds throttle delay for resizing the grid.
620
+ * @default 60
621
+ */
622
+ resizeThrottleMs: _propTypes.default.number,
618
623
  /**
619
624
  * Row region in pixels to render before/after the viewport
620
625
  * @default 150
@@ -63,6 +63,7 @@ const DATA_GRID_PROPS_DEFAULT_VALUES = exports.DATA_GRID_PROPS_DEFAULT_VALUES =
63
63
  pagination: false,
64
64
  paginationMode: 'client',
65
65
  rowHeight: 52,
66
+ resizeThrottleMs: 60,
66
67
  pageSizeOptions: [25, 50, 100],
67
68
  rowSpacingType: 'margin',
68
69
  showCellVerticalBorder: false,
@@ -161,7 +161,9 @@ function GridColumnHeaderItem(props) {
161
161
  const focusableElement = headerCellRef.current.querySelector('[tabindex="0"]');
162
162
  const elementToFocus = focusableElement || headerCellRef.current;
163
163
  elementToFocus?.focus();
164
- apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
164
+ if (apiRef.current.columnHeadersContainerRef?.current) {
165
+ apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
166
+ }
165
167
  }
166
168
  }, [apiRef, hasFocus]);
167
169
  const headerClassName = typeof colDef.headerClassName === 'function' ? colDef.headerClassName({
@@ -64,7 +64,9 @@ const GridGenericColumnHeaderItem = exports.GridGenericColumnHeaderItem = /*#__P
64
64
  const focusableElement = headerCellRef.current.querySelector('[tabindex="0"]');
65
65
  const elementToFocus = focusableElement || headerCellRef.current;
66
66
  elementToFocus?.focus();
67
- apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
67
+ if (apiRef.current.columnHeadersContainerRef?.current) {
68
+ apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
69
+ }
68
70
  }
69
71
  }, [apiRef, hasFocus]);
70
72
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", (0, _extends2.default)({
@@ -8,19 +8,31 @@ exports.GridToolbarQuickFilter = GridToolbarQuickFilter;
8
8
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
9
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
10
10
  var React = _interopRequireWildcard(require("react"));
11
+ var _clsx = _interopRequireDefault(require("clsx"));
11
12
  var _propTypes = _interopRequireDefault(require("prop-types"));
12
13
  var _TextField = _interopRequireDefault(require("@mui/material/TextField"));
13
14
  var _styles = require("@mui/material/styles");
14
15
  var _utils = require("@mui/utils");
16
+ var _composeClasses = _interopRequireDefault(require("@mui/utils/composeClasses"));
17
+ var _constants = require("../../constants");
15
18
  var _useGridApiContext = require("../../hooks/utils/useGridApiContext");
16
19
  var _useGridRootProps = require("../../hooks/utils/useGridRootProps");
17
20
  var _useGridSelector = require("../../hooks/utils/useGridSelector");
18
21
  var _filter = require("../../hooks/features/filter");
19
22
  var _utils2 = require("../../utils/utils");
20
23
  var _jsxRuntime = require("react/jsx-runtime");
21
- const _excluded = ["quickFilterParser", "quickFilterFormatter", "debounceMs"];
24
+ const _excluded = ["quickFilterParser", "quickFilterFormatter", "debounceMs", "className"];
22
25
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
23
26
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
27
+ const useUtilityClasses = ownerState => {
28
+ const {
29
+ classes
30
+ } = ownerState;
31
+ const slots = {
32
+ root: ['toolbarQuickFilter']
33
+ };
34
+ return (0, _composeClasses.default)(slots, _constants.getDataGridUtilityClass, classes);
35
+ };
24
36
  const GridToolbarQuickFilterRoot = (0, _styles.styled)(_TextField.default, {
25
37
  name: 'MuiDataGrid',
26
38
  slot: 'ToolbarQuickFilter',
@@ -56,11 +68,13 @@ const defaultSearchValueFormatter = values => values.join(' ');
56
68
  function GridToolbarQuickFilter(props) {
57
69
  const apiRef = (0, _useGridApiContext.useGridApiContext)();
58
70
  const rootProps = (0, _useGridRootProps.useGridRootProps)();
71
+ const classes = useUtilityClasses(rootProps);
59
72
  const quickFilterValues = (0, _useGridSelector.useGridSelector)(apiRef, _filter.gridQuickFilterValuesSelector);
60
73
  const {
61
74
  quickFilterParser = defaultSearchValueParser,
62
75
  quickFilterFormatter = defaultSearchValueFormatter,
63
- debounceMs = rootProps.filterDebounceMs
76
+ debounceMs = rootProps.filterDebounceMs,
77
+ className
64
78
  } = props,
65
79
  other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
66
80
  const [searchValue, setSearchValue] = React.useState(() => quickFilterFormatter(quickFilterValues ?? []));
@@ -95,6 +109,7 @@ function GridToolbarQuickFilter(props) {
95
109
  variant: "standard",
96
110
  value: searchValue,
97
111
  onChange: handleSearchValueChange,
112
+ className: (0, _clsx.default)(className, classes.root),
98
113
  placeholder: apiRef.current.getLocaleText('toolbarQuickFilterPlaceholder'),
99
114
  "aria-label": apiRef.current.getLocaleText('toolbarQuickFilterLabel'),
100
115
  type: "search"
@@ -11,6 +11,7 @@ var React = _interopRequireWildcard(require("react"));
11
11
  var _utils = require("@mui/utils");
12
12
  var _useGridApiEventHandler = require("../../utils/useGridApiEventHandler");
13
13
  var _useGridApiMethod = require("../../utils/useGridApiMethod");
14
+ var _throttle = require("../../../utils/throttle");
14
15
  var _useGridLogger = require("../../utils/useGridLogger");
15
16
  var _columns = require("../columns");
16
17
  var _gridDimensionsSelectors = require("./gridDimensionsSelectors");
@@ -68,7 +69,7 @@ function useGridDimensions(apiRef, props) {
68
69
  const leftPinnedWidth = pinnedColumns.left.reduce((w, col) => w + col.computedWidth, 0);
69
70
  const rightPinnedWidth = pinnedColumns.right.reduce((w, col) => w + col.computedWidth, 0);
70
71
  const [savedSize, setSavedSize] = React.useState();
71
- const debouncedSetSavedSize = React.useMemo(() => (0, _utils.unstable_debounce)(setSavedSize, 60), []);
72
+ const debouncedSetSavedSize = React.useMemo(() => (0, _throttle.throttle)(setSavedSize, props.resizeThrottleMs), [props.resizeThrottleMs]);
72
73
  const previousSize = React.useRef();
73
74
  const getRootDimensions = () => apiRef.current.state.dimensions;
74
75
  const setDimensions = (0, _utils.unstable_useEventCallback)(dimensions => {
@@ -54,6 +54,10 @@ const useGridRowEditing = (apiRef, props) => {
54
54
  throw new Error(`MUI X: The row with id=${id} is not in ${mode} mode.`);
55
55
  }
56
56
  }, [apiRef]);
57
+ const hasFieldsWithErrors = React.useCallback(rowId => {
58
+ const editingState = (0, _gridEditingSelectors.gridEditRowsStateSelector)(apiRef.current.state);
59
+ return Object.values(editingState[rowId]).some(fieldProps => fieldProps.error);
60
+ }, [apiRef]);
57
61
  const handleCellDoubleClick = React.useCallback((params, event) => {
58
62
  if (!params.isEditable) {
59
63
  return;
@@ -95,6 +99,9 @@ const useGridRowEditing = (apiRef, props) => {
95
99
  if (apiRef.current.getRowMode(params.id) === _gridEditRowModel.GridRowModes.View) {
96
100
  return;
97
101
  }
102
+ if (hasFieldsWithErrors(params.id)) {
103
+ return;
104
+ }
98
105
  const rowParams = apiRef.current.getRowParams(params.id);
99
106
  const newParams = (0, _extends2.default)({}, rowParams, {
100
107
  field: params.field,
@@ -103,7 +110,7 @@ const useGridRowEditing = (apiRef, props) => {
103
110
  apiRef.current.publishEvent('rowEditStop', newParams, event);
104
111
  }
105
112
  });
106
- }, [apiRef]);
113
+ }, [apiRef, hasFieldsWithErrors]);
107
114
  React.useEffect(() => {
108
115
  return () => {
109
116
  clearTimeout(focusTimeout.current);
@@ -149,6 +156,9 @@ const useGridRowEditing = (apiRef, props) => {
149
156
  }
150
157
  }
151
158
  if (reason) {
159
+ if (reason !== _gridRowParams.GridRowEditStopReasons.escapeKeyDown && hasFieldsWithErrors(params.id)) {
160
+ return;
161
+ }
152
162
  const newParams = (0, _extends2.default)({}, apiRef.current.getRowParams(params.id), {
153
163
  reason,
154
164
  field: params.field
@@ -183,7 +193,7 @@ const useGridRowEditing = (apiRef, props) => {
183
193
  apiRef.current.publishEvent('rowEditStart', newParams, event);
184
194
  }
185
195
  }
186
- }, [apiRef]);
196
+ }, [apiRef, hasFieldsWithErrors]);
187
197
  const handleRowEditStart = React.useCallback(params => {
188
198
  const {
189
199
  id,
@@ -367,8 +377,7 @@ const useGridRowEditing = (apiRef, props) => {
367
377
  prevRowModesModel.current[id].mode = _gridEditRowModel.GridRowModes.Edit;
368
378
  return;
369
379
  }
370
- const hasSomeFieldWithError = Object.values(editingState[id]).some(fieldProps => fieldProps.error);
371
- if (hasSomeFieldWithError) {
380
+ if (hasFieldsWithErrors(id)) {
372
381
  prevRowModesModel.current[id].mode = _gridEditRowModel.GridRowModes.Edit;
373
382
  // Revert the mode in the rowModesModel prop back to "edit"
374
383
  updateRowInRowModesModel(id, {
package/node/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v7.0.0
2
+ * @mui/x-data-grid v7.1.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.throttle = throttle;
7
+ function throttle(func, wait = 166) {
8
+ let timeout;
9
+ let lastArgs;
10
+ const later = () => {
11
+ timeout = undefined;
12
+ func(...lastArgs);
13
+ };
14
+ function throttled(...args) {
15
+ lastArgs = args;
16
+ if (timeout === undefined) {
17
+ timeout = setTimeout(later, wait);
18
+ }
19
+ }
20
+ throttled.clear = () => {
21
+ clearTimeout(timeout);
22
+ timeout = undefined;
23
+ };
24
+ return throttled;
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-data-grid",
3
- "version": "7.0.0",
3
+ "version": "7.1.0",
4
4
  "description": "The community edition of the data grid component (MUI X).",
5
5
  "author": "MUI Team",
6
6
  "main": "./node/index.js",
@@ -0,0 +1,4 @@
1
+ export interface Cancelable {
2
+ clear(): void;
3
+ }
4
+ export declare function throttle<T extends (...args: any[]) => any>(func: T, wait?: number): T & Cancelable;
@@ -0,0 +1,19 @@
1
+ export function throttle(func, wait = 166) {
2
+ let timeout;
3
+ let lastArgs;
4
+ const later = () => {
5
+ timeout = undefined;
6
+ func(...lastArgs);
7
+ };
8
+ function throttled(...args) {
9
+ lastArgs = args;
10
+ if (timeout === undefined) {
11
+ timeout = setTimeout(later, wait);
12
+ }
13
+ }
14
+ throttled.clear = () => {
15
+ clearTimeout(timeout);
16
+ timeout = undefined;
17
+ };
18
+ return throttled;
19
+ }