@mui/x-data-grid 7.25.0 → 7.26.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 (108) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/DataGrid/useDataGridComponent.js +2 -2
  3. package/components/GridRow.js +8 -2
  4. package/components/GridScrollArea.d.ts +5 -2
  5. package/components/GridScrollArea.js +32 -25
  6. package/components/GridSkeletonLoadingOverlay.js +2 -1
  7. package/components/containers/GridRoot.js +11 -9
  8. package/components/containers/GridRootStyles.js +3 -3
  9. package/components/virtualization/GridMainContainer.d.ts +2 -2
  10. package/components/virtualization/GridMainContainer.js +1 -1
  11. package/components/virtualization/GridVirtualScroller.js +21 -14
  12. package/hooks/core/pipeProcessing/useGridRegisterPipeProcessor.d.ts +1 -1
  13. package/hooks/core/pipeProcessing/useGridRegisterPipeProcessor.js +6 -4
  14. package/hooks/core/useGridStateInitialization.js +3 -2
  15. package/hooks/features/columnHeaders/useGridColumnHeaders.js +10 -14
  16. package/hooks/features/columns/gridColumnsSelector.d.ts +0 -5
  17. package/hooks/features/columns/gridColumnsSelector.js +0 -12
  18. package/hooks/features/dimensions/gridDimensionsSelectors.d.ts +16 -0
  19. package/hooks/features/dimensions/gridDimensionsSelectors.js +26 -1
  20. package/hooks/features/dimensions/index.d.ts +1 -1
  21. package/hooks/features/dimensions/index.js +1 -2
  22. package/hooks/features/dimensions/useGridDimensions.js +97 -70
  23. package/hooks/features/editing/gridEditingSelectors.d.ts +5 -1
  24. package/hooks/features/editing/gridEditingSelectors.js +6 -1
  25. package/hooks/features/editing/useGridRowEditing.js +4 -4
  26. package/hooks/features/filter/gridFilterState.d.ts +5 -0
  27. package/hooks/features/filter/gridFilterState.js +5 -0
  28. package/hooks/features/filter/useGridFilter.js +6 -13
  29. package/hooks/features/pagination/useGridPagination.js +1 -1
  30. package/hooks/features/rowSelection/useGridRowSelection.js +1 -1
  31. package/hooks/features/rowSelection/utils.js +1 -1
  32. package/hooks/features/rows/gridRowsMetaState.d.ts +8 -0
  33. package/hooks/features/rows/gridRowsUtils.d.ts +0 -4
  34. package/hooks/features/rows/gridRowsUtils.js +0 -16
  35. package/hooks/features/rows/useGridRowsMeta.js +33 -17
  36. package/hooks/features/sorting/gridSortingSelector.js +10 -9
  37. package/hooks/features/virtualization/useGridVirtualScroller.d.ts +6 -0
  38. package/hooks/features/virtualization/useGridVirtualScroller.js +43 -27
  39. package/hooks/utils/useGridSelector.d.ts +8 -1
  40. package/hooks/utils/useGridSelector.js +42 -8
  41. package/hooks/utils/useIsSSR.d.ts +1 -0
  42. package/hooks/utils/useIsSSR.js +5 -0
  43. package/index.js +1 -1
  44. package/internals/index.d.ts +2 -1
  45. package/internals/index.js +2 -1
  46. package/models/api/gridStateApi.d.ts +1 -0
  47. package/models/events/gridEventLookup.d.ts +6 -0
  48. package/modern/DataGrid/useDataGridComponent.js +2 -2
  49. package/modern/components/GridRow.js +8 -2
  50. package/modern/components/GridScrollArea.js +32 -25
  51. package/modern/components/GridSkeletonLoadingOverlay.js +2 -1
  52. package/modern/components/containers/GridRoot.js +11 -9
  53. package/modern/components/containers/GridRootStyles.js +3 -3
  54. package/modern/components/virtualization/GridMainContainer.js +1 -1
  55. package/modern/components/virtualization/GridVirtualScroller.js +21 -14
  56. package/modern/hooks/core/pipeProcessing/useGridRegisterPipeProcessor.js +6 -4
  57. package/modern/hooks/core/useGridStateInitialization.js +3 -2
  58. package/modern/hooks/features/columnHeaders/useGridColumnHeaders.js +10 -14
  59. package/modern/hooks/features/columns/gridColumnsSelector.js +0 -12
  60. package/modern/hooks/features/dimensions/gridDimensionsSelectors.js +26 -1
  61. package/modern/hooks/features/dimensions/index.js +1 -2
  62. package/modern/hooks/features/dimensions/useGridDimensions.js +97 -70
  63. package/modern/hooks/features/editing/gridEditingSelectors.js +6 -1
  64. package/modern/hooks/features/editing/useGridRowEditing.js +4 -4
  65. package/modern/hooks/features/filter/gridFilterState.js +5 -0
  66. package/modern/hooks/features/filter/useGridFilter.js +6 -13
  67. package/modern/hooks/features/pagination/useGridPagination.js +1 -1
  68. package/modern/hooks/features/rowSelection/useGridRowSelection.js +1 -1
  69. package/modern/hooks/features/rowSelection/utils.js +1 -1
  70. package/modern/hooks/features/rows/gridRowsUtils.js +0 -16
  71. package/modern/hooks/features/rows/useGridRowsMeta.js +33 -17
  72. package/modern/hooks/features/sorting/gridSortingSelector.js +10 -9
  73. package/modern/hooks/features/virtualization/useGridVirtualScroller.js +43 -27
  74. package/modern/hooks/utils/useGridSelector.js +42 -8
  75. package/modern/hooks/utils/useIsSSR.js +5 -0
  76. package/modern/index.js +1 -1
  77. package/modern/internals/index.js +2 -1
  78. package/node/DataGrid/useDataGridComponent.js +2 -2
  79. package/node/components/GridRow.js +7 -2
  80. package/node/components/GridScrollArea.js +31 -24
  81. package/node/components/GridSkeletonLoadingOverlay.js +2 -1
  82. package/node/components/containers/GridRoot.js +10 -8
  83. package/node/components/containers/GridRootStyles.js +3 -3
  84. package/node/components/virtualization/GridMainContainer.js +1 -1
  85. package/node/components/virtualization/GridVirtualScroller.js +21 -14
  86. package/node/hooks/core/pipeProcessing/useGridRegisterPipeProcessor.js +6 -4
  87. package/node/hooks/core/useGridStateInitialization.js +3 -2
  88. package/node/hooks/features/columnHeaders/useGridColumnHeaders.js +10 -14
  89. package/node/hooks/features/columns/gridColumnsSelector.js +1 -13
  90. package/node/hooks/features/dimensions/gridDimensionsSelectors.js +38 -2
  91. package/node/hooks/features/dimensions/index.js +13 -11
  92. package/node/hooks/features/dimensions/useGridDimensions.js +94 -67
  93. package/node/hooks/features/editing/gridEditingSelectors.js +5 -1
  94. package/node/hooks/features/editing/useGridRowEditing.js +4 -4
  95. package/node/hooks/features/filter/gridFilterState.js +6 -1
  96. package/node/hooks/features/filter/useGridFilter.js +5 -12
  97. package/node/hooks/features/pagination/useGridPagination.js +1 -1
  98. package/node/hooks/features/rowSelection/useGridRowSelection.js +1 -1
  99. package/node/hooks/features/rowSelection/utils.js +1 -1
  100. package/node/hooks/features/rows/gridRowsUtils.js +0 -17
  101. package/node/hooks/features/rows/useGridRowsMeta.js +31 -15
  102. package/node/hooks/features/sorting/gridSortingSelector.js +10 -9
  103. package/node/hooks/features/virtualization/useGridVirtualScroller.js +42 -26
  104. package/node/hooks/utils/useGridSelector.js +42 -8
  105. package/node/hooks/utils/useIsSSR.js +12 -0
  106. package/node/index.js +1 -1
  107. package/node/internals/index.js +20 -7
  108. package/package.json +3 -2
