@mui/x-data-grid 6.0.0-beta.2 → 6.0.0-beta.3

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 (82) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/components/GridRow.js +2 -6
  3. package/components/cell/GridActionsCell.js +24 -13
  4. package/components/cell/GridActionsCellItem.js +6 -3
  5. package/components/columnHeaders/ColumnHeaderMenuIcon.js +5 -4
  6. package/components/columnHeaders/GridColumnHeaderFilterIconButton.js +6 -6
  7. package/components/columnHeaders/GridColumnHeaderSortIcon.js +5 -4
  8. package/components/panel/filterPanel/GridFilterForm.js +8 -8
  9. package/components/toolbar/GridToolbarFilterButton.js +10 -7
  10. package/components/toolbar/GridToolbarQuickFilter.js +6 -6
  11. package/constants/defaultGridSlotsComponents.js +2 -0
  12. package/hooks/features/columnHeaders/useGridColumnHeaders.js +5 -3
  13. package/hooks/features/editing/useGridCellEditing.js +4 -1
  14. package/hooks/features/editing/useGridEditing.js +1 -1
  15. package/hooks/features/editing/useGridRowEditing.js +3 -0
  16. package/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +71 -10
  17. package/hooks/features/scroll/useGridScroll.js +7 -3
  18. package/hooks/features/virtualization/useGridVirtualScroller.js +20 -7
  19. package/index.js +1 -1
  20. package/legacy/components/GridRow.js +2 -6
  21. package/legacy/components/cell/GridActionsCell.js +28 -17
  22. package/legacy/components/cell/GridActionsCellItem.js +6 -3
  23. package/legacy/components/columnHeaders/ColumnHeaderMenuIcon.js +5 -4
  24. package/legacy/components/columnHeaders/GridColumnHeaderFilterIconButton.js +6 -6
  25. package/legacy/components/columnHeaders/GridColumnHeaderSortIcon.js +5 -4
  26. package/legacy/components/panel/filterPanel/GridFilterForm.js +8 -8
  27. package/legacy/components/toolbar/GridToolbarFilterButton.js +8 -2
  28. package/legacy/components/toolbar/GridToolbarQuickFilter.js +6 -6
  29. package/legacy/constants/defaultGridSlotsComponents.js +2 -0
  30. package/legacy/hooks/features/columnHeaders/useGridColumnHeaders.js +5 -3
  31. package/legacy/hooks/features/editing/useGridCellEditing.js +4 -1
  32. package/legacy/hooks/features/editing/useGridEditing.js +1 -1
  33. package/legacy/hooks/features/editing/useGridRowEditing.js +3 -0
  34. package/legacy/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +69 -10
  35. package/legacy/hooks/features/scroll/useGridScroll.js +7 -3
  36. package/legacy/hooks/features/virtualization/useGridVirtualScroller.js +20 -7
  37. package/legacy/index.js +1 -1
  38. package/legacy/utils/domUtils.js +8 -6
  39. package/models/api/gridEditingApi.d.ts +2 -2
  40. package/models/gridFilterOperator.d.ts +6 -0
  41. package/models/gridSlotsComponent.d.ts +5 -0
  42. package/models/gridSlotsComponentsProps.d.ts +1 -0
  43. package/modern/components/GridRow.js +2 -6
  44. package/modern/components/cell/GridActionsCell.js +23 -13
  45. package/modern/components/cell/GridActionsCellItem.js +5 -3
  46. package/modern/components/columnHeaders/ColumnHeaderMenuIcon.js +4 -4
  47. package/modern/components/columnHeaders/GridColumnHeaderFilterIconButton.js +4 -4
  48. package/modern/components/columnHeaders/GridColumnHeaderSortIcon.js +4 -4
  49. package/modern/components/panel/filterPanel/GridFilterForm.js +4 -4
  50. package/modern/components/toolbar/GridToolbarFilterButton.js +7 -1
  51. package/modern/components/toolbar/GridToolbarQuickFilter.js +4 -4
  52. package/modern/constants/defaultGridSlotsComponents.js +2 -0
  53. package/modern/hooks/features/columnHeaders/useGridColumnHeaders.js +5 -3
  54. package/modern/hooks/features/editing/useGridCellEditing.js +4 -1
  55. package/modern/hooks/features/editing/useGridEditing.js +1 -1
  56. package/modern/hooks/features/editing/useGridRowEditing.js +3 -0
  57. package/modern/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +71 -10
  58. package/modern/hooks/features/scroll/useGridScroll.js +7 -3
  59. package/modern/hooks/features/virtualization/useGridVirtualScroller.js +20 -7
  60. package/modern/index.js +1 -1
  61. package/modern/utils/domUtils.js +8 -6
  62. package/node/components/GridRow.js +2 -6
  63. package/node/components/cell/GridActionsCell.js +23 -13
  64. package/node/components/cell/GridActionsCellItem.js +5 -3
  65. package/node/components/columnHeaders/ColumnHeaderMenuIcon.js +4 -4
  66. package/node/components/columnHeaders/GridColumnHeaderFilterIconButton.js +4 -4
  67. package/node/components/columnHeaders/GridColumnHeaderSortIcon.js +4 -4
  68. package/node/components/panel/filterPanel/GridFilterForm.js +4 -4
  69. package/node/components/toolbar/GridToolbarFilterButton.js +7 -1
  70. package/node/components/toolbar/GridToolbarQuickFilter.js +4 -4
  71. package/node/constants/defaultGridSlotsComponents.js +2 -0
  72. package/node/hooks/features/columnHeaders/useGridColumnHeaders.js +4 -2
  73. package/node/hooks/features/editing/useGridCellEditing.js +4 -1
  74. package/node/hooks/features/editing/useGridEditing.js +1 -1
  75. package/node/hooks/features/editing/useGridRowEditing.js +3 -0
  76. package/node/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +71 -10
  77. package/node/hooks/features/scroll/useGridScroll.js +7 -3
  78. package/node/hooks/features/virtualization/useGridVirtualScroller.js +20 -7
  79. package/node/index.js +1 -1
  80. package/node/utils/domUtils.js +8 -6
  81. package/package.json +3 -3
  82. package/utils/domUtils.js +8 -6
