@mui/x-data-grid 8.3.0 → 8.4.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 (86) hide show
  1. package/CHANGELOG.md +206 -10
  2. package/DataGrid/DataGrid.js +1 -0
  3. package/components/GridApiContext.js +1 -3
  4. package/components/GridColumnUnsortedIcon.js +2 -1
  5. package/components/GridConfigurationContext.js +1 -3
  6. package/components/GridRow.js +1 -0
  7. package/components/cell/GridActionsCell.js +2 -1
  8. package/components/cell/GridBooleanCell.js +3 -1
  9. package/components/cell/GridEditBooleanCell.js +2 -1
  10. package/components/cell/GridEditDateCell.js +2 -1
  11. package/components/cell/GridEditInputCell.js +2 -1
  12. package/components/cell/GridEditSingleSelectCell.js +2 -1
  13. package/components/columnHeaders/ColumnHeaderMenuIcon.js +2 -1
  14. package/components/columnHeaders/GridColumnHeaderItem.js +1 -1
  15. package/components/columnHeaders/GridColumnHeaderSeparator.js +1 -0
  16. package/components/columnHeaders/GridColumnHeaderSortIcon.js +1 -0
  17. package/components/columnSelection/GridCellCheckboxRenderer.js +4 -2
  18. package/components/containers/GridRootStyles.js +1 -1
  19. package/components/panel/GridPanelContext.js +1 -0
  20. package/components/quickFilter/QuickFilterContext.js +1 -0
  21. package/components/toolbarV8/Toolbar.js +58 -32
  22. package/components/toolbarV8/ToolbarContext.js +1 -0
  23. package/components/toolbarV8/utils.d.ts +5 -0
  24. package/components/toolbarV8/utils.js +23 -0
  25. package/context/GridRootPropsContext.js +1 -3
  26. package/esm/DataGrid/DataGrid.js +1 -0
  27. package/esm/components/GridApiContext.js +1 -3
  28. package/esm/components/GridColumnUnsortedIcon.js +2 -1
  29. package/esm/components/GridConfigurationContext.js +1 -3
  30. package/esm/components/GridRow.js +1 -0
  31. package/esm/components/cell/GridActionsCell.js +2 -1
  32. package/esm/components/cell/GridBooleanCell.js +3 -1
  33. package/esm/components/cell/GridEditBooleanCell.js +2 -1
  34. package/esm/components/cell/GridEditDateCell.js +2 -1
  35. package/esm/components/cell/GridEditInputCell.js +2 -1
  36. package/esm/components/cell/GridEditSingleSelectCell.js +2 -1
  37. package/esm/components/columnHeaders/ColumnHeaderMenuIcon.js +2 -1
  38. package/esm/components/columnHeaders/GridColumnHeaderItem.js +1 -1
  39. package/esm/components/columnHeaders/GridColumnHeaderSeparator.js +1 -0
  40. package/esm/components/columnHeaders/GridColumnHeaderSortIcon.js +1 -0
  41. package/esm/components/columnSelection/GridCellCheckboxRenderer.js +6 -4
  42. package/esm/components/containers/GridRootStyles.js +1 -1
  43. package/esm/components/panel/GridPanelContext.js +1 -0
  44. package/esm/components/quickFilter/QuickFilterContext.js +1 -0
  45. package/esm/components/toolbarV8/Toolbar.js +58 -32
  46. package/esm/components/toolbarV8/ToolbarContext.js +1 -0
  47. package/esm/components/toolbarV8/utils.d.ts +5 -0
  48. package/esm/components/toolbarV8/utils.js +17 -0
  49. package/esm/context/GridRootPropsContext.js +1 -3
  50. package/esm/hooks/features/columnHeaders/useGridColumnHeaders.js +3 -1
  51. package/esm/hooks/features/columns/gridColumnsUtils.js +15 -7
  52. package/esm/hooks/features/overlays/useGridOverlays.js +1 -0
  53. package/esm/hooks/features/pagination/useGridPaginationModel.js +1 -1
  54. package/esm/hooks/features/rowSelection/useGridRowSelection.js +7 -7
  55. package/esm/hooks/features/rowSelection/utils.d.ts +4 -1
  56. package/esm/hooks/features/rowSelection/utils.js +33 -32
  57. package/esm/hooks/features/virtualization/useGridVirtualScroller.js +7 -6
  58. package/esm/hooks/utils/useGridPrivateApiContext.js +1 -3
  59. package/esm/index.d.ts +1 -0
  60. package/esm/index.js +2 -1
  61. package/esm/locales/isIS.js +8 -8
  62. package/esm/locales/koKR.js +68 -76
  63. package/esm/locales/nbNO.js +22 -24
  64. package/esm/material/variables.js +5 -0
  65. package/esm/models/api/gridRowSelectionApi.d.ts +4 -2
  66. package/esm/models/events/gridEventLookup.d.ts +10 -0
  67. package/esm/utils/css/context.js +2 -1
  68. package/hooks/features/columnHeaders/useGridColumnHeaders.js +3 -1
  69. package/hooks/features/columns/gridColumnsUtils.js +15 -7
  70. package/hooks/features/overlays/useGridOverlays.js +1 -0
  71. package/hooks/features/pagination/useGridPaginationModel.js +1 -1
  72. package/hooks/features/rowSelection/useGridRowSelection.js +7 -7
  73. package/hooks/features/rowSelection/utils.d.ts +4 -1
  74. package/hooks/features/rowSelection/utils.js +34 -34
  75. package/hooks/features/virtualization/useGridVirtualScroller.js +7 -6
  76. package/hooks/utils/useGridPrivateApiContext.js +1 -3
  77. package/index.d.ts +1 -0
  78. package/index.js +2 -1
  79. package/locales/isIS.js +8 -8
  80. package/locales/koKR.js +68 -76
  81. package/locales/nbNO.js +22 -24
  82. package/material/variables.js +5 -0
  83. package/models/api/gridRowSelectionApi.d.ts +4 -2
  84. package/models/events/gridEventLookup.d.ts +10 -0
  85. package/package.json +2 -2
  86. package/utils/css/context.js +2 -1