@@ -4,7 +4,7 @@ const _excluded = ["className", "children"];
4
4
  import * as React from 'react';
5
5
  import PropTypes from 'prop-types';
6
6
  import clsx from 'clsx';
7
- import { unstable_useForkRef as useForkRef, unstable_useEnhancedEffect as useEnhancedEffect, unstable_capitalize as capitalize, unstable_composeClasses as composeClasses } from '@mui/utils';
7
+ import { unstable_useForkRef as useForkRef, unstable_capitalize as capitalize, unstable_composeClasses as composeClasses } from '@mui/utils';
8
8
  import { fastMemo } from '@mui/x-internals/fastMemo';
9
9
  import { forwardRef } from '@mui/x-internals/forwardRef';
10
10
  import { GridRootStyles } from "./GridRootStyles.js";
@@ -13,6 +13,7 @@ import { useGridPrivateApiContext } from "../../hooks/utils/useGridPrivateApiCon
13
13
  import { useGridRootProps } from "../../hooks/utils/useGridRootProps.js";
14
14
  import { getDataGridUtilityClass } from "../../constants/gridClasses.js";
15
15
  import { gridDensitySelector } from "../../hooks/features/density/densitySelector.js";
16
+ import { useIsSSR } from "../../hooks/utils/useIsSSR.js";
16
17
  import { GridHeader } from "../GridHeader.js";
17
18
  import { GridBody, GridFooterPlaceholder } from "../base/index.js";