@@ -1,7 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import { unstable_composeClasses as composeClasses } from '@mui/utils';
4
- import IconButton from '@mui/material/IconButton';
5
4
  import { useGridApiContext } from '../../hooks/utils/useGridApiContext';
6
5
  import { getDataGridUtilityClass } from '../../constants/gridClasses';
7
6
  import { useGridRootProps } from '../../hooks/utils/useGridRootProps';
@@ -38,7 +37,7 @@ export const ColumnHeaderMenuIcon = /*#__PURE__*/React.memo(props => {
38
37
  }, [apiRef, colDef.field]);
39
38
  return /*#__PURE__*/_jsx("div", {
40
39
  className: classes.root,
41
- children: /*#__PURE__*/_jsx(IconButton, {
40
+ children: /*#__PURE__*/_jsx(rootProps.components.BaseIconButton, _extends({
42
41
  ref: iconButtonRef,
43
42
  tabIndex: -1,
44
43
  className: classes.button,
@@ -49,10 +48,11 @@ export const ColumnHeaderMenuIcon = /*#__PURE__*/React.memo(props => {
49
48
  "aria-expanded": open ? 'true' : undefined,
50
49
  "aria-haspopup": "true",
51
50
  "aria-controls": columnMenuId,
52
- id: columnMenuButtonId,
51
+ id: columnMenuButtonId
52
+ }, rootProps.componentsProps?.baseIconButton, {
53
53
  children: /*#__PURE__*/_jsx(rootProps.components.ColumnMenuIcon, {
54
54
  fontSize: "small"
55
55
  })
56
- })
56
+ }))
57
57
  });
58
58
  });
@@ -2,7 +2,6 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import PropTypes from 'prop-types';
4
4
  import { unstable_composeClasses as composeClasses } from '@mui/utils';
5
- import IconButton from '@mui/material/IconButton';
6
5
  import Badge from '@mui/material/Badge';
7
6
  import { gridPreferencePanelStateSelector } from '../../hooks/features/preferencesPanel/gridPreferencePanelSelector';
8
7
  import { GridPreferencePanelsValue } from '../../hooks/features/preferencesPanel/gridPreferencePanelsValue';
