@mui/x-data-grid 8.7.0 → 8.8.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 (40) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/components/GridScrollArea.d.ts +1 -1
  3. package/components/GridScrollArea.js +134 -28
  4. package/components/containers/GridRootStyles.js +2 -0
  5. package/components/virtualization/GridVirtualScroller.js +4 -0
  6. package/constants/gridClasses.d.ts +8 -0
  7. package/constants/gridClasses.js +1 -1
  8. package/esm/components/GridScrollArea.d.ts +1 -1
  9. package/esm/components/GridScrollArea.js +134 -28
  10. package/esm/components/containers/GridRootStyles.js +2 -0
  11. package/esm/components/virtualization/GridVirtualScroller.js +4 -0
  12. package/esm/constants/gridClasses.d.ts +8 -0
  13. package/esm/constants/gridClasses.js +1 -1
  14. package/esm/hooks/features/dataSource/useGridDataSourceBase.d.ts +1 -1
  15. package/esm/hooks/features/dataSource/useGridDataSourceBase.js +3 -0
  16. package/esm/hooks/features/dataSource/utils.js +3 -0
  17. package/esm/hooks/utils/useGridSelector.js +4 -0
  18. package/esm/index.js +1 -1
  19. package/esm/internals/utils/cache.d.ts +9 -0
  20. package/esm/internals/utils/cache.js +19 -0
  21. package/esm/internals/utils/index.d.ts +2 -1
  22. package/esm/internals/utils/index.js +2 -1
  23. package/esm/locales/idID.d.ts +4 -0
  24. package/esm/locales/idID.js +261 -0
  25. package/esm/locales/index.d.ts +2 -1
  26. package/esm/locales/index.js +2 -1
  27. package/hooks/features/dataSource/useGridDataSourceBase.d.ts +1 -1
  28. package/hooks/features/dataSource/useGridDataSourceBase.js +3 -0
  29. package/hooks/features/dataSource/utils.js +3 -0
  30. package/hooks/utils/useGridSelector.js +4 -0
  31. package/index.js +1 -1
  32. package/internals/utils/cache.d.ts +9 -0
  33. package/internals/utils/cache.js +26 -0
  34. package/internals/utils/index.d.ts +2 -1
  35. package/internals/utils/index.js +11 -0
  36. package/locales/idID.d.ts +4 -0
  37. package/locales/idID.js +267 -0
  38. package/locales/index.d.ts +2 -1
  39. package/locales/index.js +11 -0
  40. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -5,6 +5,104 @@
5
5
  All notable changes to this project will be documented in this file.
6
6
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
7
7
 
