@mui/x-data-grid 8.17.0 → 8.19.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 (114) hide show
  1. package/CHANGELOG.md +213 -0
  2. package/DataGrid/useDataGridComponent.js +4 -3
  3. package/components/GridRow.js +1 -1
  4. package/components/cell/GridActionsCell.d.ts +9 -0
  5. package/components/cell/GridActionsCell.js +54 -36
  6. package/components/cell/GridActionsCellItem.js +0 -4
  7. package/components/cell/GridBooleanCell.js +0 -10
  8. package/components/cell/GridCell.js +4 -10
  9. package/components/columnHeaders/GridColumnHeaderItem.js +2 -2
  10. package/components/columnSelection/GridCellCheckboxRenderer.js +37 -22
  11. package/components/containers/GridRootStyles.js +1 -1
  12. package/components/toolbarV8/Toolbar.js +1 -1
  13. package/components/virtualization/GridVirtualScrollbar.d.ts +1 -0
  14. package/components/virtualization/GridVirtualScrollbar.js +13 -8
  15. package/components/virtualization/GridVirtualScroller.js +2 -1
  16. package/components/virtualization/GridVirtualScrollerRenderZone.js +1 -1
  17. package/constants/dataGridPropsDefaultValues.js +2 -1
  18. package/esm/DataGrid/useDataGridComponent.js +5 -4
  19. package/esm/components/GridRow.js +1 -1
  20. package/esm/components/cell/GridActionsCell.d.ts +9 -0
  21. package/esm/components/cell/GridActionsCell.js +55 -36
  22. package/esm/components/cell/GridActionsCellItem.js +0 -4
  23. package/esm/components/cell/GridBooleanCell.js +0 -10
  24. package/esm/components/cell/GridCell.js +4 -10
  25. package/esm/components/columnHeaders/GridColumnHeaderItem.js +2 -2
  26. package/esm/components/columnSelection/GridCellCheckboxRenderer.js +37 -22
  27. package/esm/components/containers/GridRootStyles.js +1 -1
  28. package/esm/components/toolbarV8/Toolbar.js +1 -1
  29. package/esm/components/virtualization/GridVirtualScrollbar.d.ts +1 -0
  30. package/esm/components/virtualization/GridVirtualScrollbar.js +12 -7
  31. package/esm/components/virtualization/GridVirtualScroller.js +2 -1
  32. package/esm/components/virtualization/GridVirtualScrollerRenderZone.js +1 -1
  33. package/esm/constants/dataGridPropsDefaultValues.js +2 -1
  34. package/esm/hooks/core/gridPropsSelectors.d.ts +2 -1
  35. package/esm/hooks/core/gridPropsSelectors.js +3 -0
  36. package/esm/hooks/core/useGridProps.js +8 -2
  37. package/esm/hooks/core/useGridVirtualizer.d.ts +80 -6
  38. package/esm/hooks/core/useGridVirtualizer.js +27 -12
  39. package/esm/hooks/features/columnGrouping/useGridColumnGrouping.js +6 -1
  40. package/esm/hooks/features/columnMenu/useGridColumnMenu.js +14 -4
  41. package/esm/hooks/features/columns/useGridColumnSpanning.js +9 -4
  42. package/esm/hooks/features/dimensions/useGridDimensions.js +12 -6
  43. package/esm/hooks/features/export/useGridPrintExport.js +18 -18
  44. package/esm/hooks/features/filter/useGridFilter.d.ts +1 -1
  45. package/esm/hooks/features/filter/useGridFilter.js +3 -1
  46. package/esm/hooks/features/focus/useGridFocus.js +0 -1
  47. package/esm/hooks/features/keyboardNavigation/useGridKeyboardNavigation.d.ts +1 -1
  48. package/esm/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +189 -25
  49. package/esm/hooks/features/pagination/useGridPaginationMeta.js +3 -3
  50. package/esm/hooks/features/pagination/useGridPaginationModel.js +7 -4
  51. package/esm/hooks/features/pagination/useGridRowCount.js +31 -15
  52. package/esm/hooks/features/rowSelection/useGridRowSelection.js +8 -7
  53. package/esm/hooks/features/rowSelection/utils.d.ts +1 -0
  54. package/esm/hooks/features/rowSelection/utils.js +17 -4
  55. package/esm/hooks/features/rows/gridRowSpanningUtils.js +8 -5
  56. package/esm/hooks/features/rows/useGridParamsApi.js +2 -12
  57. package/esm/hooks/features/rows/useGridRowSpanning.js +23 -60
  58. package/esm/hooks/features/scroll/useGridScroll.js +2 -3
  59. package/esm/hooks/features/sorting/useGridSorting.d.ts +1 -1
  60. package/esm/hooks/features/sorting/useGridSorting.js +3 -1
  61. package/esm/hooks/features/virtualization/useGridVirtualization.js +24 -5
  62. package/esm/hooks/utils/useGridApiRef.d.ts +1 -2
  63. package/esm/hooks/utils/useGridEvent.js +6 -2
  64. package/esm/hooks/utils/useRunOncePerLoop.d.ts +4 -1
  65. package/esm/hooks/utils/useRunOncePerLoop.js +28 -18
  66. package/esm/index.js +1 -1
  67. package/esm/models/colDef/gridColDef.d.ts +14 -0
  68. package/esm/models/events/gridEventLookup.d.ts +5 -0
  69. package/esm/models/gridStateCommunity.d.ts +1 -1
  70. package/esm/models/params/gridCellParams.d.ts +0 -10
  71. package/esm/models/props/DataGridProps.d.ts +13 -6
  72. package/esm/utils/keyboardUtils.d.ts +1 -8
  73. package/esm/utils/keyboardUtils.js +0 -7
  74. package/hooks/core/gridPropsSelectors.d.ts +2 -1
  75. package/hooks/core/gridPropsSelectors.js +4 -1
  76. package/hooks/core/useGridProps.js +8 -2
  77. package/hooks/core/useGridVirtualizer.d.ts +80 -6
  78. package/hooks/core/useGridVirtualizer.js +26 -11
  79. package/hooks/features/columnGrouping/useGridColumnGrouping.js +6 -1
  80. package/hooks/features/columnMenu/useGridColumnMenu.js +14 -4
  81. package/hooks/features/columns/useGridColumnSpanning.js +9 -4
  82. package/hooks/features/dimensions/useGridDimensions.js +12 -6
  83. package/hooks/features/export/useGridPrintExport.js +18 -18
  84. package/hooks/features/filter/useGridFilter.d.ts +1 -1
  85. package/hooks/features/filter/useGridFilter.js +3 -1
  86. package/hooks/features/focus/useGridFocus.js +0 -1
  87. package/hooks/features/keyboardNavigation/useGridKeyboardNavigation.d.ts +1 -1
  88. package/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +189 -25
  89. package/hooks/features/pagination/useGridPaginationMeta.js +2 -2
  90. package/hooks/features/pagination/useGridPaginationModel.js +7 -4
  91. package/hooks/features/pagination/useGridRowCount.js +30 -14
  92. package/hooks/features/rowSelection/useGridRowSelection.js +8 -7
  93. package/hooks/features/rowSelection/utils.d.ts +1 -0
  94. package/hooks/features/rowSelection/utils.js +16 -3
  95. package/hooks/features/rows/gridRowSpanningUtils.js +8 -5
  96. package/hooks/features/rows/useGridParamsApi.js +2 -12
  97. package/hooks/features/rows/useGridRowSpanning.js +23 -60
  98. package/hooks/features/scroll/useGridScroll.js +2 -3
  99. package/hooks/features/sorting/useGridSorting.d.ts +1 -1
  100. package/hooks/features/sorting/useGridSorting.js +3 -1
  101. package/hooks/features/virtualization/useGridVirtualization.js +24 -5
  102. package/hooks/utils/useGridApiRef.d.ts +1 -2
  103. package/hooks/utils/useGridEvent.js +6 -2
  104. package/hooks/utils/useRunOncePerLoop.d.ts +4 -1
  105. package/hooks/utils/useRunOncePerLoop.js +27 -18
  106. package/index.js +1 -1
  107. package/models/colDef/gridColDef.d.ts +14 -0
  108. package/models/events/gridEventLookup.d.ts +5 -0
  109. package/models/gridStateCommunity.d.ts +1 -1
  110. package/models/params/gridCellParams.d.ts +0 -10
  111. package/models/props/DataGridProps.d.ts +13 -6
  112. package/package.json +4 -4
  113. package/utils/keyboardUtils.d.ts +1 -8
  114. package/utils/keyboardUtils.js +1 -13
