@mui/x-data-grid 8.18.0 → 8.20.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 (162) hide show
  1. package/CHANGELOG.md +175 -0
  2. package/DataGrid/useDataGridComponent.js +4 -3
  3. package/components/GridRow.js +5 -2
  4. package/components/GridRowDragAndDropOverlay.d.ts +7 -0
  5. package/components/GridRowDragAndDropOverlay.js +73 -0
  6. package/components/cell/GridActionsCell.d.ts +9 -0
  7. package/components/cell/GridActionsCell.js +54 -34
  8. package/components/cell/GridBooleanCell.js +0 -10
  9. package/components/cell/GridCell.js +4 -10
  10. package/components/columnHeaders/GridColumnHeaderItem.js +2 -2
  11. package/components/columnSelection/GridCellCheckboxRenderer.js +37 -22
  12. package/components/containers/GridRootStyles.js +17 -40
  13. package/components/toolbarV8/Toolbar.js +1 -1
  14. package/components/virtualization/GridVirtualScrollbar.d.ts +1 -0
  15. package/components/virtualization/GridVirtualScrollbar.js +13 -8
  16. package/components/virtualization/GridVirtualScroller.js +2 -1
  17. package/components/virtualization/GridVirtualScrollerRenderZone.js +1 -1
  18. package/constants/dataGridPropsDefaultValues.js +2 -1
  19. package/constants/gridClasses.d.ts +0 -8
  20. package/constants/gridClasses.js +1 -1
  21. package/esm/DataGrid/useDataGridComponent.js +5 -4
  22. package/esm/components/GridRow.js +5 -2
  23. package/esm/components/GridRowDragAndDropOverlay.d.ts +7 -0
  24. package/esm/components/GridRowDragAndDropOverlay.js +66 -0
  25. package/esm/components/cell/GridActionsCell.d.ts +9 -0
  26. package/esm/components/cell/GridActionsCell.js +55 -34
  27. package/esm/components/cell/GridBooleanCell.js +0 -10
  28. package/esm/components/cell/GridCell.js +4 -10
  29. package/esm/components/columnHeaders/GridColumnHeaderItem.js +2 -2
  30. package/esm/components/columnSelection/GridCellCheckboxRenderer.js +37 -22
  31. package/esm/components/containers/GridRootStyles.js +17 -40
  32. package/esm/components/toolbarV8/Toolbar.js +1 -1
  33. package/esm/components/virtualization/GridVirtualScrollbar.d.ts +1 -0
  34. package/esm/components/virtualization/GridVirtualScrollbar.js +12 -7
  35. package/esm/components/virtualization/GridVirtualScroller.js +2 -1
  36. package/esm/components/virtualization/GridVirtualScrollerRenderZone.js +1 -1
  37. package/esm/constants/dataGridPropsDefaultValues.js +2 -1
  38. package/esm/constants/gridClasses.d.ts +0 -8
  39. package/esm/constants/gridClasses.js +1 -1
  40. package/esm/hooks/core/gridPropsSelectors.d.ts +2 -1
  41. package/esm/hooks/core/gridPropsSelectors.js +3 -0
  42. package/esm/hooks/core/pipeProcessing/gridPipeProcessingApi.d.ts +4 -3
  43. package/esm/hooks/core/useGridProps.js +8 -2
  44. package/esm/hooks/core/useGridVirtualizer.d.ts +80 -6
  45. package/esm/hooks/core/useGridVirtualizer.js +27 -12
  46. package/esm/hooks/features/columnGrouping/useGridColumnGrouping.js +6 -1
  47. package/esm/hooks/features/columnMenu/useGridColumnMenu.js +14 -4
  48. package/esm/hooks/features/columns/useGridColumnSpanning.js +9 -4
  49. package/esm/hooks/features/dataSource/useGridDataSourceBase.js +2 -2
  50. package/esm/hooks/features/dimensions/useGridDimensions.js +12 -6
  51. package/esm/hooks/features/editing/useGridCellEditing.js +1 -1
  52. package/esm/hooks/features/editing/useGridRowEditing.js +1 -1
  53. package/esm/hooks/features/export/serializers/csvSerializer.js +2 -4
  54. package/esm/hooks/features/export/useGridPrintExport.js +18 -18
  55. package/esm/hooks/features/filter/gridFilterUtils.js +5 -11
  56. package/esm/hooks/features/filter/index.d.ts +1 -1
  57. package/esm/hooks/features/filter/index.js +1 -1
  58. package/esm/hooks/features/filter/useGridFilter.d.ts +1 -1
  59. package/esm/hooks/features/filter/useGridFilter.js +3 -1
  60. package/esm/hooks/features/focus/useGridFocus.js +0 -1
  61. package/esm/hooks/features/keyboardNavigation/useGridKeyboardNavigation.d.ts +1 -1
  62. package/esm/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +189 -25
  63. package/esm/hooks/features/pagination/useGridPaginationMeta.js +3 -3
  64. package/esm/hooks/features/pagination/useGridPaginationModel.js +7 -4
  65. package/esm/hooks/features/pagination/useGridRowCount.js +31 -15
  66. package/esm/hooks/features/rowReorder/gridRowReorderInterfaces.d.ts +19 -0
  67. package/esm/hooks/features/rowReorder/gridRowReorderSelector.d.ts +20 -1
  68. package/esm/hooks/features/rowReorder/gridRowReorderSelector.js +19 -1
  69. package/esm/hooks/features/rowSelection/useGridRowSelection.js +17 -8
  70. package/esm/hooks/features/rowSelection/utils.d.ts +1 -0
  71. package/esm/hooks/features/rowSelection/utils.js +17 -4
  72. package/esm/hooks/features/rows/useGridRowSpanning.js +23 -60
  73. package/esm/hooks/features/rows/useGridRows.js +3 -1
  74. package/esm/hooks/features/rows/useGridRowsOverridableMethods.d.ts +1 -0
  75. package/esm/hooks/features/rows/useGridRowsOverridableMethods.js +57 -7
  76. package/esm/hooks/features/scroll/useGridScroll.js +2 -3
  77. package/esm/hooks/features/sorting/gridSortingUtils.js +1 -3
  78. package/esm/hooks/features/sorting/useGridSorting.d.ts +1 -1
  79. package/esm/hooks/features/sorting/useGridSorting.js +3 -1
  80. package/esm/hooks/features/virtualization/useGridVirtualization.js +24 -5
  81. package/esm/hooks/utils/useGridEvent.js +6 -2
  82. package/esm/hooks/utils/useGridSelector.js +2 -4
  83. package/esm/hooks/utils/useRunOncePerLoop.d.ts +4 -1
  84. package/esm/hooks/utils/useRunOncePerLoop.js +28 -18
  85. package/esm/index.js +1 -1
  86. package/esm/internals/index.d.ts +5 -4
  87. package/esm/internals/index.js +3 -3
  88. package/esm/material/index.js +1 -4
  89. package/esm/models/api/gridRowApi.d.ts +14 -1
  90. package/esm/models/api/index.d.ts +1 -1
  91. package/esm/models/api/index.js +0 -1
  92. package/esm/models/colDef/gridColDef.d.ts +14 -0
  93. package/esm/models/configuration/gridConfiguration.d.ts +2 -2
  94. package/esm/models/configuration/gridRowConfiguration.d.ts +6 -5
  95. package/esm/models/events/gridEventLookup.d.ts +5 -0
  96. package/esm/models/gridStateCommunity.d.ts +1 -1
  97. package/esm/models/params/gridCellParams.d.ts +0 -10
  98. package/esm/models/props/DataGridProps.d.ts +13 -6
  99. package/esm/utils/keyboardUtils.d.ts +1 -8
  100. package/esm/utils/keyboardUtils.js +0 -7
  101. package/hooks/core/gridPropsSelectors.d.ts +2 -1
  102. package/hooks/core/gridPropsSelectors.js +4 -1
  103. package/hooks/core/pipeProcessing/gridPipeProcessingApi.d.ts +4 -3
  104. package/hooks/core/useGridProps.js +8 -2
  105. package/hooks/core/useGridVirtualizer.d.ts +80 -6
  106. package/hooks/core/useGridVirtualizer.js +26 -11
  107. package/hooks/features/columnGrouping/useGridColumnGrouping.js +6 -1
  108. package/hooks/features/columnMenu/useGridColumnMenu.js +14 -4
  109. package/hooks/features/columns/useGridColumnSpanning.js +9 -4
  110. package/hooks/features/dataSource/useGridDataSourceBase.js +2 -2
  111. package/hooks/features/dimensions/useGridDimensions.js +12 -6
  112. package/hooks/features/editing/useGridCellEditing.js +1 -1
  113. package/hooks/features/editing/useGridRowEditing.js +1 -1
  114. package/hooks/features/export/serializers/csvSerializer.js +2 -4
  115. package/hooks/features/export/useGridPrintExport.js +18 -18
  116. package/hooks/features/filter/gridFilterUtils.js +5 -11
  117. package/hooks/features/filter/index.d.ts +1 -1
  118. package/hooks/features/filter/index.js +6 -0
  119. package/hooks/features/filter/useGridFilter.d.ts +1 -1
  120. package/hooks/features/filter/useGridFilter.js +3 -1
  121. package/hooks/features/focus/useGridFocus.js +0 -1
  122. package/hooks/features/keyboardNavigation/useGridKeyboardNavigation.d.ts +1 -1
  123. package/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +189 -25
  124. package/hooks/features/pagination/useGridPaginationMeta.js +2 -2
  125. package/hooks/features/pagination/useGridPaginationModel.js +7 -4
  126. package/hooks/features/pagination/useGridRowCount.js +30 -14
  127. package/hooks/features/rowReorder/gridRowReorderInterfaces.d.ts +19 -0
  128. package/hooks/features/rowReorder/gridRowReorderSelector.d.ts +20 -1
  129. package/hooks/features/rowReorder/gridRowReorderSelector.js +20 -2
  130. package/hooks/features/rowSelection/useGridRowSelection.js +17 -8
  131. package/hooks/features/rowSelection/utils.d.ts +1 -0
  132. package/hooks/features/rowSelection/utils.js +16 -3
  133. package/hooks/features/rows/useGridRowSpanning.js +23 -60
  134. package/hooks/features/rows/useGridRows.js +3 -1
  135. package/hooks/features/rows/useGridRowsOverridableMethods.d.ts +1 -0
  136. package/hooks/features/rows/useGridRowsOverridableMethods.js +57 -7
  137. package/hooks/features/scroll/useGridScroll.js +2 -3
  138. package/hooks/features/sorting/gridSortingUtils.js +1 -3
  139. package/hooks/features/sorting/useGridSorting.d.ts +1 -1
  140. package/hooks/features/sorting/useGridSorting.js +3 -1
  141. package/hooks/features/virtualization/useGridVirtualization.js +24 -5
  142. package/hooks/utils/useGridEvent.js +6 -2
  143. package/hooks/utils/useGridSelector.js +2 -4
  144. package/hooks/utils/useRunOncePerLoop.d.ts +4 -1
  145. package/hooks/utils/useRunOncePerLoop.js +27 -18
  146. package/index.js +1 -1
  147. package/internals/index.d.ts +5 -4
  148. package/internals/index.js +16 -9
  149. package/material/index.js +1 -4
  150. package/models/api/gridRowApi.d.ts +14 -1
  151. package/models/api/index.d.ts +1 -1
  152. package/models/api/index.js +0 -11
  153. package/models/colDef/gridColDef.d.ts +14 -0
  154. package/models/configuration/gridConfiguration.d.ts +2 -2
  155. package/models/configuration/gridRowConfiguration.d.ts +6 -5
  156. package/models/events/gridEventLookup.d.ts +5 -0
  157. package/models/gridStateCommunity.d.ts +1 -1
  158. package/models/params/gridCellParams.d.ts +0 -10
  159. package/models/props/DataGridProps.d.ts +13 -6
  160. package/package.json +3 -3
  161. package/utils/keyboardUtils.d.ts +1 -8
  162. package/utils/keyboardUtils.js +1 -13
