@mui/x-data-grid 7.0.0-beta.4 → 7.0.0-beta.5

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 (90) hide show
  1. package/CHANGELOG.md +138 -14
  2. package/DataGrid/DataGrid.js +2 -0
  3. package/colDef/gridBooleanOperators.js +1 -1
  4. package/components/GridRow.d.ts +7 -9
  5. package/components/GridRow.js +36 -47
  6. package/components/cell/GridCell.d.ts +2 -1
  7. package/components/cell/GridCell.js +7 -3
  8. package/components/cell/GridSkeletonCell.d.ts +3 -2
  9. package/components/cell/GridSkeletonCell.js +14 -6
  10. package/components/columnSelection/GridCellCheckboxRenderer.js +6 -4
  11. package/components/columnsManagement/GridColumnsManagement.js +1 -1
  12. package/components/containers/GridRootStyles.js +9 -2
  13. package/components/virtualization/GridBottomContainer.js +1 -1
  14. package/components/virtualization/GridTopContainer.js +1 -1
  15. package/components/virtualization/GridVirtualScroller.js +2 -2
  16. package/components/virtualization/GridVirtualScrollerRenderZone.js +9 -3
  17. package/hooks/features/columnHeaders/useGridColumnHeaders.js +11 -8
  18. package/hooks/features/columns/gridColumnsSelector.d.ts +6 -0
  19. package/hooks/features/columns/gridColumnsSelector.js +8 -1
  20. package/hooks/features/columns/useGridColumns.js +4 -0
  21. package/hooks/features/editing/useGridRowEditing.js +1 -2
  22. package/hooks/features/filter/useGridFilter.js +2 -2
  23. package/hooks/features/rows/useGridRows.js +8 -4
  24. package/hooks/features/rows/useGridRowsMeta.js +5 -13
  25. package/hooks/features/sorting/gridSortingUtils.js +9 -1
  26. package/hooks/features/virtualization/gridVirtualizationSelectors.d.ts +0 -9
  27. package/hooks/features/virtualization/gridVirtualizationSelectors.js +0 -7
  28. package/hooks/features/virtualization/useGridVirtualScroller.d.ts +3 -0
  29. package/hooks/features/virtualization/useGridVirtualScroller.js +82 -138
  30. package/hooks/features/virtualization/useGridVirtualization.d.ts +0 -8
  31. package/hooks/features/virtualization/useGridVirtualization.js +1 -6
  32. package/hooks/utils/useTimeout.d.ts +5 -3
  33. package/hooks/utils/useTimeout.js +13 -5
  34. package/index.js +1 -1
  35. package/models/colDef/gridColDef.d.ts +7 -0
  36. package/modern/DataGrid/DataGrid.js +2 -0
  37. package/modern/colDef/gridBooleanOperators.js +1 -1
  38. package/modern/components/GridRow.js +35 -46
  39. package/modern/components/cell/GridCell.js +7 -3
  40. package/modern/components/cell/GridSkeletonCell.js +14 -6
  41. package/modern/components/columnSelection/GridCellCheckboxRenderer.js +6 -4
  42. package/modern/components/columnsManagement/GridColumnsManagement.js +1 -1
  43. package/modern/components/containers/GridRootStyles.js +9 -2
  44. package/modern/components/virtualization/GridBottomContainer.js +1 -1
  45. package/modern/components/virtualization/GridTopContainer.js +1 -1
  46. package/modern/components/virtualization/GridVirtualScroller.js +2 -2
  47. package/modern/components/virtualization/GridVirtualScrollerRenderZone.js +8 -3
  48. package/modern/hooks/features/columnHeaders/useGridColumnHeaders.js +11 -8
  49. package/modern/hooks/features/columns/gridColumnsSelector.js +8 -1
  50. package/modern/hooks/features/columns/useGridColumns.js +2 -0
  51. package/modern/hooks/features/editing/useGridRowEditing.js +1 -2
  52. package/modern/hooks/features/filter/useGridFilter.js +2 -2
  53. package/modern/hooks/features/rows/useGridRows.js +8 -4
  54. package/modern/hooks/features/rows/useGridRowsMeta.js +5 -13
  55. package/modern/hooks/features/sorting/gridSortingUtils.js +9 -1
  56. package/modern/hooks/features/virtualization/gridVirtualizationSelectors.js +0 -7
  57. package/modern/hooks/features/virtualization/useGridVirtualScroller.js +80 -136
  58. package/modern/hooks/features/virtualization/useGridVirtualization.js +1 -6
  59. package/modern/hooks/utils/useTimeout.js +13 -5
  60. package/modern/index.js +1 -1
  61. package/modern/utils/utils.js +9 -0
  62. package/node/DataGrid/DataGrid.js +1 -0
  63. package/node/colDef/gridBooleanOperators.js +1 -1
  64. package/node/components/GridRow.js +35 -46
  65. package/node/components/cell/GridCell.js +7 -3
  66. package/node/components/cell/GridSkeletonCell.js +15 -7
  67. package/node/components/columnSelection/GridCellCheckboxRenderer.js +6 -4
  68. package/node/components/columnsManagement/GridColumnsManagement.js +1 -1
  69. package/node/components/containers/GridRootStyles.js +9 -2
  70. package/node/components/virtualization/GridBottomContainer.js +1 -1
  71. package/node/components/virtualization/GridTopContainer.js +1 -1
  72. package/node/components/virtualization/GridVirtualScroller.js +2 -2
  73. package/node/components/virtualization/GridVirtualScrollerRenderZone.js +7 -2
  74. package/node/hooks/features/columnHeaders/useGridColumnHeaders.js +8 -5
  75. package/node/hooks/features/columns/gridColumnsSelector.js +9 -2
  76. package/node/hooks/features/columns/useGridColumns.js +2 -0
  77. package/node/hooks/features/editing/useGridRowEditing.js +1 -2
  78. package/node/hooks/features/filter/useGridFilter.js +2 -2
  79. package/node/hooks/features/rows/useGridRows.js +8 -4
  80. package/node/hooks/features/rows/useGridRowsMeta.js +5 -13
  81. package/node/hooks/features/sorting/gridSortingUtils.js +9 -1
  82. package/node/hooks/features/virtualization/gridVirtualizationSelectors.js +1 -8
  83. package/node/hooks/features/virtualization/useGridVirtualScroller.js +81 -136
  84. package/node/hooks/features/virtualization/useGridVirtualization.js +2 -7
  85. package/node/hooks/utils/useTimeout.js +13 -4
  86. package/node/index.js +1 -1
  87. package/node/utils/utils.js +12 -1
  88. package/package.json +1 -1
  89. package/utils/utils.d.ts +4 -0
  90. package/utils/utils.js +9 -0
