@mui/x-data-grid 8.21.0 → 8.22.1

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 (32) hide show
  1. package/CHANGELOG.md +238 -1
  2. package/components/GridColumnSortButton.js +13 -9
  3. package/components/columnSelection/GridCellCheckboxRenderer.js +4 -3
  4. package/components/containers/GridRootStyles.d.ts +3 -1
  5. package/components/containers/GridRootStyles.js +24 -11
  6. package/esm/components/GridColumnSortButton.js +13 -9
  7. package/esm/components/columnSelection/GridCellCheckboxRenderer.js +4 -3
  8. package/esm/components/containers/GridRootStyles.d.ts +3 -1
  9. package/esm/components/containers/GridRootStyles.js +22 -10
  10. package/esm/hooks/core/useGridProps.js +2 -1
  11. package/esm/hooks/features/columnResize/useGridColumnResize.js +16 -1
  12. package/esm/hooks/features/columns/gridColumnsUtils.js +11 -3
  13. package/esm/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +1 -1
  14. package/esm/hooks/features/rowSelection/utils.js +35 -8
  15. package/esm/hooks/features/rows/useGridRowSpanning.js +1 -0
  16. package/esm/index.js +1 -1
  17. package/esm/locales/svSE.js +2 -2
  18. package/esm/material/index.js +15 -7
  19. package/esm/material/variables.js +6 -4
  20. package/esm/utils/ResizeObserver.js +0 -2
  21. package/hooks/core/useGridProps.js +2 -1
  22. package/hooks/features/columnResize/useGridColumnResize.js +16 -1
  23. package/hooks/features/columns/gridColumnsUtils.js +11 -3
  24. package/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +1 -1
  25. package/hooks/features/rowSelection/utils.js +35 -8
  26. package/hooks/features/rows/useGridRowSpanning.js +1 -0
  27. package/index.js +1 -1
  28. package/locales/svSE.js +2 -2
  29. package/material/index.js +14 -6
  30. package/material/variables.js +6 -4
  31. package/package.json +3 -3
  32. package/utils/ResizeObserver.js +0 -2