@@ -113,15 +113,32 @@ const useGridKeyboardNavigation = (apiRef, props) => {
113
113
  // There is one exception for the checkBoxHeader
114
114
  return;
115
115
  }
116
+ if (!(0, _keyboardUtils.isNavigationKey)(event.key) && event.key !== 'Tab') {
117
+ return;
118
+ }
119
+
120
+ // Tab key is only allowed if tabbing is enabled for header/all, or if we are tabbing to the content area while `tabNavigation` is enabled for content only
121
+ if (event.key === 'Tab' && (props.tabNavigation === 'none' || props.tabNavigation === 'content' && event.shiftKey)) {
122
+ return;
123
+ }
116
124
  const currentPageRows = getCurrentPageRows();
117
125
  const viewportPageSize = apiRef.current.getViewportPageSize();
118
126
  const colIndexBefore = params.field ? apiRef.current.getColumnIndex(params.field) : 0;
119
127
  const firstRowIndexInPage = currentPageRows.length > 0 ? 0 : null;
120
- const lastRowIndexInPage = currentPageRows.length - 1;
128
+ const lastRowIndexInPage = currentPageRows.length > 0 ? currentPageRows.length - 1 : null;
121
129
  const firstColIndex = 0;
122
- const lastColIndex = (0, _gridColumnsSelector.gridVisibleColumnDefinitionsSelector)(apiRef).length - 1;
130
+ const lastColIndex = Math.max(0, (0, _gridColumnsSelector.gridVisibleColumnDefinitionsSelector)(apiRef).length - 1);
123
131
  const columnGroupMaxDepth = (0, _gridColumnGroupsSelector.gridColumnGroupsHeaderMaxDepthSelector)(apiRef);