@@ -3,24 +3,23 @@ import * as React from 'react';
3
3
  import * as ReactDOM from 'react-dom';
4
4
  import { unstable_useEnhancedEffect as useEnhancedEffect, unstable_useEventCallback as useEventCallback } from '@mui/utils';
5
5
  import { useTheme } from '@mui/material/styles';
6
- import { defaultMemoize } from 'reselect';
7
6
  import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext';
8
7
  import { useGridRootProps } from '../../utils/useGridRootProps';
9
8
  import { useGridSelector } from '../../utils/useGridSelector';
10
- import { useLazyRef } from '../../utils/useLazyRef';
11
9
  import { useResizeObserver } from '../../utils/useResizeObserver';
12
10
  import { useRunOnce } from '../../utils/useRunOnce';
13
- import { gridVisibleColumnDefinitionsSelector, gridVisiblePinnedColumnDefinitionsSelector, gridColumnPositionsSelector } from '../columns/gridColumnsSelector';
11
+ import { gridVisibleColumnDefinitionsSelector, gridVisiblePinnedColumnDefinitionsSelector, gridColumnPositionsSelector, gridHasColSpanSelector } from '../columns/gridColumnsSelector';
14
12
  import { gridDimensionsSelector } from '../dimensions/gridDimensionsSelectors';
15
13
  import { gridPinnedRowsSelector } from '../rows/gridRowsSelector';
16
14
  import { gridFocusCellSelector, gridTabIndexCellSelector } from '../focus/gridFocusStateSelector';
17
15
  import { useGridVisibleRows, getVisibleRows } from '../../utils/useGridVisibleRows';
18
- import { clamp } from '../../../utils/utils';
16
+ import { useGridApiEventHandler } from '../../utils';
17
+ import { clamp, range } from '../../../utils/utils';
19
18
  import { selectedIdsLookupSelector } from '../rowSelection/gridRowSelectionSelector';
20
19
  import { gridRowsMetaSelector } from '../rows/gridRowsMetaSelector';
21
20
  import { getFirstNonSpannedColumnToRender } from '../columns/gridColumnsUtils';
22
21
  import { getMinimalContentHeight } from '../rows/gridRowsUtils';
23
- import { gridOffsetsSelector, gridRenderContextSelector, gridVirtualizationEnabledSelector, gridVirtualizationColumnEnabledSelector } from './gridVirtualizationSelectors';
22
+ import { gridRenderContextSelector, gridVirtualizationEnabledSelector, gridVirtualizationColumnEnabledSelector } from './gridVirtualizationSelectors';
24
23
  import { EMPTY_RENDER_CONTEXT } from './useGridVirtualization';
25
24
  import { jsx as _jsx } from "react/jsx-runtime";
26
25
  export const EMPTY_DETAIL_PANELS = Object.freeze(new Map());