18
19
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -37,16 +38,17 @@ const GridRoot = forwardRef(function GridRoot(props, ref) {
37
38
  const apiRef = useGridPrivateApiContext();
38
39
  const density = useGridSelector(apiRef, gridDensitySelector);
39
40
  const rootElementRef = apiRef.current.rootElementRef;
40
- const handleRef = useForkRef(rootElementRef, ref);
41
+ const rootMountCallback = React.useCallback(node => {
42
+ if (node === null) {
43
+ return;
44
+ }
45
+ apiRef.current.publishEvent('rootMount', node);
46
+ }, [apiRef]);
47
+ const handleRef = useForkRef(rootElementRef, ref, rootMountCallback);
41
48
  const ownerState = rootProps;
42
49
  const classes = useUtilityClasses(ownerState, density);
43
-
44
- // Our implementation of <NoSsr />
45
- const [mountedState, setMountedState] = React.useState(false);
46
- useEnhancedEffect(() => {
47
- setMountedState(true);
48
- }, []);
49
- if (!mountedState) {
50
+ const isSSR = useIsSSR();
51
+ if (isSSR) {
50
52
  return null;
51
53
  }
52
54
  return /*#__PURE__*/_jsxs(GridRootStyles, _extends({
@@ -3,7 +3,6 @@ import { alpha, styled, darken, lighten, decomposeColor, recomposeColor } from '
3
3
  import { gridClasses as c } from "../../constants/gridClasses.js";
4
4
  import { useGridSelector } from "../../hooks/utils/useGridSelector.js";
5
5
  import { useGridPrivateApiContext } from "../../hooks/utils/useGridPrivateApiContext.js";
6
- import { gridDimensionsSelector } from "../../hooks/features/dimensions/gridDimensionsSelectors.js";
7
6
  function getBorderColor(theme) {
8
7
  if (theme.vars) {
9
8
  return theme.vars.palette.TableCell.border;
@@ -35,6 +34,7 @@ const separatorIconDragStyles = {
35
34
  // Emotion thinks it knows better than us which selector we should use.
36
35
  // https://github.com/emotion-js/emotion/issues/1105#issuecomment-1722524968
37
36
  const ignoreSsrWarning = '/* emotion-disable-server-rendering-unsafe-selector-warning-please-do-not-use-this-the-warning-exists-for-a-reason */';
37
+ const shouldShowBorderTopRightRadiusSelector = state => state.dimensions.hasScrollX && (!state.dimensions.hasScrollY || state.dimensions.scrollbarSize === 0);
38
38
  export const GridRootStyles = styled('div', {
39
39
  name: 'MuiDataGrid',
40
40
  slot: 'Root',
@@ -265,7 +265,7 @@ export const GridRootStyles = styled('div', {
265
265
  theme: t
266
266
  }) => {
267
267
  const apiRef = useGridPrivateApiContext();
268
- const dimensions = useGridSelector(apiRef, gridDimensionsSelector);
268
+ const shouldShowBorderTopRightRadius = useGridSelector(apiRef, shouldShowBorderTopRightRadiusSelector);
269
269
  const borderColor = getBorderColor(t);
270
270
  const radius = t.shape.borderRadius;
271
271
  const containerBackground = t.vars ? t.vars.palette.background.default : t.mixins.MuiDataGrid?.containerBackground ?? t.palette.background.default;
@@ -417,7 +417,7 @@ export const GridRootStyles = styled('div', {
417
417
  borderTopLeftRadius: 'calc(var(--unstable_DataGrid-radius) - 1px)'
418
418
  },
419
419
  [`&.${c['root--noToolbar']} [aria-rowindex="1"] .${c['columnHeader--last']}`]: {
420
- borderTopRightRadius: dimensions.hasScrollX && (!dimensions.hasScrollY || dimensions.scrollbarSize === 0) ? 'calc(var(--unstable_DataGrid-radius) - 1px)' : undefined
420
+ borderTopRightRadius: shouldShowBorderTopRightRadius ? 'calc(var(--unstable_DataGrid-radius) - 1px)' : undefined
421
421
  },
422
422
  [`& .${c.columnHeaderCheckbox}, & .${c.cellCheckbox}`]: {
423
423
  padding: 0,
@@ -18,7 +18,7 @@ const Element = styled('div', {
18
18
  const {
19
19
  ownerState
20
20
  } = props;
21
- return [styles.main, ownerState.dimensions.rightPinnedWidth > 0 && styles['main--hasPinnedRight'], ownerState.loadingOverlayVariant === 'skeleton' && styles['main--hasSkeletonLoadingOverlay']];
21
+ return [styles.main, ownerState.hasPinnedRight && styles['main--hasPinnedRight'], ownerState.loadingOverlayVariant === 'skeleton' && styles['main--hasSkeletonLoadingOverlay']];
22
22
  }
23
23
  })({
24
24
  flexGrow: 1,
@@ -2,12 +2,12 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import { styled } from '@mui/system';
4
4
  import composeClasses from '@mui/utils/composeClasses';
5
+ import { gridHasBottomFillerSelector, gridHasScrollXSelector, gridHasScrollYSelector } from "../../hooks/features/dimensions/gridDimensionsSelectors.js";
5
6
  import { GridScrollArea } from "../GridScrollArea.js";
6
7
  import { useGridRootProps } from "../../hooks/utils/useGridRootProps.js";
7
8
  import { useGridApiContext } from "../../hooks/utils/useGridApiContext.js";
8
9
  import { useGridSelector } from "../../hooks/utils/useGridSelector.js";
9
10
  import { getDataGridUtilityClass } from "../../constants/gridClasses.js";
10
- import { gridDimensionsSelector } from "../../hooks/features/dimensions/index.js";
11
11
  import { useGridVirtualScroller } from "../../hooks/features/virtualization/useGridVirtualScroller.js";
12
12
  import { useGridOverlays } from "../../hooks/features/overlays/useGridOverlays.js";
13
13
  import { GridOverlays as Overlays } from "../base/GridOverlays.js";
@@ -23,12 +23,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
23
23
  const useUtilityClasses = ownerState => {
24
24
  const {
25
25
  classes,
26
- dimensions,
26
+ hasScrollX,
27
+ hasPinnedRight,
27
28
  loadingOverlayVariant
28
29
  } = ownerState;
29
30
  const slots = {
30
- root: ['main', dimensions.rightPinnedWidth > 0 && 'main--hasPinnedRight', loadingOverlayVariant === 'skeleton' && 'main--hasSkeletonLoadingOverlay'],
31
- scroller: ['virtualScroller', dimensions.hasScrollX && 'virtualScroller--hasScrollX']
31
+ root: ['main', hasPinnedRight && 'main--hasPinnedRight', loadingOverlayVariant === 'skeleton' && 'main--hasSkeletonLoadingOverlay'],
32
+ scroller: ['virtualScroller', hasScrollX && 'virtualScroller--hasScrollX']
32
33
  };
33
34
  return composeClasses(slots, getDataGridUtilityClass, classes);
34
35
  };
@@ -39,7 +40,7 @@ const Scroller = styled('div', {
39
40
  const {
40
41
  ownerState
41
42
  } = props;
42
- return [styles.virtualScroller, ownerState.dimensions.hasScrollX && styles['virtualScroller--hasScrollX']];
43
+ return [styles.virtualScroller, ownerState.hasScrollX && styles['virtualScroller--hasScrollX']];
43
44
  }
44
45
  })({
45
46
  position: 'relative',
@@ -58,14 +59,19 @@ const Scroller = styled('div', {
58
59
  // See https://github.com/mui/mui-x/issues/10547
59
60
  zIndex: 0
60
61
  });
62
+ const hasPinnedRightSelector = state => state.dimensions.rightPinnedWidth > 0;
61
63
  function GridVirtualScroller(props) {
62
64
  const apiRef = useGridApiContext();
63
65
  const rootProps = useGridRootProps();
64
- const dimensions = useGridSelector(apiRef, gridDimensionsSelector);
66
+ const hasScrollY = useGridSelector(apiRef, gridHasScrollYSelector);
67
+ const hasScrollX = useGridSelector(apiRef, gridHasScrollXSelector);
68
+ const hasPinnedRight = useGridSelector(apiRef, hasPinnedRightSelector);
69
+ const hasBottomFiller = useGridSelector(apiRef, gridHasBottomFillerSelector);
65
70
  const overlaysProps = useGridOverlays();
66
71
  const ownerState = {
67
72
  classes: rootProps.classes,
68
- dimensions,
73
+ hasScrollX,
74
+ hasPinnedRight,
69
75
  loadingOverlayVariant: overlaysProps.loadingOverlayVariant
70
76
  };
71
77
  const classes = useUtilityClasses(ownerState);
@@ -77,18 +83,19 @@ function GridVirtualScroller(props) {
77
83
  getRenderZoneProps,
78
84
  getScrollbarVerticalProps,
79
85
  getScrollbarHorizontalProps,
80
- getRows
86
+ getRows,
87
+ getScrollAreaProps
81
88
  } = virtualScroller;
82
89
  const rows = getRows();
83
90
  return /*#__PURE__*/_jsxs(Container, _extends({
84
91
  className: classes.root
85
92
  }, getContainerProps(), {
86
93
  ownerState: ownerState,
87
- children: [/*#__PURE__*/_jsx(GridScrollArea, {
94
+ children: [/*#__PURE__*/_jsx(GridScrollArea, _extends({
88
95
  scrollDirection: "left"
89
- }), /*#__PURE__*/_jsx(GridScrollArea, {
96
+ }, getScrollAreaProps())), /*#__PURE__*/_jsx(GridScrollArea, _extends({
90
97
  scrollDirection: "right"
91
- }), /*#__PURE__*/_jsxs(Scroller, _extends({
98
+ }, getScrollAreaProps())), /*#__PURE__*/_jsxs(Scroller, _extends({
92
99
  className: classes.scroller
93
100
  }, getScrollerProps(), {
94
101
  ownerState: ownerState,
@@ -103,7 +110,7 @@ function GridVirtualScroller(props) {
103
110
  virtualScroller: virtualScroller
104
111
  })]
105
112
  }))
106
- })), /*#__PURE__*/_jsx(SpaceFiller, {
113
+ })), hasBottomFiller && /*#__PURE__*/_jsx(SpaceFiller, {
107
114
  rowsLength: rows.length
108
115
  }), /*#__PURE__*/_jsx(BottomContainer, {
109
116
  children: /*#__PURE__*/_jsx(rootProps.slots.pinnedRows, {
@@ -111,9 +118,9 @@ function GridVirtualScroller(props) {
111
118
  virtualScroller: virtualScroller
112
119
  })
113
120
  })]
114
- })), dimensions.hasScrollX && !rootProps.unstable_listView && /*#__PURE__*/_jsx(Scrollbar, _extends({
121
+ })), hasScrollX && !rootProps.unstable_listView && /*#__PURE__*/_jsx(Scrollbar, _extends({
115
122
  position: "horizontal"
116
- }, getScrollbarHorizontalProps())), dimensions.hasScrollY && /*#__PURE__*/_jsx(Scrollbar, _extends({
123
+ }, getScrollbarHorizontalProps())), hasScrollY && /*#__PURE__*/_jsx(Scrollbar, _extends({
117
124
  position: "vertical"
118
125
  }, getScrollbarVerticalProps())), props.children]
119
126
  }));
@@ -1,19 +1,21 @@
1
1
  import * as React from 'react';
2
2
  import { useFirstRender } from "../../utils/useFirstRender.js";
3
- export const useGridRegisterPipeProcessor = (apiRef, group, callback) => {
3
+ export const useGridRegisterPipeProcessor = (apiRef, group, callback, enabled = true) => {
4
4
  const cleanup = React.useRef(null);
5
5
  const id = React.useRef(`mui-${Math.round(Math.random() * 1e9)}`);
6
6
  const registerPreProcessor = React.useCallback(() => {
7
7
  cleanup.current = apiRef.current.registerPipeProcessor(group, id.current, callback);
8
8
  }, [apiRef, callback, group]);
9
9
  useFirstRender(() => {
10
- registerPreProcessor();
10
+ if (enabled) {
11
+ registerPreProcessor();
12
+ }
11
13
  });
12
14
  const isFirstRender = React.useRef(true);
13
15
  React.useEffect(() => {
14
16
  if (isFirstRender.current) {
15
17
  isFirstRender.current = false;
16
- } else {
18
+ } else if (enabled) {
17
19
  registerPreProcessor();
18
20
  }
19
21
  return () => {
@@ -22,5 +24,5 @@ export const useGridRegisterPipeProcessor = (apiRef, group, callback) => {
22
24
  cleanup.current = null;
23
25
  }
24
26
  };
25
- }, [registerPreProcessor]);
27
+ }, [registerPreProcessor, enabled]);
26
28
  };
@@ -4,7 +4,6 @@ import { useGridApiMethod } from "../utils/index.js";
4
4
  import { isFunction } from "../../utils/utils.js";
5
5
  export const useGridStateInitialization = apiRef => {
6
6
  const controlStateMapRef = React.useRef({});
7
- const [, rawForceUpdate] = React.useState();
8
7
  const registerControlState = React.useCallback(controlStateItem => {
9
8
  controlStateMapRef.current[controlStateItem.stateId] = controlStateItem;
10
9
  }, []);
@@ -79,7 +78,9 @@ export const useGridStateInitialization = apiRef => {
79
78
  });
80
79
  }, reason);
81
80
  }, [apiRef]);
82
- const forceUpdate = React.useCallback(() => rawForceUpdate(() => apiRef.current.state), [apiRef]);
81
+ const forceUpdate = React.useCallback(() => {
82
+ // @deprecated - do nothing
83
+ }, []);
83
84
  const publicStateApi = {
84
85
  setState,
85
86
  forceUpdate
@@ -7,7 +7,7 @@ import { useGridRootProps } from "../../utils/useGridRootProps.js";
7
7
  import { useGridPrivateApiContext } from "../../utils/useGridPrivateApiContext.js";
8
8
  import { useGridApiEventHandler } from "../../utils/useGridApiEventHandler.js";
9
9
  import { GridColumnHeaderItem } from "../../../components/columnHeaders/GridColumnHeaderItem.js";
10
- import { gridDimensionsSelector } from "../dimensions/index.js";
10
+ import { gridColumnsTotalWidthSelector, gridGroupHeaderHeightSelector, gridHasFillerSelector, gridHeaderHeightSelector, gridVerticalScrollbarWidthSelector } from "../dimensions/gridDimensionsSelectors.js";
11
11
  import { gridRenderContextColumnsSelector } from "../virtualization/index.js";
12
12
  import { computeOffsetLeft } from "../virtualization/useGridVirtualScroller.js";
13
13
  import { GridColumnGroupHeader } from "../../../components/columnHeaders/GridColumnGroupHeader.js";
@@ -46,19 +46,17 @@ export const useGridColumnHeaders = props => {
46
46
  const [resizeCol, setResizeCol] = React.useState('');
47
47
  const apiRef = useGridPrivateApiContext();
48
48
  const rootProps = useGridRootProps();
49
- const dimensions = useGridSelector(apiRef, gridDimensionsSelector);
50
49
  const columnGroupsModel = useGridSelector(apiRef, gridColumnGroupsUnwrappedModelSelector);
51
50
  const columnPositions = useGridSelector(apiRef, gridColumnPositionsSelector);
52
51
  const renderContext = useGridSelector(apiRef, gridRenderContextColumnsSelector);
53
52
  const pinnedColumns = useGridSelector(apiRef, gridVisiblePinnedColumnDefinitionsSelector);
54
53
  const columnsLookup = useGridSelector(apiRef, gridColumnLookupSelector);
55
54
  const offsetLeft = computeOffsetLeft(columnPositions, renderContext, pinnedColumns.left.length);
56
- const gridHasFiller = dimensions.columnsTotalWidth < dimensions.viewportOuterSize.width;
57
- React.useEffect(() => {
58
- if (apiRef.current.columnHeadersContainerRef.current) {
59
- apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
60
- }
61
- }, [apiRef]);
55
+ const columnsTotalWidth = useGridSelector(apiRef, gridColumnsTotalWidthSelector);
56
+ const gridHasFiller = useGridSelector(apiRef, gridHasFillerSelector);
57
+ const headerHeight = useGridSelector(apiRef, gridHeaderHeightSelector);
58
+ const groupHeaderHeight = useGridSelector(apiRef, gridGroupHeaderHeightSelector);
59
+ const scrollbarWidth = useGridSelector(apiRef, gridVerticalScrollbarWidthSelector);
62
60
  const handleColumnResizeStart = React.useCallback(params => setResizeCol(params.field), []);
63
61
  const handleColumnResizeStop = React.useCallback(() => setResizeCol(''), []);
64
62
  const handleColumnReorderStart = React.useCallback(params => setDragCol(params.field), []);
@@ -130,8 +128,7 @@ export const useGridColumnHeaders = props => {
130
128
  const hasFocus = columnHeaderFocus !== null && columnHeaderFocus.field === colDef.field;
131
129
  const open = columnMenuState.open && columnMenuState.field === colDef.field;
132
130
  const pinnedPosition = params?.position;
133
- const scrollbarWidth = dimensions.hasScrollY ? dimensions.scrollbarSize : 0;
134
- const pinnedOffset = getPinnedCellOffset(pinnedPosition, colDef.computedWidth, columnIndex, columnPositions, dimensions.columnsTotalWidth, scrollbarWidth);
131
+ const pinnedOffset = getPinnedCellOffset(pinnedPosition, colDef.computedWidth, columnIndex, columnPositions, columnsTotalWidth, scrollbarWidth);
135
132
  const siblingWithBorderingSeparator = pinnedPosition === PinnedColumnPosition.RIGHT ? renderedColumns[i - 1] : renderedColumns[i + 1];
136
133
  const isSiblingFocused = siblingWithBorderingSeparator ? columnHeaderFocus !== null && columnHeaderFocus.field === siblingWithBorderingSeparator.field : false;
137
134
  const isLastUnpinned = columnIndex + 1 === columnPositions.length - pinnedColumns.right.length;
@@ -142,7 +139,7 @@ export const useGridColumnHeaders = props => {
142
139
  columns.push(/*#__PURE__*/_jsx(GridColumnHeaderItem, _extends({}, sortColumnLookup[colDef.field], {
143
140
  columnMenuOpen: open,
144
141
  filterItemsCounter: filterColumnLookup[colDef.field] && filterColumnLookup[colDef.field].length,
145
- headerHeight: dimensions.headerHeight,
142
+ headerHeight: headerHeight,
146
143
  isDragging: colDef.field === dragCol,
147
144
  colDef: colDef,
148
145
  colIndex: columnIndex,
@@ -234,8 +231,7 @@ export const useGridColumnHeaders = props => {
234
231
  tabIndex
235
232
  };
236
233
  const pinnedPosition = params.position;
237
- const scrollbarWidth = dimensions.hasScrollY ? dimensions.scrollbarSize : 0;
238
- const pinnedOffset = getPinnedCellOffset(pinnedPosition, headerInfo.width, columnIndex, columnPositions, dimensions.columnsTotalWidth, scrollbarWidth);
234
+ const pinnedOffset = getPinnedCellOffset(pinnedPosition, headerInfo.width, columnIndex, columnPositions, columnsTotalWidth, scrollbarWidth);
239
235
  columnIndex += columnFields.length;
240
236
  let indexInSection = index;
241
237
  if (pinnedPosition === PinnedColumnPosition.LEFT) {
@@ -250,7 +246,7 @@ export const useGridColumnHeaders = props => {
250
246
  depth: depth,
251
247
  isLastColumn: index === visibleColumnGroupHeader.length - 1,
252
248
  maxDepth: headerGroupingMaxDepth,
253
- height: dimensions.groupHeaderHeight,
249
+ height: groupHeaderHeight,
254
250
  hasFocus: hasFocus,
255
251
  tabIndex: tabIndex,
256
252
  pinnedPosition: pinnedPosition,
@@ -107,18 +107,6 @@ export const gridColumnPositionsSelector = createSelectorMemoized(gridVisibleCol
107
107
  return positions;
108
108
  });
109
109
 
110
- /**
111
- * Get the summed width of all the visible columns.
112
- * @category Visible Columns
113
- */
114
- export const gridColumnsTotalWidthSelector = createSelector(gridVisibleColumnDefinitionsSelector, gridColumnPositionsSelector, (visibleColumns, positions) => {
115
- const colCount = visibleColumns.length;
116
- if (colCount === 0) {
117
- return 0;
118
- }
119
- return positions[colCount - 1] + visibleColumns[colCount - 1].computedWidth;
120
- });
121
-
122
110
  /**
123
111
  * Get the filterable columns as an array.
124
112
  * @category Columns
@@ -1 +1,26 @@
1
- export const gridDimensionsSelector = state => state.dimensions;
1
+ import { createSelector } from "../../../utils/createSelector.js";
2
+ export const gridDimensionsSelector = state => state.dimensions;
3
+
4
+ /**
5
+ * Get the summed width of all the visible columns.
6
+ * @category Visible Columns
7
+ */
8
+ export const gridColumnsTotalWidthSelector = createSelector(gridDimensionsSelector, dimensions => dimensions.columnsTotalWidth);
9
+ export const gridRowHeightSelector = state => state.dimensions.rowHeight;
10
+ export const gridContentHeightSelector = state => state.dimensions.contentSize.height;
11
+ export const gridHasScrollXSelector = state => state.dimensions.hasScrollX;
12
+ export const gridHasScrollYSelector = state => state.dimensions.hasScrollY;
13
+ export const gridHasFillerSelector = state => state.dimensions.columnsTotalWidth < state.dimensions.viewportOuterSize.width;
14
+ export const gridHeaderHeightSelector = state => state.dimensions.headerHeight;
15
+ export const gridGroupHeaderHeightSelector = state => state.dimensions.groupHeaderHeight;
16
+ export const gridHeaderFilterHeightSelector = state => state.dimensions.headerFilterHeight;
17
+ export const gridVerticalScrollbarWidthSelector = state => state.dimensions.hasScrollY ? state.dimensions.scrollbarSize : 0;
18
+ export const gridHorizontalScrollbarHeightSelector = state => state.dimensions.hasScrollX ? state.dimensions.scrollbarSize : 0;
19
+ export const gridHasBottomFillerSelector = state => {
20
+ const height = state.dimensions.hasScrollX ? state.dimensions.scrollbarSize : 0;
21
+ const needsLastRowBorder = state.dimensions.viewportOuterSize.height - state.dimensions.minimumSize.height > 0;
22
+ if (height === 0 && !needsLastRowBorder) {
23
+ return false;
24
+ }
25
+ return true;
26
+ };
@@ -1,2 +1 @@
1
- export * from "./gridDimensionsSelectors.js";
2
- export {};
1
+ export { gridDimensionsSelector, gridColumnsTotalWidthSelector } from "./gridDimensionsSelectors.js";
@@ -2,21 +2,23 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import { unstable_ownerDocument as ownerDocument, unstable_useEnhancedEffect as useEnhancedEffect, unstable_useEventCallback as useEventCallback, unstable_ownerWindow as ownerWindow } from '@mui/utils';
4
4
  import { throttle } from '@mui/x-internals/throttle';
5
- import { useGridApiEventHandler, useGridApiOptionHandler } from "../../utils/useGridApiEventHandler.js";
5
+ import { useGridApiOptionHandler } from "../../utils/useGridApiEventHandler.js";
6
6
  import { useGridApiMethod } from "../../utils/useGridApiMethod.js";
7
+ import { createSelector } from "../../../utils/createSelector.js";
7
8
  import { useGridLogger } from "../../utils/useGridLogger.js";
8
- import { gridColumnsTotalWidthSelector, gridVisiblePinnedColumnDefinitionsSelector } from "../columns/index.js";
9
+ import { gridColumnPositionsSelector, gridVisibleColumnDefinitionsSelector, gridVisiblePinnedColumnDefinitionsSelector } from "../columns/index.js";
9
10
  import { gridDimensionsSelector } from "./gridDimensionsSelectors.js";
10
11
  import { gridDensityFactorSelector } from "../density/index.js";
11
12
  import { gridRenderContextSelector } from "../virtualization/index.js";
12
13
  import { useGridSelector } from "../../utils/index.js";
13
14
  import { getVisibleRows } from "../../utils/useGridVisibleRows.js";
14
15
  import { gridRowsMetaSelector } from "../rows/gridRowsMetaSelector.js";
15
- import { calculatePinnedRowsHeight, getValidRowHeight, rowHeightWarning } from "../rows/gridRowsUtils.js";
16
+ import { getValidRowHeight, rowHeightWarning } from "../rows/gridRowsUtils.js";
16
17
  import { getTotalHeaderHeight } from "../columns/gridColumnsUtils.js";
17
18
  import { DATA_GRID_PROPS_DEFAULT_VALUES } from "../../../constants/dataGridPropsDefaultValues.js";
18
19
  import { roundToDecimalPlaces } from "../../../utils/roundToDecimalPlaces.js";
19
20
  import { isJSDOM } from "../../../utils/isJSDOM.js";
21
+ import { isDeepEqual } from "../../../utils/utils.js";
20
22
  const EMPTY_SIZE = {
21
23
  width: 0,
22
24
  height: 0
@@ -43,39 +45,47 @@ const EMPTY_DIMENSIONS = {
43
45
  topContainerHeight: 0,
44
46
  bottomContainerHeight: 0
45
47
  };
46
- export const dimensionsStateInitializer = state => {
48
+ export const dimensionsStateInitializer = (state, props, apiRef) => {
47
49
  const dimensions = EMPTY_DIMENSIONS;
50
+ const density = gridDensityFactorSelector(apiRef);
48
51
  return _extends({}, state, {
49
- dimensions
52
+ dimensions: _extends({}, dimensions, getStaticDimensions(props, apiRef, density, gridVisiblePinnedColumnDefinitionsSelector(apiRef)))
50
53
  });
51
54
  };
55
+ const columnsTotalWidthSelector = createSelector(gridVisibleColumnDefinitionsSelector, gridColumnPositionsSelector, (visibleColumns, positions) => {
56
+ const colCount = visibleColumns.length;
57
+ if (colCount === 0) {
58
+ return 0;
59
+ }
60
+ return roundToDecimalPlaces(positions[colCount - 1] + visibleColumns[colCount - 1].computedWidth, 1);
61
+ });
52
62
  export function useGridDimensions(apiRef, props) {
53
63
  const logger = useGridLogger(apiRef, 'useResizeContainer');
54
64
  const errorShown = React.useRef(false);
55
65
  const rootDimensionsRef = React.useRef(EMPTY_SIZE);
56
- const dimensionsState = useGridSelector(apiRef, gridDimensionsSelector);
57
- const rowsMeta = useGridSelector(apiRef, gridRowsMetaSelector);
58
66
  const pinnedColumns = useGridSelector(apiRef, gridVisiblePinnedColumnDefinitionsSelector);
59
67
  const densityFactor = useGridSelector(apiRef, gridDensityFactorSelector);
60
- const validRowHeight = React.useMemo(() => getValidRowHeight(props.rowHeight, DATA_GRID_PROPS_DEFAULT_VALUES.rowHeight, rowHeightWarning), [props.rowHeight]);
61
- const rowHeight = Math.floor(validRowHeight * densityFactor);
62
- const headerHeight = Math.floor(props.columnHeaderHeight * densityFactor);
63
- const groupHeaderHeight = Math.floor((props.columnGroupHeaderHeight ?? props.columnHeaderHeight) * densityFactor);
64
- const headerFilterHeight = Math.floor((props.headerFilterHeight ?? props.columnHeaderHeight) * densityFactor);
65
- const columnsTotalWidth = roundToDecimalPlaces(gridColumnsTotalWidthSelector(apiRef), 1);
66
- const headersTotalHeight = getTotalHeaderHeight(apiRef, props);
67
- const leftPinnedWidth = pinnedColumns.left.reduce((w, col) => w + col.computedWidth, 0);
68
- const rightPinnedWidth = pinnedColumns.right.reduce((w, col) => w + col.computedWidth, 0);
69
- const [savedSize, setSavedSize] = React.useState();
70
- const debouncedSetSavedSize = React.useMemo(() => throttle(setSavedSize, props.resizeThrottleMs), [props.resizeThrottleMs]);
71
- React.useEffect(() => debouncedSetSavedSize.clear, [debouncedSetSavedSize]);
68
+ const columnsTotalWidth = useGridSelector(apiRef, columnsTotalWidthSelector);
69
+ const isFirstSizing = React.useRef(true);
70
+ const {
71
+ rowHeight,
72
+ headerHeight,
73
+ groupHeaderHeight,
74
+ headerFilterHeight,
75
+ headersTotalHeight,
76
+ leftPinnedWidth,
77
+ rightPinnedWidth
78
+ } = getStaticDimensions(props, apiRef, densityFactor, pinnedColumns);
72
79
  const previousSize = React.useRef(undefined);
73
- const getRootDimensions = () => apiRef.current.state.dimensions;
74
- const setDimensions = useEventCallback(dimensions => {
80
+ const getRootDimensions = React.useCallback(() => gridDimensionsSelector(apiRef.current.state), [apiRef]);
81
+ const setDimensions = React.useCallback(dimensions => {
75
82
  apiRef.current.setState(state => _extends({}, state, {
76
83
  dimensions
77
84
  }));
78
- });
85
+ if (apiRef.current.rootElementRef.current) {
86
+ setCSSVariables(apiRef.current.rootElementRef.current, gridDimensionsSelector(apiRef.current.state));
87
+ }
88
+ }, [apiRef]);
79
89
  const resize = React.useCallback(() => {
80
90
  const element = apiRef.current.mainElementRef.current;
81
91
  if (!element) {
@@ -96,10 +106,7 @@ export function useGridDimensions(apiRef, props) {
96
106
  if (!dimensions.isReady) {
97
107
  return 0;
98
108
  }
99
- const currentPage = getVisibleRows(apiRef, {
100
- pagination: props.pagination,
101
- paginationMode: props.paginationMode
102
- });
109
+ const currentPage = getVisibleRows(apiRef);
103
110
 
104
111
  // TODO: Use a combination of scrollTop, dimensions.viewportInnerSize.height and rowsMeta.possitions
105
112
  // to find out the maximum number of rows that can fit in the visible part of the grid
@@ -110,16 +117,19 @@ export function useGridDimensions(apiRef, props) {
110
117
  }
111
118
  const maximumPageSizeWithoutScrollBar = Math.floor(dimensions.viewportInnerSize.height / rowHeight);
112
119
  return Math.min(maximumPageSizeWithoutScrollBar, currentPage.rows.length);
113
- }, [apiRef, props.pagination, props.paginationMode, props.getRowHeight, rowHeight]);
120
+ }, [apiRef, props.getRowHeight, rowHeight]);
114
121
  const updateDimensions = React.useCallback(() => {
122
+ if (isFirstSizing.current) {
123
+ return;
124
+ }
115
125
  // All the floating point dimensions should be rounded to .1 decimal places to avoid subpixel rendering issues
116
126
  // https://github.com/mui/mui-x/issues/9550#issuecomment-1619020477
117
127
  // https://github.com/mui/mui-x/issues/15721
118
128
  const rootElement = apiRef.current.rootElementRef.current;
119
- const pinnedRowsHeight = calculatePinnedRowsHeight(apiRef);
120
- const scrollbarSize = measureScrollbarSize(rootElement, columnsTotalWidth, props.scrollbarSize);
121
- const topContainerHeight = headersTotalHeight + pinnedRowsHeight.top;
122
- const bottomContainerHeight = pinnedRowsHeight.bottom;
129
+ const scrollbarSize = measureScrollbarSize(rootElement, props.scrollbarSize);
130
+ const rowsMeta = gridRowsMetaSelector(apiRef.current.state);
131
+ const topContainerHeight = headersTotalHeight + rowsMeta.pinnedTopRowsTotalHeight;
132
+ const bottomContainerHeight = rowsMeta.pinnedBottomRowsTotalHeight;
123
133
  const nonPinnedColumnsTotalWidth = columnsTotalWidth - leftPinnedWidth - rightPinnedWidth;
124
134
  const contentSize = {
125
135
  width: nonPinnedColumnsTotalWidth,
@@ -197,12 +207,21 @@ export function useGridDimensions(apiRef, props) {
197
207
  bottomContainerHeight
198
208
  };
199
209
  const prevDimensions = apiRef.current.state.dimensions;
210
+ if (isDeepEqual(prevDimensions, newDimensions)) {
211
+ return;
212
+ }
200
213
  setDimensions(newDimensions);
201
214
  if (!areElementSizesEqual(newDimensions.viewportInnerSize, prevDimensions.viewportInnerSize)) {
202
215
  apiRef.current.publishEvent('viewportInnerSizeChange', newDimensions.viewportInnerSize);
203
216
  }
204
217
  apiRef.current.updateRenderContext?.();
205
- }, [apiRef, setDimensions, props.scrollbarSize, props.autoHeight, rowsMeta.currentPageTotalHeight, rowHeight, headerHeight, groupHeaderHeight, headerFilterHeight, columnsTotalWidth, headersTotalHeight, leftPinnedWidth, rightPinnedWidth]);
218
+ }, [apiRef, setDimensions, props.scrollbarSize, props.autoHeight, rowHeight, headerHeight, groupHeaderHeight, headerFilterHeight, columnsTotalWidth, headersTotalHeight, leftPinnedWidth, rightPinnedWidth]);
219
+ const updateDimensionCallback = useEventCallback(updateDimensions);
220
+ const debouncedUpdateDimensions = React.useMemo(() => props.resizeThrottleMs > 0 ? throttle(() => {
221
+ updateDimensionCallback();
222
+ apiRef.current.publishEvent('debouncedResize', rootDimensionsRef.current);
223
+ }, props.resizeThrottleMs) : undefined, [apiRef, props.resizeThrottleMs, updateDimensionCallback]);
224
+ React.useEffect(() => debouncedUpdateDimensions?.clear, [debouncedUpdateDimensions]);
206
225
  const apiPublic = {
207
226
  resize,
208
227
  getRootDimensions
@@ -211,35 +230,12 @@ export function useGridDimensions(apiRef, props) {
211
230
  updateDimensions,
212
231
  getViewportPageSize
213
232
  };
233
+ useEnhancedEffect(updateDimensions, [updateDimensions]);
214
234
  useGridApiMethod(apiRef, apiPublic, 'public');
215
235
  useGridApiMethod(apiRef, apiPrivate, 'private');
216
- useEnhancedEffect(() => {
217
- if (savedSize) {
218
- updateDimensions();
219
- apiRef.current.publishEvent('debouncedResize', rootDimensionsRef.current);
220
- }
221
- }, [apiRef, savedSize, updateDimensions]);
222
- const root = apiRef.current.rootElementRef.current;
223
- useEnhancedEffect(() => {
224
- if (!root) {
225
- return;
226
- }
227
- const set = (k, v) => root.style.setProperty(k, v);
228
- set('--DataGrid-width', `${dimensionsState.viewportOuterSize.width}px`);
229
- set('--DataGrid-hasScrollX', `${Number(dimensionsState.hasScrollX)}`);
230
- set('--DataGrid-hasScrollY', `${Number(dimensionsState.hasScrollY)}`);
231
- set('--DataGrid-scrollbarSize', `${dimensionsState.scrollbarSize}px`);
232
- set('--DataGrid-rowWidth', `${dimensionsState.rowWidth}px`);
233
- set('--DataGrid-columnsTotalWidth', `${dimensionsState.columnsTotalWidth}px`);
234
- set('--DataGrid-leftPinnedWidth', `${dimensionsState.leftPinnedWidth}px`);
235
- set('--DataGrid-rightPinnedWidth', `${dimensionsState.rightPinnedWidth}px`);
236
- set('--DataGrid-headerHeight', `${dimensionsState.headerHeight}px`);
237
- set('--DataGrid-headersTotalHeight', `${dimensionsState.headersTotalHeight}px`);
238
- set('--DataGrid-topContainerHeight', `${dimensionsState.topContainerHeight}px`);
239
- set('--DataGrid-bottomContainerHeight', `${dimensionsState.bottomContainerHeight}px`);
240
- set('--height', `${dimensionsState.rowHeight}px`);
241
- }, [root, dimensionsState]);
242
- const isFirstSizing = React.useRef(true);
236
+ const handleRootMount = React.useCallback(root => {
237
+ setCSSVariables(root, gridDimensionsSelector(apiRef.current.state));
238
+ }, [apiRef]);
243
239
  const handleResize = React.useCallback(size => {
244
240
  rootDimensionsRef.current = size;
245
241
  if (size.height === 0 && !errorShown.current && !props.autoHeight && !isJSDOM) {
@@ -250,28 +246,58 @@ export function useGridDimensions(apiRef, props) {
250
246
  logger.error(['The parent DOM element of the Data Grid has an empty width.', 'Please make sure that this element has an intrinsic width.', 'The grid displays with a width of 0px.', '', 'More details: https://mui.com/r/x-data-grid-no-dimensions.'].join('\n'));
251
247
  errorShown.current = true;
252
248
  }
253
- if (isFirstSizing.current) {
249
+ if (isFirstSizing.current || !debouncedUpdateDimensions) {
254
250
  // We want to initialize the grid dimensions as soon as possible to avoid flickering
255
- setSavedSize(size);
256
251
  isFirstSizing.current = false;
252
+ updateDimensions();
257
253
  return;
258
254
  }
259
- debouncedSetSavedSize(size);
260
- }, [props.autoHeight, debouncedSetSavedSize, logger]);
261
- useEnhancedEffect(updateDimensions, [updateDimensions]);
262
- useGridApiOptionHandler(apiRef, 'sortedRowsSet', updateDimensions);
263
- useGridApiOptionHandler(apiRef, 'paginationModelChange', updateDimensions);
264
- useGridApiOptionHandler(apiRef, 'columnsChange', updateDimensions);
265
- useGridApiEventHandler(apiRef, 'resize', handleResize);
255
+ debouncedUpdateDimensions();
256
+ }, [updateDimensions, props.autoHeight, debouncedUpdateDimensions, logger]);
257
+ useGridApiOptionHandler(apiRef, 'rootMount', handleRootMount);
258
+ useGridApiOptionHandler(apiRef, 'resize', handleResize);
266
259
  useGridApiOptionHandler(apiRef, 'debouncedResize', props.onResize);
267
260
  }
268
- function measureScrollbarSize(rootElement, columnsTotalWidth, scrollbarSize) {
261
+ function setCSSVariables(root, dimensions) {
262
+ const set = (k, v) => root.style.setProperty(k, v);
263
+ set('--DataGrid-hasScrollX', `${Number(dimensions.hasScrollX)}`);
264
+ set('--DataGrid-hasScrollY', `${Number(dimensions.hasScrollY)}`);
265
+ set('--DataGrid-scrollbarSize', `${dimensions.scrollbarSize}px`);
266
+ set('--DataGrid-rowWidth', `${dimensions.rowWidth}px`);
267
+ set('--DataGrid-columnsTotalWidth', `${dimensions.columnsTotalWidth}px`);
268
+ set('--DataGrid-leftPinnedWidth', `${dimensions.leftPinnedWidth}px`);
269
+ set('--DataGrid-rightPinnedWidth', `${dimensions.rightPinnedWidth}px`);
270
+ set('--DataGrid-headerHeight', `${dimensions.headerHeight}px`);
271
+ set('--DataGrid-headersTotalHeight', `${dimensions.headersTotalHeight}px`);
272
+ set('--DataGrid-topContainerHeight', `${dimensions.topContainerHeight}px`);
273
+ set('--DataGrid-bottomContainerHeight', `${dimensions.bottomContainerHeight}px`);
274
+ set('--height', `${dimensions.rowHeight}px`);
275
+ }
276
+ function getStaticDimensions(props, apiRef, density, pinnedColumnns) {
277
+ const validRowHeight = getValidRowHeight(props.rowHeight, DATA_GRID_PROPS_DEFAULT_VALUES.rowHeight, rowHeightWarning);
278
+ return {
279
+ rowHeight: Math.floor(validRowHeight * density),
280
+ headerHeight: Math.floor(props.columnHeaderHeight * density),
281
+ groupHeaderHeight: Math.floor((props.columnGroupHeaderHeight ?? props.columnHeaderHeight) * density),
282
+ headerFilterHeight: Math.floor((props.headerFilterHeight ?? props.columnHeaderHeight) * density),
283
+ columnsTotalWidth: columnsTotalWidthSelector(apiRef),
284
+ headersTotalHeight: getTotalHeaderHeight(apiRef, props),
285
+ leftPinnedWidth: pinnedColumnns.left.reduce((w, col) => w + col.computedWidth, 0),
286
+ rightPinnedWidth: pinnedColumnns.right.reduce((w, col) => w + col.computedWidth, 0)
287
+ };
288
+ }
289
+ const scrollbarSizeCache = new WeakMap();
290
+ function measureScrollbarSize(rootElement, scrollbarSize) {
269
291
  if (scrollbarSize !== undefined) {
270
292
  return scrollbarSize;
271
293
  }
272
- if (rootElement === null || columnsTotalWidth === 0) {
294
+ if (rootElement === null) {
273
295
  return 0;
274
296
  }
297
+ const cachedSize = scrollbarSizeCache.get(rootElement);
298
+ if (cachedSize !== undefined) {
299
+ return cachedSize;
300
+ }
275
301
  const doc = ownerDocument(rootElement);
276
302
  const scrollDiv = doc.createElement('div');
277
303
  scrollDiv.style.width = '99px';
@@ -282,6 +308,7 @@ function measureScrollbarSize(rootElement, columnsTotalWidth, scrollbarSize) {
282
308
  rootElement.appendChild(scrollDiv);
283
309
  const size = scrollDiv.offsetWidth - scrollDiv.clientWidth;
284
310
  rootElement.removeChild(scrollDiv);
311
+ scrollbarSizeCache.set(rootElement, size);
285
312
  return size;
286
313
  }
287
314
  function areElementSizesEqual(a, b) {