@@ -2,6 +2,4 @@
2
2
 
3
3
  import * as React from 'react';
4
4
  export const GridApiContext = /*#__PURE__*/React.createContext(undefined);
5
- if (process.env.NODE_ENV !== 'production') {
6
- GridApiContext.displayName = 'GridApiContext';
7
- }
5
+ if (process.env.NODE_ENV !== "production") GridApiContext.displayName = "GridApiContext";
@@ -13,4 +13,5 @@ export const GridColumnUnsortedIcon = /*#__PURE__*/React.memo(function GridColum
13
13
  const [nextSortDirection] = sortingOrder;
14
14
  const Icon = nextSortDirection === 'asc' ? rootProps.slots.columnSortedAscendingIcon : rootProps.slots.columnSortedDescendingIcon;
15
15
  return Icon ? /*#__PURE__*/_jsx(Icon, _extends({}, other)) : null;
16
- });
16
+ });
17
+ if (process.env.NODE_ENV !== "production") GridColumnUnsortedIcon.displayName = "GridColumnUnsortedIcon";
@@ -2,6 +2,4 @@
2
2
 
3
3
  import * as React from 'react';
4
4
  export const GridConfigurationContext = /*#__PURE__*/React.createContext(undefined);
5
- if (process.env.NODE_ENV !== 'production') {
6
- GridConfigurationContext.displayName = 'GridConfigurationContext';
7
- }
5
+ if (process.env.NODE_ENV !== "production") GridConfigurationContext.displayName = "GridConfigurationContext";
@@ -246,6 +246,7 @@ const GridRow = forwardRef(function GridRow(props, refProp) {
246
246
  rowNode: rowNode
247
247
  }, slotProps?.cell), column.field);
248
248
  };
249
+ if (process.env.NODE_ENV !== "production") getCell.displayName = "getCell";
249
250
  const leftCells = pinnedColumns.left.map((column, i) => {
250
251
  const indexRelativeToAllColumns = i;
251
252
  return getCell(column, i, indexRelativeToAllColumns, pinnedColumns.left.length, PinnedColumnPosition.LEFT);
@@ -258,4 +258,5 @@ process.env.NODE_ENV !== "production" ? GridActionsCell.propTypes = {
258
258
  value: PropTypes.any
259
259
  } : void 0;
260
260
  export { GridActionsCell };
261
- export const renderActionsCell = params => /*#__PURE__*/_jsx(GridActionsCell, _extends({}, params));
261
+ export const renderActionsCell = params => /*#__PURE__*/_jsx(GridActionsCell, _extends({}, params));
262
+ if (process.env.NODE_ENV !== "production") renderActionsCell.displayName = "renderActionsCell";
@@ -115,10 +115,12 @@ process.env.NODE_ENV !== "production" ? GridBooleanCellRaw.propTypes = {
115
115
  value: PropTypes.any
116
116
  } : void 0;
117
117
  const GridBooleanCell = /*#__PURE__*/React.memo(GridBooleanCellRaw);
118
+ if (process.env.NODE_ENV !== "production") GridBooleanCell.displayName = "GridBooleanCell";
118
119
  export { GridBooleanCell };
119
120
  export const renderBooleanCell = params => {
120
121
  if (params.field !== GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD && isAutogeneratedRowNode(params.rowNode)) {
121
122
  return '';
122
123
  }
123
124
  return /*#__PURE__*/_jsx(GridBooleanCell, _extends({}, params));
124
- };
125
+ };
126
+ if (process.env.NODE_ENV !== "production") renderBooleanCell.displayName = "renderBooleanCell";
@@ -136,4 +136,5 @@ process.env.NODE_ENV !== "production" ? GridEditBooleanCell.propTypes = {
136
136
  value: PropTypes.any
137
137
  } : void 0;
138
138
  export { GridEditBooleanCell };
139
- export const renderEditBooleanCell = params => /*#__PURE__*/_jsx(GridEditBooleanCell, _extends({}, params));
139
+ export const renderEditBooleanCell = params => /*#__PURE__*/_jsx(GridEditBooleanCell, _extends({}, params));
140
+ if (process.env.NODE_ENV !== "production") renderEditBooleanCell.displayName = "renderEditBooleanCell";
@@ -190,4 +190,5 @@ process.env.NODE_ENV !== "production" ? GridEditDateCell.propTypes = {
190
190
  value: PropTypes.any
191
191
  } : void 0;
192
192
  export { GridEditDateCell };
193
- export const renderEditDateCell = params => /*#__PURE__*/_jsx(GridEditDateCell, _extends({}, params));
193
+ export const renderEditDateCell = params => /*#__PURE__*/_jsx(GridEditDateCell, _extends({}, params));
194
+ if (process.env.NODE_ENV !== "production") renderEditDateCell.displayName = "renderEditDateCell";
@@ -165,4 +165,5 @@ process.env.NODE_ENV !== "production" ? GridEditInputCell.propTypes = {
165
165
  value: PropTypes.any
166
166
  } : void 0;
167
167
  export { GridEditInputCell };
168
- export const renderEditInputCell = params => /*#__PURE__*/_jsx(GridEditInputCell, _extends({}, params));
168
+ export const renderEditInputCell = params => /*#__PURE__*/_jsx(GridEditInputCell, _extends({}, params));
169
+ if (process.env.NODE_ENV !== "production") renderEditInputCell.displayName = "renderEditInputCell";
@@ -186,4 +186,5 @@ process.env.NODE_ENV !== "production" ? GridEditSingleSelectCell.propTypes = {
186
186
  value: PropTypes.any
187
187
  } : void 0;
188
188
  export { GridEditSingleSelectCell };
189
- export const renderEditSingleSelectCell = params => /*#__PURE__*/_jsx(GridEditSingleSelectCell, _extends({}, params));
189
+ export const renderEditSingleSelectCell = params => /*#__PURE__*/_jsx(GridEditSingleSelectCell, _extends({}, params));
190
+ if (process.env.NODE_ENV !== "production") renderEditSingleSelectCell.displayName = "renderEditSingleSelectCell";
@@ -60,4 +60,5 @@ export const ColumnHeaderMenuIcon = /*#__PURE__*/React.memo(props => {
60
60
  }))
