@mui/x-data-grid 6.14.0 → 6.16.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 (138) hide show
  1. package/CHANGELOG.md +167 -0
  2. package/DataGrid/useDataGridComponent.js +43 -40
  3. package/components/DataGridVirtualScroller.d.ts +1 -4
  4. package/components/DataGridVirtualScroller.js +3 -5
  5. package/components/GridRow.js +4 -2
  6. package/components/base/GridBody.d.ts +0 -1
  7. package/components/base/GridBody.js +2 -22
  8. package/components/cell/GridActionsCell.js +2 -2
  9. package/components/cell/GridActionsCellItem.d.ts +6 -0
  10. package/components/cell/GridCell.js +4 -2
  11. package/components/columnHeaders/GridColumnHeaderItem.js +2 -1
  12. package/components/menu/GridMenu.d.ts +1 -2
  13. package/components/menu/GridMenu.js +21 -5
  14. package/components/menu/columnMenu/GridColumnHeaderMenu.js +11 -8
  15. package/components/panel/filterPanel/GridFilterInputBoolean.js +1 -1
  16. package/components/panel/filterPanel/GridFilterInputSingleSelect.js +1 -1
  17. package/components/toolbar/GridToolbarDensitySelector.js +2 -7
  18. package/components/toolbar/GridToolbarExportContainer.js +1 -9
  19. package/hooks/features/columnHeaders/useGridColumnHeaders.js +6 -3
  20. package/hooks/features/export/useGridPrintExport.js +37 -7
  21. package/hooks/features/filter/gridFilterUtils.js +10 -6
  22. package/hooks/features/focus/useGridFocus.js +0 -1
  23. package/hooks/features/index.d.ts +1 -0
  24. package/hooks/features/index.js +2 -1
  25. package/hooks/features/virtualization/gridVirtualizationSelectors.d.ts +16 -0
  26. package/hooks/features/virtualization/gridVirtualizationSelectors.js +18 -0
  27. package/hooks/features/virtualization/index.d.ts +2 -0
  28. package/hooks/features/virtualization/index.js +2 -0
  29. package/hooks/features/virtualization/useGridVirtualScroller.d.ts +0 -1
  30. package/hooks/features/virtualization/useGridVirtualScroller.js +53 -36
  31. package/hooks/features/virtualization/useGridVirtualization.d.ts +12 -0
  32. package/hooks/features/virtualization/useGridVirtualization.js +47 -0
  33. package/index.js +1 -1
  34. package/internals/index.d.ts +4 -0
  35. package/internals/index.js +4 -0
  36. package/legacy/DataGrid/useDataGridComponent.js +43 -40
  37. package/legacy/components/DataGridVirtualScroller.js +2 -4
  38. package/legacy/components/GridRow.js +4 -2
  39. package/legacy/components/base/GridBody.js +2 -26
  40. package/legacy/components/cell/GridActionsCell.js +2 -2
  41. package/legacy/components/cell/GridCell.js +4 -2
  42. package/legacy/components/columnHeaders/GridColumnHeaderItem.js +2 -1
  43. package/legacy/components/menu/GridMenu.js +21 -5
  44. package/legacy/components/menu/columnMenu/GridColumnHeaderMenu.js +11 -8
  45. package/legacy/components/panel/filterPanel/GridFilterInputBoolean.js +2 -1
  46. package/legacy/components/panel/filterPanel/GridFilterInputSingleSelect.js +2 -1
  47. package/legacy/components/toolbar/GridToolbarDensitySelector.js +2 -7
  48. package/legacy/components/toolbar/GridToolbarExportContainer.js +1 -9
  49. package/legacy/hooks/features/columnHeaders/useGridColumnHeaders.js +6 -3
  50. package/legacy/hooks/features/export/useGridPrintExport.js +44 -12
  51. package/legacy/hooks/features/filter/gridFilterUtils.js +10 -6
  52. package/legacy/hooks/features/focus/useGridFocus.js +0 -1
  53. package/legacy/hooks/features/index.js +2 -1
  54. package/legacy/hooks/features/virtualization/gridVirtualizationSelectors.js +24 -0
  55. package/legacy/hooks/features/virtualization/index.js +2 -0
  56. package/legacy/hooks/features/virtualization/useGridVirtualScroller.js +61 -39
  57. package/legacy/hooks/features/virtualization/useGridVirtualization.js +51 -0
  58. package/legacy/index.js +1 -1
  59. package/legacy/internals/index.js +4 -0
  60. package/legacy/locales/ruRU.js +26 -28
  61. package/legacy/models/api/index.js +1 -2
  62. package/legacy/utils/createControllablePromise.js +11 -0
  63. package/locales/ruRU.js +26 -28
  64. package/models/api/gridApiCommon.d.ts +3 -4
  65. package/models/api/gridVirtualizationApi.d.ts +20 -0
  66. package/models/api/index.d.ts +1 -2
  67. package/models/api/index.js +1 -2
  68. package/models/events/gridEventLookup.d.ts +8 -0
  69. package/models/gridExport.d.ts +17 -4
  70. package/models/gridStateCommunity.d.ts +2 -1
  71. package/models/index.d.ts +1 -1
  72. package/modern/DataGrid/useDataGridComponent.js +43 -40
  73. package/modern/components/DataGridVirtualScroller.js +3 -5
  74. package/modern/components/GridRow.js +4 -2
  75. package/modern/components/base/GridBody.js +2 -22
  76. package/modern/components/cell/GridActionsCell.js +2 -2
  77. package/modern/components/cell/GridCell.js +4 -2
  78. package/modern/components/columnHeaders/GridColumnHeaderItem.js +2 -1
  79. package/modern/components/menu/GridMenu.js +20 -5
  80. package/modern/components/menu/columnMenu/GridColumnHeaderMenu.js +11 -8
  81. package/modern/components/panel/filterPanel/GridFilterInputBoolean.js +1 -1
  82. package/modern/components/panel/filterPanel/GridFilterInputSingleSelect.js +1 -1
  83. package/modern/components/toolbar/GridToolbarDensitySelector.js +2 -7
  84. package/modern/components/toolbar/GridToolbarExportContainer.js +1 -9
  85. package/modern/hooks/features/columnHeaders/useGridColumnHeaders.js +6 -3
  86. package/modern/hooks/features/export/useGridPrintExport.js +37 -7
  87. package/modern/hooks/features/filter/gridFilterUtils.js +10 -6
  88. package/modern/hooks/features/focus/useGridFocus.js +0 -1
  89. package/modern/hooks/features/index.js +2 -1
  90. package/modern/hooks/features/virtualization/gridVirtualizationSelectors.js +18 -0
  91. package/modern/hooks/features/virtualization/index.js +2 -0
  92. package/modern/hooks/features/virtualization/useGridVirtualScroller.js +52 -36
  93. package/modern/hooks/features/virtualization/useGridVirtualization.js +47 -0
  94. package/modern/index.js +1 -1
  95. package/modern/internals/index.js +4 -0
  96. package/modern/locales/ruRU.js +26 -28
  97. package/modern/models/api/index.js +1 -2
  98. package/modern/utils/createControllablePromise.js +11 -0
  99. package/node/DataGrid/useDataGridComponent.js +43 -40
  100. package/node/components/DataGridVirtualScroller.js +3 -5
  101. package/node/components/GridRow.js +4 -2
  102. package/node/components/base/GridBody.js +2 -22
  103. package/node/components/cell/GridActionsCell.js +2 -2
  104. package/node/components/cell/GridCell.js +4 -2
  105. package/node/components/columnHeaders/GridColumnHeaderItem.js +2 -1
  106. package/node/components/menu/GridMenu.js +19 -4
  107. package/node/components/menu/columnMenu/GridColumnHeaderMenu.js +10 -7
  108. package/node/components/panel/filterPanel/GridFilterInputBoolean.js +1 -1
  109. package/node/components/panel/filterPanel/GridFilterInputSingleSelect.js +1 -1
  110. package/node/components/toolbar/GridToolbarDensitySelector.js +2 -7
  111. package/node/components/toolbar/GridToolbarExportContainer.js +1 -9
  112. package/node/hooks/features/columnHeaders/useGridColumnHeaders.js +8 -5
  113. package/node/hooks/features/export/useGridPrintExport.js +37 -7
  114. package/node/hooks/features/filter/gridFilterUtils.js +9 -6
  115. package/node/hooks/features/focus/useGridFocus.js +0 -1
  116. package/node/hooks/features/index.js +11 -0
  117. package/node/hooks/features/virtualization/gridVirtualizationSelectors.js +27 -0
  118. package/node/hooks/features/virtualization/index.js +27 -0
  119. package/node/hooks/features/virtualization/useGridVirtualScroller.js +51 -37
  120. package/node/hooks/features/virtualization/useGridVirtualization.js +58 -0
  121. package/node/index.js +1 -1
  122. package/node/internals/index.js +44 -0
  123. package/node/locales/ruRU.js +26 -28
  124. package/node/models/api/index.js +4 -15
  125. package/node/utils/createControllablePromise.js +17 -0
  126. package/package.json +1 -1
  127. package/utils/createControllablePromise.d.ts +5 -0
  128. package/utils/createControllablePromise.js +11 -0
  129. package/models/api/gridDisableVirtualizationApi.d.ts +0 -15
  130. package/models/api/gridVirtualScrollerApi.d.ts +0 -8
  131. package/models/api/gridVirtualScrollerApi.js +0 -1
  132. package/modern/models/api/gridDisableVirtualizationApi.js +0 -1
  133. package/modern/models/api/gridVirtualScrollerApi.js +0 -1
  134. package/node/models/api/gridVirtualScrollerApi.js +0 -5
  135. /package/legacy/models/api/{gridDisableVirtualizationApi.js → gridVirtualizationApi.js} +0 -0
  136. /package/{legacy/models/api/gridVirtualScrollerApi.js → models/api/gridVirtualizationApi.js} +0 -0
  137. /package/{models/api/gridDisableVirtualizationApi.js → modern/models/api/gridVirtualizationApi.js} +0 -0
  138. /package/node/models/api/{gridDisableVirtualizationApi.js → gridVirtualizationApi.js} +0 -0
