@mui/x-data-grid 7.29.12 → 7.29.13
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.
- package/CHANGELOG.md +35 -0
- package/hooks/features/dimensions/useGridDimensions.js +46 -1
- package/index.js +1 -1
- package/modern/hooks/features/dimensions/useGridDimensions.js +46 -1
- package/modern/index.js +1 -1
- package/node/hooks/features/dimensions/useGridDimensions.js +46 -1
- package/node/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,41 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## 7.29.13
|
|
7
|
+
|
|
8
|
+
_Apr 27, 2026_
|
|
9
|
+
|
|
10
|
+
We'd like to extend a big thank you to the 4 contributors who made this release possible. Here are some highlights ✨:
|
|
11
|
+
|
|
12
|
+
- 🐞 Bugfixes
|
|
13
|
+
|
|
14
|
+
The following are all team members who have contributed to this release:
|
|
15
|
+
@arminmeh, @dav-is, @LukasTy, @michelengelen
|
|
16
|
+
|
|
17
|
+
### Data Grid
|
|
18
|
+
|
|
19
|
+
#### `@mui/x-data-grid@7.29.13`
|
|
20
|
+
|
|
21
|
+
- [DataGrid] Prevent repeated `hasScrollbar` state updates (#21849) @arminmeh
|
|
22
|
+
|
|
23
|
+
#### `@mui/x-data-grid-pro@7.29.13` [](https://mui.com/r/x-pro-svg-link "Pro plan")
|
|
24
|
+
|
|
25
|
+
Same changes as in `@mui/x-data-grid@7.29.13`.
|
|
26
|
+
|
|
27
|
+
#### `@mui/x-data-grid-premium@7.29.13` [](https://mui.com/r/x-premium-svg-link "Premium plan")
|
|
28
|
+
|
|
29
|
+
Same changes as in `@mui/x-data-grid-pro@7.29.13`.
|
|
30
|
+
|
|
31
|
+
### Docs
|
|
32
|
+
|
|
33
|
+
- [docs] Add `v9` as root path link and move `v8` under subpath (#22037) @LukasTy
|
|
34
|
+
- [docs] Add check for auto-generated group rows in `renderCountry` (#22143) @michelengelen
|
|
35
|
+
- [docs] Remove obsolete v7 deprecation warning for `dayOfWeekFormatter` (@LukasTy) (#22121)
|
|
36
|
+
|
|
37
|
+
### Miscellaneous
|
|
38
|
+
|
|
39
|
+
- [docs-infra] Set `SEARCH_INDEX` Env for v7 (#21876) @dav-is
|
|
40
|
+
|
|
6
41
|
## 7.29.12
|
|
7
42
|
|
|
8
43
|
_Nov 26, 2025_
|
|
@@ -67,6 +67,21 @@ export function useGridDimensions(apiRef, props) {
|
|
|
67
67
|
const densityFactor = useGridSelector(apiRef, gridDensityFactorSelector);
|
|
68
68
|
const columnsTotalWidth = useGridSelector(apiRef, columnsTotalWidthSelector);
|
|
69
69
|
const isFirstSizing = React.useRef(true);
|
|
70
|
+
|
|
71
|
+
// Vertical scrollbar oscillation detector.
|
|
72
|
+
// Counts consecutive hasScrollY flips that happen with no row-height change.
|
|
73
|
+
// After 2 flips it is certainly a layout feedback loop, so every further flip
|
|
74
|
+
// is forced to false (no scrollbar). The counter resets when row heights change.
|
|
75
|
+
// Only vertical scrollbar can oscillate because column widths are never 'auto'.
|
|
76
|
+
// https://github.com/mui/mui-x/issues/20539
|
|
77
|
+
const scrollYOscillation = React.useRef({
|
|
78
|
+
counter: 0,
|
|
79
|
+
heights: {
|
|
80
|
+
content: 0,
|
|
81
|
+
pinnedTop: 0,
|
|
82
|
+
pinnedBottom: 0
|
|
83
|
+
}
|
|
84
|
+
});
|
|
70
85
|
const {
|
|
71
86
|
rowHeight,
|
|
72
87
|
headerHeight,
|
|
@@ -134,6 +149,7 @@ export function useGridDimensions(apiRef, props) {
|
|
|
134
149
|
width: nonPinnedColumnsTotalWidth,
|
|
135
150
|
height: roundToDecimalPlaces(rowsMeta.currentPageTotalHeight, 1)
|
|
136
151
|
};
|
|
152
|
+
const prevDimensions = apiRef.current.state.dimensions;
|
|
137
153
|
let viewportOuterSize;
|
|
138
154
|
let viewportInnerSize;
|
|
139
155
|
let hasScrollX = false;
|
|
@@ -171,6 +187,36 @@ export function useGridDimensions(apiRef, props) {
|
|
|
171
187
|
hasScrollY = content.height + scrollbarSize > container.height;
|
|
172
188
|
}
|
|
173
189
|
}
|
|
190
|
+
|
|
191
|
+
// Detect vertical scrollbar oscillation.
|
|
192
|
+
// Track consecutive hasScrollY flips with no row-height change.
|
|
193
|
+
// Once confirmed (≥ 2 flips), force hasScrollY off — the scrollbar is
|
|
194
|
+
// not genuinely needed, it is a layout feedback loop caused by stale
|
|
195
|
+
// rootSize or the horizontal scrollbar's height cascading.
|
|
196
|
+
{
|
|
197
|
+
const osc = scrollYOscillation.current;
|
|
198
|
+
const heightsChanged = rowsMeta.currentPageTotalHeight !== osc.heights.content || rowsMeta.pinnedTopRowsTotalHeight !== osc.heights.pinnedTop || rowsMeta.pinnedBottomRowsTotalHeight !== osc.heights.pinnedBottom;
|
|
199
|
+
if (heightsChanged) {
|
|
200
|
+
osc.counter = 0;
|
|
201
|
+
osc.heights = {
|
|
202
|
+
content: rowsMeta.currentPageTotalHeight,
|
|
203
|
+
pinnedTop: rowsMeta.pinnedTopRowsTotalHeight,
|
|
204
|
+
pinnedBottom: rowsMeta.pinnedBottomRowsTotalHeight
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
if (prevDimensions.isReady && hasScrollY !== prevDimensions.hasScrollY) {
|
|
208
|
+
if (!heightsChanged) {
|
|
209
|
+
osc.counter += 1;
|
|
210
|
+
}
|
|
211
|
+
if (osc.counter >= 2) {
|
|
212
|
+
hasScrollY = false;
|
|
213
|
+
// Recompute hasScrollX without the vertical scrollbar's width impact,
|
|
214
|
+
// otherwise the cascade (hasScrollY → narrower viewport → hasScrollX)
|
|
215
|
+
// keeps the horizontal scrollbar/filler alive and the root keeps resizing.
|
|
216
|
+
hasScrollX = hasScrollXIfNoYScrollBar;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
174
220
|
if (hasScrollY) {
|
|
175
221
|
viewportInnerSize.width -= scrollbarSize;
|
|
176
222
|
}
|
|
@@ -205,7 +251,6 @@ export function useGridDimensions(apiRef, props) {
|
|
|
205
251
|
topContainerHeight,
|
|
206
252
|
bottomContainerHeight
|
|
207
253
|
};
|
|
208
|
-
const prevDimensions = apiRef.current.state.dimensions;
|
|
209
254
|
if (isDeepEqual(prevDimensions, newDimensions)) {
|
|
210
255
|
return;
|
|
211
256
|
}
|
package/index.js
CHANGED
|
@@ -67,6 +67,21 @@ export function useGridDimensions(apiRef, props) {
|
|
|
67
67
|
const densityFactor = useGridSelector(apiRef, gridDensityFactorSelector);
|
|
68
68
|
const columnsTotalWidth = useGridSelector(apiRef, columnsTotalWidthSelector);
|
|
69
69
|
const isFirstSizing = React.useRef(true);
|
|
70
|
+
|
|
71
|
+
// Vertical scrollbar oscillation detector.
|
|
72
|
+
// Counts consecutive hasScrollY flips that happen with no row-height change.
|
|
73
|
+
// After 2 flips it is certainly a layout feedback loop, so every further flip
|
|
74
|
+
// is forced to false (no scrollbar). The counter resets when row heights change.
|
|
75
|
+
// Only vertical scrollbar can oscillate because column widths are never 'auto'.
|
|
76
|
+
// https://github.com/mui/mui-x/issues/20539
|
|
77
|
+
const scrollYOscillation = React.useRef({
|
|
78
|
+
counter: 0,
|
|
79
|
+
heights: {
|
|
80
|
+
content: 0,
|
|
81
|
+
pinnedTop: 0,
|
|
82
|
+
pinnedBottom: 0
|
|
83
|
+
}
|
|
84
|
+
});
|
|
70
85
|
const {
|
|
71
86
|
rowHeight,
|
|
72
87
|
headerHeight,
|
|
@@ -134,6 +149,7 @@ export function useGridDimensions(apiRef, props) {
|
|
|
134
149
|
width: nonPinnedColumnsTotalWidth,
|
|
135
150
|
height: roundToDecimalPlaces(rowsMeta.currentPageTotalHeight, 1)
|
|
136
151
|
};
|
|
152
|
+
const prevDimensions = apiRef.current.state.dimensions;
|
|
137
153
|
let viewportOuterSize;
|
|
138
154
|
let viewportInnerSize;
|
|
139
155
|
let hasScrollX = false;
|
|
@@ -171,6 +187,36 @@ export function useGridDimensions(apiRef, props) {
|
|
|
171
187
|
hasScrollY = content.height + scrollbarSize > container.height;
|
|
172
188
|
}
|
|
173
189
|
}
|
|
190
|
+
|
|
191
|
+
// Detect vertical scrollbar oscillation.
|
|
192
|
+
// Track consecutive hasScrollY flips with no row-height change.
|
|
193
|
+
// Once confirmed (≥ 2 flips), force hasScrollY off — the scrollbar is
|
|
194
|
+
// not genuinely needed, it is a layout feedback loop caused by stale
|
|
195
|
+
// rootSize or the horizontal scrollbar's height cascading.
|
|
196
|
+
{
|
|
197
|
+
const osc = scrollYOscillation.current;
|
|
198
|
+
const heightsChanged = rowsMeta.currentPageTotalHeight !== osc.heights.content || rowsMeta.pinnedTopRowsTotalHeight !== osc.heights.pinnedTop || rowsMeta.pinnedBottomRowsTotalHeight !== osc.heights.pinnedBottom;
|
|
199
|
+
if (heightsChanged) {
|
|
200
|
+
osc.counter = 0;
|
|
201
|
+
osc.heights = {
|
|
202
|
+
content: rowsMeta.currentPageTotalHeight,
|
|
203
|
+
pinnedTop: rowsMeta.pinnedTopRowsTotalHeight,
|
|
204
|
+
pinnedBottom: rowsMeta.pinnedBottomRowsTotalHeight
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
if (prevDimensions.isReady && hasScrollY !== prevDimensions.hasScrollY) {
|
|
208
|
+
if (!heightsChanged) {
|
|
209
|
+
osc.counter += 1;
|
|
210
|
+
}
|
|
211
|
+
if (osc.counter >= 2) {
|
|
212
|
+
hasScrollY = false;
|
|
213
|
+
// Recompute hasScrollX without the vertical scrollbar's width impact,
|
|
214
|
+
// otherwise the cascade (hasScrollY → narrower viewport → hasScrollX)
|
|
215
|
+
// keeps the horizontal scrollbar/filler alive and the root keeps resizing.
|
|
216
|
+
hasScrollX = hasScrollXIfNoYScrollBar;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
174
220
|
if (hasScrollY) {
|
|
175
221
|
viewportInnerSize.width -= scrollbarSize;
|
|
176
222
|
}
|
|
@@ -205,7 +251,6 @@ export function useGridDimensions(apiRef, props) {
|
|
|
205
251
|
topContainerHeight,
|
|
206
252
|
bottomContainerHeight
|
|
207
253
|
};
|
|
208
|
-
const prevDimensions = apiRef.current.state.dimensions;
|
|
209
254
|
if (isDeepEqual(prevDimensions, newDimensions)) {
|
|
210
255
|
return;
|
|
211
256
|
}
|
package/modern/index.js
CHANGED
|
@@ -77,6 +77,21 @@ function useGridDimensions(apiRef, props) {
|
|
|
77
77
|
const densityFactor = (0, _utils2.useGridSelector)(apiRef, _density.gridDensityFactorSelector);
|
|
78
78
|
const columnsTotalWidth = (0, _utils2.useGridSelector)(apiRef, columnsTotalWidthSelector);
|
|
79
79
|
const isFirstSizing = React.useRef(true);
|
|
80
|
+
|
|
81
|
+
// Vertical scrollbar oscillation detector.
|
|
82
|
+
// Counts consecutive hasScrollY flips that happen with no row-height change.
|
|
83
|
+
// After 2 flips it is certainly a layout feedback loop, so every further flip
|
|
84
|
+
// is forced to false (no scrollbar). The counter resets when row heights change.
|
|
85
|
+
// Only vertical scrollbar can oscillate because column widths are never 'auto'.
|
|
86
|
+
// https://github.com/mui/mui-x/issues/20539
|
|
87
|
+
const scrollYOscillation = React.useRef({
|
|
88
|
+
counter: 0,
|
|
89
|
+
heights: {
|
|
90
|
+
content: 0,
|
|
91
|
+
pinnedTop: 0,
|
|
92
|
+
pinnedBottom: 0
|
|
93
|
+
}
|
|
94
|
+
});
|
|
80
95
|
const {
|
|
81
96
|
rowHeight,
|
|
82
97
|
headerHeight,
|
|
@@ -144,6 +159,7 @@ function useGridDimensions(apiRef, props) {
|
|
|
144
159
|
width: nonPinnedColumnsTotalWidth,
|
|
145
160
|
height: (0, _roundToDecimalPlaces.roundToDecimalPlaces)(rowsMeta.currentPageTotalHeight, 1)
|
|
146
161
|
};
|
|
162
|
+
const prevDimensions = apiRef.current.state.dimensions;
|
|
147
163
|
let viewportOuterSize;
|
|
148
164
|
let viewportInnerSize;
|
|
149
165
|
let hasScrollX = false;
|
|
@@ -181,6 +197,36 @@ function useGridDimensions(apiRef, props) {
|
|
|
181
197
|
hasScrollY = content.height + scrollbarSize > container.height;
|
|
182
198
|
}
|
|
183
199
|
}
|
|
200
|
+
|
|
201
|
+
// Detect vertical scrollbar oscillation.
|
|
202
|
+
// Track consecutive hasScrollY flips with no row-height change.
|
|
203
|
+
// Once confirmed (≥ 2 flips), force hasScrollY off — the scrollbar is
|
|
204
|
+
// not genuinely needed, it is a layout feedback loop caused by stale
|
|
205
|
+
// rootSize or the horizontal scrollbar's height cascading.
|
|
206
|
+
{
|
|
207
|
+
const osc = scrollYOscillation.current;
|
|
208
|
+
const heightsChanged = rowsMeta.currentPageTotalHeight !== osc.heights.content || rowsMeta.pinnedTopRowsTotalHeight !== osc.heights.pinnedTop || rowsMeta.pinnedBottomRowsTotalHeight !== osc.heights.pinnedBottom;
|
|
209
|
+
if (heightsChanged) {
|
|
210
|
+
osc.counter = 0;
|
|
211
|
+
osc.heights = {
|
|
212
|
+
content: rowsMeta.currentPageTotalHeight,
|
|
213
|
+
pinnedTop: rowsMeta.pinnedTopRowsTotalHeight,
|
|
214
|
+
pinnedBottom: rowsMeta.pinnedBottomRowsTotalHeight
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
if (prevDimensions.isReady && hasScrollY !== prevDimensions.hasScrollY) {
|
|
218
|
+
if (!heightsChanged) {
|
|
219
|
+
osc.counter += 1;
|
|
220
|
+
}
|
|
221
|
+
if (osc.counter >= 2) {
|
|
222
|
+
hasScrollY = false;
|
|
223
|
+
// Recompute hasScrollX without the vertical scrollbar's width impact,
|
|
224
|
+
// otherwise the cascade (hasScrollY → narrower viewport → hasScrollX)
|
|
225
|
+
// keeps the horizontal scrollbar/filler alive and the root keeps resizing.
|
|
226
|
+
hasScrollX = hasScrollXIfNoYScrollBar;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
184
230
|
if (hasScrollY) {
|
|
185
231
|
viewportInnerSize.width -= scrollbarSize;
|
|
186
232
|
}
|
|
@@ -215,7 +261,6 @@ function useGridDimensions(apiRef, props) {
|
|
|
215
261
|
topContainerHeight,
|
|
216
262
|
bottomContainerHeight
|
|
217
263
|
};
|
|
218
|
-
const prevDimensions = apiRef.current.state.dimensions;
|
|
219
264
|
if ((0, _utils3.isDeepEqual)(prevDimensions, newDimensions)) {
|
|
220
265
|
return;
|
|
221
266
|
}
|
package/node/index.js
CHANGED