@@ -52,17 +51,18 @@ function GridColumnHeaderFilterIconButton(props) {
52
51
  if (!counter) {
53
52
  return null;
54
53
  }
55
- const iconButton = /*#__PURE__*/_jsx(IconButton, {
54
+ const iconButton = /*#__PURE__*/_jsx(rootProps.components.BaseIconButton, _extends({
56
55
  onClick: toggleFilter,
57
56
  color: "default",
58
57
  "aria-label": apiRef.current.getLocaleText('columnHeaderFiltersLabel'),
59
58
  size: "small",
60
- tabIndex: -1,
59
+ tabIndex: -1
60
+ }, rootProps.componentsProps?.baseIconButton, {
61
61
  children: /*#__PURE__*/_jsx(rootProps.components.ColumnFilteredIcon, {
62
62
  className: classes.icon,
63
63
  fontSize: "small"
64
64
  })
65
- });
65
+ }));
66
66
  return /*#__PURE__*/_jsx(rootProps.components.BaseTooltip, _extends({
67
67
  title: apiRef.current.getLocaleText('columnHeaderFiltersTooltipActive')(counter),
68
68
  enterDelay: 1000
@@ -3,7 +3,6 @@ import * as React from 'react';
3
3
  import PropTypes from 'prop-types';
4
4
  import { unstable_composeClasses as composeClasses } from '@mui/utils';
5
5
  import Badge from '@mui/material/Badge';
6
- import IconButton from '@mui/material/IconButton';
7
6
  import { useGridApiContext } from '../../hooks/utils/useGridApiContext';
8
7
  import { getDataGridUtilityClass } from '../../constants/gridClasses';
9
8
  import { useGridRootProps } from '../../hooks/utils/useGridRootProps';
@@ -51,13 +50,14 @@ function GridColumnHeaderSortIconRaw(props) {
51
50
  if (!iconElement) {
52
51
  return null;
53
52
  }
54
- const iconButton = /*#__PURE__*/_jsx(IconButton, {
53
+ const iconButton = /*#__PURE__*/_jsx(rootProps.components.BaseIconButton, _extends({
55
54
  tabIndex: -1,
56
55
  "aria-label": apiRef.current.getLocaleText('columnHeaderSortIconLabel'),
57
56
  title: apiRef.current.getLocaleText('columnHeaderSortIconLabel'),
58
- size: "small",
57
+ size: "small"
58
+ }, rootProps.componentsProps?.baseIconButton, {
59
59
  children: iconElement
60
- });
60
+ }));
61
61
  return /*#__PURE__*/_jsxs(GridIconButtonContainer, {
62
62
  children: [index != null && /*#__PURE__*/_jsx(Badge, {
63
63
  badgeContent: index,
@@ -5,7 +5,6 @@ const _excluded = ["item", "hasMultipleFilters", "deleteFilter", "applyFilterCha
5
5
  import * as React from 'react';
6
6
  import PropTypes from 'prop-types';
7
7
  import { unstable_composeClasses as composeClasses, unstable_useId as useId, unstable_capitalize as capitalize } from '@mui/utils';
8
- import IconButton from '@mui/material/IconButton';
9
8
  import MenuItem from '@mui/material/MenuItem';
10
9
  import InputLabel from '@mui/material/InputLabel';
11
10
  import FormControl from '@mui/material/FormControl';
@@ -235,15 +234,16 @@ const GridFilterForm = /*#__PURE__*/React.forwardRef(function GridFilterForm(pro
235
234
  as: rootProps.components.BaseFormControl
236
235
  }, baseFormControlProps, deleteIconProps, {
237
236
  className: clsx(classes.deleteIcon, baseFormControlProps.className, deleteIconProps.className),
238
- children: /*#__PURE__*/_jsx(IconButton, {
237
+ children: /*#__PURE__*/_jsx(rootProps.components.BaseIconButton, _extends({
239
238
  "aria-label": apiRef.current.getLocaleText('filterPanelDeleteIconLabel'),
240
239
  title: apiRef.current.getLocaleText('filterPanelDeleteIconLabel'),
241
240
  onClick: handleDeleteFilter,
242
- size: "small",
241
+ size: "small"
242
+ }, rootProps.componentsProps?.baseIconButton, {
243
243
  children: /*#__PURE__*/_jsx(rootProps.components.FilterPanelDeleteIcon, {
244
244
  fontSize: "small"
245
245
  })
246
- })
246
+ }))
247
247
  })), /*#__PURE__*/_jsx(FilterFormLogicOperatorInput, _extends({
248
248
  variant: "standard",
249
249
  as: rootProps.components.BaseFormControl
@@ -58,13 +58,19 @@ const GridToolbarFilterButton = /*#__PURE__*/React.forwardRef(function GridToolb
58
58
  return apiRef.current.getLocaleText('toolbarFiltersTooltipShow');
59
59
  }
60
60
  const getOperatorLabel = item => lookup[item.field].filterOperators.find(operator => operator.value === item.operator).label || apiRef.current.getLocaleText(`filterOperator${capitalize(item.operator)}`).toString();
61
+ const getFilterItemValue = item => {
62
+ const {
63
+ getValueAsString
64
+ } = lookup[item.field].filterOperators.find(operator => operator.value === item.operator);
65
+ return getValueAsString ? getValueAsString(item.value) : item.value;
66
+ };
61
67
  return /*#__PURE__*/_jsxs("div", {
62
68
  children: [apiRef.current.getLocaleText('toolbarFiltersTooltipActive')(activeFilters.length), /*#__PURE__*/_jsx(GridToolbarFilterListRoot, {
63
69
  className: classes.root,
64
70
  children: activeFilters.map((item, index) => _extends({}, lookup[item.field] && /*#__PURE__*/_jsx("li", {
65
71
  children: `${lookup[item.field].headerName || item.field}
66
72
  ${getOperatorLabel(item)}
67
- ${item.value ?? ''}`
73
+ ${item.value ? getFilterItemValue(item) : ''}`
68
74
  }, index)))
69
75
  })]
70
76
  });
@@ -4,7 +4,6 @@ const _excluded = ["quickFilterParser", "quickFilterFormatter", "debounceMs"];
4
4
  import * as React from 'react';
5
5
  import PropTypes from 'prop-types';
6
6
  import TextField from '@mui/material/TextField';
7
- import IconButton from '@mui/material/IconButton';
8
7
  import { styled } from '@mui/material/styles';
9
8
  import { unstable_debounce as debounce } from '@mui/utils';
10
9
  import { useGridApiContext } from '../../hooks/utils/useGridApiContext';
@@ -91,17 +90,18 @@ function GridToolbarQuickFilter(props) {
91
90
  startAdornment: /*#__PURE__*/_jsx(rootProps.components.QuickFilterIcon, {
92
91
  fontSize: "small"
93
92
  }),
94
- endAdornment: /*#__PURE__*/_jsx(IconButton, {
93
+ endAdornment: /*#__PURE__*/_jsx(rootProps.components.BaseIconButton, _extends({
95
94
  "aria-label": apiRef.current.getLocaleText('toolbarQuickFilterDeleteIconLabel'),
96
95
  size: "small",
97
96
  sx: {
98
97
  visibility: searchValue ? 'visible' : 'hidden'
99
98
  },
100
- onClick: handleSearchReset,
99
+ onClick: handleSearchReset
100
+ }, rootProps.componentsProps?.baseIconButton, {
101
101
  children: /*#__PURE__*/_jsx(rootProps.components.QuickFilterClearIcon, {
102
102
  fontSize: "small"
103
103
  })
104
- })
104
+ }))
105
105
  }
106
106
  }, other, rootProps.componentsProps?.baseTextField));
107
107
  }
@@ -5,6 +5,7 @@ import MUIFormControl from '@mui/material/FormControl';
5
5
  import MUISelect from '@mui/material/Select';
6
6
  import MUISwitch from '@mui/material/Switch';
7
7
  import MUIButton from '@mui/material/Button';
8
+ import MUIIconButton from '@mui/material/IconButton';
8
9
  import MUITooltip from '@mui/material/Tooltip';
9
10
  import MUIPopper from '@mui/material/Popper';
10
11
  import { GridArrowDownwardIcon, GridArrowUpwardIcon, GridCell, GridSkeletonCell, GridCheckIcon, GridCloseIcon, GridColumnIcon, GridColumnsPanel, GridFilterAltIcon, GridFilterListIcon, GridFilterPanel, GridFooter, GridLoadingOverlay, GridNoRowsOverlay, GridPagination, GridPanel, GridPreferencesPanel, GridRow, GridSaveAltIcon, GridSeparatorIcon, GridTableRowsIcon, GridTripleDotsVerticalIcon, GridViewHeadlineIcon, GridViewStreamIcon, GridMoreVertIcon, GridExpandMoreIcon, GridKeyboardArrowRight, GridAddIcon, GridRemoveIcon, GridDragIcon, GridColumnHeaderFilterIconButton, GridSearchIcon, GridVisibilityOffIcon, GridViewColumnIcon, GridClearIcon } from '../components';
@@ -51,6 +52,7 @@ export const DATA_GRID_DEFAULT_SLOTS_COMPONENTS = _extends({}, DEFAULT_GRID_ICON
51
52
  BaseSelect: MUISelect,
52
53
  BaseSwitch: MUISwitch,
53
54
  BaseButton: MUIButton,
55
+ BaseIconButton: MUIIconButton,
54
56
  BaseTooltip: MUITooltip,
55
57
  BasePopper: MUIPopper,
56
58
  Cell: GridCell,
@@ -2,7 +2,7 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import * as ReactDOM from 'react-dom';
4
4
  import { unstable_useForkRef as useForkRef } from '@mui/utils';
5
- import { styled } from '@mui/material/styles';
5
+ import { styled, useTheme } from '@mui/material/styles';
6
6
  import { defaultMemoize } from 'reselect';
7
7
  import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext';
8
8
  import { useGridSelector } from '../../utils/useGridSelector';
@@ -36,6 +36,7 @@ export const useGridColumnHeaders = props => {
36
36
  innerRef: innerRefProp,
37
37
  minColumnIndex = 0
38
38
  } = props;
39
+ const theme = useTheme();
39
40
  const [dragCol, setDragCol] = React.useState('');
40
41
  const [resizeCol, setResizeCol] = React.useState('');
41
42
  const apiRef = useGridPrivateApiContext();
@@ -87,9 +88,10 @@ export const useGridColumnHeaders = props => {
87
88
  apiRef,
88
89
  visibleRows: currentPage.rows
89
90
  });
90
- const offset = firstColumnToRender > 0 ? prevScrollLeft.current - columnPositions[firstColumnToRender] : prevScrollLeft.current;
91
+ const direction = theme.direction === 'ltr' ? 1 : -1;
92
+ const offset = firstColumnToRender > 0 ? prevScrollLeft.current - direction * columnPositions[firstColumnToRender] : prevScrollLeft.current;
91
93
  innerRef.current.style.transform = `translate3d(${-offset}px, 0px, 0px)`;
92
- }, [columnPositions, minColumnIndex, rootProps.columnBuffer, apiRef, currentPage.rows, rootProps.rowBuffer]);
94
+ }, [columnPositions, minColumnIndex, rootProps.columnBuffer, apiRef, currentPage.rows, rootProps.rowBuffer, theme.direction]);
93
95
  React.useLayoutEffect(() => {
94
96
  if (renderContext) {
95
97
  updateInnerPosition(renderContext);
@@ -382,10 +382,13 @@ export const useGridCellEditing = (apiRef, props) => {
382
382
  const getRowWithUpdatedValuesFromCellEditing = React.useCallback((id, field) => {
383
383
  const column = apiRef.current.getColumn(field);
384
384
  const editingState = gridEditRowsStateSelector(apiRef.current.state);
385
+ const row = apiRef.current.getRow(id);
386
+ if (!editingState[id] || !editingState[id][field]) {
387
+ return apiRef.current.getRow(id);
388
+ }
385
389
  const {
386
390
  value
387
391
  } = editingState[id][field];
388
- const row = apiRef.current.getRow(id);
389
392
  return column.valueSetter ? column.valueSetter({
390
393
  value,
391
394
  row
@@ -117,7 +117,7 @@ export const useGridEditing = (apiRef, props) => {
117
117
  const editingSharedApi = {
118
118
  isCellEditable,
119
119
  setEditCellValue,
120
- unstable_getRowWithUpdatedValues: getRowWithUpdatedValues,
120
+ getRowWithUpdatedValues,
121
121
  unstable_getEditCellMeta: getEditCellMeta
122
122
  };
123
123
  const editingSharedPrivateApi = {
@@ -503,6 +503,9 @@ export const useGridRowEditing = (apiRef, props) => {
503
503
  const getRowWithUpdatedValuesFromRowEditing = React.useCallback(id => {
504
504
  const editingState = gridEditRowsStateSelector(apiRef.current.state);
505
505
  const row = apiRef.current.getRow(id);
506
+ if (!editingState[id]) {
507
+ return apiRef.current.getRow(id);
508
+ }
506
509
  let rowUpdate = _extends({}, row);
507
510
  Object.entries(editingState[id]).forEach(([field, fieldProps]) => {
508
511
  const column = apiRef.current.getColumn(field);
@@ -1,4 +1,5 @@
1
1
  import * as React from 'react';
2
+ import { useTheme } from '@mui/material/styles';
2
3
  import { gridVisibleColumnDefinitionsSelector } from '../columns/gridColumnsSelector';
3
4
  import { useGridLogger } from '../../utils/useGridLogger';
4
5
  import { useGridApiEventHandler } from '../../utils/useGridApiEventHandler';
@@ -17,6 +18,40 @@ function enrichPageRowsWithPinnedRows(apiRef, rows) {
17
18
  const pinnedRows = gridPinnedRowsSelector(apiRef) || {};
18
19
  return [...(pinnedRows.top || []), ...rows, ...(pinnedRows.bottom || [])];
19
20
  }
21
+ const getLeftColumnIndex = ({
22
+ currentColIndex,
23
+ firstColIndex,
24
+ lastColIndex,
25
+ direction
26
+ }) => {
27
+ if (direction === 'rtl') {
28
+ if (currentColIndex < lastColIndex) {
29
+ return currentColIndex + 1;
30
+ }
31
+ } else if (direction === 'ltr') {
32
+ if (currentColIndex > firstColIndex) {
33
+ return currentColIndex - 1;
34
+ }
35
+ }
36
+ return null;
37
+ };
38
+ const getRightColumnIndex = ({
39
+ currentColIndex,
40
+ firstColIndex,
41
+ lastColIndex,
42
+ direction
43
+ }) => {
44
+ if (direction === 'rtl') {
45
+ if (currentColIndex > firstColIndex) {
46
+ return currentColIndex - 1;
47
+ }
48
+ } else if (direction === 'ltr') {
49
+ if (currentColIndex < lastColIndex) {
50
+ return currentColIndex + 1;
51
+ }
52
+ }
53
+ return null;
54
+ };
20
55
 
21
56
  /**
22
57
  * @requires useGridSorting (method) - can be after
@@ -30,6 +65,7 @@ function enrichPageRowsWithPinnedRows(apiRef, rows) {
30
65
  export const useGridKeyboardNavigation = (apiRef, props) => {
31
66
  const logger = useGridLogger(apiRef, 'useGridKeyboardNavigation');
32
67
  const initialCurrentPageRows = useGridVisibleRows(apiRef, props).rows;
68
+ const theme = useTheme();
33
69
  const currentPageRows = React.useMemo(() => enrichPageRowsWithPinnedRows(apiRef, initialCurrentPageRows), [apiRef, initialCurrentPageRows]);
34
70
 
35
71
  /**
@@ -110,15 +146,27 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
110
146
  }
111
147
  case 'ArrowRight':
112
148
  {
113
- if (colIndexBefore < lastColIndex) {
114
- goToHeader(colIndexBefore + 1, event);
149
+ const rightColIndex = getRightColumnIndex({
150
+ currentColIndex: colIndexBefore,
151
+ firstColIndex,
152
+ lastColIndex,
153
+ direction: theme.direction
154
+ });
155
+ if (rightColIndex !== null) {
156
+ goToHeader(rightColIndex, event);
115
157
  }
116
158
  break;
117
159
  }
118
160
  case 'ArrowLeft':
119
161
  {
120
- if (colIndexBefore > firstColIndex) {
121
- goToHeader(colIndexBefore - 1, event);
162
+ const leftColIndex = getLeftColumnIndex({
163
+ currentColIndex: colIndexBefore,
164
+ firstColIndex,
165
+ lastColIndex,
166
+ direction: theme.direction
167
+ });
168
+ if (leftColIndex !== null) {
169
+ goToHeader(leftColIndex, event);
122
170
  }
123
171
  break;
124
172
  }
@@ -166,7 +214,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
166
214
  if (shouldPreventDefault) {
167
215
  event.preventDefault();
168
216
  }
169
- }, [apiRef, currentPageRows.length, goToCell, getRowIdFromIndex, goToHeader, goToGroupHeader]);
217
+ }, [apiRef, currentPageRows.length, theme.direction, goToCell, getRowIdFromIndex, goToHeader, goToGroupHeader]);
170
218
  const focusedColumnGroup = useGridSelector(apiRef, unstable_gridFocusColumnGroupHeaderSelector);
171
219
  const handleColumnGroupHeaderKeyDown = React.useCallback((params, event) => {
172
220
  const dimensions = apiRef.current.getRootDimensions();
@@ -279,6 +327,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
279
327
  if (currentPageRows.length === 0 || !dimensions) {
280
328
  return;
281
329
  }
330
+ const direction = theme.direction;
282
331
  const viewportPageSize = apiRef.current.getViewportPageSize();
283
332
  const colIndexBefore = params.field ? apiRef.current.getColumnIndex(params.field) : 0;
284
333
  const rowIndexBefore = currentPageRows.findIndex(row => row.id === params.id);
@@ -307,15 +356,27 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
307
356
  }
308
357
  case 'ArrowRight':
309
358
  {
310
- if (colIndexBefore < lastColIndex) {
311
- goToCell(colIndexBefore + 1, getRowIdFromIndex(rowIndexBefore), 'right');
359
+ const rightColIndex = getRightColumnIndex({
360
+ currentColIndex: colIndexBefore,
361
+ firstColIndex,
362
+ lastColIndex,
363
+ direction
364
+ });
365
+ if (rightColIndex !== null) {
366
+ goToCell(rightColIndex, getRowIdFromIndex(rowIndexBefore), direction === 'rtl' ? 'left' : 'right');
312
367
  }
313
368
  break;
314
369
  }
315
370
  case 'ArrowLeft':
316
371
  {
317
- if (colIndexBefore > firstColIndex) {
318
- goToCell(colIndexBefore - 1, getRowIdFromIndex(rowIndexBefore));
372
+ const leftColIndex = getLeftColumnIndex({
373
+ currentColIndex: colIndexBefore,
374
+ firstColIndex,
375
+ lastColIndex,
376
+ direction
377
+ });
378
+ if (leftColIndex !== null) {
379
+ goToCell(leftColIndex, getRowIdFromIndex(rowIndexBefore), direction === 'rtl' ? 'right' : 'left');
319
380
  }
320
381
  break;
321
382
  }
@@ -388,7 +449,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
388
449
  if (shouldPreventDefault) {
389
450
  event.preventDefault();
390
451
  }
391
- }, [apiRef, currentPageRows, getRowIdFromIndex, goToCell, goToHeader]);
452
+ }, [apiRef, currentPageRows, theme.direction, getRowIdFromIndex, goToCell, goToHeader]);
392
453
  useGridApiEventHandler(apiRef, 'columnHeaderKeyDown', handleColumnHeaderKeyDown);
393
454
  useGridApiEventHandler(apiRef, 'columnGroupHeaderKeyDown', handleColumnGroupHeaderKeyDown);
394
455
  useGridApiEventHandler(apiRef, 'cellKeyDown', handleCellKeyDown);
@@ -1,4 +1,5 @@
1
1
  import * as React from 'react';
2
+ import { useTheme } from '@mui/material/styles';
2
3
  import { useGridLogger } from '../../utils/useGridLogger';
3
4
  import { gridColumnPositionsSelector, gridVisibleColumnDefinitionsSelector } from '../columns/gridColumnsSelector';
4
5
  import { useGridSelector } from '../../utils/useGridSelector';
@@ -42,6 +43,7 @@ function scrollIntoView(dimensions) {
42
43
  * @requires useGridColumnSpanning (method)
43
44
  */
44
45
  export const useGridScroll = (apiRef, props) => {
46
+ const theme = useTheme();
45
47
  const logger = useGridLogger(apiRef, 'useGridScroll');
46
48
  const colRef = apiRef.current.columnHeadersElementRef;
47
49
  const virtualScrollerRef = apiRef.current.virtualScrollerRef;
@@ -68,9 +70,10 @@ export const useGridScroll = (apiRef, props) => {
68
70
  if (typeof cellWidth === 'undefined') {
69
71
  cellWidth = visibleColumns[params.colIndex].computedWidth;
70
72
  }
73
+ // When using RTL, `scrollLeft` becomes negative, so we must ensure that we only compare values.
71
74
  scrollCoordinates.left = scrollIntoView({
72
75
  clientHeight: virtualScrollerRef.current.clientWidth,
73
- scrollTop: virtualScrollerRef.current.scrollLeft,
76
+ scrollTop: Math.abs(virtualScrollerRef.current.scrollLeft),
74
77
  offsetHeight: cellWidth,
75
78
  offsetTop: columnPositions[params.colIndex]
76
79
  });
@@ -99,8 +102,9 @@ export const useGridScroll = (apiRef, props) => {
99
102
  }, [logger, apiRef, virtualScrollerRef, props.pagination, visibleSortedRows]);
100
103
  const scroll = React.useCallback(params => {
101
104
  if (virtualScrollerRef.current && params.left != null && colRef.current) {
105
+ const direction = theme.direction === 'rtl' ? -1 : 1;
102
106
  colRef.current.scrollLeft = params.left;
103
- virtualScrollerRef.current.scrollLeft = params.left;
107
+ virtualScrollerRef.current.scrollLeft = direction * params.left;
104
108
  logger.debug(`Scrolling left: ${params.left}`);
105
109
  }
106
110
  if (virtualScrollerRef.current && params.top != null) {
@@ -108,7 +112,7 @@ export const useGridScroll = (apiRef, props) => {
108
112
  logger.debug(`Scrolling top: ${params.top}`);
109
113
  }
110
114
  logger.debug(`Scrolling, updating container, and viewport`);
111
- }, [virtualScrollerRef, colRef, logger]);
115
+ }, [virtualScrollerRef, theme.direction, colRef, logger]);
112
116
  const getScrollPosition = React.useCallback(() => {
113
117
  if (!virtualScrollerRef?.current) {
114
118
  return {
@@ -6,6 +6,7 @@ const _excluded = ["style"],
6
6
  import * as React from 'react';
7
7
  import * as ReactDOM from 'react-dom';
8
8
  import { unstable_useForkRef as useForkRef, unstable_useEnhancedEffect as useEnhancedEffect } from '@mui/utils';
9
+ import { useTheme } from '@mui/material/styles';
9
10
  import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext';
10
11
  import { useGridRootProps } from '../../utils/useGridRootProps';
11
12
  import { useGridSelector } from '../../utils/useGridSelector';
@@ -35,7 +36,7 @@ export function binarySearch(offset, positions, sliceStart = 0, sliceEnd = posit
35
36
  }
36
37
  function exponentialSearch(offset, positions, index) {
37
38
  let interval = 1;
38
- while (index < positions.length && positions[index] < offset) {
39
+ while (index < positions.length && Math.abs(positions[index]) < offset) {
39
40
  index += interval;
40
41
  interval *= 2;
41
42
  }
@@ -62,6 +63,7 @@ export const useGridVirtualScroller = props => {
62
63
  renderZoneMaxColumnIndex = visibleColumns.length,
63
64
  getRowProps
64
65
  } = props;
66
+ const theme = useTheme();
65
67
  const columnPositions = useGridSelector(apiRef, gridColumnPositionsSelector);
66
68
  const columnsTotalWidth = useGridSelector(apiRef, gridColumnsTotalWidthSelector);
67
69
  const cellFocus = useGridSelector(apiRef, gridFocusCellSelector);
@@ -137,8 +139,8 @@ export const useGridVirtualScroller = props => {
137
139
  hasRowWithAutoHeight = apiRef.current.rowHasAutoHeight(row.id);
138
140
  }
139
141
  if (!hasRowWithAutoHeight) {
140
- firstColumnIndex = binarySearch(left, columnPositions);
141
- lastColumnIndex = binarySearch(left + containerDimensions.width, columnPositions);
142
+ firstColumnIndex = binarySearch(Math.abs(left), columnPositions);
143
+ lastColumnIndex = binarySearch(Math.abs(left) + containerDimensions.width, columnPositions);
142
144
  }
143
145
  return {
144
146
  firstRowIndex,
@@ -168,7 +170,7 @@ export const useGridVirtualScroller = props => {
168
170
  height: params.height
169
171
  });
170
172
  }, []);
171
- useGridApiEventHandler(apiRef, 'resize', handleResize);
173
+ useGridApiEventHandler(apiRef, 'debouncedResize', handleResize);
172
174
  const updateRenderZonePosition = React.useCallback(nextRenderContext => {
173
175
  const [firstRowToRender, lastRowToRender] = getRenderableIndexes({
174
176
  firstIndex: nextRenderContext.firstRowIndex,
@@ -191,8 +193,9 @@ export const useGridVirtualScroller = props => {
191
193
  lastRowToRender,
192
194
  visibleRows: currentPage.rows
193
195
  });
196
+ const direction = theme.direction === 'ltr' ? 1 : -1;
194
197
  const top = gridRowsMetaSelector(apiRef.current.state).positions[firstRowToRender];
195
- const left = gridColumnPositionsSelector(apiRef)[firstColumnToRender]; // Call directly the selector because it might be outdated when this method is called
198
+ const left = direction * gridColumnPositionsSelector(apiRef)[firstColumnToRender]; // Call directly the selector because it might be outdated when this method is called
196
199
  renderZoneRef.current.style.transform = `translate3d(${left}px, ${top}px, 0px)`;
197
200
  if (typeof onRenderZonePositioning === 'function') {
198
201
  onRenderZonePositioning({
@@ -200,7 +203,7 @@ export const useGridVirtualScroller = props => {
200
203
  left
201
204
  });
202
205
  }
203
- }, [apiRef, currentPage.rows, onRenderZonePositioning, renderZoneMinColumnIndex, renderZoneMaxColumnIndex, rootProps.columnBuffer, rootProps.rowBuffer]);
206
+ }, [apiRef, currentPage.rows, onRenderZonePositioning, renderZoneMinColumnIndex, renderZoneMaxColumnIndex, rootProps.columnBuffer, rootProps.rowBuffer, theme.direction]);
204
207
  const updateRenderContext = React.useCallback(nextRenderContext => {
205
208
  setRenderContext(nextRenderContext);
206
209
  updateRenderZonePosition(nextRenderContext);
@@ -243,9 +246,19 @@ export const useGridVirtualScroller = props => {
243
246
  scrollPosition.current.left = scrollLeft;
244
247
 
245
248
  // On iOS and macOS, negative offsets are possible when swiping past the start
246
- if (scrollLeft < 0 || scrollTop < 0 || !prevRenderContext.current) {
249
+ if (!prevRenderContext.current || scrollTop < 0) {
247
250
  return;
248
251
  }
252
+ if (theme.direction === 'ltr') {
253
+ if (scrollLeft < 0) {
254
+ return;
255
+ }
256
+ }
257
+ if (theme.direction === 'rtl') {
258
+ if (scrollLeft > 0) {
259
+ return;
260
+ }
261
+ }
249
262
 
250
263
  // When virtualization is disabled, the context never changes during scroll
251
264
  const nextRenderContext = disableVirtualization ? prevRenderContext.current : computeRenderContext();
package/modern/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v6.0.0-beta.2
2
+ * @mui/x-data-grid v6.0.0-beta.3
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -25,16 +25,18 @@ function escapeOperandAttributeSelector(operand) {
25
25
  export function getGridColumnHeaderElement(root, field) {
26
26
  return root.querySelector(`[role="columnheader"][data-field="${escapeOperandAttributeSelector(field)}"]`);
27
27
  }
28
+ function getGridRowElementSelector(id) {
29
+ return `.${gridClasses.row}[data-id="${escapeOperandAttributeSelector(String(id))}"]`;
30
+ }
28
31
  export function getGridRowElement(root, id) {
29
- return root.querySelector(`.${gridClasses.row}[data-id="${escapeOperandAttributeSelector(String(id))}"]`);
32
+ return root.querySelector(getGridRowElementSelector(id));
30
33
  }
31
34
  export function getGridCellElement(root, {
32
35
  id,
33
36
  field
34
37
  }) {
35
- const row = getGridRowElement(root, id);
36
- if (!row) {
37
- return null;
38
- }
39
- return row.querySelector(`.${gridClasses.cell}[data-field="${escapeOperandAttributeSelector(field)}"]`);
38
+ const rowSelector = getGridRowElementSelector(id);
39
+ const cellSelector = `.${gridClasses.cell}[data-field="${escapeOperandAttributeSelector(field)}"]`;
40
+ const selector = `${rowSelector} ${cellSelector}`;
41
+ return root.querySelector(selector);
40
42
  }
@@ -207,11 +207,7 @@ const GridRow = /*#__PURE__*/React.forwardRef(function GridRow(props, refProp) {
207
207
  classNames.push((0, _clsx.default)(_gridClasses.gridClasses['cell--withRenderer'], rootProps.classes?.['cell--withRenderer']));
208
208
  }
209
209
  if (editCellState != null && column.renderEditCell) {
210
- let updatedRow = row;
211
- if (apiRef.current.unstable_getRowWithUpdatedValues) {
212
- // Only the new editing API has this method
213
- updatedRow = apiRef.current.unstable_getRowWithUpdatedValues(rowId, column.field);
214
- }
210
+ const updatedRow = apiRef.current.getRowWithUpdatedValues(rowId, column.field);
215
211
  const editCellStateRest = (0, _objectWithoutPropertiesLoose2.default)(editCellState, _excluded2);
216
212
  const params = (0, _extends2.default)({}, cellParams, {
217
213
  row: updatedRow
@@ -253,7 +249,7 @@ const GridRow = /*#__PURE__*/React.forwardRef(function GridRow(props, refProp) {
253
249
  }, rootProps.componentsProps?.cell, {
254
250
  children: content
255
251
  }), column.field);
256
- }, [apiRef, cellTabIndex, editRowsState, cellFocus, rootProps, row, rowHeight, rowId, treeDepth, sortModel.length]);
252
+ }, [apiRef, cellTabIndex, editRowsState, cellFocus, rootProps, rowHeight, rowId, treeDepth, sortModel.length]);
257
253
  const sizes = apiRef.current.unstable_getRowInternalSizes(rowId);
258
254
  let minHeight = rowHeight;
259
255
  if (minHeight === 'auto' && sizes) {