124
132
  let shouldPreventDefault = true;
133
+
134
+ // If we are tabbing inside the header area while only content `tabNavigation` is enabled, go to the first cell
135
+ if (event.key === 'Tab' && props.tabNavigation === 'content' && !event.shiftKey) {
136
+ if (firstRowIndexInPage !== null) {
137
+ goToCell(firstColIndex, getRowIdFromIndex(firstRowIndexInPage));
138
+ event.preventDefault();
139
+ }
140
+ return;
141
+ }
125
142
  switch (event.key) {
126
143
  case 'ArrowDown':
127
144
  {
@@ -189,6 +206,36 @@ const useGridKeyboardNavigation = (apiRef, props) => {
189
206
  }
190
207
  break;
191
208
  }
209
+ case 'Tab':
210
+ {
211
+ if (event.shiftKey) {
212
+ // if the key is pressed on the first column header, Shift+Tab should go to the group header if it is there or allow default behavior
213
+ if (colIndexBefore === firstColIndex) {
214
+ if (columnGroupMaxDepth > 0) {
215
+ goToGroupHeader(lastColIndex, columnGroupMaxDepth - 1, event);
216
+ } else {
217
+ shouldPreventDefault = false;
218
+ }
219
+ } else {
220
+ goToHeader(colIndexBefore - 1, event);
221
+ }
222
+ } else if (colIndexBefore === lastColIndex) {
223
+ // the key is pressed at the last column header. go to the first header filter or the first cell
224
+ if (headerFilteringEnabled) {
225
+ goToHeaderFilter(firstColIndex, event);
226
+ }
227
+ // this point can be reached if tabbing is enabled for all content or just header.
228
+ // if it is not enabled for all content or there is no data, then do not focus on the first cell
229
+ else if (props.tabNavigation === 'all' && firstRowIndexInPage !== null) {
230
+ goToCell(firstColIndex, getRowIdFromIndex(firstRowIndexInPage));
231
+ } else {
232
+ shouldPreventDefault = false;
233
+ }
234
+ } else {
235
+ goToHeader(colIndexBefore + 1, event);
236
+ }
237
+ break;
238
+ }
192
239
  case ' ':
193
240
  {
194
241
  // prevent Space event from scrolling
@@ -202,27 +249,43 @@ const useGridKeyboardNavigation = (apiRef, props) => {
202
249
  if (shouldPreventDefault) {
203
250
  event.preventDefault();
204
251
  }
205
- }, [apiRef, getCurrentPageRows, headerFilteringEnabled, goToHeaderFilter, goToCell, getRowIdFromIndex, isRtl, goToHeader, goToGroupHeader]);
252
+ }, [apiRef, props.tabNavigation, getCurrentPageRows, headerFilteringEnabled, goToHeaderFilter, goToCell, getRowIdFromIndex, isRtl, goToHeader, goToGroupHeader]);
206
253
  const handleHeaderFilterKeyDown = React.useCallback((params, event) => {
207
254
  const isEditing = (0, _gridHeaderFilteringSelectors.gridHeaderFilteringEditFieldSelector)(apiRef) === params.field;
208
255
  const isHeaderMenuOpen = (0, _gridHeaderFilteringSelectors.gridHeaderFilteringMenuSelector)(apiRef) === params.field;
209
- if (isEditing || isHeaderMenuOpen || !(0, _keyboardUtils.isNavigationKey)(event.key)) {
256
+ if (isHeaderMenuOpen || isEditing && event.key !== 'Tab') {
257
+ return;
258
+ }
259
+ if (!(0, _keyboardUtils.isNavigationKey)(event.key) && event.key !== 'Tab') {
260
+ return;
261
+ }
262
+
263
+ // Tab key is only allowed if tabbing is enabled for header/all, or if we are tabbing to the content area while `tabNavigation` is enabled for content only
264
+ if (event.key === 'Tab' && (props.tabNavigation === 'none' || props.tabNavigation === 'content' && event.shiftKey)) {
210
265
  return;
211
266
  }
212
267
  const currentPageRows = getCurrentPageRows();
213
268
  const viewportPageSize = apiRef.current.getViewportPageSize();
214
269
  const colIndexBefore = params.field ? apiRef.current.getColumnIndex(params.field) : 0;
215
- const firstRowIndexInPage = 0;
216
- const lastRowIndexInPage = currentPageRows.length - 1;
270
+ const firstRowIndexInPage = currentPageRows.length > 0 ? 0 : null;
271
+ const lastRowIndexInPage = currentPageRows.length > 0 ? currentPageRows.length - 1 : null;
217
272
  const firstColIndex = 0;
218
- const lastColIndex = (0, _gridColumnsSelector.gridVisibleColumnDefinitionsSelector)(apiRef).length - 1;
273
+ const lastColIndex = Math.max(0, (0, _gridColumnsSelector.gridVisibleColumnDefinitionsSelector)(apiRef).length - 1);
219
274
  let shouldPreventDefault = true;
275
+
276
+ // If we are tabbing inside the header area while only content `tabNavigation` is enabled, go to the first cell
277
+ if (event.key === 'Tab' && props.tabNavigation === 'content' && !event.shiftKey) {
278
+ if (firstRowIndexInPage !== null) {
279
+ goToCell(firstColIndex, getRowIdFromIndex(firstRowIndexInPage));
280
+ event.preventDefault();
281
+ }
282
+ return;
283
+ }
220
284
  switch (event.key) {
221
285
  case 'ArrowDown':
222
286
  {
223
- const rowId = getRowIdFromIndex(firstRowIndexInPage);
224
- if (firstRowIndexInPage !== null && rowId != null) {
225
- goToCell(colIndexBefore, rowId);
287
+ if (firstRowIndexInPage !== null) {
288
+ goToCell(colIndexBefore, getRowIdFromIndex(firstRowIndexInPage));
226
289
  }
227
290
  break;
228
291
  }
@@ -276,6 +339,29 @@ const useGridKeyboardNavigation = (apiRef, props) => {
276
339
  goToHeaderFilter(lastColIndex, event);
277
340
  break;
278
341
  }
342
+ case 'Tab':
343
+ {
344
+ if (event.shiftKey) {
345
+ // if the key is pressed on the first header filter, Shift+Tab should go to the column header
346
+ if (colIndexBefore === firstColIndex) {
347
+ goToHeader(lastColIndex, event);
348
+ } else {
349
+ goToHeaderFilter(colIndexBefore - 1, event);
350
+ }
351
+ } else if (colIndexBefore === lastColIndex) {
352
+ // the key is pressed at the last header filter.
353
+ // this point can be reached if `tabNavigation` is enabled for all content or just header.
354
+ // if it is not enabled for all content or there is no data, then do not focus on the first cell
355
+ if (props.tabNavigation === 'all' && firstRowIndexInPage !== null) {
356
+ goToCell(firstColIndex, getRowIdFromIndex(firstRowIndexInPage));
357
+ } else {
358
+ shouldPreventDefault = false;
359
+ }
360
+ } else {
361
+ goToHeaderFilter(colIndexBefore + 1, event);
362
+ }
363
+ break;
364
+ }
279
365
  case ' ':
280
366
  {
281
367
  // prevent Space event from scrolling
@@ -289,7 +375,7 @@ const useGridKeyboardNavigation = (apiRef, props) => {
289
375
  if (shouldPreventDefault) {
290
376
  event.preventDefault();
291
377
  }
292
- }, [apiRef, getCurrentPageRows, goToHeaderFilter, isRtl, goToHeader, goToCell, getRowIdFromIndex]);
378
+ }, [apiRef, props.tabNavigation, getCurrentPageRows, goToHeaderFilter, isRtl, goToHeader, goToCell, getRowIdFromIndex]);
293
379
  const handleColumnGroupHeaderKeyDown = React.useCallback((params, event) => {
294
380
  const focusedColumnGroup = (0, _focus.gridFocusColumnGroupHeaderSelector)(apiRef);
295
381
  if (focusedColumnGroup === null) {
@@ -304,15 +390,32 @@ const useGridKeyboardNavigation = (apiRef, props) => {
304
390
  depth,
305
391
  maxDepth
306
392
  } = params;
393
+ if (!(0, _keyboardUtils.isNavigationKey)(event.key) && event.key !== 'Tab') {
394
+ return;
395
+ }
396
+
397
+ // Tab key is only allowed if tabbing is enabled for header/all, or if we are tabbing to the content area while `tabNavigation` is enabled for content only
398
+ if (event.key === 'Tab' && (props.tabNavigation === 'none' || props.tabNavigation === 'content' && event.shiftKey)) {
399
+ return;
400
+ }
307
401
  const currentPageRows = getCurrentPageRows();
308
402
  const viewportPageSize = apiRef.current.getViewportPageSize();
309
403
  const currentColIndex = apiRef.current.getColumnIndex(currentField);
310
404
  const colIndexBefore = currentField ? apiRef.current.getColumnIndex(currentField) : 0;
311
- const firstRowIndexInPage = 0;
312
- const lastRowIndexInPage = currentPageRows.length - 1;
405
+ const firstRowIndexInPage = currentPageRows.length > 0 ? 0 : null;
406
+ const lastRowIndexInPage = currentPageRows.length > 0 ? currentPageRows.length - 1 : null;
313
407
  const firstColIndex = 0;
314
- const lastColIndex = (0, _gridColumnsSelector.gridVisibleColumnDefinitionsSelector)(apiRef).length - 1;
408
+ const lastColIndex = Math.max(0, (0, _gridColumnsSelector.gridVisibleColumnDefinitionsSelector)(apiRef).length - 1);
315
409
  let shouldPreventDefault = true;
410
+
411
+ // If we are tabbing inside the header area while only content `tabNavigation` is enabled, go to the first cell
412
+ if (event.key === 'Tab' && props.tabNavigation === 'content' && !event.shiftKey) {
413
+ if (firstRowIndexInPage !== null) {
414
+ goToCell(firstColIndex, getRowIdFromIndex(firstRowIndexInPage));
415
+ event.preventDefault();
416
+ }
417
+ return;
418
+ }
316
419
  switch (event.key) {
317
420
  case 'ArrowDown':
318
421
  {
@@ -363,6 +466,37 @@ const useGridKeyboardNavigation = (apiRef, props) => {
363
466
  goToGroupHeader(lastColIndex, currentDepth, event);
364
467
  break;
365
468
  }
469
+ case 'Tab':
470
+ {
471
+ if (event.shiftKey) {
472
+ const remainingLeftColumns = fields.indexOf(currentField);
473
+ const targetColIndex = currentColIndex - remainingLeftColumns - 1;
474
+ if (targetColIndex < firstColIndex) {
475
+ if (depth === 0) {
476
+ // if the key is pressed on the first column group header at the top level, Shift+Tab should allow default behavior
477
+ shouldPreventDefault = false;
478
+ } else {
479
+ // Navigate to last column group header at the previous depth
480
+ goToGroupHeader(lastColIndex, currentDepth - 1, event);
481
+ }
482
+ } else {
483
+ goToGroupHeader(targetColIndex, currentDepth, event);
484
+ }
485
+ } else {
486
+ const remainingRightColumns = fields.length - fields.indexOf(currentField) - 1;
487
+ const targetColIndex = currentColIndex + remainingRightColumns + 1;
488
+ if (targetColIndex > lastColIndex && depth === maxDepth - 1) {
489
+ // the key is pressed at the last column group header at the deepest level. go to the first column header
490
+ goToHeader(firstColIndex, event);
491
+ } else if (targetColIndex > lastColIndex) {
492
+ // go down a depth level
493
+ goToGroupHeader(firstColIndex, currentDepth + 1, event);
494
+ } else {
495
+ goToGroupHeader(targetColIndex, currentDepth, event);
496
+ }
497
+ }
498
+ break;
499
+ }
366
500
  case ' ':
367
501
  {
368
502
  // prevent Space event from scrolling
@@ -376,7 +510,7 @@ const useGridKeyboardNavigation = (apiRef, props) => {
376
510
  if (shouldPreventDefault) {
377
511
  event.preventDefault();
378
512
  }
379
- }, [apiRef, getCurrentPageRows, goToHeader, goToGroupHeader, goToCell, getRowIdFromIndex]);
513
+ }, [apiRef, props.tabNavigation, getCurrentPageRows, goToHeader, goToGroupHeader, goToCell, getRowIdFromIndex]);
380
514
  const handleCellKeyDown = React.useCallback((params, event) => {
381
515
  // Ignore portal
382
516
  if ((0, _domUtils.isEventTargetInPortal)(event)) {
@@ -385,7 +519,12 @@ const useGridKeyboardNavigation = (apiRef, props) => {
385
519
 
386
520
  // Get the most recent params because the cell mode may have changed by another listener
387
521
  const cellParams = apiRef.current.getCellParams(params.id, params.field);
388
- if (cellParams.cellMode === _gridEditRowModel.GridCellModes.Edit || !(0, _keyboardUtils.isNavigationKey)(event.key)) {
522
+ if (cellParams.cellMode === _gridEditRowModel.GridCellModes.Edit || !(0, _keyboardUtils.isNavigationKey)(event.key) && event.key !== 'Tab') {
523
+ return;
524
+ }
525
+
526
+ // Tab key is only allowed if tabbing is enabled or if we are tabbing to the header area while `tabNavigation` is enabled for header only (with Shift+Tab)
527
+ if (event.key === 'Tab' && (props.tabNavigation === 'none' || props.tabNavigation === 'header' && !event.shiftKey)) {
389
528
  return;
390
529
  }
391
530
  const canUpdateFocus = apiRef.current.unstable_applyPipeProcessors('canUpdateFocus', true, {
@@ -399,14 +538,22 @@ const useGridKeyboardNavigation = (apiRef, props) => {
399
538
  if (currentPageRows.length === 0) {
400
539
  return;
401
540
  }
541
+ const previousAreaNavigationFn = headerFilteringEnabled ? goToHeaderFilter : goToHeader;
402
542
  const viewportPageSize = apiRef.current.getViewportPageSize();
403
543
  const colIndexBefore = params.field ? apiRef.current.getColumnIndex(params.field) : 0;
404
544
  const rowIndexBefore = currentPageRows.findIndex(row => row.id === params.id);
405
545
  const firstRowIndexInPage = 0;
406
546
  const lastRowIndexInPage = currentPageRows.length - 1;
407
547
  const firstColIndex = 0;
408
- const lastColIndex = (0, _gridColumnsSelector.gridVisibleColumnDefinitionsSelector)(apiRef).length - 1;
548
+ const lastColIndex = Math.max(0, (0, _gridColumnsSelector.gridVisibleColumnDefinitionsSelector)(apiRef).length - 1);
409
549
  let shouldPreventDefault = true;
550
+
551
+ // If we are tabbing inside the content area while only header `tabNavigation` is enabled, go to the last header filter or column header
552
+ if (event.key === 'Tab' && props.tabNavigation === 'header' && event.shiftKey) {
553
+ previousAreaNavigationFn(lastColIndex, event);
554
+ event.preventDefault();
555
+ return;
556
+ }
410
557
  switch (event.key) {
411
558
  case 'ArrowDown':
412
559
  {
@@ -420,10 +567,8 @@ const useGridKeyboardNavigation = (apiRef, props) => {
420
567
  {
421
568
  if (rowIndexBefore > firstRowIndexInPage) {
422
569
  goToCell(colIndexBefore, getRowIdFromIndex(rowIndexBefore - 1));
423
- } else if (headerFilteringEnabled) {
424
- goToHeaderFilter(colIndexBefore, event);
425
570
  } else {
426
- goToHeader(colIndexBefore, event);
571
+ previousAreaNavigationFn(colIndexBefore, event);
427
572
  }
428
573
  break;
429
574
  }
@@ -455,10 +600,29 @@ const useGridKeyboardNavigation = (apiRef, props) => {
455
600
  }
456
601
  case 'Tab':
457
602
  {
458
- // "Tab" is only triggered by the row / cell editing feature
459
- if (event.shiftKey && colIndexBefore > firstColIndex) {
460
- goToCell(colIndexBefore - 1, getRowIdFromIndex(rowIndexBefore), 'left');
461
- } else if (!event.shiftKey && colIndexBefore < lastColIndex) {
603
+ if (event.shiftKey) {
604
+ // if the key is pressed on the first cell, Shift+Tab should go to the last column header
605
+ // same is if `tabNavigation` is enabled for header only
606
+ if (colIndexBefore === firstColIndex && rowIndexBefore === firstRowIndexInPage) {
607
+ if (props.tabNavigation === 'all') {
608
+ previousAreaNavigationFn(lastColIndex, event);
609
+ } else {
610
+ shouldPreventDefault = false;
611
+ }
612
+ } else if (colIndexBefore === firstColIndex) {
613
+ goToCell(lastColIndex, getRowIdFromIndex(rowIndexBefore - 1));
614
+ } else {
615
+ goToCell(colIndexBefore - 1, getRowIdFromIndex(rowIndexBefore), 'left');
616
+ }
617
+ } else if (colIndexBefore === lastColIndex) {
618
+ // the key is pressed at the last column. if it is also the last row, do not to anything to allow the default behavior
619
+ // otherwise, go to the first column of the next row
620
+ if (rowIndexBefore !== lastRowIndexInPage) {
621
+ goToCell(firstColIndex, getRowIdFromIndex(rowIndexBefore + 1));
622
+ } else {
623
+ shouldPreventDefault = false;
624
+ }
625
+ } else {
462
626
  goToCell(colIndexBefore + 1, getRowIdFromIndex(rowIndexBefore), 'right');
463
627
  }
464
628
  break;
@@ -522,7 +686,7 @@ const useGridKeyboardNavigation = (apiRef, props) => {
522
686
  if (shouldPreventDefault) {
523
687
  event.preventDefault();
524
688
  }
525
- }, [apiRef, getCurrentPageRows, isRtl, goToCell, getRowIdFromIndex, headerFilteringEnabled, goToHeaderFilter, goToHeader]);
689
+ }, [apiRef, props.tabNavigation, getCurrentPageRows, isRtl, goToCell, getRowIdFromIndex, headerFilteringEnabled, goToHeaderFilter, goToHeader]);
526
690
  const checkIfCanStartEditing = React.useCallback((initialValue, {
527
691
  event
528
692
  }) => {
@@ -14,7 +14,6 @@ var _pipeProcessing = require("../../core/pipeProcessing");
14
14
  var _gridPaginationSelector = require("./gridPaginationSelector");
15
15
  const useGridPaginationMeta = (apiRef, props) => {
16
16
  const logger = (0, _utils.useGridLogger)(apiRef, 'useGridPaginationMeta');
17
- const paginationMeta = (0, _utils.useGridSelector)(apiRef, _gridPaginationSelector.gridPaginationMetaSelector);
18
17
  apiRef.current.registerControlState({
19
18
  stateId: 'paginationMeta',
20
19
  propModel: props.paginationMeta,
@@ -27,6 +26,7 @@ const useGridPaginationMeta = (apiRef, props) => {
27
26
  * API METHODS
28
27
  */
29
28
  const setPaginationMeta = React.useCallback(newPaginationMeta => {
29
+ const paginationMeta = (0, _gridPaginationSelector.gridPaginationMetaSelector)(apiRef);
30
30
  if (paginationMeta === newPaginationMeta) {
31
31
  return;
32
32
  }
@@ -36,7 +36,7 @@ const useGridPaginationMeta = (apiRef, props) => {
36
36
  meta: newPaginationMeta
37
37
  })
38
38
  }));
39
- }, [apiRef, logger, paginationMeta]);
39
+ }, [apiRef, logger]);
40
40
  const paginationMetaApi = {
41
41
  setPaginationMeta
42
42
  };
@@ -68,6 +68,7 @@ const useGridPaginationModel = (apiRef, props) => {
68
68
  pageSize: currentModel.pageSize
69
69
  });
70
70
  }, [apiRef, logger]);
71
+ const debouncedSetPage = React.useMemo(() => (0, _debounce.default)(setPage, 0), [setPage]);
71
72
  const setPageSize = React.useCallback(pageSize => {
72
73
  const currentModel = (0, _gridPaginationSelector.gridPaginationModelSelector)(apiRef);
73
74
  if (pageSize === currentModel.pageSize) {
@@ -162,9 +163,11 @@ const useGridPaginationModel = (apiRef, props) => {
162
163
  }
163
164
  const pageCount = (0, _gridPaginationSelector.gridPageCountSelector)(apiRef);
164
165
  if (paginationModel.page > pageCount - 1) {
165
- apiRef.current.setPage(Math.max(0, pageCount - 1));
166
+ queueMicrotask(() => {
167
+ debouncedSetPage(Math.max(0, pageCount - 1));
168
+ });
166
169
  }
167
- }, [apiRef]);
170
+ }, [apiRef, debouncedSetPage]);
168
171
 
169
172
  /**
170
173
  * Goes to the first row of the grid
@@ -172,7 +175,7 @@ const useGridPaginationModel = (apiRef, props) => {
172
175
  const navigateToStart = React.useCallback(() => {
173
176
  const paginationModel = (0, _gridPaginationSelector.gridPaginationModelSelector)(apiRef);
174
177
  if (paginationModel.page !== 0) {
175
- apiRef.current.setPage(0);
178
+ debouncedSetPage(0);
176
179
  }
177
180
 
178
181
  // If the page was not changed it might be needed to scroll to the top
@@ -182,7 +185,7 @@ const useGridPaginationModel = (apiRef, props) => {
182
185
  top: 0
183
186
  });
184
187
  }
185
- }, [apiRef]);
188
+ }, [apiRef, debouncedSetPage]);
186
189
  const debouncedNavigateToStart = React.useMemo(() => (0, _debounce.default)(navigateToStart, 0), [navigateToStart]);
187
190
 
188
191
  /**
@@ -10,16 +10,13 @@ exports.useGridRowCount = void 0;
10
10
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
11
  var React = _interopRequireWildcard(require("react"));
12
12
  var _useLazyRef = _interopRequireDefault(require("@mui/utils/useLazyRef"));
13
+ var _store = require("@mui/x-internals/store");
13
14
  var _filter = require("../filter");
14
15
  var _utils = require("../../utils");
15
16
  var _pipeProcessing = require("../../core/pipeProcessing");
16
17
  var _gridPaginationSelector = require("./gridPaginationSelector");
17
18
  const useGridRowCount = (apiRef, props) => {
18
19
  const logger = (0, _utils.useGridLogger)(apiRef, 'useGridRowCount');
19
- const visibleTopLevelRowCount = (0, _utils.useGridSelector)(apiRef, _filter.gridFilteredTopLevelRowCountSelector);
20
- const rowCountState = (0, _utils.useGridSelector)(apiRef, _gridPaginationSelector.gridPaginationRowCountSelector);
21
- const paginationMeta = (0, _utils.useGridSelector)(apiRef, _gridPaginationSelector.gridPaginationMetaSelector);
22
- const paginationModel = (0, _utils.useGridSelector)(apiRef, _gridPaginationSelector.gridPaginationModelSelector);
23
20
  const previousPageSize = (0, _useLazyRef.default)(() => (0, _gridPaginationSelector.gridPaginationModelSelector)(apiRef).pageSize);
24
21
  apiRef.current.registerControlState({
25
22
  stateId: 'paginationRowCount',
@@ -33,6 +30,7 @@ const useGridRowCount = (apiRef, props) => {
33
30
  * API METHODS
34
31
  */
35
32
  const setRowCount = React.useCallback(newRowCount => {
33
+ const rowCountState = (0, _gridPaginationSelector.gridPaginationRowCountSelector)(apiRef);
36
34
  if (rowCountState === newRowCount) {
37
35
  return;
38
36
  }
@@ -42,7 +40,7 @@ const useGridRowCount = (apiRef, props) => {
42
40
  rowCount: newRowCount
43
41
  })
44
42
  }));
45
- }, [apiRef, logger, rowCountState]);
43
+ }, [apiRef, logger]);
46
44
  const paginationRowCountApi = {
47
45
  setRowCount
48
46
  };
@@ -90,29 +88,47 @@ const useGridRowCount = (apiRef, props) => {
90
88
  }
91
89
  if (model.pageSize !== previousPageSize.current) {
92
90
  previousPageSize.current = model.pageSize;
91
+ const rowCountState = (0, _gridPaginationSelector.gridPaginationRowCountSelector)(apiRef);
93
92
  if (rowCountState === -1) {
94
93
  // Row count unknown and page size changed, reset the page
95
94
  apiRef.current.setPage(0);
96
95
  }
97
96
  }
98
- }, [props.paginationMode, previousPageSize, rowCountState, apiRef]);
97
+ }, [props.paginationMode, previousPageSize, apiRef]);
99
98
  (0, _utils.useGridEvent)(apiRef, 'paginationModelChange', handlePaginationModelChange);
100
99
 
101
100
  /**
102
101
  * EFFECTS
103
102
  */
104
103
  React.useEffect(() => {
105
- if (props.paginationMode === 'client') {
106
- apiRef.current.setRowCount(visibleTopLevelRowCount);
107
- } else if (props.rowCount != null) {
104
+ if (props.paginationMode === 'server' && props.rowCount != null) {
108
105
  apiRef.current.setRowCount(props.rowCount);
109
106
  }
110
- }, [apiRef, props.paginationMode, visibleTopLevelRowCount, props.rowCount]);
111
- const isLastPage = paginationMeta.hasNextPage === false;
112
- React.useEffect(() => {
113
- if (isLastPage && rowCountState === -1) {
107
+ }, [apiRef, props.paginationMode, props.rowCount]);
108
+ (0, _store.useStoreEffect)(
109
+ // typings not supported currently, but methods work
110
+ apiRef.current.store, () => {
111
+ const isLastPage = (0, _gridPaginationSelector.gridPaginationMetaSelector)(apiRef).hasNextPage === false;
112
+ if (isLastPage) {
113
+ return true;
114
+ }
115
+ if (props.paginationMode === 'client') {
116
+ return (0, _filter.gridFilteredTopLevelRowCountSelector)(apiRef);
117
+ }
118
+ return undefined;
119
+ }, (_, isLastPageOrRowCount) => {
120
+ if (isLastPageOrRowCount === true && (0, _gridPaginationSelector.gridPaginationRowCountSelector)(apiRef) !== -1) {
121
+ const visibleTopLevelRowCount = (0, _filter.gridFilteredTopLevelRowCountSelector)(apiRef);
122
+ const paginationModel = (0, _gridPaginationSelector.gridPaginationModelSelector)(apiRef);
114
123
  apiRef.current.setRowCount(paginationModel.pageSize * paginationModel.page + visibleTopLevelRowCount);
124
+ } else if (typeof isLastPageOrRowCount === 'number') {
125
+ apiRef.current.setRowCount(isLastPageOrRowCount);
126
+ }
127
+ });
128
+ React.useEffect(() => {
129
+ if (props.paginationMode === 'client') {
130
+ apiRef.current.setRowCount((0, _filter.gridFilteredTopLevelRowCountSelector)(apiRef));
115
131
  }
116
- }, [apiRef, visibleTopLevelRowCount, isLastPage, rowCountState, paginationModel]);
132
+ }, [apiRef, props.paginationMode]);
117
133
  };
118
134
  exports.useGridRowCount = useGridRowCount;
@@ -1,3 +1,5 @@
1
+ import type { GridRowId } from "../../../models/gridRows.js";
2
+ import type { RowReorderDropPosition } from "../../../models/api/gridRowApi.js";
1
3
  /**
2
4
  * The row reorder state.
3
5
  */
@@ -6,4 +8,21 @@ export interface GridRowReorderState {
6
8
  * Whether a row drag operation is currently active.
7
9
  */
8
10
  isActive: boolean;
11
+ /**
12
+ * The row ID being dragged.
13
+ */
14
+ draggedRowId: GridRowId | null;
15
+ /**
16
+ * The current drop target information.
17
+ */
18
+ dropTarget?: {
19
+ /**
20
+ * The row ID where the drop indicator should be shown.
21
+ */
22
+ rowId: GridRowId;
23
+ /**
24
+ * The position of the drop indicator relative to the target row.
25
+ */
26
+ position: RowReorderDropPosition;
27
+ };
9
28
  }
@@ -1,5 +1,24 @@
1
1
  import { GridStateCommunity } from "../../../models/gridStateCommunity.js";
2
+ import type { GridRowId } from "../../../models/gridRows.js";
2
3
  export declare const gridRowReorderStateSelector: import("@mui/x-data-grid").OutputSelector<GridStateCommunity, unknown, import("./gridRowReorderInterfaces.js").GridRowReorderState>;
3
4
  export declare const gridIsRowDragActiveSelector: (args_0: import("react").RefObject<{
4
5
  state: GridStateCommunity;
5
- } | null>) => boolean;
6
+ } | null>) => boolean;
7
+ export declare const gridRowDropTargetSelector: (args_0: import("react").RefObject<{
8
+ state: GridStateCommunity;
9
+ } | null>) => {
10
+ rowId: GridRowId;
11
+ position: import("../../../internals/index.js").RowReorderDropPosition;
12
+ } | {
13
+ rowId: null;
14
+ position: null;
15
+ };
16
+ export declare const gridRowDropTargetRowIdSelector: (args_0: import("react").RefObject<{
17
+ state: GridStateCommunity;
18
+ } | null>) => GridRowId | null;
19
+ export declare const gridRowDropPositionSelector: (args_0: import("react").RefObject<{
20
+ state: GridStateCommunity;
21
+ } | null>, rowId: GridRowId) => import("../../../internals/index.js").RowReorderDropPosition | null;
22
+ export declare const gridDraggedRowIdSelector: (args_0: import("react").RefObject<{
23
+ state: GridStateCommunity;
24
+ } | null>) => GridRowId | null;
@@ -3,7 +3,25 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.gridRowReorderStateSelector = exports.gridIsRowDragActiveSelector = void 0;
6
+ exports.gridRowReorderStateSelector = exports.gridRowDropTargetSelector = exports.gridRowDropTargetRowIdSelector = exports.gridRowDropPositionSelector = exports.gridIsRowDragActiveSelector = exports.gridDraggedRowIdSelector = void 0;
7
7
  var _createSelector = require("../../../utils/createSelector");