@@ -49,40 +48,29 @@ export const useGridVirtualScroller = () => {
49
48
  const scrollbarHorizontalRef = React.useRef(null);
50
49
  const contentHeight = dimensions.contentSize.height;
51
50
  const columnsTotalWidth = dimensions.columnsTotalWidth;
51
+ const hasColSpan = useGridSelector(apiRef, gridHasColSpanSelector);
52
52
  useResizeObserver(mainRef, () => apiRef.current.resize());
53
53
  const previousContext = React.useRef(EMPTY_RENDER_CONTEXT);
54
54
  const previousRowContext = React.useRef(EMPTY_RENDER_CONTEXT);
55
- const offsets = useGridSelector(apiRef, gridOffsetsSelector);
56
55
  const renderContext = useGridSelector(apiRef, gridRenderContextSelector);
57
56
  const scrollPosition = React.useRef({
58
57
  top: 0,
59
58
  left: 0
60
59
  }).current;
61
60
  const prevTotalWidth = React.useRef(columnsTotalWidth);
62
- const getRenderedColumns = useLazyRef(createGetRenderedColumns).current;
63
- const indexOfRowWithFocusedCell = React.useMemo(() => {
64
- if (cellFocus !== null) {
65
- return currentPage.rows.findIndex(row => row.id === cellFocus.id);
66
- }
67
- return -1;
68
- }, [cellFocus, currentPage.rows]);
69
- const indexOfColumnWithFocusedCell = React.useMemo(() => {
70
- if (cellFocus !== null) {
71
- return visibleColumns.findIndex(column => column.field === cellFocus.field);
72
- }
73
- return -1;
74
- }, [cellFocus, visibleColumns]);
61
+ const focusedCell = {
62
+ rowIndex: React.useMemo(() => cellFocus ? currentPage.rows.findIndex(row => row.id === cellFocus.id) : -1, [cellFocus, currentPage.rows]),
63
+ columnIndex: React.useMemo(() => cellFocus ? visibleColumns.findIndex(column => column.field === cellFocus.field) : -1, [cellFocus, visibleColumns])
64
+ };
75
65
  const updateRenderContext = React.useCallback((nextRenderContext, rawRenderContext) => {
76
66
  if (areRenderContextsEqual(nextRenderContext, apiRef.current.state.virtualization.renderContext)) {
77
67
  return;
78
68
  }
79
69
  const didRowsIntervalChange = nextRenderContext.firstRowIndex !== previousRowContext.current.firstRowIndex || nextRenderContext.lastRowIndex !== previousRowContext.current.lastRowIndex;
80
- const nextOffsets = computeOffsets(apiRef, nextRenderContext, theme.direction, pinnedColumns.left.length);
81
70
  apiRef.current.setState(state => {
82
71
  return _extends({}, state, {
83
72
  virtualization: _extends({}, state.virtualization, {
84
- renderContext: nextRenderContext,
85
- offsets: nextOffsets
73
+ renderContext: nextRenderContext
86
74
  })
87
75
  });
88
76
  });
@@ -96,7 +84,7 @@ export const useGridVirtualScroller = () => {
96
84
  }
97
85
  previousContext.current = rawRenderContext;
98
86
  prevTotalWidth.current = dimensions.columnsTotalWidth;
99
- }, [apiRef, pinnedColumns.left.length, theme.direction, dimensions.isReady, dimensions.columnsTotalWidth]);
87
+ }, [apiRef, dimensions.isReady, dimensions.columnsTotalWidth]);
100
88
  const triggerUpdateRenderContext = () => {
101
89
  const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns);
102
90
  const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition);