61
61
  }))
62
62
  });
63
- });
63
+ });
64
+ if (process.env.NODE_ENV !== "production") ColumnHeaderMenuIcon.displayName = "ColumnHeaderMenuIcon";
@@ -110,7 +110,7 @@ function GridColumnHeaderItem(props) {
110
110
  onDragStart: publish('columnHeaderDragStart'),
111
111
  onDragEnter: publish('columnHeaderDragEnter'),
112
112
  onDragOver: publish('columnHeaderDragOver'),
113
- onDragEnd: publish('columnHeaderDragEnd')
113
+ onDragEndCapture: publish('columnHeaderDragEnd')
114
114
  } : {}, [isDraggable, publish]);
115
115
  const columnHeaderSeparatorProps = React.useMemo(() => ({
116
116
  onMouseDown: publish('columnSeparatorMouseDown'),
@@ -58,6 +58,7 @@ function GridColumnHeaderSeparatorRaw(props) {
58
58
  );
59
59
  }
60
60
  const GridColumnHeaderSeparator = /*#__PURE__*/React.memo(GridColumnHeaderSeparatorRaw);
61
+ if (process.env.NODE_ENV !== "production") GridColumnHeaderSeparator.displayName = "GridColumnHeaderSeparator";
61
62
  process.env.NODE_ENV !== "production" ? GridColumnHeaderSeparatorRaw.propTypes = {
62
63
  // ----------------------------- Warning --------------------------------
63
64
  // | These PropTypes are generated from the TypeScript type definitions |
@@ -12,6 +12,7 @@ function GridColumnHeaderSortIconRaw(props) {
12
12
  });
13
13
  }
14
14
  const GridColumnHeaderSortIcon = /*#__PURE__*/React.memo(GridColumnHeaderSortIconRaw);
15
+ if (process.env.NODE_ENV !== "production") GridColumnHeaderSortIcon.displayName = "GridColumnHeaderSortIcon";
15
16
  process.env.NODE_ENV !== "production" ? GridColumnHeaderSortIconRaw.propTypes = {
16
17
  // ----------------------------- Warning --------------------------------
17
18
  // | These PropTypes are generated from the TypeScript type definitions |
@@ -8,8 +8,8 @@ import { forwardRef } from '@mui/x-internals/forwardRef';
8
8
  import { useGridApiContext } from "../../hooks/utils/useGridApiContext.js";
9
9
  import { useGridRootProps } from "../../hooks/utils/useGridRootProps.js";
10
10
  import { getDataGridUtilityClass } from "../../constants/gridClasses.js";
11
- import { objectShallowCompare, useGridSelector } from "../../hooks/utils/useGridSelector.js";
12
- import { getCheckboxPropsSelector } from "../../hooks/features/rowSelection/utils.js";
11
+ import { useGridSelector } from "../../hooks/utils/useGridSelector.js";
12
+ import { checkboxPropsSelector } from "../../hooks/features/rowSelection/utils.js";
13
13
  import { jsx as _jsx } from "react/jsx-runtime";
14
14
  const useUtilityClasses = ownerState => {
15
15
  const {
@@ -57,11 +57,13 @@ const GridCellCheckboxForwardRef = forwardRef(function GridCellCheckboxRenderer(
57
57
  }
58
58
  }, []);
59
59
  const isSelectable = apiRef.current.isRowSelectable(id);
60
- const checkboxPropsSelector = getCheckboxPropsSelector(id, rootProps.rowSelectionPropagation?.parents ?? false);
61
60
  const {
62
61
  isIndeterminate,
63
62
  isChecked
64
- } = useGridSelector(apiRef, checkboxPropsSelector, undefined, objectShallowCompare);
63
+ } = useGridSelector(apiRef, checkboxPropsSelector, {
64
+ groupId: id,
65
+ autoSelectParents: rootProps.rowSelectionPropagation?.parents ?? false
66
+ });
65
67
  if (rowNode.type === 'footer' || rowNode.type === 'pinnedRow') {
66
68
  return null;
67
69
  }
@@ -657,7 +657,7 @@ export const GridRootStyles = styled('div', {
657
657
  borderTop: 'none'
658
658
  }
659
659
  },
660
- [`&.${c['root--disableUserSelection']} .${c.cell}`]: {
660
+ [`&.${c['root--disableUserSelection']}`]: {
661
661
  userSelect: 'none'
662
662
  },
663
663
  [`& .${c['row--dynamicHeight']} > .${c.cell}`]: {
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  export const GridPanelContext = /*#__PURE__*/React.createContext(undefined);
4
+ if (process.env.NODE_ENV !== "production") GridPanelContext.displayName = "GridPanelContext";
4
5
  export function useGridPanelContext() {
5
6
  const context = React.useContext(GridPanelContext);
6
7
  if (context === undefined) {
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
  export const QuickFilterContext = /*#__PURE__*/React.createContext(undefined);
3
+ if (process.env.NODE_ENV !== "production") QuickFilterContext.displayName = "QuickFilterContext";
3
4
  export function useQuickFilterContext() {
4
5
  const context = React.useContext(QuickFilterContext);
5
6
  if (context === undefined) {
@@ -12,6 +12,7 @@ import { getDataGridUtilityClass } from "../../constants/gridClasses.js";
12
12
  import { useGridComponentRenderer } from "../../hooks/utils/useGridComponentRenderer.js";
13
13
  import { ToolbarContext } from "./ToolbarContext.js";
14
14
  import { useGridRootProps } from "../../hooks/utils/useGridRootProps.js";
15
+ import { sortByDocumentPosition } from "./utils.js";
15
16
  import { jsx as _jsx } from "react/jsx-runtime";
16
17
  const useUtilityClasses = ownerState => {
17
18
  const {
@@ -59,21 +60,11 @@ const Toolbar = forwardRef(function Toolbar(props, ref) {
59
60
  const classes = useUtilityClasses(rootProps);
60
61
  const [focusableItemId, setFocusableItemId] = React.useState(null);
61
62
  const [items, setItems] = React.useState([]);
62
- const registerItem = React.useCallback((id, itemRef) => {
63
- setItems(prevItems => [...prevItems, {
64
- id,
65
- ref: itemRef
66
- }]);
67
- }, []);
68
- const unregisterItem = React.useCallback(id => {
69
- setItems(prevItems => prevItems.filter(i => i.id !== id));
70
- if (focusableItemId === id) {
71
- setFocusableItemId(null);
72
- }
73
- }, [focusableItemId]);
63
+ const getSortedItems = React.useCallback(() => items.sort(sortByDocumentPosition), [items]);
74
64
  const findEnabledItem = React.useCallback((startIndex, step, wrap = true) => {
75
65
  let index = startIndex;
76
- const itemCount = items.length;
66
+ const sortedItems = getSortedItems();
67
+ const itemCount = sortedItems.length;
77
68
 
78
69
  // Look for enabled items in the specified direction
79
70
  for (let i = 0; i < itemCount; i += 1) {
@@ -93,53 +84,93 @@ const Toolbar = forwardRef(function Toolbar(props, ref) {
93
84
  }
94
85
 
95
86
  // Return if we found an enabled item
96
- if (!items[index].ref.current?.disabled && items[index].ref.current?.ariaDisabled !== 'true') {
87
+ if (!sortedItems[index].ref.current?.disabled && sortedItems[index].ref.current?.ariaDisabled !== 'true') {
97
88
  return index;
98
89
  }
99
90
  }
100
91
 
101
92
  // If we've checked all items and found none enabled
102
93
  return -1;
103
- }, [items]);
94
+ }, [getSortedItems]);
95
+ const registerItem = React.useCallback((id, itemRef) => {
96
+ setItems(prevItems => [...prevItems, {
97
+ id,
98
+ ref: itemRef
99
+ }]);
100
+ }, []);
101
+ const unregisterItem = React.useCallback(id => {
102
+ setItems(prevItems => prevItems.filter(i => i.id !== id));
103
+ }, []);
104
104
  const onItemKeyDown = React.useCallback(event => {
105
105
  if (!focusableItemId) {
106
106
  return;
107
107
  }
108
- const currentIndex = items.findIndex(item => item.id === focusableItemId);
108
+ const sortedItems = getSortedItems();
109
+ const focusableItemIndex = sortedItems.findIndex(item => item.id === focusableItemId);
109
110
  let newIndex = -1;
110
111
  if (event.key === 'ArrowRight') {
111
112
  event.preventDefault();
112
- newIndex = findEnabledItem(currentIndex, 1);
113
+ newIndex = findEnabledItem(focusableItemIndex, 1);
113
114
  } else if (event.key === 'ArrowLeft') {
114
115
  event.preventDefault();
115
- newIndex = findEnabledItem(currentIndex, -1);
116
+ newIndex = findEnabledItem(focusableItemIndex, -1);
116
117
  } else if (event.key === 'Home') {
117
118
  event.preventDefault();
118
119
  newIndex = findEnabledItem(-1, 1, false);
119
120
  } else if (event.key === 'End') {
120
121
  event.preventDefault();
121
- newIndex = findEnabledItem(items.length, -1, false);
122
+ newIndex = findEnabledItem(sortedItems.length, -1, false);
122
123
  }
123
- if (newIndex >= 0 && newIndex < items.length) {
124
- const item = items[newIndex];
124
+
125
+ // TODO: Check why this is necessary
126
+ if (newIndex >= 0 && newIndex < sortedItems.length) {
127
+ const item = sortedItems[newIndex];
125
128
  setFocusableItemId(item.id);
126
129
  item.ref.current?.focus();
127
130
  }
128
- }, [items, focusableItemId, findEnabledItem]);
131
+ }, [getSortedItems, focusableItemId, findEnabledItem]);
129
132
  const onItemFocus = React.useCallback(id => {
130
133
  if (focusableItemId !== id) {
131
134
  setFocusableItemId(id);
132
135
  }
133
- }, [focusableItemId]);
136
+ }, [focusableItemId, setFocusableItemId]);
134
137
  const onItemDisabled = React.useCallback(id => {
135
- const currentIndex = items.findIndex(item => item.id === id);
138
+ const sortedItems = getSortedItems();
139
+ const currentIndex = sortedItems.findIndex(item => item.id === id);
136
140
  const newIndex = findEnabledItem(currentIndex, 1);
137
- if (newIndex >= 0 && newIndex < items.length) {
138
- const item = items[newIndex];
141
+ if (newIndex >= 0 && newIndex < sortedItems.length) {
142
+ const item = sortedItems[newIndex];
139
143
  setFocusableItemId(item.id);
140
144
  item.ref.current?.focus();
141
145
  }
142
- }, [items, findEnabledItem]);
146
+ }, [getSortedItems, findEnabledItem]);
147
+ React.useEffect(() => {
148
+ const sortedItems = getSortedItems();
149
+ if (sortedItems.length > 0) {
150
+ // Set initial focusable item
151
+ if (!focusableItemId) {
152
+ setFocusableItemId(sortedItems[0].id);
153
+ return;
154
+ }
155
+ const focusableItemIndex = sortedItems.findIndex(item => item.id === focusableItemId);
156
+ if (!sortedItems[focusableItemIndex]) {
157
+ // Last item has been removed from the items array
158
+ const item = sortedItems[sortedItems.length - 1];
159
+ if (item) {
160
+ setFocusableItemId(item.id);
161
+ item.ref.current?.focus();
162
+ }
163
+ } else if (focusableItemIndex === -1) {
164
+ // Focused item has been removed from the items array
165
+ const item = sortedItems[focusableItemIndex];
166
+ if (item) {
167
+ setFocusableItemId(item.id);
168
+ item.ref.current?.focus();
169
+ }
170
+ }
171
+ }
172
+ // eslint-disable-next-line react-hooks/exhaustive-deps
173
+ }, [getSortedItems, findEnabledItem]);
143
174
  const contextValue = React.useMemo(() => ({
144
175
  focusableItemId,
145
176
  registerItem,
@@ -156,11 +187,6 @@ const Toolbar = forwardRef(function Toolbar(props, ref) {
156
187
  }, other, {
157
188
  ref
158
189
  }));
159
- React.useEffect(() => {
160
- if (items.length > 0) {
161
- setFocusableItemId(items[0].id);
162
- }
163
- }, [items]);
164
190
  return /*#__PURE__*/_jsx(ToolbarContext.Provider, {
165
191
  value: contextValue,
166
192
  children: element
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
  export const ToolbarContext = /*#__PURE__*/React.createContext(undefined);
3
+ if (process.env.NODE_ENV !== "production") ToolbarContext.displayName = "ToolbarContext";
3
4
  export function useToolbarContext() {
4
5
  const context = React.useContext(ToolbarContext);
5
6
  if (context === undefined) {
@@ -0,0 +1,5 @@
1
+ export declare function sortByDocumentPosition(a: {
2
+ ref: React.RefObject<HTMLButtonElement | null>;
3
+ }, b: {
4
+ ref: React.RefObject<HTMLButtonElement | null>;
5
+ }): 0 | 1 | -1;
@@ -0,0 +1,17 @@
1
+ /* eslint-disable no-bitwise */
2
+ export function sortByDocumentPosition(a, b) {
3
+ if (!a.ref.current || !b.ref.current) {
4
+ return 0;
5
+ }
6
+ const position = a.ref.current.compareDocumentPosition(b.ref.current);
7
+ if (!position) {
8
+ return 0;
9
+ }
10
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING || position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
11
+ return -1;
12
+ }
13
+ if (position & Node.DOCUMENT_POSITION_PRECEDING || position & Node.DOCUMENT_POSITION_CONTAINS) {
14
+ return 1;
15
+ }
16
+ return 0;
17
+ }
@@ -2,7 +2,5 @@
2
2
 
3
3
  import * as React from 'react';
4
4
  const GridRootPropsContext = /*#__PURE__*/React.createContext(undefined);
5
- if (process.env.NODE_ENV !== 'production') {
6
- GridRootPropsContext.displayName = 'GridRootPropsContext';
7
- }
5
+ if (process.env.NODE_ENV !== "production") GridRootPropsContext.displayName = "GridRootPropsContext";
8
6
  export { GridRootPropsContext };
@@ -75,7 +75,7 @@ export const useGridColumnHeaders = props => {
75
75
  useGridEvent(apiRef, 'columnResizeStart', handleColumnResizeStart);
76
76
  useGridEvent(apiRef, 'columnResizeStop', handleColumnResizeStop);
77
77
  useGridEvent(apiRef, 'columnHeaderDragStart', handleColumnReorderStart);
78
- useGridEvent(apiRef, 'columnHeaderDragEnd', handleColumnReorderStop);
78
+ useGridEvent(apiRef, 'columnHeaderDragEndNative', handleColumnReorderStop);
79
79
 
80
80
  // Helper for computation common between getColumnHeaders and getColumnGroupHeaders
81
81
  const getColumnsToRender = params => {
@@ -113,6 +113,7 @@ export const useGridColumnHeaders = props => {
113
113
  })]
114
114
  });
115
115
  };
116
+ if (process.env.NODE_ENV !== "production") getFillers.displayName = "getFillers";
116
117
  const getColumnHeaders = (params, other = {}) => {
117
118
  const {
118
119
  renderedColumns,
@@ -181,6 +182,7 @@ export const useGridColumnHeaders = props => {
181
182
  })]
182
183
  });
183
184
  };
185
+ if (process.env.NODE_ENV !== "production") getColumnHeadersRow.displayName = "getColumnHeadersRow";
184
186
  const getColumnGroupHeaders = ({
185
187
  depth,
186
188
  params
@@ -302,13 +302,21 @@ export function getFirstNonSpannedColumnToRender({
302
302
  visibleRows
303
303
  }) {
304
304
  let firstNonSpannedColumnToRender = firstColumnToRender;
305
- for (let i = firstRowToRender; i < lastRowToRender; i += 1) {
306
- const row = visibleRows[i];
307
- if (row) {
308
- const rowId = visibleRows[i].id;
309
- const cellColSpanInfo = apiRef.current.unstable_getCellColSpanInfo(rowId, firstColumnToRender);
310
- if (cellColSpanInfo && cellColSpanInfo.spannedByColSpan) {
311
- firstNonSpannedColumnToRender = cellColSpanInfo.leftVisibleCellIndex;
305
+ let foundStableColumn = false;
306
+
307
+ // Keep checking columns until we find one that's not spanned in any visible row
308
+ while (!foundStableColumn && firstNonSpannedColumnToRender >= 0) {
309
+ foundStableColumn = true;
310
+ for (let i = firstRowToRender; i < lastRowToRender; i += 1) {
311
+ const row = visibleRows[i];
312
+ if (row) {
313
+ const rowId = visibleRows[i].id;
314
+ const cellColSpanInfo = apiRef.current.unstable_getCellColSpanInfo(rowId, firstNonSpannedColumnToRender);
315
+ if (cellColSpanInfo && cellColSpanInfo.spannedByColSpan && cellColSpanInfo.leftVisibleCellIndex < firstNonSpannedColumnToRender) {
316
+ firstNonSpannedColumnToRender = cellColSpanInfo.leftVisibleCellIndex;
317
+ foundStableColumn = false;
318
+ break; // Check the new column index against the visible rows, because it might be spanned
319
+ }
312
320
  }
313
321
  }
314
322
  }
@@ -61,6 +61,7 @@ export const useGridOverlays = () => {
61
61
  children: /*#__PURE__*/_jsx(Overlay, _extends({}, overlayProps))
62
62
  }));
63
63
  };
64
+ if (process.env.NODE_ENV !== "production") getOverlay.displayName = "getOverlay";
64
65
  return {
65
66
  getOverlay,
66
67
  overlaysProps
@@ -138,7 +138,7 @@ export const useGridPaginationModel = (apiRef, props) => {
138
138
  return;
139
139
  }
140
140
  const dimensions = apiRef.current.getRootDimensions();
141
- const maximumPageSizeWithoutScrollBar = Math.floor(dimensions.viewportInnerSize.height / rowHeight);
141
+ const maximumPageSizeWithoutScrollBar = Math.max(1, Math.floor(dimensions.viewportInnerSize.height / rowHeight));
142
142
  apiRef.current.setPageSize(maximumPageSizeWithoutScrollBar);
143
143
  }, [apiRef, props.autoPageSize, rowHeight]);
144
144
  const handleRowCountChange = React.useCallback(newRowCount => {
@@ -92,7 +92,7 @@ export const useGridRowSelection = (apiRef, props) => {
92
92
  /*
93
93
  * API METHODS
94
94
  */
95
- const setRowSelectionModel = React.useCallback(model => {
95
+ const setRowSelectionModel = React.useCallback((model, reason) => {
96
96
  if (props.signature === GridSignature.DataGrid && !canHaveMultipleSelection && (model.type !== 'include' || model.ids.size > 1)) {
97
97
  throw new Error(['MUI X: `rowSelectionModel` can only contain 1 item in DataGrid.', 'You need to upgrade to DataGridPro or DataGridPremium component to unlock multiple selection.'].join('\n'));
98
98
  }
@@ -101,7 +101,7 @@ export const useGridRowSelection = (apiRef, props) => {
101
101
  logger.debug(`Setting selection model`);
102
102
  apiRef.current.setState(state => _extends({}, state, {
103
103
  rowSelection: props.rowSelection ? model : emptyModel
104
- }));
104
+ }), reason);
105
105
  }
106
106
  }, [apiRef, logger, props.rowSelection, props.signature, canHaveMultipleSelection]);
107
107
  const isRowSelected = React.useCallback(id => {
@@ -142,7 +142,7 @@ export const useGridRowSelection = (apiRef, props) => {
142
142
  findRowsToSelect(apiRef, tree, id, props.rowSelectionPropagation?.descendants ?? false, props.rowSelectionPropagation?.parents ?? false, addRow);
143
143
  }
144
144
  }
145
- apiRef.current.setRowSelectionModel(newSelectionModel);
145
+ apiRef.current.setRowSelectionModel(newSelectionModel, 'singleRowSelection');
146
146
  } else {
147
147
  logger.debug(`Toggling selection for row ${id}`);
148
148
  const selectionModel = gridRowSelectionStateSelector(apiRef);
@@ -168,7 +168,7 @@ export const useGridRowSelection = (apiRef, props) => {
168
168
  }
169
169
  const isSelectionValid = newSelectionModel.type === 'include' && newSelectionModel.ids.size < 2 || canHaveMultipleSelection;
170
170
  if (isSelectionValid) {
171
- apiRef.current.setRowSelectionModel(newSelectionModel);
171
+ apiRef.current.setRowSelectionModel(newSelectionModel, 'singleRowSelection');
172
172
  }
173
173
  }
174
174
  }, [apiRef, logger, applyAutoSelection, tree, props.rowSelectionPropagation?.descendants, props.rowSelectionPropagation?.parents, canHaveMultipleSelection]);
@@ -235,7 +235,7 @@ export const useGridRowSelection = (apiRef, props) => {
235
235
  }
236
236
  const isSelectionValid = newSelectionModel.type === 'include' && newSelectionModel.ids.size < 2 || canHaveMultipleSelection;
237
237
  if (isSelectionValid) {
238
- apiRef.current.setRowSelectionModel(newSelectionModel);
238
+ apiRef.current.setRowSelectionModel(newSelectionModel, 'multipleRowsSelection');
239
239
  }
240
240
  }, [logger, applyAutoSelection, canHaveMultipleSelection, apiRef, tree, props.rowSelectionPropagation?.descendants, props.rowSelectionPropagation?.parents, props.rowSelection]);
241
241
  const getPropagatedRowSelectionModel = React.useCallback(inputSelectionModel => {
@@ -360,7 +360,7 @@ export const useGridRowSelection = (apiRef, props) => {
360
360
  apiRef.current.selectRows(Array.from(newSelectionModel.ids), true, true);
361
361
  }
362
362
  } else {
363
- apiRef.current.setRowSelectionModel(newSelectionModel);
363
+ apiRef.current.setRowSelectionModel(newSelectionModel, 'multipleRowsSelection');
364
364
  }
365
365
  }
366
366
  }, [apiRef, isNestedData, props.rowSelectionPropagation?.parents, props.keepNonExistentRowsSelected, props.filterMode, tree, getRowsToBeSelected]);
@@ -427,7 +427,7 @@ export const useGridRowSelection = (apiRef, props) => {
427
427
  const toggleAllRows = React.useCallback(value => {
428
428
  const filterModel = gridFilterModelSelector(apiRef);
429
429
  const quickFilterModel = gridQuickFilterValuesSelector(apiRef);
430
- const hasFilters = filterModel.items.length > 0 || (quickFilterModel?.length || 0) > 0;
430
+ const hasFilters = filterModel.items.length > 0 || quickFilterModel?.some(val => val.length);
431
431
  if (!props.isRowSelectable && !props.checkboxSelectionVisibleOnly && applyAutoSelection && !hasFilters) {
432
432
  apiRef.current.setRowSelectionModel({
433
433
  type: value ? 'exclude' : 'include',
@@ -5,7 +5,10 @@ import type { GridPrivateApiCommunity } from "../../../models/api/gridApiCommuni
5
5
  import { type GridRowSelectionPropagation } from "../../../models/gridRowSelectionModel.js";
6
6
  import { type RowSelectionManager } from "../../../models/gridRowSelectionManager.js";
7
7
  export declare const ROW_SELECTION_PROPAGATION_DEFAULT: GridRowSelectionPropagation;
8
- export declare function getCheckboxPropsSelector(groupId: GridRowId, autoSelectParents: boolean): import("@mui/x-data-grid").OutputSelector<import("../../../models/gridStateCommunity.js").GridStateCommunity, RowSelectionManager, {
8
+ export declare const checkboxPropsSelector: import("@mui/x-data-grid").OutputSelector<import("../../../models/gridStateCommunity.js").GridStateCommunity, {
9
+ groupId: GridRowId;
10
+ autoSelectParents: boolean;
11
+ }, {
9
12
  isIndeterminate: boolean;
10
13
  isChecked: boolean;
11
14
  }>;
@@ -27,41 +27,42 @@ function getGridRowGroupSelectableDescendants(apiRef, groupId) {
27
27
  }
28
28
  return descendants;
29
29
  }
30
-
31
- // TODO v8: Use `createSelectorV8`
32
- export function getCheckboxPropsSelector(groupId, autoSelectParents) {
33
- return createSelector(gridRowTreeSelector, gridSortedRowIdsSelector, gridFilteredRowsLookupSelector, gridRowSelectionManagerSelector, (rowTree, sortedRowIds, filteredRowsLookup, rowSelectionManager) => {
34
- const groupNode = rowTree[groupId];
35
- if (!groupNode || groupNode.type !== 'group') {
36
- return {
37
- isIndeterminate: false,
38
- isChecked: rowSelectionManager.has(groupId)
39
- };
30
+ export const checkboxPropsSelector = createSelector(gridRowTreeSelector, gridFilteredRowsLookupSelector, gridRowSelectionManagerSelector, (rowTree, filteredRowsLookup, rowSelectionManager, {
31
+ groupId,
32
+ autoSelectParents
33
+ }) => {
34
+ const groupNode = rowTree[groupId];
35
+ if (!groupNode || groupNode.type !== 'group' || rowSelectionManager.has(groupId)) {
36
+ return {
37
+ isIndeterminate: false,
38
+ isChecked: rowSelectionManager.has(groupId)
39
+ };
40
+ }
41
+ let hasSelectedDescendant = false;
42
+ let hasUnSelectedDescendant = false;
43
+ const traverseDescendants = itemToTraverseId => {
44
+ if (filteredRowsLookup[itemToTraverseId] === false ||
45
+ // Perf: Skip checking the rest of the descendants if we already
46
+ // know that there is a selected and an unselected descendant
47
+ hasSelectedDescendant && hasUnSelectedDescendant) {
48
+ return;
40
49
  }
41
- if (rowSelectionManager.has(groupId)) {
42
- return {
43
- isIndeterminate: false,
44
- isChecked: true
45
- };
50
+ const node = rowTree[itemToTraverseId];
51
+ if (node?.type === 'group') {
52
+ node.children.forEach(traverseDescendants);
46
53
  }
47
- let selectableDescendantsCount = 0;
48
- let selectedDescendantsCount = 0;
49
- const startIndex = sortedRowIds.findIndex(id => id === groupId) + 1;
50
- for (let index = startIndex; index < sortedRowIds.length && rowTree[sortedRowIds[index]]?.depth > groupNode.depth; index += 1) {
51
- const id = sortedRowIds[index];
52
- if (filteredRowsLookup[id] !== false) {
53
- selectableDescendantsCount += 1;
54
- if (rowSelectionManager.has(id)) {
55
- selectedDescendantsCount += 1;
56
- }
57
- }
54
+ if (rowSelectionManager.has(itemToTraverseId)) {
55
+ hasSelectedDescendant = true;
56
+ } else {
57
+ hasUnSelectedDescendant = true;
58
58
  }
59
- return {
60
- isIndeterminate: selectedDescendantsCount > 0 && (selectedDescendantsCount < selectableDescendantsCount || !rowSelectionManager.has(groupId)),
61
- isChecked: autoSelectParents ? selectedDescendantsCount > 0 : rowSelectionManager.has(groupId)
62
- };
63
- });
64
- }
59
+ };
60
+ traverseDescendants(groupId);
61
+ return {
62
+ isIndeterminate: hasSelectedDescendant && hasUnSelectedDescendant,
63
+ isChecked: autoSelectParents ? hasSelectedDescendant && !hasUnSelectedDescendant : false
64
+ };
65
+ });
65
66
  export function isMultipleRowSelectionEnabled(props) {
66
67
  if (props.signature === GridSignature.DataGrid) {
67
68
  // DataGrid Community has multiple row selection enabled only if checkbox selection is enabled.
@@ -218,12 +218,13 @@ export const useGridVirtualScroller = () => {
218
218
  scrollCache.buffer = bufferForDirection(isRtl, direction, rootProps.rowBufferPx, rootProps.columnBufferPx, rowHeight * 15, MINIMUM_COLUMN_WIDTH * 6);
219
219
  const inputs = inputsSelector(apiRef, rootProps, enabledForRows, enabledForColumns);
220
220
  const nextRenderContext = computeRenderContext(inputs, scrollPosition.current, scrollCache);
221
-
222
- // Prevents batching render context changes
223
- ReactDOM.flushSync(() => {
224
- updateRenderContext(nextRenderContext);
225
- });
226
- scrollTimeout.start(1000, triggerUpdateRenderContext);
221
+ if (!areRenderContextsEqual(nextRenderContext, renderContext)) {
222
+ // Prevents batching render context changes
223
+ ReactDOM.flushSync(() => {
224
+ updateRenderContext(nextRenderContext);
225
+ });
226
+ scrollTimeout.start(1000, triggerUpdateRenderContext);
227
+ }
227
228
  return nextRenderContext;
228
229
  });
229
230
  const forceUpdateRenderContext = () => {