@@ -40,18 +40,8 @@ export function useGridParamsApi(apiRef, props, configuration) {
40
40
  value: forcedValue,
41
41
  formattedValue: forcedFormattedValue
42
42
  }) => {
43
- let value = row[field];
44
- if (forcedValue !== undefined) {
45
- value = forcedValue;
46
- } else if (colDef?.valueGetter) {
47
- value = colDef.valueGetter(value, row, colDef, apiRef);
48
- }
49
- let formattedValue = value;
50
- if (forcedFormattedValue !== undefined) {
51
- formattedValue = forcedFormattedValue;
52
- } else if (colDef?.valueFormatter) {
53
- formattedValue = colDef.valueFormatter(value, row, colDef, apiRef);
54
- }
43
+ const value = forcedValue !== undefined ? forcedValue : apiRef.current.getRowValue(row, colDef);
44
+ const formattedValue = forcedFormattedValue !== undefined ? forcedFormattedValue : apiRef.current.getRowFormattedValue(row, colDef);
55
45
  const params = {
56
46
  id,
57
47
  field,
@@ -9,8 +9,7 @@ import { gridRenderContextSelector } from "../virtualization/gridVirtualizationS
9
9
  import { getUnprocessedRange, isRowContextInitialized, getCellValue } from "./gridRowSpanningUtils.js";
10
10
  import { useGridEvent } from "../../utils/useGridEvent.js";
11
11
  import { runIf } from "../../../utils/utils.js";
12
- import { gridPageSizeSelector } from "../pagination/index.js";
13
- import { gridDataRowIdsSelector } from "./gridRowsSelector.js";
12
+ import { useRunOncePerLoop } from "../../utils/useRunOncePerLoop.js";
14
13
  const EMPTY_CACHES = {
15
14
  spannedCells: {},
16
15
  hiddenCells: {},
@@ -24,13 +23,6 @@ const EMPTY_STATE = {
24
23
  caches: EMPTY_CACHES,
25
24
  processedRange: EMPTY_RANGE
26
25
  };
27
-
28
- /**
29
- * Default number of rows to process during state initialization to avoid flickering.
30
- * Number `20` is arbitrarily chosen to be large enough to cover most of the cases without
31
- * compromising performance.
32
- */
33
- const DEFAULT_ROWS_TO_PROCESS = 20;
34
26
  const computeRowSpanningState = (apiRef, colDefs, visibleRows, range, rangeToProcess, resetState) => {
35
27
  const virtualizer = apiRef.current.virtualizer;
36
28
  const previousState = resetState ? EMPTY_STATE : Rowspan.selectors.state(virtualizer.store.state);
@@ -128,65 +120,25 @@ const computeRowSpanningState = (apiRef, colDefs, visibleRows, range, rangeToPro
128
120
  processedRange
129
121
  };
130
122
  };
131
- const getInitialRangeToProcess = (props, apiRef) => {
132
- const rowCount = gridDataRowIdsSelector(apiRef).length;
133
- if (props.pagination) {
134
- const pageSize = gridPageSizeSelector(apiRef);
135
- let paginationLastRowIndex = DEFAULT_ROWS_TO_PROCESS;
136
- if (pageSize > 0) {
137
- paginationLastRowIndex = pageSize - 1;
138
- }
139
- return {
140
- firstRowIndex: 0,
141
- lastRowIndex: Math.min(paginationLastRowIndex, rowCount)
142
- };
143
- }
144
- return {
145
- firstRowIndex: 0,
146
- lastRowIndex: Math.min(DEFAULT_ROWS_TO_PROCESS, rowCount)
147
- };
148
- };
149
123
 
150
124
  /**
151
125
  * @requires columnsStateInitializer (method) - should be initialized before
152
126
  * @requires rowsStateInitializer (method) - should be initialized before
153
127
  * @requires filterStateInitializer (method) - should be initialized before
154
128
  */
155
- export const rowSpanningStateInitializer = (state, props, apiRef) => {
156
- if (!props.rowSpanning) {
157
- return _extends({}, state, {
158
- rowSpanning: EMPTY_STATE
159
- });
160
- }
161
- const rowIds = state.rows.dataRowIds || [];
162
- const orderedFields = state.columns.orderedFields || [];
163
- const dataRowIdToModelLookup = state.rows.dataRowIdToModelLookup;
164
- const columnsLookup = state.columns.lookup;
165
- const isFilteringPending = Boolean(state.filter.filterModel.items.length) || Boolean(state.filter.filterModel.quickFilterValues?.length);
166
- if (!rowIds.length || !orderedFields.length || !dataRowIdToModelLookup || !columnsLookup || isFilteringPending) {
167
- return _extends({}, state, {
168
- rowSpanning: EMPTY_STATE
169
- });
170
- }
171
- const rangeToProcess = getInitialRangeToProcess(props, apiRef);
172
- const rows = rowIds.map(id => ({
173
- id,
174
- model: dataRowIdToModelLookup[id]
175
- }));
176
- const colDefs = orderedFields.map(field => columnsLookup[field]);
177
- const rowSpanning = computeRowSpanningState(apiRef, colDefs, rows, rangeToProcess, rangeToProcess, true);
129
+ export const rowSpanningStateInitializer = state => {
178
130
  return _extends({}, state, {
179
- rowSpanning
131
+ rowSpanning: EMPTY_STATE
180
132
  });
181
133
  };
182
134
  export const useGridRowSpanning = (apiRef, props) => {
183
- const store = apiRef.current.virtualizer.store;
184
135
  const updateRowSpanningState = React.useCallback((renderContext, resetState = false) => {
136
+ const store = apiRef.current.virtualizer.store;
185
137
  const {
186
138
  range,
187
139
  rows: visibleRows
188
140
  } = getVisibleRows(apiRef);
189
- if (resetState && store.getSnapshot().rowSpanning !== EMPTY_STATE) {
141
+ if (resetState) {
190
142
  store.set('rowSpanning', EMPTY_STATE);
191
143
  }
192
144
  if (range === null || !isRowContextInitialized(renderContext)) {
@@ -212,7 +164,7 @@ export const useGridRowSpanning = (apiRef, props) => {
212
164
  return;
213
165
  }
214
166
  store.set('rowSpanning', newState);
215
- }, [apiRef, store]);
167
+ }, [apiRef]);
216
168
 
217
169
  // Reset events trigger a full re-computation of the row spanning state:
218
170
  // - The `rowSpanning` prop is updated (feature flag)
@@ -220,25 +172,36 @@ export const useGridRowSpanning = (apiRef, props) => {
220
172
  // - The sorting is applied
221
173
  // - The `paginationModel` is updated
222
174
  // - The rows are updated
175
+ const {
176
+ schedule: deferredUpdateRowSpanningState,
177
+ cancel
178
+ } = useRunOncePerLoop(updateRowSpanningState);
223
179
  const resetRowSpanningState = React.useCallback(() => {
224
180
  const renderContext = gridRenderContextSelector(apiRef);
225
181
  if (!isRowContextInitialized(renderContext)) {
226
182
  return;
227
183
  }
228
- updateRowSpanningState(renderContext, true);
229
- }, [apiRef, updateRowSpanningState]);
230
- useGridEvent(apiRef, 'renderedRowsIntervalChange', runIf(props.rowSpanning, updateRowSpanningState));
184
+ deferredUpdateRowSpanningState(renderContext, true);
185
+ }, [apiRef, deferredUpdateRowSpanningState]);
186
+ useGridEvent(apiRef, 'renderedRowsIntervalChange', runIf(props.rowSpanning, renderContext => {
187
+ const didHavePendingReset = cancel();
188
+ updateRowSpanningState(renderContext, didHavePendingReset);
189
+ }));
231
190
  useGridEvent(apiRef, 'sortedRowsSet', runIf(props.rowSpanning, resetRowSpanningState));
232
191
  useGridEvent(apiRef, 'paginationModelChange', runIf(props.rowSpanning, resetRowSpanningState));
233
192
  useGridEvent(apiRef, 'filteredRowsSet', runIf(props.rowSpanning, resetRowSpanningState));
234
193
  useGridEvent(apiRef, 'columnsChange', runIf(props.rowSpanning, resetRowSpanningState));
235
194
  React.useEffect(() => {
195
+ const store = apiRef.current.virtualizer?.store;
196
+ if (!store) {
197
+ return;
198
+ }
236
199
  if (!props.rowSpanning) {
237
200
  if (store.state.rowSpanning !== EMPTY_STATE) {
238
201
  store.set('rowSpanning', EMPTY_STATE);
239
202
  }
240
- } else if (store.state.rowSpanning.caches === EMPTY_CACHES) {
241
- resetRowSpanningState();
203
+ } else if (store.state.rowSpanning === EMPTY_STATE) {
204
+ updateRowSpanningState(gridRenderContextSelector(apiRef));
242
205
  }
243
- }, [apiRef, store, resetRowSpanningState, props.rowSpanning]);
206
+ }, [apiRef, props.rowSpanning, updateRowSpanningState]);
244
207
  };
@@ -2,7 +2,6 @@ import * as React from 'react';
2
2
  import { useRtl } from '@mui/system/RtlProvider';
3
3
  import { useGridLogger } from "../../utils/useGridLogger.js";
4
4
  import { gridColumnPositionsSelector, gridVisibleColumnDefinitionsSelector } from "../columns/gridColumnsSelector.js";
5
- import { useGridSelector } from "../../utils/useGridSelector.js";
6
5
  import { gridPageSelector, gridPageSizeSelector } from "../pagination/gridPaginationSelector.js";
7
6
  import { gridRowCountSelector } from "../rows/gridRowsSelector.js";
8
7
  import { gridRowsMetaSelector } from "../rows/gridRowsMetaSelector.js";
@@ -47,7 +46,6 @@ export const useGridScroll = (apiRef, props) => {
47
46
  const logger = useGridLogger(apiRef, 'useGridScroll');
48
47
  const colRef = apiRef.current.columnHeadersContainerRef;
49
48
  const virtualScrollerRef = apiRef.current.virtualScrollerRef;
50
- const visibleSortedRows = useGridSelector(apiRef, gridExpandedSortedRowEntriesSelector);
51
49
  const scrollToIndexes = React.useCallback(params => {
52
50
  const dimensions = gridDimensionsSelector(apiRef);
53
51
  const totalRowCount = gridRowCountSelector(apiRef);
@@ -62,6 +60,7 @@ export const useGridScroll = (apiRef, props) => {
62
60
  const columnPositions = gridColumnPositionsSelector(apiRef);
63
61
  let cellWidth;
64
62
  if (typeof params.rowIndex !== 'undefined') {
63
+ const visibleSortedRows = gridExpandedSortedRowEntriesSelector(apiRef);
65
64
  const rowId = visibleSortedRows[params.rowIndex]?.id;
66
65
  const cellColSpanInfo = apiRef.current.unstable_getCellColSpanInfo(rowId, params.colIndex);
67
66
  if (cellColSpanInfo && !cellColSpanInfo.spannedByColSpan) {
@@ -98,7 +97,7 @@ export const useGridScroll = (apiRef, props) => {
98
97
  return true;
99
98
  }
100
99
  return false;
101
- }, [logger, apiRef, virtualScrollerRef, props.pagination, visibleSortedRows]);
100
+ }, [logger, apiRef, virtualScrollerRef, props.pagination]);
102
101
  const scroll = React.useCallback(params => {
103
102
  if (virtualScrollerRef.current && params.left !== undefined && colRef.current) {
104
103
  const direction = isRtl ? -1 : 1;
@@ -7,4 +7,4 @@ export declare const sortingStateInitializer: GridStateInitializer<Pick<DataGrid
7
7
  * @requires useGridRows (event)
8
8
  * @requires useGridColumns (event)
9
9
  */
10
- export declare const useGridSorting: (apiRef: RefObject<GridPrivateApiCommunity>, props: Pick<DataGridProcessedProps, "initialState" | "sortModel" | "onSortModelChange" | "sortingOrder" | "sortingMode" | "disableColumnSorting" | "disableMultipleColumnsSorting" | "multipleColumnsSortingMode">) => void;
10
+ export declare const useGridSorting: (apiRef: RefObject<GridPrivateApiCommunity>, props: Pick<DataGridProcessedProps, "initialState" | "sortModel" | "onSortModelChange" | "sortingOrder" | "sortingMode" | "disableColumnSorting" | "disableMultipleColumnsSorting" | "multipleColumnsSortingMode" | "signature">) => void;
@@ -236,7 +236,9 @@ export const useGridSorting = (apiRef, props) => {
236
236
  * 1ST RENDER
237
237
  */
238
238
  useFirstRender(() => {
239
- apiRef.current.applySorting();
239
+ if (props.signature === 'DataGrid') {
240
+ apiRef.current.applySorting();
241
+ }
240
242
  });
241
243
 
242
244
  /**
@@ -30,9 +30,6 @@ export const virtualizationStateInitializer = (state, props) => {
30
30
  });
31
31
  };
32
32
  export function useGridVirtualization(apiRef, rootProps) {
33
- const {
34
- virtualizer
35
- } = apiRef.current;
36
33
  const {
37
34
  autoHeight,
38
35
  disableVirtualization
@@ -43,7 +40,14 @@ export function useGridVirtualization(apiRef, rootProps) {
43
40
  */
44
41
 
45
42
  const setVirtualization = enabled => {
43
+ const {
44
+ virtualizer
45
+ } = apiRef.current;
46
46
  enabled &&= HAS_LAYOUT;
47
+ const snapshot = virtualizer.store.getSnapshot();
48
+ if (snapshot.virtualization.enabled === enabled && snapshot.virtualization.enabledForRows === enabled && snapshot.virtualization.enabledForColumns === enabled) {
49
+ return;
50
+ }
47
51
  virtualizer.store.set('virtualization', _extends({}, virtualizer.store.state.virtualization, {
48
52
  enabled,
49
53
  enabledForColumns: enabled,
@@ -51,7 +55,14 @@ export function useGridVirtualization(apiRef, rootProps) {
51
55
  }));
52
56
  };
53
57
  const setColumnVirtualization = enabled => {
58
+ const {
59
+ virtualizer
60
+ } = apiRef.current;
54
61
  enabled &&= HAS_LAYOUT;
62
+ const snapshot = virtualizer.store.getSnapshot();
63
+ if (snapshot.virtualization.enabledForColumns === enabled) {
64
+ return;
65
+ }
55
66
  virtualizer.store.set('virtualization', _extends({}, virtualizer.store.state.virtualization, {
56
67
  enabledForColumns: enabled
57
68
  }));
@@ -61,7 +72,12 @@ export function useGridVirtualization(apiRef, rootProps) {
61
72
  unstable_setColumnVirtualization: setColumnVirtualization
62
73
  };
63
74
  useGridApiMethod(apiRef, api, 'public');
64
- const forceUpdateRenderContext = virtualizer.api.forceUpdateRenderContext;
75
+ const forceUpdateRenderContext = () => {
76
+ const {
77
+ virtualizer
78
+ } = apiRef.current;
79
+ virtualizer?.api.scheduleUpdateRenderContext();
80
+ };
65
81
  apiRef.current.register('private', {
66
82
  updateRenderContext: forceUpdateRenderContext
67
83
  });
@@ -76,7 +92,10 @@ export function useGridVirtualization(apiRef, rootProps) {
76
92
 
77
93
  /* eslint-disable react-hooks/exhaustive-deps */
78
94
  React.useEffect(() => {
95
+ if (!apiRef.current.virtualizer) {
96
+ return;
97
+ }
79
98
  setVirtualization(!rootProps.disableVirtualization);
80
- }, [disableVirtualization, autoHeight]);
99
+ }, [apiRef, disableVirtualization, autoHeight]);
81
100
  /* eslint-enable react-hooks/exhaustive-deps */
82
101
  }
@@ -1,7 +1,6 @@
1
1
  import { RefObject } from '@mui/x-internals/types';
2
- import { GridApiCommon } from "../../models/index.js";
3
2
  import { GridApiCommunity } from "../../models/api/gridApiCommunity.js";
4
3
  /**
5
4
  * Hook that instantiate a [[GridApiRef]].
6
5
  */
7
- export declare const useGridApiRef: <Api extends GridApiCommon = GridApiCommunity>() => RefObject<Api | null>;
6
+ export declare const useGridApiRef: () => RefObject<GridApiCommunity | null>;
@@ -24,7 +24,9 @@ export function useGridEvent(apiRef, eventName, handler, options) {
24
24
  const cleanupTokenRef = React.useRef(null);
25
25
  if (!subscription.current && handlerRef.current) {
26
26
  const enhancedHandler = (params, event, details) => {
27
- if (!event.defaultMuiPrevented) {
27
+ // Check for the existence of the event once more to avoid Safari 26 issue
28
+ // https://github.com/mui/mui-x/issues/20159
29
+ if (event && !event.defaultMuiPrevented) {
28
30
  handlerRef.current?.(params, event, details);
29
31
  }
30
32
  };
@@ -51,7 +53,9 @@ export function useGridEvent(apiRef, eventName, handler, options) {
51
53
  React.useEffect(() => {
52
54
  if (!subscription.current && handlerRef.current) {
53
55
  const enhancedHandler = (params, event, details) => {
54
- if (!event.defaultMuiPrevented) {
56
+ // Check for the existence of the event once more to avoid Safari 26 issue
57
+ // https://github.com/mui/mui-x/issues/20159
58
+ if (event && !event.defaultMuiPrevented) {
55
59
  handlerRef.current?.(params, event, details);
56
60
  }
57
61
  };
@@ -1 +1,4 @@
1
- export declare function useRunOncePerLoop<T extends (...args: any[]) => void>(callback: T, nextFrame?: boolean): (...args: Parameters<T>) => void;
1
+ export declare function useRunOncePerLoop<T extends (...args: any[]) => void>(callback: T): {
2
+ schedule: (...args: Parameters<T>) => void;
3
+ cancel: () => boolean;
4
+ };
@@ -1,26 +1,36 @@
1
+ 'use client';
2
+
1
3
  import * as React from 'react';
2
- export function useRunOncePerLoop(callback, nextFrame = false) {
3
- const scheduledRef = React.useRef(false);
4
+ export function useRunOncePerLoop(callback) {
5
+ const scheduledCallbackRef = React.useRef(null);
4
6
  const schedule = React.useCallback((...args) => {
5
- if (scheduledRef.current) {
6
- return;
7
+ // for robustness, a fallback in case we don't react to state updates and layoutEffect is not run
8
+ // if we react to state updates, layoutEffect will run before microtasks
9
+ if (!scheduledCallbackRef.current) {
10
+ queueMicrotask(() => {
11
+ if (scheduledCallbackRef.current) {
12
+ scheduledCallbackRef.current();
13
+ }
14
+ });
7
15
  }
8
- scheduledRef.current = true;
9
- const runner = () => {
10
- scheduledRef.current = false;
16
+ scheduledCallbackRef.current = () => {
17
+ scheduledCallbackRef.current = null;
11
18
  callback(...args);
12
19
  };
13
- if (nextFrame) {
14
- if (typeof requestAnimationFrame === 'function') {
15
- requestAnimationFrame(runner);
16
- }
17
- return;
20
+ }, [callback]);
21
+ React.useLayoutEffect(() => {
22
+ if (scheduledCallbackRef.current) {
23
+ scheduledCallbackRef.current();
18
24
  }
19
- if (typeof queueMicrotask === 'function') {
20
- queueMicrotask(runner);
21
- } else {
22
- Promise.resolve().then(runner);
25
+ });
26
+ return {
27
+ schedule,
28
+ cancel: () => {
29
+ if (scheduledCallbackRef.current) {
30
+ scheduledCallbackRef.current = null;
31
+ return true;
32
+ }
33
+ return false;
23
34
  }
24
- }, [callback, nextFrame]);
25
- return schedule;
35
+ };
26
36
  }
package/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v8.17.0
2
+ * @mui/x-data-grid v8.19.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -257,6 +257,20 @@ export interface GridActionsColDef<R extends GridValidRowModel = any, V = any, F
257
257
  * Function that returns the actions to be shown.
258
258
  * @param {GridRowParams} params The params for each row.
259
259
  * @returns {readonly React.ReactElement<GridActionsCellItemProps>[]} An array of [[GridActionsCell]] elements.
260
+ * @deprecated Use `renderCell` instead
261
+ * @example
262
+ * // Before
263
+ * getActions: (params) => [
264
+ * <GridActionsCellItem icon={...} onClick={...} label="Delete" />,
265
+ * <GridActionsCellItem icon={...} onClick={...} label="Print" showInMenu />,
266
+ * ],
267
+ * // After
268
+ * renderCell: (params) => (
269
+ * <GridActionsCell {...params}>
270
+ * <GridActionsCellItem icon={...} onClick={...} label="Delete" />
271
+ * <GridActionsCellItem icon={...} onClick={...} label="Print" showInMenu />
272
+ * </GridActionsCell>
273
+ * ),
260
274
  */
261
275
  getActions: (params: GridRowParams<R>) => readonly React.ReactElement<GridActionsCellItemProps>[];
262
276
  }
@@ -516,6 +516,11 @@ export interface GridEventLookup extends GridRowEventLookup, GridColumnHeaderEve
516
516
  * @ignore - do not document
517
517
  */
518
518
  sortedRowsSet: {};
519
+ /**
520
+ * Fired when the aggregations are done
521
+ * @ignore - do not document
522
+ */
523
+ aggregationLookupSet: {};
519
524
  /**
520
525
  * Fired when the expansion of a row is changed. Called with a [[GridGroupNode]] object.
521
526
  */
@@ -13,7 +13,7 @@ import type { GridRowReorderState } from "../hooks/features/rowReorder/gridRowRe
13
13
  * Some props are passed on the state to enable grid selectors to select
14
14
  * and react to them.
15
15
  */
16
- export type GridStateProps = Pick<DataGridProcessedProps, 'getRowId' | 'listView' | 'isCellEditable'>;
16
+ export type GridStateProps = Pick<DataGridProcessedProps, 'getRowId' | 'listView' | 'isCellEditable' | 'isRowSelectable'>;
17
17
  /**
18
18
  * The state of Data Grid.
19
19
  */
@@ -1,4 +1,3 @@
1
- import * as React from 'react';
2
1
  import { GridCellMode } from "../gridCell.js";
3
2
  import { GridRowId, GridRowModel, GridTreeNode, GridTreeNodeWithRender, GridValidRowModel } from "../gridRows.js";
4
3
  import type { GridStateColDef } from "../colDef/gridColDef.js";
@@ -58,9 +57,6 @@ export interface GridCellParams<R extends GridValidRowModel = any, V = unknown,
58
57
  */
59
58
  api: GridApiCommunity;
60
59
  }
61
- export interface FocusElement {
62
- focus(): void;
63
- }
64
60
  /**
65
61
  * GridCellParams containing api.
66
62
  */
@@ -69,12 +65,6 @@ export interface GridRenderCellParams<R extends GridValidRowModel = any, V = any
69
65
  * GridApi that let you manipulate the grid.
70
66
  */
71
67
  api: GridApiCommunity;
72
- /**
73
- * A ref allowing to set imperative focus.
74
- * It can be passed to the element that should receive focus.
75
- * @ignore - do not document.
76
- */
77
- focusElementRef?: React.Ref<FocusElement>;
78
68
  }
79
69
  /**
80
70
  * GridEditCellProps containing api.
@@ -79,13 +79,11 @@ export interface DataGridPropsWithComplexDefaultValueBeforeProcessing {
79
79
  */
80
80
  export interface DataGridPropsWithDefaultValues<R extends GridValidRowModel = any> {
81
81
  /**
82
- * If `true`, the Data Grid height is dynamic and follows the number of rows in the Data Grid.
82
+ * If `true`, the Data Grid height is dynamic and takes as much space as it needs to display all rows.
83
+ * Use it instead of a flex parent container approach, if:
84
+ * - you don't need to set a minimum or maximum height for the Data Grid
85
+ * - you want to avoid the scrollbar flickering when the content changes
83
86
  * @default false
84
- * @deprecated Use flex parent container instead: https://mui.com/x/react-data-grid/layout/#flex-parent-container
85
- * @example
86
- * <div style={{ display: 'flex', flexDirection: 'column' }}>
87
- * <DataGrid />
88
- * </div>
89
87
  */
90
88
  autoHeight: boolean;
91
89
  /**
@@ -381,6 +379,15 @@ export interface DataGridPropsWithDefaultValues<R extends GridValidRowModel = an
381
379
  * @default false
382
380
  */
383
381
  virtualizeColumnsWithAutoRowHeight: boolean;
382
+ /**
383
+ * Sets the tab navigation behavior for the Data Grid.
384
+ * - "none": No Data Grid specific tab navigation. Pressing the tab key will move the focus to the next element in the tab sequence.
385
+ * - "content": Pressing the tab key will move the focus to the next cell in the same row or the first cell in the next row. Shift+Tab will move the focus to the previous cell in the same row or the last cell in the previous row. Tab navigation is not enabled for the header.
386
+ * - "header": Pressing the tab key will move the focus to the next column group, column header or header filter. Shift+Tab will move the focus to the previous column group, column header or header filter. Tab navigation is not enabled for the content.
387
+ * - "all": Combines the "content" and "header" behavior.
388
+ * @default "none"
389
+ */
390
+ tabNavigation: 'none' | 'content' | 'header' | 'all';
384
391
  }
385
392
  /**
386
393
  * The Data Grid props with no default value.
@@ -1,14 +1,7 @@
1
1
  import * as React from 'react';
2
2
  export declare function isPrintableKey(event: React.KeyboardEvent<HTMLElement>): boolean;
3
- export declare const GRID_MULTIPLE_SELECTION_KEYS: string[];
4
- export declare const GRID_CELL_EXIT_EDIT_MODE_KEYS: string[];
5
- export declare const GRID_CELL_EDIT_COMMIT_KEYS: string[];
6
- export declare const isMultipleKey: (key: string) => boolean;
7
- export declare const isCellEnterEditModeKeys: (event: React.KeyboardEvent<HTMLElement>) => boolean;
8
- export declare const isCellExitEditModeKeys: (key: string) => boolean;
9
- export declare const isCellEditCommitKeys: (key: string) => boolean;
10
3
  export declare const isNavigationKey: (key: string) => boolean;
11
4
  export declare const isKeyboardEvent: (event: any) => event is React.KeyboardEvent<HTMLElement>;
12
- export declare const isHideMenuKey: (key: React.KeyboardEvent["key"]) => key is "Escape" | "Tab";
5
+ export declare const isHideMenuKey: (key: React.KeyboardEvent["key"]) => key is "Tab" | "Escape";
13
6
  export declare function isPasteShortcut(event: React.KeyboardEvent): boolean;
14
7
  export declare function isCopyShortcut(event: KeyboardEvent): boolean;
@@ -8,13 +8,6 @@
8
8
  export function isPrintableKey(event) {
9
9
  return event.key.length === 1 && !event.ctrlKey && !event.metaKey;
10
10
  }
11
- export const GRID_MULTIPLE_SELECTION_KEYS = ['Meta', 'Control', 'Shift'];
12
- export const GRID_CELL_EXIT_EDIT_MODE_KEYS = ['Enter', 'Escape', 'Tab'];
13
- export const GRID_CELL_EDIT_COMMIT_KEYS = ['Enter', 'Tab'];
14
- export const isMultipleKey = key => GRID_MULTIPLE_SELECTION_KEYS.indexOf(key) > -1;
15
- export const isCellEnterEditModeKeys = event => isPrintableKey(event) || event.key === 'Enter' || event.key === 'Backspace' || event.key === 'Delete';
16
- export const isCellExitEditModeKeys = key => GRID_CELL_EXIT_EDIT_MODE_KEYS.indexOf(key) > -1;
17
- export const isCellEditCommitKeys = key => GRID_CELL_EDIT_COMMIT_KEYS.indexOf(key) > -1;
18
11
  export const isNavigationKey = key => key.indexOf('Arrow') === 0 || key.indexOf('Page') === 0 || key === ' ' || key === 'Home' || key === 'End';
19
12
  export const isKeyboardEvent = event => !!event.key;
20
13
  export const isHideMenuKey = key => key === 'Tab' || key === 'Escape';
@@ -6,4 +6,5 @@ import type { GridRowId } from "../../models/gridRows.js";
6
6
  * @param {GridRowModel} row - The row to get the id for
7
7
  * @returns {GridRowId} The row id
8
8
  */
9
- export declare const gridRowIdSelector: import("@mui/x-data-grid").OutputSelector<GridStateCommunity, import("@mui/x-data-grid").GridValidRowModel, GridRowId>;
9
+ export declare const gridRowIdSelector: import("@mui/x-data-grid").OutputSelector<GridStateCommunity, import("@mui/x-data-grid").GridValidRowModel, GridRowId>;
10
+ export declare const gridRowSelectableSelector: import("@mui/x-data-grid").OutputSelector<GridStateCommunity, unknown, ((params: import("@mui/x-data-grid").GridRowParams<any>) => boolean) | undefined>;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.gridRowIdSelector = void 0;
6
+ exports.gridRowSelectableSelector = exports.gridRowIdSelector = void 0;
7
7
  var _gridRowsUtils = require("../features/rows/gridRowsUtils");
8
8
  var _createSelector = require("../../utils/createSelector");
9
9
  /**
@@ -17,4 +17,7 @@ const gridRowIdSelector = exports.gridRowIdSelector = (0, _createSelector.create
17
17
  return row[_gridRowsUtils.GRID_ID_AUTOGENERATED];
18
18
  }
19
19
  return state.props.getRowId ? state.props.getRowId(row) : row.id;
20
+ });
21
+ const gridRowSelectableSelector = exports.gridRowSelectableSelector = (0, _createSelector.createRootSelector)(state => {
22
+ return state.props.isRowSelectable;
20
23
  });
@@ -20,14 +20,20 @@ const propsStateInitializer = (state, props) => {
20
20
  };
21
21
  exports.propsStateInitializer = propsStateInitializer;
22
22
  const useGridProps = (apiRef, props) => {
23
+ const isFirstRender = React.useRef(true);
23
24
  React.useEffect(() => {
25
+ if (isFirstRender.current) {
26
+ isFirstRender.current = false;
27
+ return;
28
+ }
24
29
  apiRef.current.setState(state => (0, _extends2.default)({}, state, {
25
30
  props: {
26
31
  listView: props.listView,
27
32
  getRowId: props.getRowId,
28
- isCellEditable: props.isCellEditable
33
+ isCellEditable: props.isCellEditable,
34
+ isRowSelectable: props.isRowSelectable
29
35
  }
30
36
  }));
31
- }, [apiRef, props.listView, props.getRowId, props.isCellEditable]);
37
+ }, [apiRef, props.listView, props.getRowId, props.isCellEditable, props.isRowSelectable]);
32
38
  };
33
39
  exports.useGridProps = useGridProps;