@@ -157,9 +145,12 @@ export const useGridVirtualScroller = () => {
157
145
  const handleTouchMove = useEventCallback(event => {
158
146
  apiRef.current.publishEvent('virtualScrollerTouchMove', {}, event);
159
147
  });
160
- const minFirstColumn = pinnedColumns.left.length;
161
- const maxLastColumn = visibleColumns.length - pinnedColumns.right.length;
162
148
  const getRows = (params = {}) => {
149
+ if (!params.rows && !currentPage.range) {
150
+ return [];
151
+ }
152
+ const columnPositions = gridColumnPositionsSelector(apiRef);
153
+ const currentRenderContext = params.renderContext ?? renderContext;
163
154
  const isLastSection = !hasBottomPinnedRows && params.position === undefined || hasBottomPinnedRows && params.position === 'bottom';
164
155
  const isPinnedSection = params.position !== undefined;
165
156
  let rowIndexOffset;
@@ -176,77 +167,57 @@ export const useGridVirtualScroller = () => {
176
167
  rowIndexOffset = pinnedRows.top.length;
177
168
  break;
178
169
  }
179
- const firstRowToRender = renderContext.firstRowIndex;
180
- const lastRowToRender = renderContext.lastRowIndex;
181
- const firstColumnToRender = renderContext.firstColumnIndex;
182
- const lastColumnToRender = renderContext.lastColumnIndex;
183
- if (!params.rows && !currentPage.range) {
184
- return [];
185
- }
186
- const renderedRows = params.rows ?? currentPage.rows.slice(firstRowToRender, lastRowToRender);
187
-
188
- // If the selected row is not within the current range of rows being displayed,
189
- // we need to render it at either the top or bottom of the rows,
190
- // depending on whether it is above or below the range.
191
- let isRowWithFocusedCellNotInRange = false;
192
- if (!isPinnedSection && indexOfRowWithFocusedCell > -1 && (firstRowToRender > indexOfRowWithFocusedCell || lastRowToRender < indexOfRowWithFocusedCell)) {
193
- isRowWithFocusedCellNotInRange = true;
194
- const rowWithFocusedCell = currentPage.rows[indexOfRowWithFocusedCell];
195
- if (indexOfRowWithFocusedCell > firstRowToRender) {
196
- renderedRows.push(rowWithFocusedCell);
197
- } else {
198
- renderedRows.unshift(rowWithFocusedCell);
199
- }
200
- }
201
- let isColumnWihFocusedCellNotInRange = false;
202
- if (!isPinnedSection && (firstColumnToRender > indexOfColumnWithFocusedCell || lastColumnToRender < indexOfColumnWithFocusedCell)) {
203
- isColumnWihFocusedCellNotInRange = true;
204
- }
205
- const {
206
- focusedCellColumnIndexNotInRange,
207
- renderedColumns
208
- } = getRenderedColumns(visibleColumns, firstColumnToRender, lastColumnToRender, minFirstColumn, maxLastColumn, isColumnWihFocusedCellNotInRange ? indexOfColumnWithFocusedCell : -1);
209
- renderedRows.forEach(row => {
210
- apiRef.current.calculateColSpan({
211
- rowId: row.id,
212
- minFirstColumn,
213
- maxLastColumn,
214
- columns: visibleColumns
215
- });
216
- if (pinnedColumns.left.length > 0) {
217
- apiRef.current.calculateColSpan({
218
- rowId: row.id,
219
- minFirstColumn: 0,
220
- maxLastColumn: pinnedColumns.left.length,
221
- columns: visibleColumns
222
- });
170
+ const rowModels = params.rows ?? currentPage.rows;
171
+ const firstRowToRender = currentRenderContext.firstRowIndex;
172
+ const lastRowToRender = Math.min(currentRenderContext.lastRowIndex, rowModels.length);
173
+ const rowIndexes = params.rows ? range(0, params.rows.length) : range(firstRowToRender, lastRowToRender);
174
+ let virtualRowIndex = -1;
175
+ if (!isPinnedSection && focusedCell.rowIndex !== -1) {
176
+ if (focusedCell.rowIndex < firstRowToRender) {
177
+ virtualRowIndex = focusedCell.rowIndex;
178
+ rowIndexes.unshift(virtualRowIndex);
223
179
  }
224
- if (pinnedColumns.right.length > 0) {
225
- apiRef.current.calculateColSpan({
226
- rowId: row.id,
227
- minFirstColumn: visibleColumns.length - pinnedColumns.right.length,
228
- maxLastColumn: visibleColumns.length,
229
- columns: visibleColumns
230
- });
180
+ if (focusedCell.rowIndex >= lastRowToRender) {
181
+ virtualRowIndex = focusedCell.rowIndex;
182
+ rowIndexes.push(virtualRowIndex);
231
183
  }
232
- });
184
+ }
233
185
  const rows = [];
234
186
  const rowProps = rootProps.slotProps?.row;
235
- let isRowWithFocusedCellRendered = false;
236
- for (let i = 0; i < renderedRows.length; i += 1) {
187
+ rowIndexes.forEach(rowIndexInPage => {
237
188
  const {
238
189
  id,
239
190
  model
240
- } = renderedRows[i];
241
- const rowIndexInPage = (currentPage?.range?.firstRowIndex || 0) + firstRowToRender + i;
242
- let index = rowIndexOffset + rowIndexInPage;
243
- if (isRowWithFocusedCellNotInRange && cellFocus?.id === id) {
244
- index = indexOfRowWithFocusedCell;
245
- isRowWithFocusedCellRendered = true;
246
- } else if (isRowWithFocusedCellRendered) {
247
- index -= 1;
191
+ } = rowModels[rowIndexInPage];
192
+
193
+ // NOTE: This is an expensive feature, the colSpan code could be optimized.
194
+ if (hasColSpan) {
195
+ const minFirstColumn = pinnedColumns.left.length;
196
+ const maxLastColumn = visibleColumns.length - pinnedColumns.right.length;
197
+ apiRef.current.calculateColSpan({
198
+ rowId: id,
199
+ minFirstColumn,
200
+ maxLastColumn,
201
+ columns: visibleColumns
202
+ });
203
+ if (pinnedColumns.left.length > 0) {
204
+ apiRef.current.calculateColSpan({
205
+ rowId: id,
206
+ minFirstColumn: 0,
207
+ maxLastColumn: pinnedColumns.left.length,
208
+ columns: visibleColumns
209
+ });
210
+ }
211
+ if (pinnedColumns.right.length > 0) {
212
+ apiRef.current.calculateColSpan({
213
+ rowId: id,
214
+ minFirstColumn: visibleColumns.length - pinnedColumns.right.length,
215
+ maxLastColumn: visibleColumns.length,
216
+ columns: visibleColumns
217
+ });
218
+ }
248
219
  }
249
- const isRowNotVisible = isRowWithFocusedCellNotInRange && cellFocus.id === id;
220
+ const hasFocus = cellFocus?.id === id;
250
221
  const baseRowHeight = !apiRef.current.rowHasAutoHeight(id) ? apiRef.current.unstable_getRowHeight(id) : 'auto';
251
222
  let isSelected;
252
223
  if (selectedRowsLookup[id] == null) {
@@ -262,47 +233,46 @@ export const useGridVirtualScroller = () => {
262
233
  if (isLastSection) {
263
234
  if (!isPinnedSection) {
264
235
  const lastIndex = currentPage.rows.length - 1;
265
- const isLastVisibleRowIndex = isRowWithFocusedCellNotInRange ? firstRowToRender + i === lastIndex + 1 : firstRowToRender + i === lastIndex;
236
+ const isLastVisibleRowIndex = rowIndexInPage === lastIndex;
266
237
  if (isLastVisibleRowIndex) {
267
238
  isLastVisible = true;
268
239
  }
269
240
  } else {
270
- isLastVisible = i === renderedRows.length - 1;
241
+ isLastVisible = rowIndexInPage === rowModels.length - 1;
271
242
  }
272
243
  }
273
- const focusedCell = cellFocus !== null && cellFocus.id === id ? cellFocus.field : null;
274
- const columnWithFocusedCellNotInRange = focusedCellColumnIndexNotInRange !== undefined && visibleColumns[focusedCellColumnIndexNotInRange];
275
- const renderedColumnsWithFocusedCell = columnWithFocusedCellNotInRange && focusedCell ? [columnWithFocusedCellNotInRange, ...renderedColumns] : renderedColumns;
244
+ const isVirtualRow = rowIndexInPage === virtualRowIndex;
245
+ const isNotVisible = isVirtualRow;
276
246
  let tabbableCell = null;
277
247
  if (cellTabIndex !== null && cellTabIndex.id === id) {
278
248
  const cellParams = apiRef.current.getCellParams(id, cellTabIndex.field);
279
249
  tabbableCell = cellParams.cellMode === 'view' ? cellTabIndex.field : null;
280
250
  }
251
+ const offsetLeft = computeOffsetLeft(columnPositions, currentRenderContext, theme.direction, pinnedColumns.left.length);
252
+ const rowIndex = (currentPage?.range?.firstRowIndex || 0) + rowIndexOffset + rowIndexInPage;
281
253
  rows.push( /*#__PURE__*/_jsx(rootProps.slots.row, _extends({
282
254
  row: model,
283
255
  rowId: id,
284
- index: index,
256
+ index: rowIndex,
257
+ selected: isSelected,
258
+ offsetTop: params.rows ? undefined : rowsMeta.positions[rowIndexInPage],
259
+ offsetLeft: offsetLeft,
260
+ dimensions: dimensions,
285
261
  rowHeight: baseRowHeight,
286
- focusedCell: focusedCell,
287
262
  tabbableCell: tabbableCell,
288
- focusedCellColumnIndexNotInRange: focusedCellColumnIndexNotInRange,
289
- renderedColumns: renderedColumnsWithFocusedCell,
290
- visibleColumns: visibleColumns,
291
263
  pinnedColumns: pinnedColumns,
292
- firstColumnToRender: firstColumnToRender,
293
- lastColumnToRender: lastColumnToRender,
294
- selected: isSelected,
295
- offsets: offsets,
296
- dimensions: dimensions,
264
+ visibleColumns: visibleColumns,
265
+ renderContext: currentRenderContext,
266
+ focusedColumnIndex: hasFocus ? focusedCell.columnIndex : undefined,
297
267
  isFirstVisible: isFirstVisible,
298
268
  isLastVisible: isLastVisible,
299
- isNotVisible: isRowNotVisible
269
+ isNotVisible: isNotVisible
300
270
  }, rowProps), id));
301
271
  const panel = panels.get(id);
302
272
  if (panel) {
303
273
  rows.push(panel);
304
274
  }
305
- }
275
+ });
306
276
  return rows;
307
277
  };
308
278
  const needsHorizontalScrollbar = outerSize.width && columnsTotalWidth >= outerSize.width;
@@ -355,6 +325,9 @@ export const useGridVirtualScroller = () => {
355
325
  apiRef.current.register('private', {
356
326
  updateRenderContext: forceUpdateRenderContext
357
327
  });
328
+ useGridApiEventHandler(apiRef, 'columnsChange', forceUpdateRenderContext);
329
+ useGridApiEventHandler(apiRef, 'filteredRowsSet', forceUpdateRenderContext);
330
+ useGridApiEventHandler(apiRef, 'rowExpansionChange', forceUpdateRenderContext);
358
331
  return {
359
332
  renderContext,
360
333
  setPanels,
@@ -388,29 +361,6 @@ export const useGridVirtualScroller = () => {
388
361
  })
389
362
  };
390
363
  };
391
- function createGetRenderedColumns() {
392
- return defaultMemoize((columns, firstColumnToRender, lastColumnToRender, minFirstColumn, maxLastColumn, indexOfColumnWithFocusedCell) => {
393
- // If the selected column is not within the current range of columns being displayed,
394
- // we need to render it at either the left or right of the columns,
395
- // depending on whether it is above or below the range.
396
- let focusedCellColumnIndexNotInRange;
397
- const renderedColumns = columns.slice(firstColumnToRender, lastColumnToRender);
398
- if (indexOfColumnWithFocusedCell > -1) {
399
- // check if it is not on the left pinned column.
400
- if (firstColumnToRender > indexOfColumnWithFocusedCell && indexOfColumnWithFocusedCell >= minFirstColumn) {
401
- focusedCellColumnIndexNotInRange = indexOfColumnWithFocusedCell;
402
- }
403
- // check if it is not on the right pinned column.
404
- else if (lastColumnToRender < indexOfColumnWithFocusedCell && indexOfColumnWithFocusedCell < maxLastColumn) {
405
- focusedCellColumnIndexNotInRange = indexOfColumnWithFocusedCell;
406
- }
407
- }
408
- return {
409
- focusedCellColumnIndexNotInRange,
410
- renderedColumns
411
- };
412
- });
413
- }
414
364
  function inputsSelector(apiRef, rootProps, enabled, enabledForColumns) {
415
365
  const dimensions = gridDimensionsSelector(apiRef.current.state);
416
366
  const currentPage = getVisibleRows(apiRef, rootProps);
@@ -588,14 +538,8 @@ export function areRenderContextsEqual(context1, context2) {
588
538
  }
589
539
  return context1.firstRowIndex === context2.firstRowIndex && context1.lastRowIndex === context2.lastRowIndex && context1.firstColumnIndex === context2.firstColumnIndex && context1.lastColumnIndex === context2.lastColumnIndex;
590
540
  }
591
- function computeOffsets(apiRef, renderContext, direction, pinnedLeftLength) {
541
+ export function computeOffsetLeft(columnPositions, renderContext, direction, pinnedLeftLength) {
592
542
  const factor = direction === 'ltr' ? 1 : -1;
593
- const rowPositions = gridRowsMetaSelector(apiRef.current.state).positions;
594
- const columnPositions = gridColumnPositionsSelector(apiRef);
595
- const top = rowPositions[renderContext.firstRowIndex] ?? 0;
596
543
  const left = factor * (columnPositions[renderContext.firstColumnIndex] ?? 0) - (columnPositions[pinnedLeftLength] ?? 0);
597
- return {
598
- top,
599
- left
600
- };
544
+ return left;
601
545
  }
@@ -1,10 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import { useGridApiMethod } from '../../utils/useGridApiMethod';
4
- export const EMPTY_OFFSETS = {
5
- top: 0,
6
- left: 0
7
- };
8
4
  export const EMPTY_RENDER_CONTEXT = {
9
5
  firstRowIndex: 0,
10
6
  lastRowIndex: 0,
@@ -15,8 +11,7 @@ export const virtualizationStateInitializer = (state, props) => {
15
11
  const virtualization = {
16
12
  enabled: !props.disableVirtualization,
17
13
  enabledForColumns: true,
18
- renderContext: EMPTY_RENDER_CONTEXT,
19
- offsets: EMPTY_OFFSETS
14
+ renderContext: EMPTY_RENDER_CONTEXT
20
15
  };
21
16
  return _extends({}, state, {
22
17
  virtualization
@@ -1,12 +1,14 @@
1
+ 'use client';
2
+
1
3
  import { useLazyRef } from './useLazyRef';
2
4
  import { useOnMount } from './useOnMount';
3
- class Timeout {
5
+ export class Timeout {
4
6
  constructor() {
5
- this.currentId = 0;
7
+ this.currentId = null;
6
8
  this.clear = () => {
7
- if (this.currentId !== 0) {
9
+ if (this.currentId !== null) {
8
10
  clearTimeout(this.currentId);
9
- this.currentId = 0;
11
+ this.currentId = null;
10
12
  }
11
13
  };
12
14
  this.disposeEffect = () => {
@@ -16,9 +18,15 @@ class Timeout {
16
18
  static create() {
17
19
  return new Timeout();
18
20
  }
21
+ /**
22
+ * Executes `fn` after `delay`, clearing any previously scheduled call.
23
+ */
19
24
  start(delay, fn) {
20
25
  this.clear();
21
- this.currentId = setTimeout(fn, delay);
26
+ this.currentId = setTimeout(() => {
27
+ this.currentId = null;
28
+ fn();
29
+ }, delay);
22
30
  }
23
31
  }
24
32
  export function useTimeout() {
package/modern/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v7.0.0-beta.4
2
+ * @mui/x-data-grid v7.0.0-beta.5
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -30,6 +30,15 @@ export function escapeRegExp(value) {
30
30
  */
31
31
  export const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
32
32
 
33
+ /**
34
+ * Create an array containing the range [from, to[
35
+ */
36
+ export function range(from, to) {
37
+ return Array.from({
38
+ length: to - from
39
+ }).map((_, i) => from + i);
40
+ }
41
+
33
42
  /**
34
43
  * Based on `fast-deep-equal`
35
44
  *
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ 'use client';
2
3
 
3
4
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5
  Object.defineProperty(exports, "__esModule", {
@@ -11,7 +11,7 @@ const getGridBooleanOperators = () => [{
11
11
  if (!filterItem.value) {
12
12
  return null;
13
13
  }
14
- const valueAsBoolean = filterItem.value === 'true';
14
+ const valueAsBoolean = String(filterItem.value) === 'true';
15
15
  return value => {
16
16
  return Boolean(value) === valueAsBoolean;
17
17
  };
@@ -27,11 +27,10 @@ var _gridSortingSelector = require("../hooks/features/sorting/gridSortingSelecto
27
27
  var _gridRowsSelector = require("../hooks/features/rows/gridRowsSelector");
28
28
  var _gridColumnGroupsSelector = require("../hooks/features/columnGrouping/gridColumnGroupsSelector");
29
29
  var _gridEditingSelectors = require("../hooks/features/editing/gridEditingSelectors");
30
- var _utils2 = require("../utils/utils");
31
30
  var _GridCell = require("./cell/GridCell");
32
31
  var _GridScrollbarFillerCell = require("./GridScrollbarFillerCell");
33
32
  var _jsxRuntime = require("react/jsx-runtime");
34
- const _excluded = ["selected", "rowId", "row", "index", "style", "rowHeight", "className", "visibleColumns", "renderedColumns", "pinnedColumns", "offsets", "dimensions", "firstColumnToRender", "lastColumnToRender", "isFirstVisible", "isLastVisible", "focusedCellColumnIndexNotInRange", "isNotVisible", "focusedCell", "tabbableCell", "onClick", "onDoubleClick", "onMouseEnter", "onMouseLeave", "onMouseOut", "onMouseOver"];
33
+ const _excluded = ["selected", "rowId", "row", "index", "style", "rowHeight", "className", "visibleColumns", "pinnedColumns", "offsetTop", "offsetLeft", "dimensions", "renderContext", "focusedColumnIndex", "isFirstVisible", "isLastVisible", "isNotVisible", "focusedCell", "tabbableCell", "onClick", "onDoubleClick", "onMouseEnter", "onMouseLeave", "onMouseOut", "onMouseOver"];
35
34
  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); }
36
35
  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; }
37
36
  const useUtilityClasses = ownerState => {
@@ -73,16 +72,14 @@ const GridRow = /*#__PURE__*/React.forwardRef(function GridRow(props, refProp) {
73
72
  rowHeight,
74
73
  className,
75
74
  visibleColumns,
76
- renderedColumns,
77
75
  pinnedColumns,
78
- offsets,
76
+ offsetLeft,
79
77
  dimensions,
80
- firstColumnToRender,
78
+ renderContext,
79
+ focusedColumnIndex,
81
80
  isFirstVisible,
82
81
  isLastVisible,
83
- focusedCellColumnIndexNotInRange,
84
82
  isNotVisible,
85
- focusedCell,
86
83
  onClick,
87
84
  onDoubleClick,
88
85
  onMouseEnter,
@@ -103,6 +100,9 @@ const GridRow = /*#__PURE__*/React.forwardRef(function GridRow(props, refProp) {
103
100
  const handleRef = (0, _utils.unstable_useForkRef)(ref, refProp);
104
101
  const rowNode = apiRef.current.getRowNode(rowId);
105
102
  const scrollbarWidth = dimensions.hasScrollY ? dimensions.scrollbarSize : 0;
103
+ const hasFocusCell = focusedColumnIndex !== undefined;
104
+ const hasVirtualFocusCellLeft = hasFocusCell && focusedColumnIndex >= pinnedColumns.left.length && focusedColumnIndex < renderContext.firstColumnIndex;
105
+ const hasVirtualFocusCellRight = hasFocusCell && focusedColumnIndex < visibleColumns.length - pinnedColumns.right.length && focusedColumnIndex >= renderContext.lastColumnIndex;
106
106
  const ariaRowIndex = index + headerGroupingMaxDepth + 2; // 1 for the header row and 1 as it's 1-based
107
107
 
108
108
  const ownerState = {
@@ -251,12 +251,13 @@ const GridRow = /*#__PURE__*/React.forwardRef(function GridRow(props, refProp) {
251
251
  });
252
252
  rowClassNames.push(rootProps.getRowClassName(rowParams));
253
253
  }
254
- const randomNumber = (0, _utils2.randomNumberBetween)(10000, 20, 80);
255
254
  const getCell = (column, indexInSection, indexRelativeToAllColumns, sectionLength, pinnedPosition = _GridCell.PinnedPosition.NONE) => {
256
255
  const cellColSpanInfo = apiRef.current.unstable_getCellColSpanInfo(rowId, indexRelativeToAllColumns);
257
- if (!cellColSpanInfo || cellColSpanInfo.spannedByColSpan) {
256
+ if (cellColSpanInfo?.spannedByColSpan) {
258
257
  return null;
259
258
  }
259
+ const width = cellColSpanInfo?.cellProps.width ?? column.computedWidth;
260
+ const colSpan = cellColSpanInfo?.cellProps.colSpan ?? 1;
260
261
  let pinnedOffset;
261
262
  // FIXME: Why is the switch check exhaustiveness not validated with typescript-eslint?
262
263
  // eslint-disable-next-line default-case
@@ -268,25 +269,18 @@ const GridRow = /*#__PURE__*/React.forwardRef(function GridRow(props, refProp) {
268
269
  pinnedOffset = dimensions.columnsTotalWidth - columnPositions[indexRelativeToAllColumns] - column.computedWidth + scrollbarWidth;
269
270
  break;
270
271
  case _GridCell.PinnedPosition.NONE:
272
+ case _GridCell.PinnedPosition.VIRTUAL:
271
273
  pinnedOffset = 0;
272
274
  break;
273
275
  }
274
276
  if (rowNode?.type === 'skeletonRow') {
275
- const {
276
- width
277
- } = cellColSpanInfo.cellProps;
278
- const contentWidth = Math.round(randomNumber());
279
277
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(slots.skeletonCell, {
280
278
  width: width,
281
- contentWidth: contentWidth,
279
+ height: rowHeight,
282
280
  field: column.field,
283
281
  align: column.align ?? 'left'
284
282
  }, column.field);
285
283
  }
286
- const {
287
- colSpan,
288
- width
289
- } = cellColSpanInfo.cellProps;
290
284
  const editCellState = editRowsState[rowId]?.[column.field] ?? null;
291
285
 
292
286
  // when the cell is a reorder cell we are not allowing to reorder the col
@@ -296,10 +290,7 @@ const GridRow = /*#__PURE__*/React.forwardRef(function GridRow(props, refProp) {
296
290
  const canReorderColumn = !(disableColumnReorder || column.disableReorder);
297
291
  const canReorderRow = rowReordering && !sortModel.length && treeDepth <= 1 && !isEditingRows;
298
292
  const disableDragEvents = !(canReorderColumn || isReorderCell && canReorderRow);
299
- let cellIsNotVisible = false;
300
- if (focusedCellColumnIndexNotInRange !== undefined && visibleColumns[focusedCellColumnIndexNotInRange].field === column.field) {
301
- cellIsNotVisible = true;
302
- }
293
+ const cellIsNotVisible = pinnedPosition === _GridCell.PinnedPosition.VIRTUAL;
303
294
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(slots.cell, (0, _extends2.default)({
304
295
  column: column,
305
296
  width: width,
@@ -335,18 +326,16 @@ const GridRow = /*#__PURE__*/React.forwardRef(function GridRow(props, refProp) {
335
326
  });
336
327
  const middleColumnsLength = visibleColumns.length - pinnedColumns.left.length - pinnedColumns.right.length;
337
328
  const cells = [];
338
- for (let i = 0; i < renderedColumns.length; i += 1) {
339
- const column = renderedColumns[i];
340
- let indexRelativeToAllColumns = firstColumnToRender + i;
341
- if (focusedCellColumnIndexNotInRange !== undefined && focusedCell) {
342
- if (visibleColumns[focusedCellColumnIndexNotInRange].field === column.field) {
343
- indexRelativeToAllColumns = focusedCellColumnIndexNotInRange;
344
- } else {
345
- indexRelativeToAllColumns -= 1;
346
- }
347
- }
348
- const indexInSection = indexRelativeToAllColumns - pinnedColumns.left.length;
349
- cells.push(getCell(column, indexInSection, indexRelativeToAllColumns, middleColumnsLength));
329
+ if (hasVirtualFocusCellLeft) {
330
+ cells.push(getCell(visibleColumns[focusedColumnIndex], focusedColumnIndex - pinnedColumns.left.length, focusedColumnIndex, middleColumnsLength, _GridCell.PinnedPosition.VIRTUAL));
331
+ }
332
+ for (let i = renderContext.firstColumnIndex; i < renderContext.lastColumnIndex; i += 1) {
333
+ const column = visibleColumns[i];
334
+ const indexInSection = i - pinnedColumns.left.length;
335
+ cells.push(getCell(column, indexInSection, i, middleColumnsLength));
336
+ }
337
+ if (hasVirtualFocusCellRight) {
338
+ cells.push(getCell(visibleColumns[focusedColumnIndex], focusedColumnIndex - pinnedColumns.left.length, focusedColumnIndex, middleColumnsLength, _GridCell.PinnedPosition.VIRTUAL));
350
339
  }
351
340
  const eventHandlers = row ? {
352
341
  onClick: publishClick,
@@ -372,7 +361,7 @@ const GridRow = /*#__PURE__*/React.forwardRef(function GridRow(props, refProp) {
372
361
  role: "presentation",
373
362
  className: _gridClasses.gridClasses.cellOffsetLeft,
374
363
  style: {
375
- width: offsets.left
364
+ width: offsetLeft
376
365
  }
377
366
  }), cells, emptyCellWidth > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyCell, {
378
367
  width: emptyCellWidth
@@ -426,13 +415,11 @@ process.env.NODE_ENV !== "production" ? GridRow.propTypes = {
426
415
  width: _propTypes.default.number.isRequired
427
416
  }).isRequired
428
417
  }).isRequired,
429
- firstColumnToRender: _propTypes.default.number.isRequired,
430
418
  /**
431
419
  * Determines which cell has focus.
432
420
  * If `null`, no cell in this row has focus.
433
421
  */
434
- focusedCell: _propTypes.default.string,
435
- focusedCellColumnIndexNotInRange: _propTypes.default.number,
422
+ focusedColumnIndex: _propTypes.default.number,
436
423
  /**
437
424
  * Index of the row in the whole sorted and filtered dataset.
438
425
  * If some rows above have expanded children, this index also take those children into account.
@@ -440,19 +427,21 @@ process.env.NODE_ENV !== "production" ? GridRow.propTypes = {
440
427
  index: _propTypes.default.number.isRequired,
441
428
  isFirstVisible: _propTypes.default.bool.isRequired,
442
429
  isLastVisible: _propTypes.default.bool.isRequired,
443
- isNotVisible: _propTypes.default.bool,
444
- lastColumnToRender: _propTypes.default.number.isRequired,
445
- offsets: _propTypes.default.shape({
446
- left: _propTypes.default.number.isRequired,
447
- top: _propTypes.default.number.isRequired
448
- }).isRequired,
430
+ isNotVisible: _propTypes.default.bool.isRequired,
431
+ offsetLeft: _propTypes.default.number.isRequired,
432
+ offsetTop: _propTypes.default.number,
449
433
  onClick: _propTypes.default.func,
450
434
  onDoubleClick: _propTypes.default.func,
451
435
  onMouseEnter: _propTypes.default.func,
452
436
  onMouseLeave: _propTypes.default.func,
453
437
  pinnedColumns: _propTypes.default.object.isRequired,
454
- renderedColumns: _propTypes.default.arrayOf(_propTypes.default.object).isRequired,
455
- row: _propTypes.default.object,
438
+ renderContext: _propTypes.default.shape({
439
+ firstColumnIndex: _propTypes.default.number.isRequired,
440
+ firstRowIndex: _propTypes.default.number.isRequired,
441
+ lastColumnIndex: _propTypes.default.number.isRequired,
442
+ lastRowIndex: _propTypes.default.number.isRequired
443
+ }).isRequired,
444
+ row: _propTypes.default.object.isRequired,
456
445
  rowHeight: _propTypes.default.oneOfType([_propTypes.default.oneOf(['auto']), _propTypes.default.number]).isRequired,
457
446
  rowId: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired,
458
447
  selected: _propTypes.default.bool.isRequired,
@@ -29,6 +29,7 @@ let PinnedPosition = exports.PinnedPosition = /*#__PURE__*/function (PinnedPosit
29
29
  PinnedPosition[PinnedPosition["NONE"] = 0] = "NONE";
30
30
  PinnedPosition[PinnedPosition["LEFT"] = 1] = "LEFT";
31
31
  PinnedPosition[PinnedPosition["RIGHT"] = 2] = "RIGHT";
32
+ PinnedPosition[PinnedPosition["VIRTUAL"] = 3] = "VIRTUAL";
32
33
  return PinnedPosition;
33
34
  }({});
34
35
  const EMPTY_CELL_PARAMS = {
@@ -140,10 +141,13 @@ const GridCell = /*#__PURE__*/React.forwardRef((props, ref) => {
140
141
  classes: rootClasses,
141
142
  getCellClassName
142
143
  } = rootProps;
143
- const classNames = apiRef.current.unstable_applyPipeProcessors('cellClassName', [], {
144
+
145
+ // There is a hidden grid state access in `applyPipeProcessor('cellClassName', ...)`
146
+ const pipesClassName = (0, _useGridSelector.useGridSelector)(apiRef, () => apiRef.current.unstable_applyPipeProcessors('cellClassName', [], {
144
147
  id: rowId,
145
148
  field
146
- });
149
+ }).filter(Boolean).join(' '));
150
+ const classNames = [pipesClassName];
147
151
  if (column.cellClassName) {
148
152
  classNames.push(typeof column.cellClassName === 'function' ? column.cellClassName(cellParamsWithAPI) : column.cellClassName);
149
153
  }
@@ -339,7 +343,7 @@ process.env.NODE_ENV !== "production" ? GridCell.propTypes = {
339
343
  onMouseDown: _propTypes.default.func,
340
344
  onMouseUp: _propTypes.default.func,
341
345
  pinnedOffset: _propTypes.default.number.isRequired,
342
- pinnedPosition: _propTypes.default.oneOf([0, 1, 2]).isRequired,
346
+ pinnedPosition: _propTypes.default.oneOf([0, 1, 2, 3]).isRequired,
343
347
  rowId: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired,
344
348
  sectionIndex: _propTypes.default.number.isRequired,
345
349
  sectionLength: _propTypes.default.number.isRequired,