@@ -38,14 +38,6 @@ export const GridToolbarExportContainer = /*#__PURE__*/React.forwardRef(function
38
38
  handleMenuClose();
39
39
  }
40
40
  };
41
- const handleMenuClickAway = event => {
42
- var _buttonRef$current;
43
- if (buttonRef.current === event.target || // if user clicked on the icon
44
- (_buttonRef$current = buttonRef.current) != null && _buttonRef$current.contains(event.target)) {
45
- return;
46
- }
47
- setOpen(false);
48
- };
49
41
  if (children == null) {
50
42
  return null;
51
43
  }
@@ -66,7 +58,7 @@ export const GridToolbarExportContainer = /*#__PURE__*/React.forwardRef(function
66
58
  })), /*#__PURE__*/_jsx(GridMenu, {
67
59
  open: open,
68
60
  target: buttonRef.current,
69
- onClickAway: handleMenuClickAway,
61
+ onClose: handleMenuClose,
70
62
  position: "bottom-start",
71
63
  children: /*#__PURE__*/_jsx(MenuList, {
72
64
  id: exportMenuId,
@@ -2,8 +2,9 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import * as ReactDOM from 'react-dom';
4
4
  import { unstable_useForkRef as useForkRef } from '@mui/utils';
5
- import { styled, useTheme } from '@mui/system';
5
+ import { styled, useTheme } from '@mui/material/styles';
6
6
  import { defaultMemoize } from 'reselect';
7
+ import { useGridSelector } from '../../utils';
7
8
  import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext';
8
9
  import { useGridRootProps } from '../../utils/useGridRootProps';
9
10
  import { useGridApiEventHandler } from '../../utils/useGridApiEventHandler';
@@ -11,6 +12,7 @@ import { GridColumnHeaderItem } from '../../../components/columnHeaders/GridColu
11
12
  import { getFirstColumnIndexToRender, getTotalHeaderHeight } from '../columns/gridColumnsUtils';
12
13
  import { useGridVisibleRows } from '../../utils/useGridVisibleRows';
13
14
  import { areRenderContextsEqual, getRenderableIndexes } from '../virtualization/useGridVirtualScroller';
15
+ import { gridVirtualizationColumnEnabledSelector } from '../virtualization';
14
16
  import { GridColumnGroupHeader } from '../../../components/columnHeaders/GridColumnGroupHeader';
15
17
  import { jsx as _jsx } from "react/jsx-runtime";
16
18
  const GridColumnHeaderRow = styled('div', {
@@ -46,6 +48,7 @@ export const useGridColumnHeaders = props => {
46
48
  const [dragCol, setDragCol] = React.useState('');
47
49
  const [resizeCol, setResizeCol] = React.useState('');
48
50
  const apiRef = useGridPrivateApiContext();
51
+ const hasVirtualization = useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector);
49
52
  const rootProps = useGridRootProps();
50
53
  const innerRef = React.useRef(null);
51
54
  const handleInnerRef = useForkRef(innerRefProp, innerRef);
@@ -164,7 +167,7 @@ export const useGridColumnHeaders = props => {
164
167
  maxLastIndex: currentPage.rows.length,
165
168
  buffer: rootProps.rowBuffer
166
169
  });
167
- const firstColumnToRender = getFirstColumnIndexToRenderRef.current({
170
+ const firstColumnToRender = !hasVirtualization ? 0 : getFirstColumnIndexToRenderRef.current({
168
171
  firstColumnIndex: nextRenderContext.firstColumnIndex,
169
172
  minColumnIndex: minFirstColumn,
170
173
  columnBuffer: rootProps.columnBuffer,
@@ -173,7 +176,7 @@ export const useGridColumnHeaders = props => {
173
176
  lastRowToRender,
174
177
  visibleRows: currentPage.rows
175
178
  });
176
- const lastColumnToRender = Math.min(nextRenderContext.lastColumnIndex + rootProps.columnBuffer, maxLastColumn);
179
+ const lastColumnToRender = !hasVirtualization ? maxLastColumn : Math.min(nextRenderContext.lastColumnIndex + rootProps.columnBuffer, maxLastColumn);
177
180
  const renderedColumns = visibleColumns.slice(firstColumnToRender, lastColumnToRender);
178
181
  return {
179
182
  renderedColumns,
@@ -12,6 +12,7 @@ import { mergeStateWithPaginationModel } from '../pagination/useGridPagination';
12
12
  import { useGridRegisterPipeProcessor } from '../../core/pipeProcessing';
13
13
  import { GridPrintExportMenuItem } from '../../../components/toolbar/GridToolbarExport';
14
14
  import { getTotalHeaderHeight } from '../columns/gridColumnsUtils';
15
+ import { GRID_CHECKBOX_SELECTION_COL_DEF } from '../../../colDef/gridCheckboxSelectionColDef';
15
16
  import { jsx as _jsx } from "react/jsx-runtime";
16
17
  function raf() {
17
18
  return new Promise(resolve => {
@@ -40,13 +41,14 @@ export const useGridPrintExport = (apiRef, props) => {
40
41
  const doc = React.useRef(null);
41
42
  const previousGridState = React.useRef(null);
42
43
  const previousColumnVisibility = React.useRef({});
44
+ const previousRows = React.useRef([]);
43
45
  React.useEffect(() => {
44
46
  doc.current = ownerDocument(apiRef.current.rootElementRef.current);
45
47
  }, [apiRef]);
46
48
 
47
49
  // Returns a promise because updateColumns triggers state update and
48
50
  // the new state needs to be in place before the grid can be sized correctly
49
- const updateGridColumnsForPrint = React.useCallback((fields, allColumns) => new Promise(resolve => {
51
+ const updateGridColumnsForPrint = React.useCallback((fields, allColumns, includeCheckboxes) => new Promise(resolve => {
50
52
  const exportedColumnFields = getColumnsToExport({
51
53
  apiRef,
52
54
  options: {
@@ -59,15 +61,26 @@ export const useGridPrintExport = (apiRef, props) => {
59
61
  columns.forEach(column => {
60
62
  newColumnVisibilityModel[column.field] = exportedColumnFields.includes(column.field);
61
63
  });
64
+ if (includeCheckboxes) {
65
+ newColumnVisibilityModel[GRID_CHECKBOX_SELECTION_COL_DEF.field] = true;
66
+ }
62
67
  apiRef.current.setColumnVisibilityModel(newColumnVisibilityModel);
63
68
  resolve();
64
69
  }), [apiRef]);
70
+ const updateGridRowsForPrint = React.useCallback(getRowsToExport => {
71
+ const rowsToExportIds = getRowsToExport({
72
+ apiRef
73
+ });
74
+ const newRows = rowsToExportIds.map(id => apiRef.current.getRow(id));
75
+ apiRef.current.setRows(newRows);
76
+ }, [apiRef]);
65
77
  const handlePrintWindowLoad = React.useCallback((printWindow, options) => {
66
78
  var _querySelector, _querySelector2;
67
79
  const normalizeOptions = _extends({
68
80
  copyStyles: true,
69
81
  hideToolbar: false,
70
- hideFooter: false
82
+ hideFooter: false,
83
+ includeCheckboxes: false
71
84
  }, options);
72
85
  const printDoc = printWindow.contentDocument;
73
86
  if (!printDoc) {
@@ -100,10 +113,21 @@ export const useGridPrintExport = (apiRef, props) => {
100
113
  }
101
114
 
102
115
  // Expand container height to accommodate all rows
103
- gridClone.style.height = `${rowsMeta.currentPageTotalHeight + getTotalHeaderHeight(apiRef, props.columnHeaderHeight) + gridToolbarElementHeight + gridFooterElementHeight}px`;
116
+ const computedTotalHeight = rowsMeta.currentPageTotalHeight + getTotalHeaderHeight(apiRef, props.columnHeaderHeight) + gridToolbarElementHeight + gridFooterElementHeight;
117
+ gridClone.style.height = `${computedTotalHeight}px`;
104
118
  // The height above does not include grid border width, so we need to exclude it
105
119
  gridClone.style.boxSizing = 'content-box';
106
120
 
121
+ // the footer is always being placed at the bottom of the page as if all rows are exported
122
+ // so if getRowsToExport is being used to only export a subset of rows then we need to
123
+ // adjust the footer position to be correctly placed at the bottom of the grid
124
+ if (options != null && options.getRowsToExport) {
125
+ const gridFooterElement = gridClone.querySelector(`.${gridClasses.footerContainer}`);
126
+ gridFooterElement.style.position = 'absolute';
127
+ gridFooterElement.style.width = '100%';
128
+ gridFooterElement.style.top = `${computedTotalHeight - gridFooterElementHeight}px`;
129
+ }
130
+
107
131
  // printDoc.body.appendChild(gridClone); should be enough but a clone isolation bug in Safari
108
132
  // prevents us to do it
109
133
  const container = document.createElement('div');
@@ -177,11 +201,13 @@ export const useGridPrintExport = (apiRef, props) => {
177
201
  // if the apiRef.current.exportState(); did not exported the column visibility, we update it
178
202
  apiRef.current.setColumnVisibilityModel(previousColumnVisibility.current);
179
203
  }
180
- apiRef.current.unstable_enableVirtualization();
204
+ apiRef.current.unstable_setVirtualization(true);
205
+ apiRef.current.setRows(previousRows.current);
181
206
 
182
207
  // Clear local state
183
208
  previousGridState.current = null;
184
209
  previousColumnVisibility.current = {};
210
+ previousRows.current = [];
185
211
  }, [apiRef]);
186
212
  const exportDataAsPrint = React.useCallback(async options => {
187
213
  logger.debug(`Export data as Print`);
@@ -191,6 +217,7 @@ export const useGridPrintExport = (apiRef, props) => {
191
217
  previousGridState.current = apiRef.current.exportState();
192
218
  // It appends that the visibility model is not exported, especially if columnVisibility is not controlled
193
219
  previousColumnVisibility.current = gridColumnVisibilityModelSelector(apiRef);
220
+ previousRows.current = apiRef.current.getSortedRows();
194
221
  if (props.pagination) {
195
222
  const visibleRowCount = gridExpandedRowCountSelector(apiRef);
196
223
  const paginationModel = {
@@ -202,8 +229,11 @@ export const useGridPrintExport = (apiRef, props) => {
202
229
  mergeStateWithPaginationModel(visibleRowCount, 'DataGridPro', paginationModel));
203
230
  apiRef.current.forceUpdate();
204
231
  }
205
- await updateGridColumnsForPrint(options == null ? void 0 : options.fields, options == null ? void 0 : options.allColumns);
206
- apiRef.current.unstable_disableVirtualization();
232
+ await updateGridColumnsForPrint(options == null ? void 0 : options.fields, options == null ? void 0 : options.allColumns, options == null ? void 0 : options.includeCheckboxes);
233
+ if (options != null && options.getRowsToExport) {
234
+ updateGridRowsForPrint(options.getRowsToExport);
235
+ }
236
+ apiRef.current.unstable_setVirtualization(false);
207
237
  await raf(); // wait for the state changes to take action
208
238
  const printWindow = buildPrintWindow(options == null ? void 0 : options.fileName);
209
239
  if (process.env.NODE_ENV === 'test') {
@@ -224,7 +254,7 @@ export const useGridPrintExport = (apiRef, props) => {
224
254
  };
225
255
  doc.current.body.appendChild(printWindow);
226
256
  }
227
- }, [props, logger, apiRef, handlePrintWindowLoad, handlePrintWindowAfterPrint, updateGridColumnsForPrint]);
257
+ }, [props, logger, apiRef, handlePrintWindowLoad, handlePrintWindowAfterPrint, updateGridColumnsForPrint, updateGridRowsForPrint]);
228
258
  const printExportApi = {
229
259
  exportDataAsPrint
230
260
  };
@@ -4,10 +4,13 @@ import { GLOBAL_API_REF, isInternalFilter } from '../../../colDef/utils';
4
4
  import { getDefaultGridFilterModel } from './gridFilterState';
5
5
  import { buildWarning } from '../../../utils/warning';
6
6
  import { gridColumnFieldsSelector, gridColumnLookupSelector, gridVisibleColumnFieldsSelector } from '../columns';
7
+
8
+ // Fixes https://github.com/mui/mui-x/issues/10056
9
+ const globalScope = typeof window === 'undefined' ? globalThis : window;
10
+ const evalCode = globalScope[atob('ZXZhbA==')];
7
11
  let hasEval;
8
12
  try {
9
- // eslint-disable-next-line no-eval
10
- hasEval = eval('true');
13
+ hasEval = evalCode('true');
11
14
  } catch (_) {
12
15
  hasEval = false;
13
16
  }
@@ -158,7 +161,7 @@ export const buildAggregatedFilterItemsApplier = (getRowId, filterModel, apiRef,
158
161
 
159
162
  // We generate a new function with `eval()` to avoid expensive patterns for JS engines
160
163
  // such as a dynamic object assignment, e.g. `{ [dynamicKey]: value }`.
161
- const filterItemTemplate = `(function filterItem$$(row, shouldApplyFilter) {
164
+ const filterItemTemplate = `(function filterItem$$(appliers, row, shouldApplyFilter) {
162
165
  ${appliers.map((applier, i) => `const shouldApply${i} = !shouldApplyFilter || shouldApplyFilter(${JSON.stringify(applier.item.field)});`).join('\n')}
163
166
 
164
167
  const result$$ = {
@@ -170,9 +173,10 @@ export const buildAggregatedFilterItemsApplier = (getRowId, filterModel, apiRef,
170
173
 
171
174
  return result$$;
172
175
  })`;
173
-
174
- // eslint-disable-next-line no-eval
175
- const filterItem = eval(filterItemTemplate.replaceAll('$$', String(filterItemsApplierId)));
176
+ const filterItemCore = evalCode(filterItemTemplate.replaceAll('$$', String(filterItemsApplierId)));
177
+ const filterItem = (row, shouldApplyItem) => {
178
+ return filterItemCore(appliers, row, shouldApplyItem);
179
+ };
176
180
  filterItemsApplierId += 1;
177
181
  return filterItem;
178
182
  };
@@ -383,7 +383,6 @@ export const useGridFocus = (apiRef, props) => {
383
383
  };
384
384
  }, [apiRef, handleDocumentClick]);
385
385
  useGridApiEventHandler(apiRef, 'columnHeaderBlur', handleBlur);
386
- useGridApiEventHandler(apiRef, 'headerFilterBlur', handleBlur);
387
386
  useGridApiEventHandler(apiRef, 'cellDoubleClick', handleCellDoubleClick);
388
387
  useGridApiEventHandler(apiRef, 'cellMouseDown', handleCellMouseDown);
389
388
  useGridApiEventHandler(apiRef, 'cellKeyDown', handleCellKeyDown);
@@ -12,3 +12,4 @@ export * from './sorting';
12
12
  export * from './dimensions';
13
13
  export * from './statePersistence';
14
14
  export * from './headerFiltering';
15
+ export * from './virtualization';
@@ -12,4 +12,5 @@ export * from './rowSelection';
12
12
  export * from './sorting';
13
13
  export * from './dimensions';
14
14
  export * from './statePersistence';
15
- export * from './headerFiltering';
15
+ export * from './headerFiltering';
16
+ export * from './virtualization';
@@ -0,0 +1,16 @@
1
+ import { GridStateCommunity } from '../../../models/gridStateCommunity';
2
+ /**
3
+ * Get the columns state
4
+ * @category Virtualization
5
+ */
6
+ export declare const gridVirtualizationSelector: (state: GridStateCommunity) => import("./useGridVirtualization").GridVirtualizationState;
7
+ /**
8
+ * Get the enabled state for virtualization
9
+ * @category Virtualization
10
+ */
11
+ export declare const gridVirtualizationEnabledSelector: import("../../../utils/createSelector").OutputSelector<GridStateCommunity, boolean>;
12
+ /**
13
+ * Get the enabled state for virtualization
14
+ * @category Virtualization
15
+ */
16
+ export declare const gridVirtualizationColumnEnabledSelector: import("../../../utils/createSelector").OutputSelector<GridStateCommunity, boolean>;
@@ -0,0 +1,18 @@
1
+ import { createSelector } from '../../../utils/createSelector';
2
+ /**
3
+ * Get the columns state
4
+ * @category Virtualization
5
+ */
6
+ export const gridVirtualizationSelector = state => state.virtualization;
7
+
8
+ /**
9
+ * Get the enabled state for virtualization
10
+ * @category Virtualization
11
+ */
12
+ export const gridVirtualizationEnabledSelector = createSelector(gridVirtualizationSelector, state => state.enabled);
13
+
14
+ /**
15
+ * Get the enabled state for virtualization
16
+ * @category Virtualization
17
+ */
18
+ export const gridVirtualizationColumnEnabledSelector = createSelector(gridVirtualizationSelector, state => state.enabledForColumns);
@@ -0,0 +1,2 @@
1
+ export * from './useGridVirtualization';
2
+ export * from './gridVirtualizationSelectors';
@@ -0,0 +1,2 @@
1
+ export * from './useGridVirtualization';
2
+ export * from './gridVirtualizationSelectors';
@@ -12,7 +12,6 @@ export declare const getRenderableIndexes: ({ firstIndex, lastIndex, buffer, min
12
12
  export declare const areRenderContextsEqual: (context1: GridRenderContext, context2: GridRenderContext) => boolean;
13
13
  interface UseGridVirtualScrollerProps {
14
14
  ref: React.Ref<HTMLDivElement>;
15
- disableVirtualization?: boolean;
16
15
  renderZoneMinColumnIndex?: number;
17
16
  renderZoneMaxColumnIndex?: number;
18
17
  onRenderZonePositioning?: (params: {
@@ -19,8 +19,10 @@ import { selectedIdsLookupSelector } from '../rowSelection/gridRowSelectionSelec
19
19
  import { gridRowsMetaSelector } from '../rows/gridRowsMetaSelector';
20
20
  import { getFirstNonSpannedColumnToRender } from '../columns/gridColumnsUtils';
21
21
  import { getMinimalContentHeight } from '../rows/gridRowsUtils';
22
- import { jsx as _jsx } from "react/jsx-runtime";
22
+ import { gridVirtualizationEnabledSelector, gridVirtualizationColumnEnabledSelector } from './gridVirtualizationSelectors';
23
+
23
24
  // Uses binary search to avoid looping through all possible positions
25
+ import { jsx as _jsx } from "react/jsx-runtime";
24
26
  export function binarySearch(offset, positions, sliceStart = 0, sliceEnd = positions.length) {
25
27
  if (positions.length <= 0) {
26
28
  return -1;
@@ -65,9 +67,10 @@ export const useGridVirtualScroller = props => {
65
67
  const apiRef = useGridPrivateApiContext();
66
68
  const rootProps = useGridRootProps();
67
69
  const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector);
70
+ const enabled = useGridSelector(apiRef, gridVirtualizationEnabledSelector);
71
+ const enabledForColumns = useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector);
68
72
  const {
69
73
  ref,
70
- disableVirtualization,
71
74
  onRenderZonePositioning,
72
75
  renderZoneMinColumnIndex = 0,
73
76
  renderZoneMaxColumnIndex = visibleColumns.length,
@@ -84,7 +87,7 @@ export const useGridVirtualScroller = props => {
84
87
  const renderZoneRef = React.useRef(null);
85
88
  const rootRef = React.useRef(null);
86
89
  const handleRef = useForkRef(ref, rootRef);
87
- const [renderContext, setRenderContext] = React.useState(null);
90
+ const [renderContext, setRenderContextState] = React.useState(null);
88
91
  const prevRenderContext = React.useRef(renderContext);
89
92
  const scrollPosition = React.useRef({
90
93
  top: 0,
@@ -95,6 +98,12 @@ export const useGridVirtualScroller = props => {
95
98
  height: null
96
99
  });
97
100
  const prevTotalWidth = React.useRef(columnsTotalWidth);
101
+ // Each visible row (not to be confused with a filter result) is composed of a central row element
102
+ // and up to two additional row elements for pinned columns (left and right).
103
+ // When hovering any of these elements, the :hover styles are applied only to the row element that
104
+ // was actually hovered, not its additional siblings. To make it look like a contiguous row,
105
+ // we add/remove the .Mui-hovered class to all of the row elements inside one visible row.
106
+ const [hoveredRowId, setHoveredRowId] = React.useState(null);
98
107
  const rowStyleCache = React.useRef(Object.create(null));
99
108
  const prevGetRowProps = React.useRef();
100
109
  const prevRootRowStyle = React.useRef();
@@ -147,7 +156,7 @@ export const useGridVirtualScroller = props => {
147
156
  return exponentialSearch(offset, rowsMeta.positions, lastMeasuredIndexRelativeToCurrentPage);
148
157
  }, [apiRef, (_currentPage$range3 = currentPage.range) == null ? void 0 : _currentPage$range3.firstRowIndex, (_currentPage$range4 = currentPage.range) == null ? void 0 : _currentPage$range4.lastRowIndex, rowsMeta.positions]);
149
158
  const computeRenderContext = React.useCallback(() => {
150
- if (disableVirtualization) {
159
+ if (!enabled) {
151
160
  return {
152
161
  firstRowIndex: 0,
153
162
  lastRowIndex: currentPage.rows.length,
@@ -164,23 +173,25 @@ export const useGridVirtualScroller = props => {
164
173
  // In the last index, this is not needed because Array.slice doesn't include it.
165
174
  const firstRowIndex = Math.min(getNearestIndexToRender(top), rowsMeta.positions.length - 1);
166
175
  const lastRowIndex = rootProps.autoHeight ? firstRowIndex + currentPage.rows.length : getNearestIndexToRender(top + containerDimensions.height);
167
- let hasRowWithAutoHeight = false;
168
176
  let firstColumnIndex = 0;
169
177
  let lastColumnIndex = columnPositions.length;
170
- const [firstRowToRender, lastRowToRender] = getRenderableIndexes({
171
- firstIndex: firstRowIndex,
172
- lastIndex: lastRowIndex,
173
- minFirstIndex: 0,
174
- maxLastIndex: currentPage.rows.length,
175
- buffer: rootProps.rowBuffer
176
- });
177
- for (let i = firstRowToRender; i < lastRowToRender && !hasRowWithAutoHeight; i += 1) {
178
- const row = currentPage.rows[i];
179
- hasRowWithAutoHeight = apiRef.current.rowHasAutoHeight(row.id);
180
- }
181
- if (!hasRowWithAutoHeight) {
182
- firstColumnIndex = binarySearch(Math.abs(left), columnPositions);
183
- lastColumnIndex = binarySearch(Math.abs(left) + containerDimensions.width, columnPositions);
178
+ if (enabledForColumns) {
179
+ let hasRowWithAutoHeight = false;
180
+ const [firstRowToRender, lastRowToRender] = getRenderableIndexes({
181
+ firstIndex: firstRowIndex,
182
+ lastIndex: lastRowIndex,
183
+ minFirstIndex: 0,
184
+ maxLastIndex: currentPage.rows.length,
185
+ buffer: rootProps.rowBuffer
186
+ });
187
+ for (let i = firstRowToRender; i < lastRowToRender && !hasRowWithAutoHeight; i += 1) {
188
+ const row = currentPage.rows[i];
189
+ hasRowWithAutoHeight = apiRef.current.rowHasAutoHeight(row.id);
190
+ }
191
+ if (!hasRowWithAutoHeight) {
192
+ firstColumnIndex = binarySearch(Math.abs(left), columnPositions);
193
+ lastColumnIndex = binarySearch(Math.abs(left) + containerDimensions.width, columnPositions);
194
+ }
184
195
  }
185
196
  return {
186
197
  firstRowIndex,
@@ -188,16 +199,16 @@ export const useGridVirtualScroller = props => {
188
199
  firstColumnIndex,
189
200
  lastColumnIndex
190
201
  };
191
- }, [disableVirtualization, getNearestIndexToRender, rowsMeta.positions.length, rootProps.autoHeight, rootProps.rowBuffer, currentPage.rows, columnPositions, visibleColumns.length, apiRef, containerDimensions]);
202
+ }, [enabled, enabledForColumns, getNearestIndexToRender, rowsMeta.positions.length, rootProps.autoHeight, rootProps.rowBuffer, currentPage.rows, columnPositions, visibleColumns.length, apiRef, containerDimensions]);
192
203
  useEnhancedEffect(() => {
193
- if (disableVirtualization) {
194
- renderZoneRef.current.style.transform = `translate3d(0px, 0px, 0px)`;
195
- } else {
204
+ if (enabled) {
196
205
  // TODO a scroll reset should not be necessary
197
206
  rootRef.current.scrollLeft = 0;
198
207
  rootRef.current.scrollTop = 0;
208
+ } else {
209
+ renderZoneRef.current.style.transform = `translate3d(0px, 0px, 0px)`;
199
210
  }
200
- }, [disableVirtualization]);
211
+ }, [enabled]);
201
212
  useEnhancedEffect(() => {
202
213
  setContainerDimensions({
203
214
  width: rootRef.current.clientWidth,
@@ -246,12 +257,13 @@ export const useGridVirtualScroller = props => {
246
257
  });
247
258
  }
248
259
  }, [apiRef, currentPage.rows, onRenderZonePositioning, renderZoneMinColumnIndex, renderZoneMaxColumnIndex, rootProps.columnBuffer, rootProps.rowBuffer, theme.direction]);
249
- const updateRenderContext = React.useCallback(nextRenderContext => {
260
+ const getRenderContext = React.useCallback(() => prevRenderContext.current, []);
261
+ const setRenderContext = React.useCallback(nextRenderContext => {
250
262
  if (prevRenderContext.current && areRenderContextsEqual(nextRenderContext, prevRenderContext.current)) {
251
263
  updateRenderZonePosition(nextRenderContext);
252
264
  return;
253
265
  }
254
- setRenderContext(nextRenderContext);
266
+ setRenderContextState(nextRenderContext);
255
267
  updateRenderZonePosition(nextRenderContext);
256
268
  const [firstRowToRender, lastRowToRender] = getRenderableIndexes({
257
269
  firstIndex: nextRenderContext.firstRowIndex,
@@ -265,13 +277,13 @@ export const useGridVirtualScroller = props => {
265
277
  lastRowToRender
266
278
  });
267
279
  prevRenderContext.current = nextRenderContext;
268
- }, [apiRef, setRenderContext, prevRenderContext, currentPage.rows.length, rootProps.rowBuffer, updateRenderZonePosition]);
280
+ }, [apiRef, setRenderContextState, prevRenderContext, currentPage.rows.length, rootProps.rowBuffer, updateRenderZonePosition]);
269
281
  useEnhancedEffect(() => {
270
282
  if (containerDimensions.width == null) {
271
283
  return;
272
284
  }
273
285
  const initialRenderContext = computeRenderContext();
274
- updateRenderContext(initialRenderContext);
286
+ setRenderContext(initialRenderContext);
275
287
  const {
276
288
  top,
277
289
  left
@@ -282,7 +294,7 @@ export const useGridVirtualScroller = props => {
282
294
  renderContext: initialRenderContext
283
295
  };
284
296
  apiRef.current.publishEvent('scrollPositionChange', params);
285
- }, [apiRef, computeRenderContext, containerDimensions.width, updateRenderContext]);
297
+ }, [apiRef, computeRenderContext, containerDimensions.width, setRenderContext]);
286
298
  const handleScroll = useEventCallback(event => {
287
299
  const {
288
300
  scrollTop,
@@ -307,7 +319,7 @@ export const useGridVirtualScroller = props => {
307
319
  }
308
320
 
309
321
  // When virtualization is disabled, the context never changes during scroll
310
- const nextRenderContext = disableVirtualization ? prevRenderContext.current : computeRenderContext();
322
+ const nextRenderContext = enabled ? computeRenderContext() : prevRenderContext.current;
311
323
  const topRowsScrolledSincePreviousRender = Math.abs(nextRenderContext.firstRowIndex - prevRenderContext.current.firstRowIndex);
312
324
  const bottomRowsScrolledSincePreviousRender = Math.abs(nextRenderContext.lastRowIndex - prevRenderContext.current.lastRowIndex);
313
325
  const topColumnsScrolledSincePreviousRender = Math.abs(nextRenderContext.firstColumnIndex - prevRenderContext.current.firstColumnIndex);
@@ -321,7 +333,7 @@ export const useGridVirtualScroller = props => {
321
333
  if (shouldSetState) {
322
334
  // Prevents batching render context changes
323
335
  ReactDOM.flushSync(() => {
324
- updateRenderContext(nextRenderContext);
336
+ setRenderContext(nextRenderContext);
325
337
  });
326
338
  prevTotalWidth.current = columnsTotalWidth;
327
339
  }
@@ -338,6 +350,13 @@ export const useGridVirtualScroller = props => {
338
350
  }
339
351
  return -1;
340
352
  }, [cellFocus, currentPage.rows]);
353
+ useGridApiEventHandler(apiRef, 'rowMouseEnter', params => {
354
+ var _params$id;
355
+ setHoveredRowId((_params$id = params.id) != null ? _params$id : null);
356
+ });
357
+ useGridApiEventHandler(apiRef, 'rowMouseLeave', () => {
358
+ setHoveredRowId(null);
359
+ });
341
360
  const getRows = (params = {
342
361
  renderContext
343
362
  }) => {
@@ -354,8 +373,8 @@ export const useGridVirtualScroller = props => {
354
373
  if (!nextRenderContext || availableSpace == null) {
355
374
  return null;
356
375
  }
357
- const rowBuffer = !disableVirtualization ? rootProps.rowBuffer : 0;
358
- const columnBuffer = !disableVirtualization ? rootProps.columnBuffer : 0;
376
+ const rowBuffer = enabled ? rootProps.rowBuffer : 0;
377
+ const columnBuffer = enabled ? rootProps.columnBuffer : 0;
359
378
  const [firstRowToRender, lastRowToRender] = getRenderableIndexes({
360
379
  firstIndex: nextRenderContext.firstRowIndex,
361
380
  lastIndex: nextRenderContext.lastRowIndex,
@@ -496,6 +515,7 @@ export const useGridVirtualScroller = props => {
496
515
  isLastVisible: lastVisibleRowIndex,
497
516
  position: position
498
517
  }, rowProps, rootRowProps, {
518
+ hovered: hoveredRowId === id,
499
519
  style: rowStyleCache.current[id]
500
520
  }), id));
501
521
  }
@@ -537,9 +557,6 @@ export const useGridVirtualScroller = props => {
537
557
  }
538
558
  return style;
539
559
  }, [needsHorizontalScrollbar, rootProps.autoHeight]);
540
- const getRenderContext = React.useCallback(() => {
541
- return prevRenderContext.current;
542
- }, []);
543
560
  apiRef.current.register('private', {
544
561
  getRenderContext
545
562
  });
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity';
3
+ import { DataGridProcessedProps } from '../../../models/props/DataGridProps';
4
+ import { GridStateInitializer } from '../../utils/useGridInitializeState';
5
+ type RootProps = Pick<DataGridProcessedProps, 'disableVirtualization'>;
6
+ export type GridVirtualizationState = {
7
+ enabled: boolean;
8
+ enabledForColumns: boolean;
9
+ };
10
+ export declare const virtualizationStateInitializer: GridStateInitializer<RootProps>;
11
+ export declare function useGridVirtualization(apiRef: React.MutableRefObject<GridPrivateApiCommunity>, props: RootProps): void;
12
+ export {};
@@ -0,0 +1,47 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import * as React from 'react';
3
+ import { useGridApiMethod } from '../../utils/useGridApiMethod';
4
+ export const virtualizationStateInitializer = (state, props) => {
5
+ const virtualization = {
6
+ enabled: !props.disableVirtualization,
7
+ enabledForColumns: true
8
+ };
9
+ return _extends({}, state, {
10
+ virtualization
11
+ });
12
+ };
13
+ export function useGridVirtualization(apiRef, props) {
14
+ /*
15
+ * API METHODS
16
+ */
17
+
18
+ const setVirtualization = enabled => {
19
+ apiRef.current.setState(state => _extends({}, state, {
20
+ virtualization: _extends({}, state.virtualization, {
21
+ enabled
22
+ })
23
+ }));
24
+ };
25
+ const setColumnVirtualization = enabled => {
26
+ apiRef.current.setState(state => _extends({}, state, {
27
+ virtualization: _extends({}, state.virtualization, {
28
+ enabledForColumns: enabled
29
+ })
30
+ }));
31
+ };
32
+ const api = {
33
+ unstable_setVirtualization: setVirtualization,
34
+ unstable_setColumnVirtualization: setColumnVirtualization
35
+ };
36
+ useGridApiMethod(apiRef, api, 'public');
37
+
38
+ /*
39
+ * EFFECTS
40
+ */
41
+
42
+ /* eslint-disable react-hooks/exhaustive-deps */
43
+ React.useEffect(() => {
44
+ setVirtualization(!props.disableVirtualization);
45
+ }, [props.disableVirtualization]);
46
+ /* eslint-enable react-hooks/exhaustive-deps */
47
+ }
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v6.14.0
2
+ * @mui/x-data-grid v6.16.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -21,6 +21,7 @@ export { useGridColumnMenu, columnMenuStateInitializer, } from '../hooks/feature
21
21
  export { useGridColumns, columnsStateInitializer } from '../hooks/features/columns/useGridColumns';
22
22
  export { getTotalHeaderHeight } from '../hooks/features/columns/gridColumnsUtils';
23
23
  export { useGridColumnSpanning } from '../hooks/features/columns/useGridColumnSpanning';
24
+ export { gridColumnsStateSelector } from '../hooks/features/columns/gridColumnsSelector';
24
25
  export { useGridColumnGrouping, columnGroupsStateInitializer, } from '../hooks/features/columnGrouping/useGridColumnGrouping';
25
26
  export type { GridColumnGroupLookup } from '../hooks/features/columnGrouping/gridColumnGroupsInterfaces';
26
27
  export type { GridColumnRawLookup, GridColumnsRawState, GridHydrateColumnsValue, } from '../hooks/features/columns/gridColumnsInterfaces';
@@ -57,12 +58,14 @@ export { useGridDimensions } from '../hooks/features/dimensions/useGridDimension
57
58
  export { useGridStatePersistence } from '../hooks/features/statePersistence/useGridStatePersistence';
58
59
  export type { GridRestoreStatePreProcessingContext } from '../hooks/features/statePersistence/gridStatePersistenceInterface';
59
60
  export { useGridVirtualScroller, getRenderableIndexes, } from '../hooks/features/virtualization/useGridVirtualScroller';
61
+ export * from '../hooks/features/virtualization';
60
62
  export { useTimeout } from '../hooks/utils/useTimeout';
61
63
  export { useGridVisibleRows, getVisibleRows } from '../hooks/utils/useGridVisibleRows';
62
64
  export { useGridInitializeState } from '../hooks/utils/useGridInitializeState';
63
65
  export type { GridStateInitializer } from '../hooks/utils/useGridInitializeState';
64
66
  export type { GridExperimentalFeatures, DataGridPropsWithoutDefaultValue, DataGridPropsWithDefaultValues, DataGridPropsWithComplexDefaultValueAfterProcessing, DataGridPropsWithComplexDefaultValueBeforeProcessing, } from '../models/props/DataGridProps';
65
67
  export { getColumnsToExport, defaultGetRowsToExport } from '../hooks/features/export/utils';
68
+ export * from '../utils/createControllablePromise';
66
69
  export { createSelector, createSelectorMemoized, unstable_resetCreateSelectorCache, } from '../utils/createSelector';
67
70
  export { findParentElementFromClassName, getActiveElement } from '../utils/domUtils';
68
71
  export { isNavigationKey } from '../utils/keyboardUtils';
@@ -71,6 +74,7 @@ export { buildWarning } from '../utils/warning';
71
74
  export { exportAs } from '../utils/exportAs';
72
75
  export type { GridPrivateOnlyApiCommon } from '../models/api/gridApiCommon';
73
76
  export { useGridPrivateApiContext } from '../hooks/utils/useGridPrivateApiContext';
77
+ export * from '../hooks/utils/useOnMount';
74
78
  export type { GridApiCommunity } from '../models/api/gridApiCommunity';
75
79
  export type { GridApiCaches } from '../models/gridApiCaches';
76
80
  export { serializeCellValue } from '../hooks/features/export/serializers/csvSerializer';