8
8
  const gridRowReorderStateSelector = exports.gridRowReorderStateSelector = (0, _createSelector.createRootSelector)(state => state.rowReorder);
9
- const gridIsRowDragActiveSelector = exports.gridIsRowDragActiveSelector = (0, _createSelector.createSelector)(gridRowReorderStateSelector, rowReorder => rowReorder?.isActive ?? false);
9
+ const gridIsRowDragActiveSelector = exports.gridIsRowDragActiveSelector = (0, _createSelector.createSelector)(gridRowReorderStateSelector, rowReorder => rowReorder?.isActive ?? false);
10
+
11
+ // Selector for the entire drop target state
12
+ const gridRowDropTargetSelector = exports.gridRowDropTargetSelector = (0, _createSelector.createSelector)(gridRowReorderStateSelector, rowReorder => rowReorder?.dropTarget ?? {
13
+ rowId: null,
14
+ position: null
15
+ });
16
+ const gridRowDropTargetRowIdSelector = exports.gridRowDropTargetRowIdSelector = (0, _createSelector.createSelector)(gridRowDropTargetSelector, dropTarget => dropTarget.rowId ?? null);
17
+
18
+ // Selector for a specific row's drop position
19
+ const gridRowDropPositionSelector = exports.gridRowDropPositionSelector = (0, _createSelector.createSelector)(gridRowDropTargetSelector, (dropTarget, rowId) => {
20
+ if (dropTarget.rowId === rowId) {
21
+ return dropTarget.position;
22
+ }
23
+ return null;
24
+ });
25
+
26
+ // Selector for the dragged row ID
27
+ const gridDraggedRowIdSelector = exports.gridDraggedRowIdSelector = (0, _createSelector.createSelector)(gridRowReorderStateSelector, rowReorder => rowReorder?.draggedRowId ?? null);