package/CHANGELOG.md CHANGED
@@ -5,6 +5,243 @@
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.22.1
9
+
10
+ _Dec 17, 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
+ - 🌎 Improve Swedish (sv-SE) locale on the Data Grid
15
+ - 🐞 Bugfixes
16
+
17
+ Special thanks go out to the community members for their valuable contributions:
18
+ @KyeongJooni, @VismaAndreasIvarsson
19
+
20
+ The following team members contributed to this release:
21
+ @alelthomas, @alexfauquette, @arminmeh, @bernardobelchior, @Janpot, @JCQuintas, @mapache-salvaje, @michelengelen, @mj12albert, @prakhargupta1, @romgrk, @siriwatknp
22
+
23
+ ### Data Grid
24
+
25
+ #### `@mui/x-data-grid@8.22.1`
26
+
27
+ - [data grid] Fix column menu keyboard shortcut (#20621) @mj12albert
28
+ - [data grid] Fix row checkbox disabled state on first render and keep cell focusable (ARIA) (#20641) @michelengelen
29
+ - [data grid] Fix tree data selection bug (#20528) @michelengelen
30
+ - [data grid] Prevent clear cell selection on edit mode (#20544) @siriwatknp
31
+ - [data grid] Refactor column merge logic to prioritize defined properties only (#20640) @michelengelen
32
+ - [data grid] Reset row spanning on row expansion change (#20661) @siriwatknp
33
+ - [data grid] Resize newly added rows while resize action is happening (#20676)
34
+ - [l10n] Improve Swedish (sv-SE) locale (#20682) @VismaAndreasIvarsson
35
+
36
+ #### `@mui/x-data-grid-pro@8.22.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
37
+
38
+ Same changes as in `@mui/x-data-grid@8.22.1`.
39
+
40
+ #### `@mui/x-data-grid-premium@8.22.1` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
41
+
42
+ Same changes as in `@mui/x-data-grid-pro@8.22.1`, plus:
43
+
44
+ - [DataGridPremium] Import `useId()` from `@mui/utils` to maintain React 17 compatibility (#20635) @arminmeh
45
+
46
+ ### Date and Time Pickers
47
+
48
+ #### `@mui/x-date-pickers@8.22.1`
49
+
50
+ - [pickers] Add minutesStep validation test (#20672) @KyeongJooni
51
+ - [pickers] Fix `onAccept()` returning wrong year after selecting year then month (#20639) @michelengelen
52
+
53
+ #### `@mui/x-date-pickers-pro@8.22.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
54
+
55
+ Same changes as in `@mui/x-date-pickers@8.22.1`.
56
+
57
+ ### Charts
58
+
59
+ #### `@mui/x-charts@8.22.1`
60
+
61
+ - [charts] Extract `FocusedPieArc` from `PieArcPlot` (#20613) @alexfauquette
62
+ - [charts] Fix regression on the highlight control (#20627) @alexfauquette
63
+ - [charts] Refactor: `useSelector()` => `store.use()` (#20681) @romgrk
64
+ - [charts] Remove duplicated types (#20694) @alexfauquette
65
+ - [charts] Remove unused generics from bar charts (#20642) @bernardobelchior
66
+ - [charts] Simplify tooltip position getter for pie chart (#20625) @alexfauquette
67
+
68
+ #### `@mui/x-charts-pro@8.22.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
69
+
70
+ Same changes as in `@mui/x-charts@8.22.1`, plus:
71
+
72
+ - [charts-pro] Add heatmap performance benchmark (#20695) @bernardobelchior
73
+
74
+ #### `@mui/x-charts-premium@8.22.1` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
75
+
76
+ Same changes as in `@mui/x-charts-pro@8.22.1`, plus:
77
+
78
+ - [charts-premium] Create `BarChartPremium` (#20643) @bernardobelchior
79
+
80
+ ### Tree View
81
+
82
+ #### `@mui/x-tree-view@8.22.1`
83
+
84
+ Internal changes.
85
+
86
+ #### `@mui/x-tree-view-pro@8.22.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
87
+
88
+ Same changes as in `@mui/x-tree-view@8.22.1`.
89
+
90
+ ### Codemod
91
+
92
+ #### `@mui/x-codemod@8.22.1`
93
+
94
+ Internal changes.
95
+
96
+ ### Docs
97
+
98
+ - [docs] Add button to GitHub source code for the Data Grid advanced demos (DX-50) (#20633) @alelthomas
99
+ - [docs] Remove `seriesConfig` to prevent future confusion (#20678) @alexfauquette
100
+ - [docs] Revise the Data Grid's API object doc for clarity and style (#20649) @mapache-salvaje
101
+ - [docs] Update list of charts (#20479) @prakhargupta1
102
+
103
+ ### Core
104
+
105
+ - [code-infra] Regression tests improvements (#20441) @Janpot
106
+ - [code-infra] Test utils upgrade (#20592) @Janpot
107
+ - [code-infra] Try to fix the Tree View flacky tests (#20573) @JCQuintas
108
+
109
+ ## 8.22.0
110
+
111
+ _Dec 11, 2025_
112
+
113
+ We'd like to extend a big thank you to the 11 contributors who made this release possible. Here are some highlights ✨:
114
+
115
+ - Each Tree View component now exposes its own hook to initialize the `apiRef` object with accurate typing:
116
+
117
+ ```diff
118
+ -import { useTreeViewApiRef } from '@mui/x-tree-view/hooks';
119
+ +import { useSimpleTreeViewApiRef } from '@mui/x-tree-view/hooks';
120
+ -const apiRef = useTreeViewApiRef();
121
+ +const apiRef = useSimpleTreeViewApiRef();
122
+
123
+ -import { useTreeViewApiRef } from '@mui/x-tree-view/hooks';
124
+ +import { useRichTreeViewApiRef } from '@mui/x-tree-view/hooks';
125
+ -const apiRef = useTreeViewApiRef();
126
+ +const apiRef = useRichTreeViewApiRef();
127
+
128
+ -import { useTreeViewApiRef } from '@mui/x-tree-view/hooks';
129
+ +import { useRichTreeViewProApiRef } from '@mui/x-tree-view-pro/hooks';
130
+ -const apiRef = useTreeViewApiRef();
131
+ +const apiRef = useRichTreeViewProApiRef();
132
+ ```
133
+
134
+ - 📚 [Tutorial](https://mui.com/x/react-data-grid/tutorials/server-side-data/) on building a Data Grid with server-side data
135
+ - 🐞 Bugfixes
136
+
137
+ Special thanks go out to this community member for their valuable contributions:
138
+ @kzhgit
139
+
140
+ The following team members contributed to this release:
141
+ @alexfauquette, @arminmeh, @bernardobelchior, @cherniavskii, @flaviendelangle, @JCQuintas, @mapache-salvaje, @michelengelen, @noraleonte, @oliviertassinari
142
+
143
+ ### Data Grid
144
+
145
+ #### `@mui/x-data-grid@8.22.0`
146
+
147
+ - [DataGrid] Sync component props with theme defaults (#20590) @michelengelen
148
+ - [DataGrid] Add fallback for CSS `color-mix` if it is unsupported (#20597) @cherniavskii
149
+ - [DataGrid] Use `baseTooltip` slot for column header sort icon (#20460) @kzhgit
150
+
151
+ #### `@mui/x-data-grid-pro@8.22.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
152
+
153
+ Same changes as in `@mui/x-data-grid@8.22.0`.
154
+
155
+ #### `@mui/x-data-grid-premium@8.22.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
156
+
157
+ Same changes as in `@mui/x-data-grid-pro@8.22.0`, plus:
158
+
159
+ - [DataGridPremium] Handle pivoting column name generation for empty strings (#20608) @arminmeh
160
+ - [DataGridPremium] Pass a row with aggregated value to the custom aggregation function `valueFormatter` (#20607) @arminmeh
161
+
162
+ ### Date and Time Pickers
163
+
164
+ #### `@mui/x-date-pickers@8.22.0`
165
+
166
+ - [pickers] Fix invalid date tests (#20606) @michelengelen
167
+
168
+ #### `@mui/x-date-pickers-pro@8.22.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
169
+
170
+ Same changes as in `@mui/x-date-pickers@8.22.0`.
171
+
172
+ ### Charts
173
+
174
+ #### `@mui/x-charts@8.22.0`
175
+
176
+ - [charts] Add consistent animation duration and timing (#20564) @JCQuintas
177
+ - [charts] Extract a tooltip plugin from the interaction one (#20591) @alexfauquette
178
+ - [charts] General type improvements (#20565) @JCQuintas
179
+ - [charts] Place ordinal ticks according to a continuous scale (#19808) @alexfauquette
180
+ - [charts] Remove layout data from the tooltip internals (#20548) @alexfauquette
181
+ - [charts] Remove usage of focus outline for item highlight (#19856) @alexfauquette
182
+ - [charts] Simplify `MarkPlot` by moving calculation to `useMarkPlotData` (#20570) @JCQuintas
183
+ - [charts] Use `store.state` over `store.getSnapshot()` (#20616) @bernardobelchior
184
+ - [charts] Vendor flatqueue (#20610) @bernardobelchior
185
+ - [charts] Extract pie layout computation (#20611) @alexfauquette
186
+ - [charts][infra] Enable `@typescript-eslint/consistent-type-imports` eslint rules (#20560) @JCQuintas
187
+ - [charts][infra] Enable `import/no-cycle` eslint rules (#20554) @JCQuintas
188
+
189
+ #### `@mui/x-charts-pro@8.22.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
190
+
191
+ Same changes as in `@mui/x-charts@8.22.0`, plus:
192
+
193
+ - [charts-pro] Display sankey labels on top of nodes (#20569) @alexfauquette
194
+
195
+ #### `@mui/x-charts-premium@8.22.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
196
+
197
+ Same changes as in `@mui/x-charts-pro@8.22.0`.
198
+
199
+ ### Tree View
200
+
201
+ #### `@mui/x-tree-view@8.22.0`
202
+
203
+ - [tree view] Expose one hook per component to initialize the `apiRef` (#20235) @flaviendelangle
204
+ - [tree view] Update the typing of `updateItemChildren()` to accept `null` (#20483) @noraleonte
205
+
206
+ #### `@mui/x-tree-view-pro@8.22.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
207
+
208
+ Same changes as in `@mui/x-tree-view@8.22.0`.
209
+
210
+ ### Codemod
211
+
212
+ #### `@mui/x-codemod@8.22.0`
213
+
214
+ Internal changes.
215
+
216
+ ### Docs
217
+
218
+ - [docs] Add tutorial on building a Data Grid with server-side data (DX-22) (#19782) @mapache-salvaje
219
+ - [docs] Modify the default value for the stacking demo (#20596) @alexfauquette
220
+ - [docs] Revise the Charts Custom Components doc (#19793) @mapache-salvaje
221
+ - [docs] Remove copy-pasted `aria-label` (#20620) @alexfauquette
222
+
223
+ ### Core
224
+
225
+ - [internal] Remove unsafe dependency version from range (#20574) @oliviertassinari
226
+
227
+ ### Miscellaneous
228
+
229
+ - Bump `@mui/monorepo` digest to `800638d` (#20337) @renovate[bot]
230
+ - Bump `@next/eslint-plugin-next` to `15.5.7` (#20575) @renovate[bot]
231
+ - Bump GitHub Actions (#20577) @renovate[bot]
232
+ - Bump Tanstack query to `^5.90.12` (#20582) @renovate[bot]
233
+ - Bump Vite & Vitest (#20583) @renovate[bot]
234
+ - Bump `eslint` to `^8.48.1` (#20576) @renovate[bot]
235
+ - Bump `markdown-to-jsx` to `^9.3.2` (#20507) @renovate[bot]
236
+ - Bump `motion` to `^12.23.25` (#20579) @renovate[bot]
237
+ - Bump react monorepo to `19.2.1` (#20581) @renovate[bot]
238
+ - Bump `react-hook-form` to `^7.68.0` (#20584) @renovate[bot]
239
+ - Bump `react-router` to `^7.10.1` (#20341) @renovate[bot]
240
+ - Bump `tsx` to `^4.21.0` (#20585) @renovate[bot]
241
+ - Bump MUI infra packages (#20478) @renovate[bot]
242
+ - [infra] Automatically add teams to release PRs (#20558) @JCQuintas
243
+ - [infra] Fix codeowners typo (#20562) @JCQuintas
244
+
8
245
  ## 8.21.0
9
246
 
10
247
  _Dec 3, 2025_
@@ -115,7 +352,7 @@ Internal changes.
115
352
  - Bump react-hook-form to ^7.66.1 (#20497) @renovate[bot]
116
353
  - Bump rimraf to ^6.1.2 (#20498) @renovate[bot]
117
354
  - Bump webpack-bundle-analyzer to ^5.0.1 (#20508) @renovate[bot]
118
- - Bump next to ^15.5.6 [SECURITY] (#20555) @renovate[bot]
355
+ - Bump next to ^15.5.7 [SECURITY] (#20555) @renovate[bot]
119
356
 
120
357
  ## 8.20.0
121
358
 
@@ -78,21 +78,25 @@ function GridColumnSortButton(props) {
78
78
  as: rootProps.slots.baseIconButton,
79
79
  ownerState: ownerState,
80
80
  "aria-label": apiRef.current.getLocaleText('columnHeaderSortIconLabel'),
81
- title: apiRef.current.getLocaleText('columnHeaderSortIconLabel'),
82
81
  size: "small",
83
82
  disabled: disabled,
84
83
  className: (0, _clsx.default)(classes.root, className)
85
84
  }, rootProps.slotProps?.baseIconButton, other, {
86
85
  children: iconElement
87
86
  }));
88
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(React.Fragment, {
89
- children: [index != null && /*#__PURE__*/(0, _jsxRuntime.jsx)(rootProps.slots.baseBadge, {
90
- badgeContent: index,
91
- color: "default",
92
- overlap: "circular",
93
- children: iconButton
94
- }), index == null && iconButton]
95
- });
87
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(rootProps.slots.baseTooltip, (0, _extends2.default)({
88
+ title: apiRef.current.getLocaleText('columnHeaderSortIconLabel'),
89
+ enterDelay: 1000
90
+ }, rootProps.slotProps?.baseTooltip, {
91
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
92
+ children: [index != null && /*#__PURE__*/(0, _jsxRuntime.jsx)(rootProps.slots.baseBadge, {
93
+ badgeContent: index,
94
+ color: "default",
95
+ overlap: "circular",
96
+ children: iconButton
97
+ }), index == null && iconButton]
98
+ })
99
+ }));
96
100
  }
97
101
  process.env.NODE_ENV !== "production" ? GridColumnSortButton.propTypes = {
98
102
  // ----------------------------- Warning --------------------------------
@@ -65,13 +65,13 @@ const GridCellCheckboxForwardRef = exports.GridCellCheckboxForwardRef = (0, _for
65
65
  apiRef.current.publishEvent('rowSelectionCheckboxChange', params, event);
66
66
  };
67
67
  React.useLayoutEffect(() => {
68
- if (tabIndex === 0) {
68
+ if (tabIndex === 0 && !disabled) {
69
69
  const element = apiRef.current.getCellElement(id, field);
70
70
  if (element) {
71
71
  element.tabIndex = -1;
72
72
  }
73
73
  }
74
- }, [apiRef, tabIndex, id, field]);
74
+ }, [apiRef, tabIndex, id, field, disabled]);
75
75
  const handleKeyDown = (0, _useEventCallback.default)(event => {
76
76
  if (event.key === ' ') {
77
77
  // We call event.stopPropagation to avoid selecting the row and also scrolling to bottom
@@ -98,12 +98,13 @@ const GridCellCheckboxForwardRef = exports.GridCellCheckboxForwardRef = (0, _for
98
98
  }
99
99
  const label = apiRef.current.getLocaleText(isChecked && !isIndeterminate ? 'checkboxSelectionUnselectRow' : 'checkboxSelectionSelectRow');
100
100
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(rootProps.slots.baseCheckbox, (0, _extends2.default)({
101
- tabIndex: tabIndex,
101
+ tabIndex: disabled ? -1 : tabIndex,
102
102
  checked: isChecked && !isIndeterminate,
103
103
  onChange: handleChange,
104
104
  onClick: handleClick,
105
105
  onMouseDown: handleMouseDown,
106
106
  className: (0, _clsx.default)(classes.root, disabled && 'Mui-disabled'),
107
+ disabled: disabled,
107
108
  material: {
108
109
  disableRipple: disabled
109
110
  },
@@ -2,4 +2,6 @@ import { DataGridProcessedProps } from "../../models/props/DataGridProps.js";
2
2
  export type OwnerState = DataGridProcessedProps;
3
3
  export declare const GridRootStyles: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme> & {
4
4
  ownerState: OwnerState;
5
- }, Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof import("react").ClassAttributes<HTMLDivElement> | keyof import("react").HTMLAttributes<HTMLDivElement>>, {}>;
5
+ }, Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof import("react").ClassAttributes<HTMLDivElement> | keyof import("react").HTMLAttributes<HTMLDivElement>>, {}>;
6
+ export declare const supportsColorMix: boolean;
7
+ export declare const colorMixIfSupported: (colorMixValue: string, fallback: string) => string;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.GridRootStyles = void 0;
6
+ exports.supportsColorMix = exports.colorMixIfSupported = exports.GridRootStyles = void 0;
7
7
  var _styles = require("@mui/material/styles");
8
8
  var _gridClasses = require("../../constants/gridClasses");
9
9
  var _cssVariables = require("../../constants/cssVariables");
@@ -254,19 +254,24 @@ const GridRootStyles = exports.GridRootStyles = (0, _styles.styled)('div', {
254
254
  const selectedOpacity = _cssVariables.vars.colors.interactive.selectedOpacity;
255
255
  const selectedHoverColor = selectedColor;
256
256
  const selectedHoverOpacity = `calc(${selectedOpacity} + ${hoverOpacity})`;
257
- const hoverBackground = mix(baseBackground, hoverColor, hoverOpacity);
258
- const selectedBackground = mix(baseBackground, selectedColor, selectedOpacity);
259
- const selectedHoverBackground = mix(baseBackground, selectedHoverColor, selectedHoverOpacity);
260
- const pinnedHoverBackground = mix(pinnedBackground, hoverColor, hoverOpacity);
261
- const pinnedSelectedBackground = mix(pinnedBackground, selectedColor, selectedOpacity);
262
- const pinnedSelectedHoverBackground = mix(pinnedBackground, selectedHoverColor, selectedHoverOpacity);
257
+ const fallbackColors = {
258
+ hover: _cssVariables.vars.colors.interactive.hover,
259
+ selected: selectedColor,
260
+ selectedHover: selectedColor
261
+ };
262
+ const hoverBackground = mix(baseBackground, hoverColor, hoverOpacity, fallbackColors.hover);
263
+ const selectedBackground = mix(baseBackground, selectedColor, selectedOpacity, fallbackColors.selected);
264
+ const selectedHoverBackground = mix(baseBackground, selectedHoverColor, selectedHoverOpacity, fallbackColors.selectedHover);
265
+ const pinnedHoverBackground = mix(pinnedBackground, hoverColor, hoverOpacity, fallbackColors.hover);
266
+ const pinnedSelectedBackground = mix(pinnedBackground, selectedColor, selectedOpacity, fallbackColors.selected);
267
+ const pinnedSelectedHoverBackground = mix(pinnedBackground, selectedHoverColor, selectedHoverOpacity, fallbackColors.selectedHover);
263
268
  const getPinnedBackgroundStyles = backgroundColor => ({
264
269
  [`& .${_gridClasses.gridClasses['cell--pinnedLeft']}, & .${_gridClasses.gridClasses['cell--pinnedRight']}`]: {
265
270
  backgroundColor,
266
271
  '&.Mui-selected': {
267
- backgroundColor: mix(backgroundColor, selectedBackground, selectedOpacity),
272
+ backgroundColor: mix(backgroundColor, selectedBackground, selectedOpacity, fallbackColors.selected),
268
273
  '&:hover': {
269
- backgroundColor: mix(backgroundColor, selectedHoverBackground, selectedHoverOpacity)
274
+ backgroundColor: mix(backgroundColor, selectedHoverBackground, selectedHoverOpacity, fallbackColors.selectedHover)
270
275
  }
271
276
  }
272
277
  }
@@ -897,6 +902,14 @@ function setOpacity(color, opacity) {
897
902
  function removeOpacity(color) {
898
903
  return setOpacity(color, 1);
899
904
  }
900
- function mix(background, overlay, opacity) {
901
- return `color-mix(in srgb,${background}, ${overlay} calc(${opacity} * 100%))`;
905
+ const supportsColorMix = exports.supportsColorMix = typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('color', 'color-mix(in srgb, red 50%, blue 50%)');
906
+ const colorMixIfSupported = (colorMixValue, fallback) => {
907
+ if (!supportsColorMix) {
908
+ return fallback;
909
+ }
910
+ return colorMixValue;
911
+ };
912
+ exports.colorMixIfSupported = colorMixIfSupported;
913
+ function mix(background, overlay, opacity, fallback) {
914
+ return colorMixIfSupported(`color-mix(in srgb,${background}, ${overlay} calc(${opacity} * 100%))`, fallback);
902
915
  }
@@ -70,21 +70,25 @@ function GridColumnSortButton(props) {
70
70
  as: rootProps.slots.baseIconButton,
71
71
  ownerState: ownerState,
72
72
  "aria-label": apiRef.current.getLocaleText('columnHeaderSortIconLabel'),
73
- title: apiRef.current.getLocaleText('columnHeaderSortIconLabel'),
74
73
  size: "small",
75
74
  disabled: disabled,
76
75
  className: clsx(classes.root, className)
77
76
  }, rootProps.slotProps?.baseIconButton, other, {
78
77
  children: iconElement
79
78
  }));
80
- return /*#__PURE__*/_jsxs(React.Fragment, {
81
- children: [index != null && /*#__PURE__*/_jsx(rootProps.slots.baseBadge, {
82
- badgeContent: index,
83
- color: "default",
84
- overlap: "circular",
85
- children: iconButton
86
- }), index == null && iconButton]
87
- });
79
+ return /*#__PURE__*/_jsx(rootProps.slots.baseTooltip, _extends({
80
+ title: apiRef.current.getLocaleText('columnHeaderSortIconLabel'),
81
+ enterDelay: 1000
82
+ }, rootProps.slotProps?.baseTooltip, {
83
+ children: /*#__PURE__*/_jsxs("span", {
84
+ children: [index != null && /*#__PURE__*/_jsx(rootProps.slots.baseBadge, {
85
+ badgeContent: index,
86
+ color: "default",
87
+ overlap: "circular",
88
+ children: iconButton
89
+ }), index == null && iconButton]
90
+ })
91
+ }));
88
92
  }
89
93
  process.env.NODE_ENV !== "production" ? GridColumnSortButton.propTypes = {
90
94
  // ----------------------------- Warning --------------------------------
@@ -58,13 +58,13 @@ const GridCellCheckboxForwardRef = forwardRef(function GridCellCheckboxRenderer(
58
58
  apiRef.current.publishEvent('rowSelectionCheckboxChange', params, event);
59
59
  };
60
60
  React.useLayoutEffect(() => {
61
- if (tabIndex === 0) {
61
+ if (tabIndex === 0 && !disabled) {
62
62
  const element = apiRef.current.getCellElement(id, field);
63
63
  if (element) {
64
64
  element.tabIndex = -1;
65
65
  }
66
66
  }
67
- }, [apiRef, tabIndex, id, field]);
67
+ }, [apiRef, tabIndex, id, field, disabled]);
68
68
  const handleKeyDown = useEventCallback(event => {
69
69
  if (event.key === ' ') {
70
70
  // We call event.stopPropagation to avoid selecting the row and also scrolling to bottom
@@ -91,12 +91,13 @@ const GridCellCheckboxForwardRef = forwardRef(function GridCellCheckboxRenderer(
91
91
  }
92
92
  const label = apiRef.current.getLocaleText(isChecked && !isIndeterminate ? 'checkboxSelectionUnselectRow' : 'checkboxSelectionSelectRow');
93
93
  return /*#__PURE__*/_jsx(rootProps.slots.baseCheckbox, _extends({
94
- tabIndex: tabIndex,
94
+ tabIndex: disabled ? -1 : tabIndex,
95
95
  checked: isChecked && !isIndeterminate,
96
96
  onChange: handleChange,
97
97
  onClick: handleClick,
98
98
  onMouseDown: handleMouseDown,
99
99
  className: clsx(classes.root, disabled && 'Mui-disabled'),
100
+ disabled: disabled,
100
101
  material: {
101
102
  disableRipple: disabled
102
103
  },
@@ -2,4 +2,6 @@ import { DataGridProcessedProps } from "../../models/props/DataGridProps.js";
2
2
  export type OwnerState = DataGridProcessedProps;
3
3
  export declare const GridRootStyles: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme> & {
4
4
  ownerState: OwnerState;
5
- }, Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof import("react").ClassAttributes<HTMLDivElement> | keyof import("react").HTMLAttributes<HTMLDivElement>>, {}>;
5
+ }, Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof import("react").ClassAttributes<HTMLDivElement> | keyof import("react").HTMLAttributes<HTMLDivElement>>, {}>;
6
+ export declare const supportsColorMix: boolean;
7
+ export declare const colorMixIfSupported: (colorMixValue: string, fallback: string) => string;
@@ -248,19 +248,24 @@ export const GridRootStyles = styled('div', {
248
248
  const selectedOpacity = vars.colors.interactive.selectedOpacity;
249
249
  const selectedHoverColor = selectedColor;
250
250
  const selectedHoverOpacity = `calc(${selectedOpacity} + ${hoverOpacity})`;
251
- const hoverBackground = mix(baseBackground, hoverColor, hoverOpacity);
252
- const selectedBackground = mix(baseBackground, selectedColor, selectedOpacity);
253
- const selectedHoverBackground = mix(baseBackground, selectedHoverColor, selectedHoverOpacity);
254
- const pinnedHoverBackground = mix(pinnedBackground, hoverColor, hoverOpacity);
255
- const pinnedSelectedBackground = mix(pinnedBackground, selectedColor, selectedOpacity);
256
- const pinnedSelectedHoverBackground = mix(pinnedBackground, selectedHoverColor, selectedHoverOpacity);
251
+ const fallbackColors = {
252
+ hover: vars.colors.interactive.hover,
253
+ selected: selectedColor,
254
+ selectedHover: selectedColor
255
+ };
256
+ const hoverBackground = mix(baseBackground, hoverColor, hoverOpacity, fallbackColors.hover);
257
+ const selectedBackground = mix(baseBackground, selectedColor, selectedOpacity, fallbackColors.selected);
258
+ const selectedHoverBackground = mix(baseBackground, selectedHoverColor, selectedHoverOpacity, fallbackColors.selectedHover);
259
+ const pinnedHoverBackground = mix(pinnedBackground, hoverColor, hoverOpacity, fallbackColors.hover);
260
+ const pinnedSelectedBackground = mix(pinnedBackground, selectedColor, selectedOpacity, fallbackColors.selected);
261
+ const pinnedSelectedHoverBackground = mix(pinnedBackground, selectedHoverColor, selectedHoverOpacity, fallbackColors.selectedHover);
257
262
  const getPinnedBackgroundStyles = backgroundColor => ({
258
263
  [`& .${c['cell--pinnedLeft']}, & .${c['cell--pinnedRight']}`]: {
259
264
  backgroundColor,
260
265
  '&.Mui-selected': {
261
- backgroundColor: mix(backgroundColor, selectedBackground, selectedOpacity),
266
+ backgroundColor: mix(backgroundColor, selectedBackground, selectedOpacity, fallbackColors.selected),
262
267
  '&:hover': {
263
- backgroundColor: mix(backgroundColor, selectedHoverBackground, selectedHoverOpacity)
268
+ backgroundColor: mix(backgroundColor, selectedHoverBackground, selectedHoverOpacity, fallbackColors.selectedHover)
264
269
  }
265
270
  }
266
271
  }
@@ -891,6 +896,13 @@ function setOpacity(color, opacity) {
891
896
  function removeOpacity(color) {
892
897
  return setOpacity(color, 1);
893
898
  }
894
- function mix(background, overlay, opacity) {
895
- return `color-mix(in srgb,${background}, ${overlay} calc(${opacity} * 100%))`;
899
+ export const supportsColorMix = typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('color', 'color-mix(in srgb, red 50%, blue 50%)');
900
+ export const colorMixIfSupported = (colorMixValue, fallback) => {
901
+ if (!supportsColorMix) {
902
+ return fallback;
903
+ }
904
+ return colorMixValue;
905
+ };
906
+ function mix(background, overlay, opacity, fallback) {
907
+ return colorMixIfSupported(`color-mix(in srgb,${background}, ${overlay} calc(${opacity} * 100%))`, fallback);
896
908
  }
@@ -7,7 +7,8 @@ export const propsStateInitializer = (state, props) => {
7
7
  props: {
8
8
  listView: props.listView,
9
9
  getRowId: props.getRowId,
10
- isCellEditable: props.isCellEditable
10
+ isCellEditable: props.isCellEditable,
11
+ isRowSelectable: props.isRowSelectable
11
12
  }
12
13
  });
13
14
  };
@@ -17,6 +17,7 @@ import { useTimeout } from "../../utils/useTimeout.js";
17
17
  import { GridPinnedColumnPosition } from "../columns/gridColumnsInterfaces.js";
18
18
  import { gridColumnsStateSelector } from "../columns/index.js";
19
19
  import { gridDimensionsSelector } from "../dimensions/index.js";
20
+ import { gridResizingColumnFieldSelector } from "./columnResizeSelector.js";
20
21
  function trackFinger(event, currentTouchId) {
21
22
  if (currentTouchId !== undefined && event.changedTouches) {
22
23
  for (let i = 0; i < event.changedTouches.length; i += 1) {
@@ -320,6 +321,11 @@ export const useGridColumnResize = (apiRef, props) => {
320
321
  apiRef.current.publishEvent('columnResizeStop', null, nativeEvent);
321
322
  });
322
323
  };
324
+ const setCellElementsRef = () => {
325
+ if (refs.columnHeaderElement) {
326
+ refs.cellElements = findGridCellElementsFromCol(refs.columnHeaderElement, apiRef.current);
327
+ }
328
+ };
323
329
  const storeReferences = (colDef, separator, xStart) => {
324
330
  const root = apiRef.current.rootElementRef.current;
325
331
  refs.initialColWidth = colDef.computedWidth;
@@ -331,7 +337,7 @@ export const useGridColumnResize = (apiRef, props) => {
331
337
  refs.headerFilterElement = headerFilterElement;
332
338
  }
333
339
  refs.groupHeaderElements = findGroupHeaderElementsFromField(apiRef.current.columnHeadersContainerRef?.current, colDef.field);
334
- refs.cellElements = findGridCellElementsFromCol(refs.columnHeaderElement, apiRef.current);
340
+ setCellElementsRef();
335
341
  refs.fillerLeft = findGridElement(apiRef.current, isRtl ? 'filler--pinnedRight' : 'filler--pinnedLeft');
336
342
  refs.fillerRight = findGridElement(apiRef.current, isRtl ? 'filler--pinnedLeft' : 'filler--pinnedRight');
337
343
  const pinnedPosition = apiRef.current.unstable_applyPipeProcessors('isColumnPinned', false, refs.colDef.field);
@@ -578,6 +584,15 @@ export const useGridColumnResize = (apiRef, props) => {
578
584
  useGridEvent(apiRef, 'columnResizeStart', handleResizeStart);
579
585
  useGridEvent(apiRef, 'columnSeparatorMouseDown', handleColumnResizeMouseDown);
580
586
  useGridEvent(apiRef, 'columnSeparatorDoubleClick', handleColumnSeparatorDoubleClick);
587
+ useGridEvent(apiRef, 'rowsSet', () => {
588
+ // if the user is still resizing the column, update the cell references included in the resize action
589
+ if (gridResizingColumnFieldSelector(apiRef) !== '') {
590
+ // wait until the rows are in the DOM
591
+ requestAnimationFrame(() => {
592
+ setCellElementsRef();
593
+ });
594
+ }
595
+ });
581
596
  useGridEventPriority(apiRef, 'columnResize', props.onColumnResize);
582
597
  useGridEventPriority(apiRef, 'columnWidthChange', props.onColumnWidthChange);
583
598
  };
@@ -283,9 +283,17 @@ export const createColumnsState = ({
283
283
  }
284
284
  }
285
285
  });
286
- columnsState.lookup[field] = resolveProps(existingState, _extends({}, getDefaultColTypeDef(newColumn.type), newColumn, {
287
- hasBeenResized
288
- }));
286
+ const mergedProps = _extends({}, getDefaultColTypeDef(newColumn.type), {
287
+ hasBeenResized,
288
+ field
289
+ });
290
+ let key;
291
+ for (key in newColumn) {
292
+ if (newColumn[key] !== undefined && key !== 'field') {
293
+ mergedProps[key] = newColumn[key];
294
+ }
295
+ }
296
+ columnsState.lookup[field] = resolveProps(existingState, mergedProps);
289
297
  });
290
298
  if (keepOnlyColumnsToUpsert && !isInsideStateInitializer) {
291
299
  Object.keys(columnsState.lookup).forEach(field => {
@@ -106,7 +106,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
106
106
  // There is one exception for the checkBoxHeader
107
107
  return;
108
108
  }
109
- if (!isNavigationKey(event.key) && event.key !== 'Tab') {
109
+ if (!isNavigationKey(event.key) && event.key !== 'Tab' && event.key !== 'Enter') {
110
110
  return;
111
111
  }
112
112
 
@@ -63,10 +63,21 @@ export const checkboxPropsSelector = createSelector(gridColumnDefinitionsSelecto
63
63
  if (node?.type === 'group') {
64
64
  node.children.forEach(traverseDescendants);
65
65
  }
66
- if (rowSelectionManager.has(itemToTraverseId)) {
67
- hasSelectedDescendant = true;
68
- } else {
69
- hasUnSelectedDescendant = true;
66
+ // Check if row is selectable before considering it for parent selection state
67
+ const descendantRowParams = {
68
+ id: itemToTraverseId,
69
+ row: rowsLookup[itemToTraverseId],
70
+ columns
71
+ };
72
+ const rowIsSelectable = typeof isRowSelectable === 'function' ? isRowSelectable(descendantRowParams) : true;
73
+
74
+ // Only consider selectable rows when determining parent selection state
75
+ if (rowIsSelectable) {
76
+ if (rowSelectionManager.has(itemToTraverseId)) {
77
+ hasSelectedDescendant = true;
78
+ } else {
79
+ hasUnSelectedDescendant = true;
80
+ }
70
81
  }
71
82
  };
72
83
  traverseDescendants(groupId);
@@ -126,21 +137,37 @@ export const findRowsToSelect = (apiRef, tree, selectedRow, autoSelectDescendant
126
137
  }
127
138
  if (autoSelectParents) {
128
139
  const checkAllDescendantsSelected = rowId => {
129
- if (!rowSelectionManager.has(rowId) && !selectedDescendants.has(rowId)) {
130
- return false;
131
- }
132
140
  const node = tree[rowId];
133
141
  if (!node) {
134
142
  return false;
135
143
  }
144
+ // For non-group nodes, check if it's selected or if it's non-selectable
136
145
  if (node.type !== 'group') {
146
+ // If the row is selectable, it must be selected
147
+ if (apiRef.current.isRowSelectable(rowId)) {
148
+ return rowSelectionManager.has(rowId) || selectedDescendants.has(rowId);
149
+ }
150
+ // Non-selectable rows don't affect parent selection
137
151
  return true;
138
152
  }
153
+ // For group nodes, check if it's selected or all its children are selected
154
+ if (rowSelectionManager.has(rowId) || selectedDescendants.has(rowId)) {
155
+ return true;
156
+ }
157
+ // Recursively check all children
139
158
  return node.children.every(checkAllDescendantsSelected);
140
159
  };
141
160
  const traverseParents = rowId => {
142
161
  const siblings = getFilteredRowNodeSiblings(tree, filteredRows, rowId);
143
- if (siblings.length === 0 || siblings.every(checkAllDescendantsSelected)) {
162
+ // Check if all selectable siblings are selected
163
+ const allSelectableSiblingsSelected = siblings.every(siblingId => {
164
+ // Non-selectable siblings don't affect parent selection
165
+ if (!apiRef.current.isRowSelectable(siblingId)) {
166
+ return true;
167
+ }
168
+ return checkAllDescendantsSelected(siblingId);
169
+ });
170
+ if (siblings.length === 0 || allSelectableSiblingsSelected) {
144
171
  const rowNode = tree[rowId];
145
172
  const parent = rowNode?.parent;
146
173
  if (parent != null && parent !== GRID_ROOT_GROUP_ID && apiRef.current.isRowSelectable(parent)) {
@@ -191,6 +191,7 @@ export const useGridRowSpanning = (apiRef, props) => {
191
191
  useGridEvent(apiRef, 'paginationModelChange', runIf(props.rowSpanning, resetRowSpanningState));
192
192
  useGridEvent(apiRef, 'filteredRowsSet', runIf(props.rowSpanning, resetRowSpanningState));
193
193
  useGridEvent(apiRef, 'columnsChange', runIf(props.rowSpanning, resetRowSpanningState));
194
+ useGridEvent(apiRef, 'rowExpansionChange', runIf(props.rowSpanning, resetRowSpanningState));
194
195
  React.useEffect(() => {
195
196
  const store = apiRef.current.virtualizer?.store;
196
197
  if (!store) {
package/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v8.21.0
2
+ * @mui/x-data-grid v8.22.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -3,8 +3,8 @@ const svSEGrid = {
3
3
  // Root
4
4
  noRowsLabel: 'Inga rader',
5
5
  noResultsOverlayLabel: 'Inga resultat funna.',
6
- // noColumnsOverlayLabel: 'No columns',
7
- // noColumnsOverlayManageColumns: 'Manage columns',
6
+ noColumnsOverlayLabel: 'Inga kolumner',
7
+ noColumnsOverlayManageColumns: 'Hantera kolumner',
8
8
  // emptyPivotOverlayLabel: 'Add fields to rows, columns, and values to create a pivot table',
9
9
 
10
10
  // Density selector toolbar button text
@@ -29,7 +29,7 @@ import * as React from 'react';
29
29
  import clsx from 'clsx';
30
30
  import useForkRef from '@mui/utils/useForkRef';
31
31
  import useEventCallback from '@mui/utils/useEventCallback';
32
- import { styled } from '@mui/material/styles';
32
+ import { styled, useTheme } from '@mui/material/styles';
33
33
  import MUIAutocomplete from '@mui/material/Autocomplete';
34
34
  import MUIBadge from '@mui/material/Badge';
35
35
  import MUICheckbox from '@mui/material/Checkbox';
@@ -142,6 +142,10 @@ const BaseSelect = forwardRef(function BaseSelect(props, ref) {
142
142
  fullWidth
143
143
  } = props,
144
144
  other = _objectWithoutPropertiesLoose(props, _excluded);
145
+ const theme = useTheme();
146
+ const textFieldDefaults = theme.components?.MuiTextField?.defaultProps ?? {};
147
+ const computedSize = size ?? textFieldDefaults.size;
148
+ const computedVariant = textFieldDefaults.variant ?? 'outlined';
145
149
  const menuProps = {
146
150
  PaperProps: {
147
151
  onKeyDown
@@ -151,7 +155,7 @@ const BaseSelect = forwardRef(function BaseSelect(props, ref) {
151
155
  menuProps.onClose = onClose;
152
156
  }
153
157
  return /*#__PURE__*/_jsxs(MUIFormControl, {
154
- size: size,
158
+ size: computedSize,
155
159
  fullWidth: fullWidth,
156
160
  style: style,
157
161
  disabled: disabled,
@@ -160,7 +164,7 @@ const BaseSelect = forwardRef(function BaseSelect(props, ref) {
160
164
  id: labelId,
161
165
  htmlFor: id,
162
166
  shrink: true,
163
- variant: "outlined",
167
+ variant: computedVariant,
164
168
  children: label
165
169
  }), /*#__PURE__*/_jsx(MUISelect, _extends({
166
170
  id: id,
@@ -168,13 +172,12 @@ const BaseSelect = forwardRef(function BaseSelect(props, ref) {
168
172
  label: label,
169
173
  displayEmpty: true,
170
174
  onChange: onChange,
171
- variant: "outlined"
175
+ variant: computedVariant
172
176
  }, other, {
173
- notched: true,
174
177
  inputProps: slotProps?.htmlInput,
175
178
  onOpen: onOpen,
176
179
  MenuProps: menuProps,
177
- size: size
180
+ size: computedSize
178
181
  }, material))]
179
182
  });
180
183
  });
@@ -449,8 +452,13 @@ function BaseTextField(props) {
449
452
  material
450
453
  } = props,
451
454
  other = _objectWithoutPropertiesLoose(props, _excluded15);
455
+ const theme = useTheme();
456
+ const textFieldDefaults = theme.components?.MuiTextField?.defaultProps ?? {};
457
+ const computedVariant = other.variant ?? textFieldDefaults.variant ?? 'outlined';
458
+ const computedSize = other.size ?? textFieldDefaults.size;
452
459
  return /*#__PURE__*/_jsx(MUITextField, _extends({
453
- variant: "outlined"
460
+ variant: computedVariant,
461
+ size: computedSize
454
462
  }, other, material, {
455
463
  inputProps: slotProps?.htmlInput,
456
464
  InputProps: transformInputProps(slotProps?.input),
@@ -3,6 +3,7 @@ import { alpha, darken, lighten } from '@mui/material/styles';
3
3
  import { useTheme } from '@mui/material/styles';
4
4
  import { hash } from '@mui/x-internals/hash';
5
5
  import { vars } from "../constants/cssVariables.js";
6
+ import { colorMixIfSupported, supportsColorMix } from "../components/containers/GridRootStyles.js";
6
7
  export function useMaterialCSSVariables() {
7
8
  const theme = useTheme();
8
9
  return React.useMemo(() => {
@@ -17,11 +18,12 @@ export function useMaterialCSSVariables() {
17
18
  function transformTheme(t) {
18
19
  const borderColor = getBorderColor(t);
19
20
  const dataGridPalette = (t.vars || t).palette.DataGrid;
20
- const backgroundBase = dataGridPalette?.bg ?? (t.palette.mode === 'dark' ? `color-mix(in srgb, ${(t.vars || t).palette.background.paper} 95%, #fff)` : (t.vars || t).palette.background.paper);
21
+ const paperColor = (t.vars || t).palette.background.paper;
22
+ const backgroundBase = dataGridPalette?.bg ?? (t.palette.mode === 'dark' ? colorMixIfSupported(`color-mix(in srgb, ${paperColor} 95%, #fff)`, paperColor) : paperColor);
21
23
  const backgroundHeader = dataGridPalette?.headerBg ?? backgroundBase;
22
24
  const backgroundPinned = dataGridPalette?.pinnedBg ?? backgroundBase;
23
25
  const backgroundBackdrop = t.vars ? `rgba(${t.vars.palette.background.defaultChannel} / ${t.vars.palette.action.disabledOpacity})` : alpha(t.palette.background.default, t.palette.action.disabledOpacity);
24
- const backgroundOverlay = t.palette.mode === 'dark' ? `color-mix(in srgb, ${(t.vars || t).palette.background.paper} 90%, #fff)` : (t.vars || t).palette.background.paper;
26
+ const backgroundOverlay = t.palette.mode === 'dark' ? colorMixIfSupported(`color-mix(in srgb, ${paperColor} 90%, #fff)`, paperColor) : paperColor;
25
27
  const selectedColor = t.vars ? `rgb(${t.vars.palette.primary.mainChannel})` : t.palette.primary.main;
26
28
  const radius = getRadius(t);
27
29
  const fontBody = t.vars?.font?.body2 ?? formatFont(t.typography.body2);
@@ -39,13 +41,13 @@ function transformTheme(t) {
39
41
  [k.colors.foreground.accent]: (t.vars || t).palette.primary.dark,
40
42
  [k.colors.foreground.disabled]: (t.vars || t).palette.text.disabled,
41
43
  [k.colors.foreground.error]: (t.vars || t).palette.error.dark,
42
- [k.colors.interactive.hover]: (t.vars || t).palette.action.hover,
44
+ [k.colors.interactive.hover]: supportsColorMix ? (t.vars || t).palette.action.hover : (t.vars || t).palette.grey[t.palette.mode === 'dark' ? 800 : 100],
43
45
  [k.colors.interactive.hoverOpacity]: (t.vars || t).palette.action.hoverOpacity,
44
46
  [k.colors.interactive.focus]: removeOpacity((t.vars || t).palette.primary.main),
45
47
  [k.colors.interactive.focusOpacity]: (t.vars || t).palette.action.focusOpacity,
46
48
  [k.colors.interactive.disabled]: removeOpacity((t.vars || t).palette.action.disabled),
47
49
  [k.colors.interactive.disabledOpacity]: (t.vars || t).palette.action.disabledOpacity,
48
- [k.colors.interactive.selected]: selectedColor,
50
+ [k.colors.interactive.selected]: supportsColorMix ? selectedColor : (t.vars || t).palette.grey[t.palette.mode === 'dark' ? 700 : 200],
49
51
  [k.colors.interactive.selectedOpacity]: (t.vars || t).palette.action.selectedOpacity,
50
52
  [k.header.background.base]: backgroundHeader,
51
53
  [k.cell.background.pinned]: backgroundPinned,
@@ -1,5 +1,3 @@
1
- /* eslint-disable */
2
-
3
1
  /**
4
2
  * HACK: Minimal shim to get jsdom to work.
5
3
  */
@@ -14,7 +14,8 @@ const propsStateInitializer = (state, props) => {
14
14
  props: {
15
15
  listView: props.listView,
16
16
  getRowId: props.getRowId,
17
- isCellEditable: props.isCellEditable
17
+ isCellEditable: props.isCellEditable,
18
+ isRowSelectable: props.isRowSelectable
18
19
  }
19
20
  });
20
21
  };
@@ -24,6 +24,7 @@ var _useTimeout = require("../../utils/useTimeout");
24
24
  var _gridColumnsInterfaces = require("../columns/gridColumnsInterfaces");
25
25
  var _columns = require("../columns");
26
26
  var _dimensions = require("../dimensions");
27
+ var _columnResizeSelector = require("./columnResizeSelector");
27
28
  function trackFinger(event, currentTouchId) {
28
29
  if (currentTouchId !== undefined && event.changedTouches) {
29
30
  for (let i = 0; i < event.changedTouches.length; i += 1) {
@@ -328,6 +329,11 @@ const useGridColumnResize = (apiRef, props) => {
328
329
  apiRef.current.publishEvent('columnResizeStop', null, nativeEvent);
329
330
  });
330
331
  };
332
+ const setCellElementsRef = () => {
333
+ if (refs.columnHeaderElement) {
334
+ refs.cellElements = (0, _domUtils.findGridCellElementsFromCol)(refs.columnHeaderElement, apiRef.current);
335
+ }
336
+ };
331
337
  const storeReferences = (colDef, separator, xStart) => {
332
338
  const root = apiRef.current.rootElementRef.current;
333
339
  refs.initialColWidth = colDef.computedWidth;
@@ -339,7 +345,7 @@ const useGridColumnResize = (apiRef, props) => {
339
345
  refs.headerFilterElement = headerFilterElement;
340
346
  }
341
347
  refs.groupHeaderElements = (0, _domUtils.findGroupHeaderElementsFromField)(apiRef.current.columnHeadersContainerRef?.current, colDef.field);
342
- refs.cellElements = (0, _domUtils.findGridCellElementsFromCol)(refs.columnHeaderElement, apiRef.current);
348
+ setCellElementsRef();
343
349
  refs.fillerLeft = (0, _domUtils.findGridElement)(apiRef.current, isRtl ? 'filler--pinnedRight' : 'filler--pinnedLeft');
344
350
  refs.fillerRight = (0, _domUtils.findGridElement)(apiRef.current, isRtl ? 'filler--pinnedLeft' : 'filler--pinnedRight');
345
351
  const pinnedPosition = apiRef.current.unstable_applyPipeProcessors('isColumnPinned', false, refs.colDef.field);
@@ -586,6 +592,15 @@ const useGridColumnResize = (apiRef, props) => {
586
592
  (0, _utils.useGridEvent)(apiRef, 'columnResizeStart', handleResizeStart);
587
593
  (0, _utils.useGridEvent)(apiRef, 'columnSeparatorMouseDown', handleColumnResizeMouseDown);
588
594
  (0, _utils.useGridEvent)(apiRef, 'columnSeparatorDoubleClick', handleColumnSeparatorDoubleClick);
595
+ (0, _utils.useGridEvent)(apiRef, 'rowsSet', () => {
596
+ // if the user is still resizing the column, update the cell references included in the resize action
597
+ if ((0, _columnResizeSelector.gridResizingColumnFieldSelector)(apiRef) !== '') {
598
+ // wait until the rows are in the DOM
599
+ requestAnimationFrame(() => {
600
+ setCellElementsRef();
601
+ });
602
+ }
603
+ });
589
604
  (0, _utils.useGridEventPriority)(apiRef, 'columnResize', props.onColumnResize);
590
605
  (0, _utils.useGridEventPriority)(apiRef, 'columnWidthChange', props.onColumnWidthChange);
591
606
  };
@@ -298,9 +298,17 @@ const createColumnsState = ({
298
298
  }
299
299
  }
300
300
  });
301
- columnsState.lookup[field] = (0, _resolveProps.default)(existingState, (0, _extends2.default)({}, getDefaultColTypeDef(newColumn.type), newColumn, {
302
- hasBeenResized
303
- }));
301
+ const mergedProps = (0, _extends2.default)({}, getDefaultColTypeDef(newColumn.type), {
302
+ hasBeenResized,
303
+ field
304
+ });
305
+ let key;
306
+ for (key in newColumn) {
307
+ if (newColumn[key] !== undefined && key !== 'field') {
308
+ mergedProps[key] = newColumn[key];
309
+ }
310
+ }
311
+ columnsState.lookup[field] = (0, _resolveProps.default)(existingState, mergedProps);
304
312
  });
305
313
  if (keepOnlyColumnsToUpsert && !isInsideStateInitializer) {
306
314
  Object.keys(columnsState.lookup).forEach(field => {
@@ -113,7 +113,7 @@ const useGridKeyboardNavigation = (apiRef, props) => {
113
113
  // There is one exception for the checkBoxHeader
114
114
  return;
115
115
  }
116
- if (!(0, _keyboardUtils.isNavigationKey)(event.key) && event.key !== 'Tab') {
116
+ if (!(0, _keyboardUtils.isNavigationKey)(event.key) && event.key !== 'Tab' && event.key !== 'Enter') {
117
117
  return;
118
118
  }
119
119
 
@@ -70,10 +70,21 @@ const checkboxPropsSelector = exports.checkboxPropsSelector = (0, _createSelecto
70
70
  if (node?.type === 'group') {
71
71
  node.children.forEach(traverseDescendants);
72
72
  }
73
- if (rowSelectionManager.has(itemToTraverseId)) {
74
- hasSelectedDescendant = true;
75
- } else {
76
- hasUnSelectedDescendant = true;
73
+ // Check if row is selectable before considering it for parent selection state
74
+ const descendantRowParams = {
75
+ id: itemToTraverseId,
76
+ row: rowsLookup[itemToTraverseId],
77
+ columns
78
+ };
79
+ const rowIsSelectable = typeof isRowSelectable === 'function' ? isRowSelectable(descendantRowParams) : true;
80
+
81
+ // Only consider selectable rows when determining parent selection state
82
+ if (rowIsSelectable) {
83
+ if (rowSelectionManager.has(itemToTraverseId)) {
84
+ hasSelectedDescendant = true;
85
+ } else {
86
+ hasUnSelectedDescendant = true;
87
+ }
77
88
  }
78
89
  };
79
90
  traverseDescendants(groupId);
@@ -133,21 +144,37 @@ const findRowsToSelect = (apiRef, tree, selectedRow, autoSelectDescendants, auto
133
144
  }
134
145
  if (autoSelectParents) {
135
146
  const checkAllDescendantsSelected = rowId => {
136
- if (!rowSelectionManager.has(rowId) && !selectedDescendants.has(rowId)) {
137
- return false;
138
- }
139
147
  const node = tree[rowId];
140
148
  if (!node) {
141
149
  return false;
142
150
  }
151
+ // For non-group nodes, check if it's selected or if it's non-selectable
143
152
  if (node.type !== 'group') {
153
+ // If the row is selectable, it must be selected
154
+ if (apiRef.current.isRowSelectable(rowId)) {
155
+ return rowSelectionManager.has(rowId) || selectedDescendants.has(rowId);
156
+ }
157
+ // Non-selectable rows don't affect parent selection
158
+ return true;
159
+ }
160
+ // For group nodes, check if it's selected or all its children are selected
161
+ if (rowSelectionManager.has(rowId) || selectedDescendants.has(rowId)) {
144
162
  return true;
145
163
  }
164
+ // Recursively check all children
146
165
  return node.children.every(checkAllDescendantsSelected);
147
166
  };
148
167
  const traverseParents = rowId => {
149
168
  const siblings = getFilteredRowNodeSiblings(tree, filteredRows, rowId);
150
- if (siblings.length === 0 || siblings.every(checkAllDescendantsSelected)) {
169
+ // Check if all selectable siblings are selected
170
+ const allSelectableSiblingsSelected = siblings.every(siblingId => {
171
+ // Non-selectable siblings don't affect parent selection
172
+ if (!apiRef.current.isRowSelectable(siblingId)) {
173
+ return true;
174
+ }
175
+ return checkAllDescendantsSelected(siblingId);
176
+ });
177
+ if (siblings.length === 0 || allSelectableSiblingsSelected) {
151
178
  const rowNode = tree[rowId];
152
179
  const parent = rowNode?.parent;
153
180
  if (parent != null && parent !== _gridRowsUtils.GRID_ROOT_GROUP_ID && apiRef.current.isRowSelectable(parent)) {
@@ -199,6 +199,7 @@ const useGridRowSpanning = (apiRef, props) => {
199
199
  (0, _useGridEvent.useGridEvent)(apiRef, 'paginationModelChange', (0, _utils.runIf)(props.rowSpanning, resetRowSpanningState));
200
200
  (0, _useGridEvent.useGridEvent)(apiRef, 'filteredRowsSet', (0, _utils.runIf)(props.rowSpanning, resetRowSpanningState));
201
201
  (0, _useGridEvent.useGridEvent)(apiRef, 'columnsChange', (0, _utils.runIf)(props.rowSpanning, resetRowSpanningState));
202
+ (0, _useGridEvent.useGridEvent)(apiRef, 'rowExpansionChange', (0, _utils.runIf)(props.rowSpanning, resetRowSpanningState));
202
203
  React.useEffect(() => {
203
204
  const store = apiRef.current.virtualizer?.store;
204
205
  if (!store) {
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v8.21.0
2
+ * @mui/x-data-grid v8.22.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
package/locales/svSE.js CHANGED
@@ -9,8 +9,8 @@ const svSEGrid = {
9
9
  // Root
10
10
  noRowsLabel: 'Inga rader',
11
11
  noResultsOverlayLabel: 'Inga resultat funna.',
12
- // noColumnsOverlayLabel: 'No columns',
13
- // noColumnsOverlayManageColumns: 'Manage columns',
12
+ noColumnsOverlayLabel: 'Inga kolumner',
13
+ noColumnsOverlayManageColumns: 'Hantera kolumner',
14
14
  // emptyPivotOverlayLabel: 'Add fields to rows, columns, and values to create a pivot table',
15
15
 
16
16
  // Density selector toolbar button text
package/material/index.js CHANGED
@@ -155,6 +155,10 @@ const BaseSelect = (0, _forwardRef.forwardRef)(function BaseSelect(props, ref) {
155
155
  fullWidth
156
156
  } = props,
157
157
  other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
158
+ const theme = (0, _styles.useTheme)();
159
+ const textFieldDefaults = theme.components?.MuiTextField?.defaultProps ?? {};
160
+ const computedSize = size ?? textFieldDefaults.size;
161
+ const computedVariant = textFieldDefaults.variant ?? 'outlined';
158
162
  const menuProps = {
159
163
  PaperProps: {
160
164
  onKeyDown
@@ -164,7 +168,7 @@ const BaseSelect = (0, _forwardRef.forwardRef)(function BaseSelect(props, ref) {
164
168
  menuProps.onClose = onClose;
165
169
  }
166
170
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_FormControl.default, {
167
- size: size,
171
+ size: computedSize,
168
172
  fullWidth: fullWidth,
169
173
  style: style,
170
174
  disabled: disabled,
@@ -173,7 +177,7 @@ const BaseSelect = (0, _forwardRef.forwardRef)(function BaseSelect(props, ref) {
173
177
  id: labelId,
174
178
  htmlFor: id,
175
179
  shrink: true,
176
- variant: "outlined",
180
+ variant: computedVariant,
177
181
  children: label
178
182
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Select.default, (0, _extends2.default)({
179
183
  id: id,
@@ -181,13 +185,12 @@ const BaseSelect = (0, _forwardRef.forwardRef)(function BaseSelect(props, ref) {
181
185
  label: label,
182
186
  displayEmpty: true,
183
187
  onChange: onChange,
184
- variant: "outlined"
188
+ variant: computedVariant
185
189
  }, other, {
186
- notched: true,
187
190
  inputProps: slotProps?.htmlInput,
188
191
  onOpen: onOpen,
189
192
  MenuProps: menuProps,
190
- size: size
193
+ size: computedSize
191
194
  }, material))]
192
195
  });
193
196
  });
@@ -462,8 +465,13 @@ function BaseTextField(props) {
462
465
  material
463
466
  } = props,
464
467
  other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded15);
468
+ const theme = (0, _styles.useTheme)();
469
+ const textFieldDefaults = theme.components?.MuiTextField?.defaultProps ?? {};
470
+ const computedVariant = other.variant ?? textFieldDefaults.variant ?? 'outlined';
471
+ const computedSize = other.size ?? textFieldDefaults.size;
465
472
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, (0, _extends2.default)({
466
- variant: "outlined"
473
+ variant: computedVariant,
474
+ size: computedSize
467
475
  }, other, material, {
468
476
  inputProps: slotProps?.htmlInput,
469
477
  InputProps: transformInputProps(slotProps?.input),
@@ -9,6 +9,7 @@ var React = _interopRequireWildcard(require("react"));
9
9
  var _styles = require("@mui/material/styles");
10
10
  var _hash = require("@mui/x-internals/hash");
11
11
  var _cssVariables = require("../constants/cssVariables");
12
+ var _GridRootStyles = require("../components/containers/GridRootStyles");
12
13
  function useMaterialCSSVariables() {
13
14
  const theme = (0, _styles.useTheme)();
14
15
  return React.useMemo(() => {
@@ -23,11 +24,12 @@ function useMaterialCSSVariables() {
23
24
  function transformTheme(t) {
24
25
  const borderColor = getBorderColor(t);
25
26
  const dataGridPalette = (t.vars || t).palette.DataGrid;
26
- const backgroundBase = dataGridPalette?.bg ?? (t.palette.mode === 'dark' ? `color-mix(in srgb, ${(t.vars || t).palette.background.paper} 95%, #fff)` : (t.vars || t).palette.background.paper);
27
+ const paperColor = (t.vars || t).palette.background.paper;
28
+ const backgroundBase = dataGridPalette?.bg ?? (t.palette.mode === 'dark' ? (0, _GridRootStyles.colorMixIfSupported)(`color-mix(in srgb, ${paperColor} 95%, #fff)`, paperColor) : paperColor);
27
29
  const backgroundHeader = dataGridPalette?.headerBg ?? backgroundBase;
28
30
  const backgroundPinned = dataGridPalette?.pinnedBg ?? backgroundBase;
29
31
  const backgroundBackdrop = t.vars ? `rgba(${t.vars.palette.background.defaultChannel} / ${t.vars.palette.action.disabledOpacity})` : (0, _styles.alpha)(t.palette.background.default, t.palette.action.disabledOpacity);
30
- const backgroundOverlay = t.palette.mode === 'dark' ? `color-mix(in srgb, ${(t.vars || t).palette.background.paper} 90%, #fff)` : (t.vars || t).palette.background.paper;
32
+ const backgroundOverlay = t.palette.mode === 'dark' ? (0, _GridRootStyles.colorMixIfSupported)(`color-mix(in srgb, ${paperColor} 90%, #fff)`, paperColor) : paperColor;
31
33
  const selectedColor = t.vars ? `rgb(${t.vars.palette.primary.mainChannel})` : t.palette.primary.main;
32
34
  const radius = getRadius(t);
33
35
  const fontBody = t.vars?.font?.body2 ?? formatFont(t.typography.body2);
@@ -45,13 +47,13 @@ function transformTheme(t) {
45
47
  [k.colors.foreground.accent]: (t.vars || t).palette.primary.dark,
46
48
  [k.colors.foreground.disabled]: (t.vars || t).palette.text.disabled,
47
49
  [k.colors.foreground.error]: (t.vars || t).palette.error.dark,
48
- [k.colors.interactive.hover]: (t.vars || t).palette.action.hover,
50
+ [k.colors.interactive.hover]: _GridRootStyles.supportsColorMix ? (t.vars || t).palette.action.hover : (t.vars || t).palette.grey[t.palette.mode === 'dark' ? 800 : 100],
49
51
  [k.colors.interactive.hoverOpacity]: (t.vars || t).palette.action.hoverOpacity,
50
52
  [k.colors.interactive.focus]: removeOpacity((t.vars || t).palette.primary.main),
51
53
  [k.colors.interactive.focusOpacity]: (t.vars || t).palette.action.focusOpacity,
52
54
  [k.colors.interactive.disabled]: removeOpacity((t.vars || t).palette.action.disabled),
53
55
  [k.colors.interactive.disabledOpacity]: (t.vars || t).palette.action.disabledOpacity,
54
- [k.colors.interactive.selected]: selectedColor,
56
+ [k.colors.interactive.selected]: _GridRootStyles.supportsColorMix ? selectedColor : (t.vars || t).palette.grey[t.palette.mode === 'dark' ? 700 : 200],
55
57
  [k.colors.interactive.selectedOpacity]: (t.vars || t).palette.action.selectedOpacity,
56
58
  [k.header.background.base]: backgroundHeader,
57
59
  [k.cell.background.pinned]: backgroundPinned,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-data-grid",
3
- "version": "8.21.0",
3
+ "version": "8.22.1",
4
4
  "author": "MUI Team",
5
5
  "description": "The Community plan edition of the MUI X Data Grid components.",
6
6
  "license": "MIT",
@@ -42,8 +42,8 @@
42
42
  "clsx": "^2.1.1",
43
43
  "prop-types": "^15.8.1",
44
44
  "use-sync-external-store": "^1.6.0",
45
- "@mui/x-internals": "8.21.0",
46
- "@mui/x-virtualizer": "0.2.11"
45
+ "@mui/x-internals": "8.22.0",
46
+ "@mui/x-virtualizer": "0.2.13"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@emotion/react": "^11.9.0",
@@ -4,8 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.ResizeObserver = void 0;
7
- /* eslint-disable */
8
-
9
7
  /**
10
8
  * HACK: Minimal shim to get jsdom to work.
11
9
  */