8
+ ## 8.8.0
9
+
10
+ _Jul 11, 2025_
11
+
12
+ We'd like to extend a big thank you to the 13 contributors who made this release possible. Here are some highlights ✨:
13
+
14
+ - 📊 Chart zoom preview can be enabled
15
+
16
+ <img width="758" alt="chart with x-axis preview" src="https://github.com/user-attachments/assets/50ce6f61-16dc-4e9b-a727-ca65d80927d7" />
17
+
18
+ - 🌎 Add Indonesian (id-ID) locale on the Data Grid
19
+
20
+ Special thanks go out to the community members for their valuable contributions:
21
+ @kennarddh
22
+
23
+ The following are all team members who have contributed to this release:
24
+ @alexfauquette, @arminmeh, @bernardobelchior, @cherniavskii, @JCQuintas, @KenanYusuf, @LukasTy, @MBilalShafi, @noraleonte, @prakhargupta1, @rita-codes, @siriwatknp
25
+
26
+ ### Data Grid
27
+
28
+ #### `@mui/x-data-grid@8.8.0`
29
+
30
+ - [DataGrid] Fix `useGridSelector` missing subscription in `React.StrictMode` (#18676) @cherniavskii
31
+ - [DataGrid] Fix scrollbar filler `z-index` (#18688) @KenanYusuf
32
+ - [DataGrid] Set correct data source cache chunk size when pagination is disabled (#18636) @arminmeh
33
+ - [l10n] Add Indonesian (id-ID) locale (#18710) @kennarddh
34
+
35
+ #### `@mui/x-data-grid-pro@8.8.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
36
+
37
+ Same changes as in `@mui/x-data-grid@8.8.0`, plus:
38
+
39
+ - [DataGridPro] Fix row ordering not auto-scrolling when moving beyond viewport (#18557) @MBilalShafi
40
+ - [DataGridPro] Set correct parent paths when tree is refreshed with data source tree data and row grouping (#18715) @arminmeh
41
+
42
+ #### `@mui/x-data-grid-premium@8.8.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
43
+
44
+ Same changes as in `@mui/x-data-grid-pro@8.8.0`.
45
+
46
+ ### Date and Time Pickers
47
+
48
+ #### `@mui/x-date-pickers@8.8.0`
49
+
50
+ Internal changes.
51
+
52
+ #### `@mui/x-date-pickers-pro@8.8.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
53
+
54
+ Same changes as in `@mui/x-date-pickers@8.8.0`.
55
+
56
+ ### Charts
57
+
58
+ #### `@mui/x-charts@8.8.0`
59
+
60
+ - [charts] Add control to the axis highlight (#17900) @alexfauquette
61
+ - [charts] Avoid processing area plot data if area isn't used in series (#18712) @bernardobelchior
62
+ - [charts] Make smarter default domain limit (#18506) @alexfauquette
63
+
64
+ #### `@mui/x-charts-pro@8.8.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
65
+
66
+ Same changes as in `@mui/x-charts@8.8.0`, plus:
67
+
68
+ - [charts-pro] Add `funnelDirection` to control pyramid direction (#18568) @JCQuintas
69
+ - [charts-pro] Add `onBeforeExport` callback (#18722) @bernardobelchior
70
+ - [charts-pro] Add chart zoom preview (#18267) @bernardobelchior
71
+ - [charts-pro] Allow customizing scatter preview marker size (#18726) @bernardobelchior
72
+ - [charts-pro] Allow disabling the copy of styles in charts export (#18753) @bernardobelchior
73
+
74
+ ### Tree View
75
+
76
+ #### `@mui/x-tree-view@8.8.0`
77
+
78
+ - [tree view] Fix state update that caused scrolling bug when lazy loading and `checkboxSelection` are enabled (#18749) @rita-codes
79
+
80
+ #### `@mui/x-tree-view-pro@8.8.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
81
+
82
+ Same changes as in `@mui/x-tree-view@8.8.0`.
83
+
84
+ ### Codemod
85
+
86
+ #### `@mui/x-codemod@8.8.0`
87
+
88
+ Internal changes.
89
+
90
+ ### Docs
91
+
92
+ - [docs] Add standalone Pyramid chart page to improve SEO (#18527) @prakhargupta1
93
+ - [docs] Add example to customise line interaction (#18539) @alexfauquette
94
+ - [docs] Fix `size` column filtering in files tree demo (#17952) @cherniavskii
95
+ - [docs] Generate `llms.txt` for X and their products (#18595) @siriwatknp
96
+ - [docs] Improve bar chart demos on mobile (#18721) @alexfauquette
97
+ - [docs] Refine charts overview page (#17447) @noraleonte
98
+
99
+ ### Miscellaneous
100
+
101
+ - [code-infra] Ensure all `@mui/*` packages are picked by `Material UI` renovate group (#18711) @LukasTy
102
+ - [code-infra] Fix broken CI (#18716) @LukasTy
103
+ - [code-infra] Refactor `prettier` config resolving (#18720) @LukasTy
104
+ - [test] Increase data points in chart benchmarks (#18714) @bernardobelchior
105
+
8
106
  ## 8.7.0
9
107
 
10
108
  _Jul 4, 2025_
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import { RefObject } from '@mui/x-internals/types';
3
3
  import { GridScrollParams } from "../models/params/gridScrollParams.js";
4
4
  interface ScrollAreaProps {
5
- scrollDirection: 'left' | 'right';
5
+ scrollDirection: 'left' | 'right' | 'up' | 'down';
6
6
  scrollPosition: RefObject<GridScrollParams>;
7
7
  }
8
8
  declare function GridScrollAreaWrapper(props: ScrollAreaProps): React.JSX.Element | null;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  'use client';
3
3
 
4
+ /* eslint-disable @typescript-eslint/no-use-before-define */
4
5
  var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
6
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
6
7
  Object.defineProperty(exports, "__esModule", {
@@ -13,6 +14,7 @@ var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallb
13
14
  var _composeClasses = _interopRequireDefault(require("@mui/utils/composeClasses"));
14
15
  var _system = require("@mui/system");
15
16
  var _fastMemo = require("@mui/x-internals/fastMemo");
17
+ var _forwardRef = require("@mui/x-internals/forwardRef");
16
18
  var _useGridRootProps = require("../hooks/utils/useGridRootProps");
17
19
  var _constants = require("../constants");
18
20
  var _useGridApiContext = require("../hooks/utils/useGridApiContext");
@@ -23,6 +25,7 @@ var _densitySelector = require("../hooks/features/density/densitySelector");
23
25
  var _useTimeout = require("../hooks/utils/useTimeout");
24
26
  var _gridColumnsUtils = require("../hooks/features/columns/gridColumnsUtils");
25
27
  var _createSelector = require("../utils/createSelector");
28
+ var _gridRowsMetaSelector = require("../hooks/features/rows/gridRowsMetaSelector");
26
29
  var _jsxRuntime = require("react/jsx-runtime");
27
30
  const CLIFF = 1;
28
31
  const SLOP = 1.5;
@@ -43,18 +46,39 @@ const GridScrollAreaRawRoot = (0, _system.styled)('div', {
43
46
  [`&.${_constants.gridClasses['scrollArea--left']}`]: styles['scrollArea--left']
44
47
  }, {
45
48
  [`&.${_constants.gridClasses['scrollArea--right']}`]: styles['scrollArea--right']
49
+ }, {
50
+ [`&.${_constants.gridClasses['scrollArea--up']}`]: styles['scrollArea--up']
51
+ }, {
52
+ [`&.${_constants.gridClasses['scrollArea--down']}`]: styles['scrollArea--down']
46
53
  }, styles.scrollArea]
47
54
  })(() => ({
48
55
  position: 'absolute',
49
- top: 0,
50
56
  zIndex: 101,
51
- width: 20,
52
- bottom: 0,
57
+ // Horizontal scroll areas
53
58
  [`&.${_constants.gridClasses['scrollArea--left']}`]: {
54
- left: 0
59
+ top: 0,
60
+ left: 0,
61
+ width: 20,
62
+ bottom: 0
55
63
  },
56
64
  [`&.${_constants.gridClasses['scrollArea--right']}`]: {
57
- right: 0
65
+ top: 0,
66
+ right: 0,
67
+ width: 20,
68
+ bottom: 0
69
+ },
70
+ // Vertical scroll areas
71
+ [`&.${_constants.gridClasses['scrollArea--up']}`]: {
72
+ top: 0,
73
+ left: 0,
74
+ right: 0,
75
+ height: 20
76
+ },
77
+ [`&.${_constants.gridClasses['scrollArea--down']}`]: {
78
+ bottom: 0,
79
+ left: 0,
80
+ right: 0,
81
+ height: 20
58
82
  }
59
83
  }));
60
84
  const offsetSelector = (0, _createSelector.createSelector)(_gridDimensionsSelectors.gridDimensionsSelector, (dimensions, direction) => {
@@ -64,19 +88,27 @@ const offsetSelector = (0, _createSelector.createSelector)(_gridDimensionsSelect
64
88
  if (direction === 'right') {
65
89
  return dimensions.rightPinnedWidth + (dimensions.hasScrollX ? dimensions.scrollbarSize : 0);
66
90
  }
91
+ // For vertical scroll areas, we don't need horizontal offset
67
92
  return 0;
68
93
  });
69
94
  function GridScrollAreaWrapper(props) {
70
95
  const apiRef = (0, _useGridApiContext.useGridApiContext)();
71
- const [dragging, setDragging] = React.useState(false);
72
- (0, _useGridEvent.useGridEvent)(apiRef, 'columnHeaderDragStart', () => setDragging(true));
73
- (0, _useGridEvent.useGridEvent)(apiRef, 'columnHeaderDragEnd', () => setDragging(false));
74
- if (!dragging) {
96
+ const [dragDirection, setDragDirection] = React.useState('none');
97
+
98
+ // Listen for both column and row drag events
99
+ (0, _useGridEvent.useGridEvent)(apiRef, 'columnHeaderDragStart', () => setDragDirection('horizontal'));
100
+ (0, _useGridEvent.useGridEvent)(apiRef, 'columnHeaderDragEnd', () => setDragDirection('none'));
101
+ (0, _useGridEvent.useGridEvent)(apiRef, 'rowDragStart', () => setDragDirection('vertical'));
102
+ (0, _useGridEvent.useGridEvent)(apiRef, 'rowDragEnd', () => setDragDirection('none'));
103
+ if (dragDirection === 'none') {
75
104
  return null;
76
105
  }
77
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(GridScrollAreaContent, (0, _extends2.default)({}, props));
106
+ if (dragDirection === 'horizontal') {
107
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(GridHorizontalScrollAreaContent, (0, _extends2.default)({}, props));
108
+ }
109
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(GridVerticalScrollAreaContent, (0, _extends2.default)({}, props));
78
110
  }
79
- function GridScrollAreaContent(props) {
111
+ function GridHorizontalScrollAreaContent(props) {
80
112
  const {
81
113
  scrollDirection,
82
114
  scrollPosition
@@ -100,26 +132,17 @@ function GridScrollAreaContent(props) {
100
132
  }
101
133
  return false;
102
134
  };
103
- const [canScrollMore, setCanScrollMore] = React.useState(getCanScrollMore);
104
135
  const rootProps = (0, _useGridRootProps.useGridRootProps)();
105
- const ownerState = (0, _extends2.default)({}, rootProps, {
106
- scrollDirection
107
- });
108
- const classes = useUtilityClasses(ownerState);
109
136
  const totalHeaderHeight = (0, _gridColumnsUtils.getTotalHeaderHeight)(apiRef, rootProps);
110
137
  const headerHeight = Math.floor(rootProps.columnHeaderHeight * densityFactor);
111
- const style = {
138
+ const style = (0, _extends2.default)({
112
139
  height: headerHeight,
113
140
  top: totalHeaderHeight - headerHeight
114
- };
115
- if (scrollDirection === 'left') {
116
- style.left = sideOffset;
117
- } else if (scrollDirection === 'right') {
118
- style.right = sideOffset;
119
- }
120
- const handleScrolling = () => {
121
- setCanScrollMore(getCanScrollMore);
122
- };
141
+ }, scrollDirection === 'left' ? {
142
+ left: sideOffset
143
+ } : {}, scrollDirection === 'right' ? {
144
+ right: sideOffset
145
+ } : {});
123
146
  const handleDragOver = (0, _useEventCallback.default)(event => {
124
147
  let offset;
125
148
 
@@ -142,16 +165,99 @@ function GridScrollAreaContent(props) {
142
165
  });
143
166
  });
144
167
  });
168
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(GridScrollAreaContent, (0, _extends2.default)({}, props, {
169
+ ref: rootRef,
170
+ getCanScrollMore: getCanScrollMore,
171
+ style: style,
172
+ handleDragOver: handleDragOver
173
+ }));
174
+ }
175
+ function GridVerticalScrollAreaContent(props) {
176
+ const {
177
+ scrollDirection,
178
+ scrollPosition
179
+ } = props;
180
+ const rootRef = React.useRef(null);
181
+ const apiRef = (0, _useGridApiContext.useGridApiContext)();
182
+ const timeout = (0, _useTimeout.useTimeout)();
183
+ const rowsMeta = (0, _useGridSelector.useGridSelector)(apiRef, _gridRowsMetaSelector.gridRowsMetaSelector);
184
+ const getCanScrollMore = () => {
185
+ const dimensions = (0, _gridDimensionsSelectors.gridDimensionsSelector)(apiRef);
186
+ if (scrollDirection === 'up') {
187
+ // Only render if the user has not reached yet the top of the list
188
+ return scrollPosition.current.top > 0;
189
+ }
190
+ if (scrollDirection === 'down') {
191
+ // Only render if the user has not reached yet the bottom of the list
192
+ const totalRowsHeight = rowsMeta.currentPageTotalHeight || 0;
193
+ const maxScrollTop = totalRowsHeight - dimensions.viewportInnerSize.height - dimensions.scrollbarSize;
194
+ return scrollPosition.current.top < maxScrollTop;
195
+ }
196
+ return false;
197
+ };
198
+ const rootProps = (0, _useGridRootProps.useGridRootProps)();
199
+ const totalHeaderHeight = (0, _gridColumnsUtils.getTotalHeaderHeight)(apiRef, rootProps);
200
+ const style = {
201
+ top: scrollDirection === 'up' ? totalHeaderHeight : undefined,
202
+ bottom: scrollDirection === 'down' ? 0 : undefined
203
+ };
204
+ const handleDragOver = (0, _useEventCallback.default)(event => {
205
+ let offset;
206
+
207
+ // Prevents showing the forbidden cursor
208
+ event.preventDefault();
209
+ if (scrollDirection === 'up') {
210
+ offset = event.clientY - rootRef.current.getBoundingClientRect().bottom;
211
+ } else if (scrollDirection === 'down') {
212
+ offset = Math.max(1, event.clientY - rootRef.current.getBoundingClientRect().top);
213
+ } else {
214
+ throw new Error('MUI X: Wrong drag direction');
215
+ }
216
+ offset = (offset - CLIFF) * SLOP + CLIFF;
217
+
218
+ // Avoid freeze and inertia.
219
+ timeout.start(0, () => {
220
+ apiRef.current.scroll({
221
+ left: scrollPosition.current.left,
222
+ top: scrollPosition.current.top + offset
223
+ });
224
+ });
225
+ });
226
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(GridScrollAreaContent, (0, _extends2.default)({}, props, {
227
+ ref: rootRef,
228
+ getCanScrollMore: getCanScrollMore,
229
+ style: style,
230
+ handleDragOver: handleDragOver
231
+ }));
232
+ }
233
+ const GridScrollAreaContent = (0, _forwardRef.forwardRef)(function GridScrollAreaContent(props, ref) {
234
+ const {
235
+ scrollDirection,
236
+ getCanScrollMore,
237
+ style,
238
+ handleDragOver
239
+ } = props;
240
+ const apiRef = (0, _useGridApiContext.useGridApiContext)();
241
+ const [canScrollMore, setCanScrollMore] = React.useState(getCanScrollMore);
242
+ const rootProps = (0, _useGridRootProps.useGridRootProps)();
243
+ const ownerState = (0, _extends2.default)({}, rootProps, {
244
+ scrollDirection
245
+ });
246
+ const classes = useUtilityClasses(ownerState);
247
+ const handleScrolling = () => {
248
+ setCanScrollMore(getCanScrollMore);
249
+ };
145
250
  (0, _useGridEvent.useGridEvent)(apiRef, 'scrollPositionChange', handleScrolling);
146
251
  if (!canScrollMore) {
147
252
  return null;
148
253
  }
149
254
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(GridScrollAreaRawRoot, {
150
- ref: rootRef,
255
+ ref: ref,
151
256
  className: classes.root,
152
257
  ownerState: ownerState,
153
258
  onDragOver: handleDragOver,
154
259
  style: style
155
260
  });
156
- }
261
+ });
262
+ if (process.env.NODE_ENV !== "production") GridScrollAreaContent.displayName = "GridScrollAreaContent";
157
263
  const GridScrollArea = exports.GridScrollArea = (0, _fastMemo.fastMemo)(GridScrollAreaWrapper);
@@ -842,6 +842,8 @@ const GridRootStyles = exports.GridRootStyles = (0, _styles.styled)('div', {
842
842
  [`&.${_gridClasses.gridClasses['scrollbarFiller--pinnedRight']}`]: {
843
843
  backgroundColor: _cssVariables.vars.cell.background.pinned,
844
844
  position: 'sticky',
845
+ zIndex: 40,
846
+ // Should be above the column separator
845
847
  right: 0
846
848
  }
847
849
  },
@@ -105,6 +105,10 @@ function GridVirtualScroller(props) {
105
105
  scrollDirection: "left"
106
106
  }, getScrollAreaProps())), /*#__PURE__*/(0, _jsxRuntime.jsx)(_GridScrollArea.GridScrollArea, (0, _extends2.default)({
107
107
  scrollDirection: "right"
108
+ }, getScrollAreaProps())), /*#__PURE__*/(0, _jsxRuntime.jsx)(_GridScrollArea.GridScrollArea, (0, _extends2.default)({
109
+ scrollDirection: "up"
110
+ }, getScrollAreaProps())), /*#__PURE__*/(0, _jsxRuntime.jsx)(_GridScrollArea.GridScrollArea, (0, _extends2.default)({
111
+ scrollDirection: "down"
108
112
  }, getScrollAreaProps())), /*#__PURE__*/(0, _jsxRuntime.jsxs)(Scroller, (0, _extends2.default)({
109
113
  className: classes.scroller
110
114
  }, getScrollerProps(), {
@@ -639,6 +639,14 @@ export interface GridClasses {
639
639
  * Styles applied to the right scroll area element.
640
640
  */
641
641
  'scrollArea--right': string;
642
+ /**
643
+ * Styles applied to the top scroll area element.
644
+ */
645
+ 'scrollArea--up': string;
646
+ /**
647
+ * Styles applied to the bottom scroll area element.
648
+ */
649
+ 'scrollArea--down': string;
642
650
  /**
643
651
  * Styles applied to the scrollbars.
644
652
  */
@@ -11,4 +11,4 @@ var _generateUtilityClasses = _interopRequireDefault(require("@mui/utils/generat
11
11
  function getDataGridUtilityClass(slot) {
12
12
  return (0, _generateUtilityClass.default)('MuiDataGrid', slot);
13
13
  }
14
- const gridClasses = exports.gridClasses = (0, _generateUtilityClasses.default)('MuiDataGrid', ['aiAssistantPanel', 'aiAssistantPanelHeader', 'aiAssistantPanelTitleContainer', 'aiAssistantPanelTitle', 'aiAssistantPanelBody', 'aiAssistantPanelEmptyText', 'aiAssistantPanelFooter', 'aiAssistantPanelConversation', 'aiAssistantPanelConversationList', 'aiAssistantPanelConversationTitle', 'aiAssistantPanelSuggestions', 'aiAssistantPanelSuggestionsList', 'aiAssistantPanelSuggestionsItem', 'aiAssistantPanelSuggestionsLabel', 'actionsCell', 'aggregationColumnHeader', 'aggregationColumnHeader--alignLeft', 'aggregationColumnHeader--alignCenter', 'aggregationColumnHeader--alignRight', 'aggregationColumnHeaderLabel', 'aggregationRowOverlayWrapper', 'autoHeight', 'autosizing', 'mainContent', 'withSidePanel', 'booleanCell', 'cell--editable', 'cell--editing', 'cell--flex', 'cell--textCenter', 'cell--textLeft', 'cell--textRight', 'cell--rangeTop', 'cell--rangeBottom', 'cell--rangeLeft', 'cell--rangeRight', 'cell--pinnedLeft', 'cell--pinnedRight', 'cell--selectionMode', 'cell', 'cellCheckbox', 'cellEmpty', 'cellSkeleton', 'cellOffsetLeft', 'checkboxInput', 'collapsible', 'collapsibleTrigger', 'collapsibleIcon', 'collapsiblePanel', 'columnHeader', 'columnHeader--alignCenter', 'columnHeader--alignLeft', 'columnHeader--alignRight', 'columnHeader--dragging', 'columnHeader--moving', 'columnHeader--numeric', 'columnHeader--sortable', 'columnHeader--sorted', 'columnHeader--filtered', 'columnHeader--pinnedLeft', 'columnHeader--pinnedRight', 'columnHeader--last', 'columnHeader--lastUnpinned', 'columnHeader--siblingFocused', 'columnHeader--filter', 'columnHeaderFilterInput', 'columnHeaderFilterOperatorLabel', 'columnHeaderCheckbox', 'columnHeaderDraggableContainer', 'columnHeaderTitle', 'columnHeaderTitleContainer', 'columnHeaderTitleContainerContent', 'columnHeader--filledGroup', 'columnHeader--emptyGroup', 'columnHeaders', 'columnSeparator--resizable', 'columnSeparator--resizing', 'columnSeparator--sideLeft', 'columnSeparator--sideRight', 'columnSeparator', 'columnsManagement', 'columnsManagementRow', 'columnsManagementHeader', 'columnsManagementSearchInput', 'columnsManagementFooter', 'columnsManagementScrollArea', 'columnsManagementEmptyText', 'container--top', 'container--bottom', 'detailPanel', 'detailPanelToggleCell', 'detailPanelToggleCell--expanded', 'footerCell', 'panel', 'panelHeader', 'panelWrapper', 'panelContent', 'panelFooter', 'paper', 'editBooleanCell', 'editInputCell', 'filler', 'filler--borderBottom', 'filler--pinnedLeft', 'filler--pinnedRight', 'filterForm', 'filterFormDeleteIcon', 'filterFormLogicOperatorInput', 'filterFormColumnInput', 'filterFormOperatorInput', 'filterFormValueInput', 'filterIcon', 'footerContainer', 'headerFilterRow', 'iconButtonContainer', 'iconSeparator', 'main', 'main--hasPinnedRight', 'main--hiddenContent', 'menu', 'menuIcon', 'menuIconButton', 'menuOpen', 'menuList', 'overlay', 'overlayWrapper', 'overlayWrapperInner', 'root', 'root--densityStandard', 'root--densityComfortable', 'root--densityCompact', 'root--disableUserSelection', 'root--noToolbar', 'row', 'row--editable', 'row--editing', 'row--firstVisible', 'row--lastVisible', 'row--dragging', 'row--dynamicHeight', 'row--detailPanelExpanded', 'row--borderBottom', 'rowReorderCellPlaceholder', 'rowCount', 'rowReorderCellContainer', 'rowReorderCell', 'rowReorderCell--draggable', 'rowReorderIcon', 'rowSkeleton', 'scrollArea--left', 'scrollArea--right', 'scrollArea', 'scrollbar', 'scrollbar--vertical', 'scrollbar--horizontal', 'scrollbarFiller', 'scrollbarFiller--header', 'scrollbarFiller--borderTop', 'scrollbarFiller--borderBottom', 'scrollbarFiller--pinnedRight', 'selectedRowCount', 'sortButton', 'sortIcon', 'shadowScrollArea', 'sidebar', 'sidebarHeader', 'toolbarContainer', 'toolbar', 'toolbarLabel', 'toolbarDivider', 'toolbarFilterList', 'toolbarQuickFilter', 'toolbarQuickFilterTrigger', 'toolbarQuickFilterControl', 'virtualScroller', 'virtualScroller--hasScrollX', 'virtualScrollerContent', 'virtualScrollerContent--overflowed', 'virtualScrollerRenderZone', 'withVerticalBorder', 'withBorderColor', 'cell--withRightBorder', 'cell--withLeftBorder', 'columnHeader--withRightBorder', 'columnHeader--withLeftBorder', 'treeDataGroupingCell', 'treeDataGroupingCellToggle', 'treeDataGroupingCellLoadingContainer', 'groupingCriteriaCell', 'groupingCriteriaCellToggle', 'groupingCriteriaCellLoadingContainer', 'pinnedRows', 'pinnedRows--top', 'pinnedRows--bottom', 'pivotPanelAvailableFields', 'pivotPanelField', 'pivotPanelField--sorted', 'pivotPanelFieldActionContainer', 'pivotPanelFieldCheckbox', 'pivotPanelFieldDragIcon', 'pivotPanelFieldList', 'pivotPanelFieldName', 'pivotPanelHeader', 'pivotPanelPlaceholder', 'pivotPanelScrollArea', 'pivotPanelSearchContainer', 'pivotPanelSection', 'pivotPanelSectionTitle', 'pivotPanelSections', 'pivotPanelSwitch', 'pivotPanelSwitchLabel', 'prompt', 'promptContent', 'promptText', 'promptFeedback', 'promptChangeList', 'promptChangesToggle', 'promptChangesToggleIcon', 'promptIcon', 'promptIconContainer', 'promptError', 'promptAction']);
14
+ const gridClasses = exports.gridClasses = (0, _generateUtilityClasses.default)('MuiDataGrid', ['aiAssistantPanel', 'aiAssistantPanelHeader', 'aiAssistantPanelTitleContainer', 'aiAssistantPanelTitle', 'aiAssistantPanelBody', 'aiAssistantPanelEmptyText', 'aiAssistantPanelFooter', 'aiAssistantPanelConversation', 'aiAssistantPanelConversationList', 'aiAssistantPanelConversationTitle', 'aiAssistantPanelSuggestions', 'aiAssistantPanelSuggestionsList', 'aiAssistantPanelSuggestionsItem', 'aiAssistantPanelSuggestionsLabel', 'actionsCell', 'aggregationColumnHeader', 'aggregationColumnHeader--alignLeft', 'aggregationColumnHeader--alignCenter', 'aggregationColumnHeader--alignRight', 'aggregationColumnHeaderLabel', 'aggregationRowOverlayWrapper', 'autoHeight', 'autosizing', 'mainContent', 'withSidePanel', 'booleanCell', 'cell--editable', 'cell--editing', 'cell--flex', 'cell--textCenter', 'cell--textLeft', 'cell--textRight', 'cell--rangeTop', 'cell--rangeBottom', 'cell--rangeLeft', 'cell--rangeRight', 'cell--pinnedLeft', 'cell--pinnedRight', 'cell--selectionMode', 'cell', 'cellCheckbox', 'cellEmpty', 'cellSkeleton', 'cellOffsetLeft', 'checkboxInput', 'collapsible', 'collapsibleTrigger', 'collapsibleIcon', 'collapsiblePanel', 'columnHeader', 'columnHeader--alignCenter', 'columnHeader--alignLeft', 'columnHeader--alignRight', 'columnHeader--dragging', 'columnHeader--moving', 'columnHeader--numeric', 'columnHeader--sortable', 'columnHeader--sorted', 'columnHeader--filtered', 'columnHeader--pinnedLeft', 'columnHeader--pinnedRight', 'columnHeader--last', 'columnHeader--lastUnpinned', 'columnHeader--siblingFocused', 'columnHeader--filter', 'columnHeaderFilterInput', 'columnHeaderFilterOperatorLabel', 'columnHeaderCheckbox', 'columnHeaderDraggableContainer', 'columnHeaderTitle', 'columnHeaderTitleContainer', 'columnHeaderTitleContainerContent', 'columnHeader--filledGroup', 'columnHeader--emptyGroup', 'columnHeaders', 'columnSeparator--resizable', 'columnSeparator--resizing', 'columnSeparator--sideLeft', 'columnSeparator--sideRight', 'columnSeparator', 'columnsManagement', 'columnsManagementRow', 'columnsManagementHeader', 'columnsManagementSearchInput', 'columnsManagementFooter', 'columnsManagementScrollArea', 'columnsManagementEmptyText', 'container--top', 'container--bottom', 'detailPanel', 'detailPanelToggleCell', 'detailPanelToggleCell--expanded', 'footerCell', 'panel', 'panelHeader', 'panelWrapper', 'panelContent', 'panelFooter', 'paper', 'editBooleanCell', 'editInputCell', 'filler', 'filler--borderBottom', 'filler--pinnedLeft', 'filler--pinnedRight', 'filterForm', 'filterFormDeleteIcon', 'filterFormLogicOperatorInput', 'filterFormColumnInput', 'filterFormOperatorInput', 'filterFormValueInput', 'filterIcon', 'footerContainer', 'headerFilterRow', 'iconButtonContainer', 'iconSeparator', 'main', 'main--hasPinnedRight', 'main--hiddenContent', 'menu', 'menuIcon', 'menuIconButton', 'menuOpen', 'menuList', 'overlay', 'overlayWrapper', 'overlayWrapperInner', 'root', 'root--densityStandard', 'root--densityComfortable', 'root--densityCompact', 'root--disableUserSelection', 'root--noToolbar', 'row', 'row--editable', 'row--editing', 'row--firstVisible', 'row--lastVisible', 'row--dragging', 'row--dynamicHeight', 'row--detailPanelExpanded', 'row--borderBottom', 'rowReorderCellPlaceholder', 'rowCount', 'rowReorderCellContainer', 'rowReorderCell', 'rowReorderCell--draggable', 'rowReorderIcon', 'rowSkeleton', 'scrollArea--left', 'scrollArea--right', 'scrollArea--up', 'scrollArea--down', 'scrollArea', 'scrollbar', 'scrollbar--vertical', 'scrollbar--horizontal', 'scrollbarFiller', 'scrollbarFiller--header', 'scrollbarFiller--borderTop', 'scrollbarFiller--borderBottom', 'scrollbarFiller--pinnedRight', 'selectedRowCount', 'sortButton', 'sortIcon', 'shadowScrollArea', 'sidebar', 'sidebarHeader', 'toolbarContainer', 'toolbar', 'toolbarLabel', 'toolbarDivider', 'toolbarFilterList', 'toolbarQuickFilter', 'toolbarQuickFilterTrigger', 'toolbarQuickFilterControl', 'virtualScroller', 'virtualScroller--hasScrollX', 'virtualScrollerContent', 'virtualScrollerContent--overflowed', 'virtualScrollerRenderZone', 'withVerticalBorder', 'withBorderColor', 'cell--withRightBorder', 'cell--withLeftBorder', 'columnHeader--withRightBorder', 'columnHeader--withLeftBorder', 'treeDataGroupingCell', 'treeDataGroupingCellToggle', 'treeDataGroupingCellLoadingContainer', 'groupingCriteriaCell', 'groupingCriteriaCellToggle', 'groupingCriteriaCellLoadingContainer', 'pinnedRows', 'pinnedRows--top', 'pinnedRows--bottom', 'pivotPanelAvailableFields', 'pivotPanelField', 'pivotPanelField--sorted', 'pivotPanelFieldActionContainer', 'pivotPanelFieldCheckbox', 'pivotPanelFieldDragIcon', 'pivotPanelFieldList', 'pivotPanelFieldName', 'pivotPanelHeader', 'pivotPanelPlaceholder', 'pivotPanelScrollArea', 'pivotPanelSearchContainer', 'pivotPanelSection', 'pivotPanelSectionTitle', 'pivotPanelSections', 'pivotPanelSwitch', 'pivotPanelSwitchLabel', 'prompt', 'promptContent', 'promptText', 'promptFeedback', 'promptChangeList', 'promptChangesToggle', 'promptChangesToggleIcon', 'promptIcon', 'promptIconContainer', 'promptError', 'promptAction']);
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import { RefObject } from '@mui/x-internals/types';
3
3
  import { GridScrollParams } from "../models/params/gridScrollParams.js";
4
4
  interface ScrollAreaProps {
5
- scrollDirection: 'left' | 'right';
5
+ scrollDirection: 'left' | 'right' | 'up' | 'down';
6
6
  scrollPosition: RefObject<GridScrollParams>;
7
7
  }
8
8
  declare function GridScrollAreaWrapper(props: ScrollAreaProps): React.JSX.Element | null;
@@ -1,11 +1,13 @@
1
1
  'use client';
2
2
 
3
+ /* eslint-disable @typescript-eslint/no-use-before-define */
3
4
  import _extends from "@babel/runtime/helpers/esm/extends";
4
5
  import * as React from 'react';
5
6
  import useEventCallback from '@mui/utils/useEventCallback';
6
7
  import composeClasses from '@mui/utils/composeClasses';
7
8
  import { styled } from '@mui/system';
8
9
  import { fastMemo } from '@mui/x-internals/fastMemo';
10
+ import { forwardRef } from '@mui/x-internals/forwardRef';
9
11
  import { useGridRootProps } from "../hooks/utils/useGridRootProps.js";
10
12
  import { getDataGridUtilityClass, gridClasses } from "../constants/index.js";
11
13
  import { useGridApiContext } from "../hooks/utils/useGridApiContext.js";
@@ -16,6 +18,7 @@ import { gridDensityFactorSelector } from "../hooks/features/density/densitySele
16
18
  import { useTimeout } from "../hooks/utils/useTimeout.js";
17
19
  import { getTotalHeaderHeight } from "../hooks/features/columns/gridColumnsUtils.js";
18
20
  import { createSelector } from "../utils/createSelector.js";
21
+ import { gridRowsMetaSelector } from "../hooks/features/rows/gridRowsMetaSelector.js";
19
22
  import { jsx as _jsx } from "react/jsx-runtime";
20
23
  const CLIFF = 1;
21
24
  const SLOP = 1.5;
@@ -36,18 +39,39 @@ const GridScrollAreaRawRoot = styled('div', {
36
39
  [`&.${gridClasses['scrollArea--left']}`]: styles['scrollArea--left']
37
40
  }, {
38
41
  [`&.${gridClasses['scrollArea--right']}`]: styles['scrollArea--right']
42
+ }, {
43
+ [`&.${gridClasses['scrollArea--up']}`]: styles['scrollArea--up']
44
+ }, {
45
+ [`&.${gridClasses['scrollArea--down']}`]: styles['scrollArea--down']
39
46
  }, styles.scrollArea]
40
47
  })(() => ({
41
48
  position: 'absolute',
42
- top: 0,
43
49
  zIndex: 101,
44
- width: 20,
45
- bottom: 0,
50
+ // Horizontal scroll areas
46
51
  [`&.${gridClasses['scrollArea--left']}`]: {
47
- left: 0
52
+ top: 0,
53
+ left: 0,
54
+ width: 20,
55
+ bottom: 0
48
56
  },
49
57
  [`&.${gridClasses['scrollArea--right']}`]: {
50
- right: 0
58
+ top: 0,
59
+ right: 0,
60
+ width: 20,
61
+ bottom: 0
62
+ },
63
+ // Vertical scroll areas
64
+ [`&.${gridClasses['scrollArea--up']}`]: {
65
+ top: 0,
66
+ left: 0,
67
+ right: 0,
68
+ height: 20
69
+ },
70
+ [`&.${gridClasses['scrollArea--down']}`]: {
71
+ bottom: 0,
72
+ left: 0,
73
+ right: 0,
74
+ height: 20
51
75
  }
52
76
  }));
53
77
  const offsetSelector = createSelector(gridDimensionsSelector, (dimensions, direction) => {
@@ -57,19 +81,27 @@ const offsetSelector = createSelector(gridDimensionsSelector, (dimensions, direc
57
81
  if (direction === 'right') {
58
82
  return dimensions.rightPinnedWidth + (dimensions.hasScrollX ? dimensions.scrollbarSize : 0);
59
83
  }
84
+ // For vertical scroll areas, we don't need horizontal offset
60
85
  return 0;
61
86
  });
62
87
  function GridScrollAreaWrapper(props) {
63
88
  const apiRef = useGridApiContext();
64
- const [dragging, setDragging] = React.useState(false);
65
- useGridEvent(apiRef, 'columnHeaderDragStart', () => setDragging(true));
66
- useGridEvent(apiRef, 'columnHeaderDragEnd', () => setDragging(false));
67
- if (!dragging) {
89
+ const [dragDirection, setDragDirection] = React.useState('none');
90
+
91
+ // Listen for both column and row drag events
92
+ useGridEvent(apiRef, 'columnHeaderDragStart', () => setDragDirection('horizontal'));
93
+ useGridEvent(apiRef, 'columnHeaderDragEnd', () => setDragDirection('none'));
94
+ useGridEvent(apiRef, 'rowDragStart', () => setDragDirection('vertical'));
95
+ useGridEvent(apiRef, 'rowDragEnd', () => setDragDirection('none'));
96
+ if (dragDirection === 'none') {
68
97
  return null;
69
98
  }
70
- return /*#__PURE__*/_jsx(GridScrollAreaContent, _extends({}, props));
99
+ if (dragDirection === 'horizontal') {
100
+ return /*#__PURE__*/_jsx(GridHorizontalScrollAreaContent, _extends({}, props));
101
+ }
102
+ return /*#__PURE__*/_jsx(GridVerticalScrollAreaContent, _extends({}, props));
71
103
  }
72
- function GridScrollAreaContent(props) {
104
+ function GridHorizontalScrollAreaContent(props) {
73
105
  const {
74
106
  scrollDirection,
75
107
  scrollPosition
@@ -93,26 +125,17 @@ function GridScrollAreaContent(props) {
93
125
  }
94
126
  return false;
95
127
  };
96
- const [canScrollMore, setCanScrollMore] = React.useState(getCanScrollMore);
97
128
  const rootProps = useGridRootProps();
98
- const ownerState = _extends({}, rootProps, {
99
- scrollDirection
100
- });
101
- const classes = useUtilityClasses(ownerState);
102
129
  const totalHeaderHeight = getTotalHeaderHeight(apiRef, rootProps);
103
130
  const headerHeight = Math.floor(rootProps.columnHeaderHeight * densityFactor);
104
- const style = {
131
+ const style = _extends({
105
132
  height: headerHeight,
106
133
  top: totalHeaderHeight - headerHeight
107
- };
108
- if (scrollDirection === 'left') {
109
- style.left = sideOffset;
110
- } else if (scrollDirection === 'right') {
111
- style.right = sideOffset;
112
- }
113
- const handleScrolling = () => {
114
- setCanScrollMore(getCanScrollMore);
115
- };
134
+ }, scrollDirection === 'left' ? {
135
+ left: sideOffset
136
+ } : {}, scrollDirection === 'right' ? {
137
+ right: sideOffset
138
+ } : {});
116
139
  const handleDragOver = useEventCallback(event => {
117
140
  let offset;
118
141
 
@@ -135,16 +158,99 @@ function GridScrollAreaContent(props) {
135
158
  });
136
159
  });
137
160
  });
161
+ return /*#__PURE__*/_jsx(GridScrollAreaContent, _extends({}, props, {
162
+ ref: rootRef,
163
+ getCanScrollMore: getCanScrollMore,
164
+ style: style,
165
+ handleDragOver: handleDragOver
166
+ }));
167
+ }
168
+ function GridVerticalScrollAreaContent(props) {
169
+ const {
170
+ scrollDirection,
171
+ scrollPosition
172
+ } = props;
173
+ const rootRef = React.useRef(null);
174
+ const apiRef = useGridApiContext();
175
+ const timeout = useTimeout();
176
+ const rowsMeta = useGridSelector(apiRef, gridRowsMetaSelector);
177
+ const getCanScrollMore = () => {
178
+ const dimensions = gridDimensionsSelector(apiRef);
179
+ if (scrollDirection === 'up') {
180
+ // Only render if the user has not reached yet the top of the list
181
+ return scrollPosition.current.top > 0;
182
+ }
183
+ if (scrollDirection === 'down') {
184
+ // Only render if the user has not reached yet the bottom of the list
185
+ const totalRowsHeight = rowsMeta.currentPageTotalHeight || 0;
186
+ const maxScrollTop = totalRowsHeight - dimensions.viewportInnerSize.height - dimensions.scrollbarSize;
187
+ return scrollPosition.current.top < maxScrollTop;
188
+ }
189
+ return false;
190
+ };
191
+ const rootProps = useGridRootProps();
192
+ const totalHeaderHeight = getTotalHeaderHeight(apiRef, rootProps);
193
+ const style = {
194
+ top: scrollDirection === 'up' ? totalHeaderHeight : undefined,
195
+ bottom: scrollDirection === 'down' ? 0 : undefined
196
+ };
197
+ const handleDragOver = useEventCallback(event => {
198
+ let offset;
199
+
200
+ // Prevents showing the forbidden cursor
201
+ event.preventDefault();
202
+ if (scrollDirection === 'up') {
203
+ offset = event.clientY - rootRef.current.getBoundingClientRect().bottom;
204
+ } else if (scrollDirection === 'down') {
205
+ offset = Math.max(1, event.clientY - rootRef.current.getBoundingClientRect().top);
206
+ } else {
207
+ throw new Error('MUI X: Wrong drag direction');
208
+ }
209
+ offset = (offset - CLIFF) * SLOP + CLIFF;
210
+
211
+ // Avoid freeze and inertia.
212
+ timeout.start(0, () => {
213
+ apiRef.current.scroll({
214
+ left: scrollPosition.current.left,
215
+ top: scrollPosition.current.top + offset
216
+ });
217
+ });
218
+ });
219
+ return /*#__PURE__*/_jsx(GridScrollAreaContent, _extends({}, props, {
220
+ ref: rootRef,
221
+ getCanScrollMore: getCanScrollMore,
222
+ style: style,
223
+ handleDragOver: handleDragOver
224
+ }));
225
+ }
226
+ const GridScrollAreaContent = forwardRef(function GridScrollAreaContent(props, ref) {
227
+ const {
228
+ scrollDirection,
229
+ getCanScrollMore,
230
+ style,
231
+ handleDragOver
232
+ } = props;
233
+ const apiRef = useGridApiContext();
234
+ const [canScrollMore, setCanScrollMore] = React.useState(getCanScrollMore);
235
+ const rootProps = useGridRootProps();
236
+ const ownerState = _extends({}, rootProps, {
237
+ scrollDirection
238
+ });
239
+ const classes = useUtilityClasses(ownerState);
240
+ const handleScrolling = () => {
241
+ setCanScrollMore(getCanScrollMore);
242
+ };
138
243
  useGridEvent(apiRef, 'scrollPositionChange', handleScrolling);
139
244
  if (!canScrollMore) {
140
245
  return null;
141
246
  }
142
247
  return /*#__PURE__*/_jsx(GridScrollAreaRawRoot, {
143
- ref: rootRef,
248
+ ref: ref,
144
249
  className: classes.root,
145
250
  ownerState: ownerState,
146
251
  onDragOver: handleDragOver,
147
252
  style: style
148
253
  });
149
- }
254
+ });
255
+ if (process.env.NODE_ENV !== "production") GridScrollAreaContent.displayName = "GridScrollAreaContent";
150
256
  export const GridScrollArea = fastMemo(GridScrollAreaWrapper);