@mui/material 7.3.10 → 7.3.11

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 (52) hide show
  1. package/Autocomplete/Autocomplete.js +63 -12
  2. package/Button/Button.js +18 -1
  3. package/CHANGELOG.md +35 -0
  4. package/Checkbox/Checkbox.js +2 -1
  5. package/ClickAwayListener/ClickAwayListener.js +2 -5
  6. package/Dialog/Dialog.js +11 -6
  7. package/Drawer/Drawer.js +18 -4
  8. package/Fab/Fab.js +7 -1
  9. package/InputBase/InputBase.js +39 -7
  10. package/ListItemButton/ListItemButton.js +7 -1
  11. package/MenuItem/MenuItem.js +6 -1
  12. package/Popper/BasePopper.js +23 -1
  13. package/Slider/useSlider.js +6 -3
  14. package/SwipeableDrawer/SwipeableDrawer.js +5 -4
  15. package/Switch/Switch.js +3 -4
  16. package/Unstable_TrapFocus/FocusTrap.js +15 -5
  17. package/esm/Autocomplete/Autocomplete.js +63 -12
  18. package/esm/Button/Button.js +18 -1
  19. package/esm/Checkbox/Checkbox.js +2 -1
  20. package/esm/ClickAwayListener/ClickAwayListener.js +2 -5
  21. package/esm/Dialog/Dialog.js +11 -6
  22. package/esm/Drawer/Drawer.js +18 -4
  23. package/esm/Fab/Fab.js +7 -1
  24. package/esm/InputBase/InputBase.js +39 -7
  25. package/esm/ListItemButton/ListItemButton.js +7 -1
  26. package/esm/MenuItem/MenuItem.js +6 -1
  27. package/esm/Popper/BasePopper.js +23 -1
  28. package/esm/Slider/useSlider.js +6 -3
  29. package/esm/SwipeableDrawer/SwipeableDrawer.js +5 -4
  30. package/esm/Switch/Switch.js +3 -4
  31. package/esm/Unstable_TrapFocus/FocusTrap.js +15 -5
  32. package/esm/index.js +1 -1
  33. package/esm/useAutocomplete/useAutocomplete.d.ts +4 -5
  34. package/esm/useAutocomplete/useAutocomplete.js +155 -46
  35. package/esm/utils/contains.d.ts +2 -0
  36. package/esm/utils/contains.js +2 -0
  37. package/esm/utils/focusable.d.ts +7 -0
  38. package/esm/utils/focusable.js +13 -0
  39. package/esm/utils/getEventTarget.d.ts +2 -0
  40. package/esm/utils/getEventTarget.js +2 -0
  41. package/esm/version/index.js +2 -2
  42. package/index.js +1 -1
  43. package/package.json +5 -5
  44. package/useAutocomplete/useAutocomplete.d.ts +4 -5
  45. package/useAutocomplete/useAutocomplete.js +155 -46
  46. package/utils/contains.d.ts +2 -0
  47. package/utils/contains.js +9 -0
  48. package/utils/focusable.d.ts +7 -0
  49. package/utils/focusable.js +20 -0
  50. package/utils/getEventTarget.d.ts +2 -0
  51. package/utils/getEventTarget.js +9 -0
  52. package/version/index.js +2 -2
@@ -18,6 +18,8 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
18
18
  var _integerPropType = _interopRequireDefault(require("@mui/utils/integerPropType"));
19
19
  var _chainPropTypes = _interopRequireDefault(require("@mui/utils/chainPropTypes"));
20
20
  var _composeClasses = _interopRequireDefault(require("@mui/utils/composeClasses"));
21
+ var _useForcedRerendering = _interopRequireDefault(require("@mui/utils/useForcedRerendering"));
22
+ var _useEnhancedEffect = _interopRequireDefault(require("@mui/utils/useEnhancedEffect"));
21
23
  var _useAutocomplete = _interopRequireWildcard(require("../useAutocomplete"));
22
24
  var _Popper = _interopRequireDefault(require("../Popper"));
23
25
  var _ListSubheader = _interopRequireDefault(require("../ListSubheader"));
@@ -507,6 +509,46 @@ const Autocomplete = /*#__PURE__*/React.forwardRef(function Autocomplete(inProps
507
509
  ...props,
508
510
  componentName: 'Autocomplete'
509
511
  });
512
+
513
+ // Re-render when anchorEl resizes so the Popper width stays in sync.
514
+ // Width is always read synchronously from anchorEl.clientWidth during render
515
+ // (no stale cached value). The hook just triggers a re-render on resize.
516
+ const forceRenderOnResize = (0, _useForcedRerendering.default)();
517
+ React.useEffect(() => {
518
+ if (!popupOpen || !anchorEl || typeof ResizeObserver === 'undefined') {
519
+ return undefined;
520
+ }
521
+ let lastWidth = anchorEl.clientWidth;
522
+ const observer = new ResizeObserver(() => {
523
+ const newWidth = anchorEl.clientWidth;
524
+ if (lastWidth !== newWidth) {
525
+ lastWidth = newWidth;
526
+ forceRenderOnResize();
527
+ }
528
+ });
529
+ observer.observe(anchorEl);
530
+ return () => {
531
+ observer.disconnect();
532
+ };
533
+ }, [popupOpen, anchorEl, forceRenderOnResize]);
534
+
535
+ // When popupOpen becomes false, useAutocomplete returns [] for groupedOptions.
536
+ // Transitioned Poppers can remain mounted for their exit animation, so keep rendering
537
+ // the last open-state options instead of flashing "No options" or an empty Paper.
538
+ // These options are stale because they no longer reflect the hook's current
539
+ // groupedOptions, but they are non-interactive while closing and reset on next open.
540
+ const previousGroupedOptionsRef = React.useRef([]);
541
+ const prevPopupOpenRef = React.useRef(false);
542
+ const renderedOptions = popupOpen ? groupedOptions : previousGroupedOptionsRef.current;
543
+ (0, _useEnhancedEffect.default)(() => {
544
+ if (popupOpen && !prevPopupOpenRef.current) {
545
+ previousGroupedOptionsRef.current = [];
546
+ }
547
+ prevPopupOpenRef.current = popupOpen;
548
+ if (popupOpen && groupedOptions.length > 0) {
549
+ previousGroupedOptionsRef.current = groupedOptions;
550
+ }
551
+ }, [popupOpen, groupedOptions]);
510
552
  const hasClearIcon = !disableClearable && !disabled && dirty && !readOnly;
511
553
  const hasPopupIcon = (!freeSolo || forcePopupIcon === true) && forcePopupIcon !== false;
512
554
  const {
@@ -580,13 +622,24 @@ const Autocomplete = /*#__PURE__*/React.forwardRef(function Autocomplete(inProps
580
622
  additionalProps: {
581
623
  disablePortal,
582
624
  style: {
583
- width: anchorEl ? anchorEl.clientWidth : null
625
+ width: anchorEl ? anchorEl.clientWidth : null,
626
+ // Prevent interaction with stale cached options during exit transitions.
627
+ // The hook's filteredOptions is [] when popupOpen=false, so clicks on stale
628
+ // rendered options would pass undefined to selectNewValue.
629
+ pointerEvents: popupOpen ? undefined : 'none'
584
630
  },
585
631
  role: 'presentation',
586
632
  anchorEl,
587
633
  open: popupOpen
588
634
  }
589
635
  });
636
+
637
+ // Don't render the Popper when there's no content to show.
638
+ // In freeSolo mode, "No options" text is suppressed, so if there are also no
639
+ // matching options and loading is false, the Paper would be empty.
640
+ // Uses renderedOptions (not groupedOptions) so Popper stays during exit transitions.
641
+ // Respect keepMounted from resolved popperProps (handles both object and callback slotProps forms).
642
+ const hasPopupContent = renderedOptions.length > 0 || loading || !freeSolo || popperProps.keepMounted === true;
590
643
  const [ClearIndicatorSlot, clearIndicatorProps] = (0, _useSlot.default)('clearIndicator', {
591
644
  elementType: AutocompleteClearIndicator,
592
645
  externalForwardedProps,
@@ -732,17 +785,17 @@ const Autocomplete = /*#__PURE__*/React.forwardRef(function Autocomplete(inProps
732
785
  ...getInputProps()
733
786
  }
734
787
  })
735
- }), anchorEl ? /*#__PURE__*/(0, _jsxRuntime.jsx)(AutocompletePopper, {
788
+ }), anchorEl && hasPopupContent ? /*#__PURE__*/(0, _jsxRuntime.jsx)(AutocompletePopper, {
736
789
  as: PopperSlot,
737
790
  ...popperProps,
738
791
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(AutocompletePaper, {
739
792
  as: PaperSlot,
740
793
  ...paperProps,
741
- children: [loading && groupedOptions.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(AutocompleteLoading, {
794
+ children: [loading && renderedOptions.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(AutocompleteLoading, {
742
795
  className: classes.loading,
743
796
  ownerState: ownerState,
744
797
  children: loadingText
745
- }) : null, groupedOptions.length === 0 && !freeSolo && !loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(AutocompleteNoOptions, {
798
+ }) : null, renderedOptions.length === 0 && !freeSolo && !loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(AutocompleteNoOptions, {
746
799
  className: classes.noOptions,
747
800
  ownerState: ownerState,
748
801
  role: "presentation",
@@ -751,10 +804,9 @@ const Autocomplete = /*#__PURE__*/React.forwardRef(function Autocomplete(inProps
751
804
  event.preventDefault();
752
805
  },
753
806
  children: noOptionsText
754
- }) : null, groupedOptions.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(ListboxSlot, {
755
- as: ListboxComponentProp,
807
+ }) : null, renderedOptions.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(ListboxSlot, {
756
808
  ...listboxProps,
757
- children: groupedOptions.map((option, index) => {
809
+ children: renderedOptions.map((option, index) => {
758
810
  if (groupBy) {
759
811
  return renderGroup({
760
812
  key: option.key,
@@ -787,12 +839,11 @@ process.env.NODE_ENV !== "production" ? Autocomplete.propTypes /* remove-proptyp
787
839
  */
788
840
  autoHighlight: _propTypes.default.bool,
789
841
  /**
790
- * If `true`, the selected option becomes the value of the input
791
- * when the Autocomplete loses focus unless the user chooses
792
- * a different option or changes the character string in the input.
842
+ * If `true`, the value is updated when the input loses focus under one of these conditions:
793
843
  *
794
- * When using the `freeSolo` mode, the typed value will be the input value
795
- * if the Autocomplete loses focus without highlighting an option.
844
+ * - An option highlighted via keyboard navigation or `autoHighlight` is selected.
845
+ * Hover and touch highlights are ignored.
846
+ * - Otherwise, in `freeSolo` mode, the typed text becomes the value.
796
847
  * @default false
797
848
  */
798
849
  autoSelect: _propTypes.default.bool,
package/Button/Button.js CHANGED
@@ -109,6 +109,17 @@ const ButtonRoot = (0, _zeroStyled.styled)(_ButtonBase.default, {
109
109
  color: (theme.vars || theme).palette.action.disabled
110
110
  },
111
111
  variants: [{
112
+ props: ({
113
+ ownerState
114
+ }) => ownerState.startIcon || ownerState.loading && ownerState.loadingPosition === 'start',
115
+ style: {
116
+ '&::before': {
117
+ content: '"\\200b"',
118
+ width: 0,
119
+ overflow: 'hidden'
120
+ }
121
+ }
122
+ }, {
112
123
  props: {
113
124
  variant: 'contained'
114
125
  },
@@ -558,6 +569,12 @@ const Button = /*#__PURE__*/React.forwardRef(function Button(inProps, ref) {
558
569
  children: loadingIndicator
559
570
  })
560
571
  }) : null;
572
+
573
+ // Don't forward the 'root' classes to the ButtonBase, as they will get duplicated with the one passed to the className prop.
574
+ const {
575
+ root,
576
+ ...forwardedClasses
577
+ } = classes;
561
578
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(ButtonRoot, {
562
579
  ownerState: ownerState,
563
580
  className: (0, _clsx.default)(contextProps.className, classes.root, className, positionClassName),
@@ -569,7 +586,7 @@ const Button = /*#__PURE__*/React.forwardRef(function Button(inProps, ref) {
569
586
  type: type,
570
587
  id: loading ? loadingId : idProp,
571
588
  ...other,
572
- classes: classes,
589
+ classes: forwardedClasses,
573
590
  children: [startIcon, loadingPosition !== 'end' && loader, children, loadingPosition === 'end' && loader, endIcon]
574
591
  });
575
592
  });
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # [Versions](https://mui.com/versions/)
2
2
 
3
+ ## 7.3.11
4
+
5
+ <!-- generated comparing v7.3.10..v7.x -->
6
+
7
+ _May 6, 2026_
8
+
9
+ A big thanks to the 5 contributors who made this release possible.
10
+
11
+ ### `@mui/material@7.3.11`
12
+
13
+ - [autocomplete] Fix highlight sync and scroll preservation (#48350) @mj12albert
14
+ - [autocomplete] Fix popper rendering issues (#48343) @mj12albert
15
+ - [autocomplete] Improve highlight tracking and selection state (#48318) @mj12albert
16
+ - [button] Fix `startIcon` alignment (#48339) @mj12albert
17
+ - [button] Remove duplicated className entries (#48284) @silviuaavram
18
+ - [checkbox] Set `aria-checked=mixed` when indeterminate (#48286) @mj12albert
19
+ - [dialog][drawer][focus trap] Fix initial focus target (#48324) @mj12albert
20
+ - [drawer] Fix transition jump (#48340) @mj12albert
21
+ - [input] Fix layout shift with display: flex (#48359) @oliviertassinari
22
+ - [inputs] Fix autofocus in SSR environment (#48307) @mj12albert
23
+ - [popper] Persist positioning styles when popperOptions changes reference (#48302) @mj12albert
24
+ - [switch] Fix incorrect `role` with `slotProps.input` (#48472) @mj12albert
25
+ - [utils] Add shadow dom utils (#48309) @mj12albert
26
+
27
+ ### Docs
28
+
29
+ - [docs] Update banner to announce v9 (#48299) @siriwatknp
30
+ - [docs] Add v9 in the versions select in v7.mui.com (#48233) @alexfauquette
31
+
32
+ ### Core
33
+
34
+ - [internal] Update some host-reference entries (#48225) @silviuaavram
35
+
36
+ All contributors of this release in alphabetical order: @alexfauquette, @mj12albert, @oliviertassinari, @silviuaavram, @siriwatknp
37
+
3
38
  ## 7.3.10
4
39
 
5
40
  <!-- generated comparing v7.3.9..v7.x -->
@@ -159,7 +159,8 @@ const Checkbox = /*#__PURE__*/React.forwardRef(function Checkbox(inProps, ref) {
159
159
  slots,
160
160
  slotProps: {
161
161
  input: (0, _utils.mergeSlotProps)(typeof externalInputProps === 'function' ? externalInputProps(ownerState) : externalInputProps, {
162
- 'data-indeterminate': indeterminate
162
+ 'data-indeterminate': indeterminate,
163
+ 'aria-checked': indeterminate ? 'mixed' : undefined
163
164
  })
164
165
  }
165
166
  }
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "__esModule", {
9
9
  exports.ClickAwayListener = ClickAwayListener;
10
10
  var React = _interopRequireWildcard(require("react"));
11
11
  var _propTypes = _interopRequireDefault(require("prop-types"));
12
+ var _contains = _interopRequireDefault(require("@mui/utils/contains"));
12
13
  var _ownerDocument = _interopRequireDefault(require("@mui/utils/ownerDocument"));
13
14
  var _useForkRef = _interopRequireDefault(require("@mui/utils/useForkRef"));
14
15
  var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
@@ -90,11 +91,7 @@ function ClickAwayListener(props) {
90
91
  if (event.composedPath) {
91
92
  insideDOM = event.composedPath().includes(nodeRef.current);
92
93
  } else {
93
- insideDOM = !doc.documentElement.contains(
94
- // @ts-expect-error returns `false` as intended when not dispatched from a Node
95
- event.target) || nodeRef.current.contains(
96
- // @ts-expect-error returns `false` as intended when not dispatched from a Node
97
- event.target);
94
+ insideDOM = !(0, _contains.default)(doc.documentElement, event.target) || (0, _contains.default)(nodeRef.current, event.target);
98
95
  }
99
96
  if (!insideDOM && (disableReactTree || !insideReactTree)) {
100
97
  onClickAway(event);
package/Dialog/Dialog.js CHANGED
@@ -23,6 +23,7 @@ var _zeroStyled = require("../zero-styled");
23
23
  var _memoTheme = _interopRequireDefault(require("../utils/memoTheme"));
24
24
  var _DefaultPropsProvider = require("../DefaultPropsProvider");
25
25
  var _useSlot = _interopRequireDefault(require("../utils/useSlot"));
26
+ var _focusable = require("../utils/focusable");
26
27
  var _jsxRuntime = require("react/jsx-runtime");
27
28
  const DialogBackdrop = (0, _zeroStyled.styled)(_Backdrop.default, {
28
29
  name: 'MuiDialog',
@@ -301,7 +302,16 @@ const Dialog = /*#__PURE__*/React.forwardRef(function Dialog(inProps, ref) {
301
302
  shouldForwardComponentProp: true,
302
303
  externalForwardedProps,
303
304
  ownerState,
304
- className: (0, _clsx.default)(classes.paper, PaperProps.className)
305
+ className: classes.paper,
306
+ additionalProps: {
307
+ elevation: 24,
308
+ role,
309
+ 'aria-describedby': ariaDescribedby,
310
+ 'aria-labelledby': ariaLabelledby,
311
+ 'aria-modal': ariaModal,
312
+ tabIndex: -1,
313
+ [_focusable.FOCUSABLE_ATTRIBUTE]: ''
314
+ }
305
315
  });
306
316
  const [ContainerSlot, containerSlotProps] = (0, _useSlot.default)('container', {
307
317
  elementType: DialogContainer,
@@ -345,11 +355,6 @@ const Dialog = /*#__PURE__*/React.forwardRef(function Dialog(inProps, ref) {
345
355
  ...containerSlotProps,
346
356
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(PaperSlot, {
347
357
  as: PaperComponent,
348
- elevation: 24,
349
- role: role,
350
- "aria-describedby": ariaDescribedby,
351
- "aria-labelledby": ariaLabelledby,
352
- "aria-modal": ariaModal,
353
358
  ...paperSlotProps,
354
359
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_DialogContext.default.Provider, {
355
360
  value: dialogContextValue,
package/Drawer/Drawer.js CHANGED
@@ -23,8 +23,10 @@ var _rootShouldForwardProp = _interopRequireDefault(require("../styles/rootShoul
23
23
  var _zeroStyled = require("../zero-styled");
24
24
  var _memoTheme = _interopRequireDefault(require("../utils/memoTheme"));
25
25
  var _DefaultPropsProvider = require("../DefaultPropsProvider");
26
+ var _useForkRef = _interopRequireDefault(require("../utils/useForkRef"));
26
27
  var _drawerClasses = require("./drawerClasses");
27
28
  var _useSlot = _interopRequireDefault(require("../utils/useSlot"));
29
+ var _focusable = require("../utils/focusable");
28
30
  var _utils = require("../utils");
29
31
  var _jsxRuntime = require("react/jsx-runtime");
30
32
  const overridesResolver = (props, styles) => {
@@ -217,9 +219,15 @@ const Drawer = /*#__PURE__*/React.forwardRef(function Drawer(inProps, ref) {
217
219
  // We use this state is order to skip the appear transition during the
218
220
  // initial mount of the component.
219
221
  const mounted = React.useRef(false);
222
+ const rootRef = React.useRef(null);
223
+ const handleRef = (0, _useForkRef.default)(ref, rootRef);
220
224
  React.useEffect(() => {
221
225
  mounted.current = true;
222
226
  }, []);
227
+
228
+ // Resolve the container lazily so Slide reads the mounted modal root
229
+ // after refs are assigned, rather than the initial null ref during render.
230
+ const resolveSlideContainer = React.useCallback(() => rootRef.current, []);
223
231
  const anchorInvariant = getAnchor({
224
232
  direction: isRtl ? 'rtl' : 'ltr'
225
233
  }, anchorProp);
@@ -251,7 +259,7 @@ const Drawer = /*#__PURE__*/React.forwardRef(function Drawer(inProps, ref) {
251
259
  }
252
260
  };
253
261
  const [RootSlot, rootSlotProps] = (0, _useSlot.default)('root', {
254
- ref,
262
+ ref: handleRef,
255
263
  elementType: DrawerRoot,
256
264
  className: (0, _clsx.default)(classes.root, classes.modal, className),
257
265
  shouldForwardComponentProp: true,
@@ -262,6 +270,7 @@ const Drawer = /*#__PURE__*/React.forwardRef(function Drawer(inProps, ref) {
262
270
  ...ModalProps
263
271
  },
264
272
  additionalProps: {
273
+ closeAfterTransition: true,
265
274
  open,
266
275
  onClose,
267
276
  hideBackdrop,
@@ -284,13 +293,15 @@ const Drawer = /*#__PURE__*/React.forwardRef(function Drawer(inProps, ref) {
284
293
  square: true,
285
294
  ...(variant === 'temporary' && {
286
295
  role: 'dialog',
287
- 'aria-modal': 'true'
296
+ 'aria-modal': 'true',
297
+ [_focusable.FOCUSABLE_ATTRIBUTE]: '',
298
+ tabIndex: -1
288
299
  })
289
300
  }
290
301
  });
291
302
  const [DockedSlot, dockedSlotProps] = (0, _useSlot.default)('docked', {
292
303
  elementType: DrawerDockedRoot,
293
- ref,
304
+ ref: handleRef,
294
305
  className: (0, _clsx.default)(classes.root, classes.docked, className),
295
306
  ownerState,
296
307
  externalForwardedProps,
@@ -304,7 +315,10 @@ const Drawer = /*#__PURE__*/React.forwardRef(function Drawer(inProps, ref) {
304
315
  in: open,
305
316
  direction: oppositeDirection[anchorInvariant],
306
317
  timeout: transitionDuration,
307
- appear: mounted.current
318
+ appear: mounted.current,
319
+ ...(variant === 'temporary' && (slots.transition == null || slots.transition === _Slide.default) && {
320
+ container: resolveSlideContainer
321
+ })
308
322
  }
309
323
  });
310
324
  const drawer = /*#__PURE__*/(0, _jsxRuntime.jsx)(PaperSlot, {
package/Fab/Fab.js CHANGED
@@ -194,6 +194,12 @@ const Fab = /*#__PURE__*/React.forwardRef(function Fab(inProps, ref) {
194
194
  variant
195
195
  };
196
196
  const classes = useUtilityClasses(ownerState);
197
+
198
+ // Don't forward the 'root' class to the ButtonBase, as it will get duplicated with the one passed to the className prop.
199
+ const {
200
+ root,
201
+ ...forwardedClasses
202
+ } = classes;
197
203
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(FabRoot, {
198
204
  className: (0, _clsx.default)(classes.root, className),
199
205
  component: component,
@@ -203,7 +209,7 @@ const Fab = /*#__PURE__*/React.forwardRef(function Fab(inProps, ref) {
203
209
  ownerState: ownerState,
204
210
  ref: ref,
205
211
  ...other,
206
- classes: classes,
212
+ classes: forwardedClasses,
207
213
  children: children
208
214
  });
209
215
  });
@@ -25,10 +25,14 @@ var _DefaultPropsProvider = require("../DefaultPropsProvider");
25
25
  var _capitalize = _interopRequireDefault(require("../utils/capitalize"));
26
26
  var _useForkRef = _interopRequireDefault(require("../utils/useForkRef"));
27
27
  var _useEnhancedEffect = _interopRequireDefault(require("../utils/useEnhancedEffect"));
28
+ var _ownerDocument = _interopRequireDefault(require("../utils/ownerDocument"));
29
+ var _getActiveElement = _interopRequireDefault(require("../utils/getActiveElement"));
28
30
  var _utils = require("./utils");
29
31
  var _inputBaseClasses = _interopRequireWildcard(require("./inputBaseClasses"));
30
32
  var _jsxRuntime = require("react/jsx-runtime");
31
33
  var _InputGlobalStyles;
34
+ const MUI_AUTO_FILL = 'mui-auto-fill';
35
+ const MUI_AUTO_FILL_CANCEL = 'mui-auto-fill-cancel';
32
36
  const rootOverridesResolver = (props, styles) => {
33
37
  const {
34
38
  ownerState
@@ -193,11 +197,11 @@ const InputBaseInput = exports.InputBaseInput = (0, _zeroStyled.styled)('input',
193
197
  ownerState
194
198
  }) => !ownerState.disableInjectingGlobalStyles,
195
199
  style: {
196
- animationName: 'mui-auto-fill-cancel',
200
+ animationName: MUI_AUTO_FILL_CANCEL,
197
201
  animationDuration: '10ms',
198
202
  '&:-webkit-autofill': {
199
203
  animationDuration: '5000s',
200
- animationName: 'mui-auto-fill'
204
+ animationName: MUI_AUTO_FILL
201
205
  }
202
206
  }
203
207
  }, {
@@ -228,14 +232,16 @@ const InputBaseInput = exports.InputBaseInput = (0, _zeroStyled.styled)('input',
228
232
  };
229
233
  }));
230
234
  const InputGlobalStyles = (0, _zeroStyled.globalCss)({
231
- '@keyframes mui-auto-fill': {
235
+ // Keep keyframes non-empty for Emotion production builds. Animation properties are ignored
236
+ // inside keyframes, avoiding the visible display animation triggered by Chrome 117+.
237
+ [`@keyframes ${MUI_AUTO_FILL}`]: {
232
238
  from: {
233
- display: 'block'
239
+ animationName: MUI_AUTO_FILL
234
240
  }
235
241
  },
236
- '@keyframes mui-auto-fill-cancel': {
242
+ [`@keyframes ${MUI_AUTO_FILL_CANCEL}`]: {
237
243
  from: {
238
- display: 'block'
244
+ animationName: MUI_AUTO_FILL_CANCEL
239
245
  }
240
246
  }
241
247
  });
@@ -351,6 +357,32 @@ const InputBase = /*#__PURE__*/React.forwardRef(function InputBase(inProps, ref)
351
357
  });
352
358
  }
353
359
  }, [value, checkDirty, isControlled]);
360
+
361
+ // Sync focused state when autoFocus is used in SSR.
362
+ // If the browser focused the element before hydration, the onFocus handler never
363
+ // fires. If it did not, React hydration does not call focus() for autoFocus.
364
+ (0, _useEnhancedEffect.default)(() => {
365
+ if (!autoFocus) {
366
+ return;
367
+ }
368
+ const input = inputRef.current;
369
+ if (!input) {
370
+ return;
371
+ }
372
+ const doc = (0, _ownerDocument.default)(input);
373
+ const activeElement = (0, _getActiveElement.default)(doc);
374
+ const noElementFocused = activeElement == null || activeElement === doc.body || activeElement === doc.documentElement;
375
+ if (input === activeElement) {
376
+ if (muiFormControl && muiFormControl.onFocus) {
377
+ muiFormControl.onFocus();
378
+ } else {
379
+ setFocused(true);
380
+ }
381
+ } else if (noElementFocused) {
382
+ input.focus();
383
+ }
384
+ // eslint-disable-next-line react-hooks/exhaustive-deps
385
+ }, [autoFocus]);
354
386
  const handleFocus = event => {
355
387
  if (onFocus) {
356
388
  onFocus(event);
@@ -439,7 +471,7 @@ const InputBase = /*#__PURE__*/React.forwardRef(function InputBase(inProps, ref)
439
471
  }
440
472
  const handleAutoFill = event => {
441
473
  // Provide a fake value as Chrome might not let you access it for security reasons.
442
- checkDirty(event.animationName === 'mui-auto-fill-cancel' ? inputRef.current : {
474
+ checkDirty(event.animationName === MUI_AUTO_FILL_CANCEL ? inputRef.current : {
443
475
  value: 'x'
444
476
  });
445
477
  };
@@ -172,6 +172,12 @@ const ListItemButton = /*#__PURE__*/React.forwardRef(function ListItemButton(inP
172
172
  selected
173
173
  };
174
174
  const classes = useUtilityClasses(ownerState);
175
+
176
+ // Don't forward the 'root' class to the ButtonBase, as it will get duplicated with the one passed to the className prop.
177
+ const {
178
+ root,
179
+ ...forwardedClasses
180
+ } = classes;
175
181
  const handleRef = (0, _useForkRef.default)(listItemRef, ref);
176
182
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ListContext.default.Provider, {
177
183
  value: childContext,
@@ -185,7 +191,7 @@ const ListItemButton = /*#__PURE__*/React.forwardRef(function ListItemButton(inP
185
191
  ownerState: ownerState,
186
192
  className: (0, _clsx.default)(classes.root, className),
187
193
  ...other,
188
- classes: classes,
194
+ classes: forwardedClasses,
189
195
  children: children
190
196
  })
191
197
  });
@@ -213,6 +213,11 @@ const MenuItem = /*#__PURE__*/React.forwardRef(function MenuItem(inProps, ref) {
213
213
  };
214
214
  const classes = useUtilityClasses(props);
215
215
  const handleRef = (0, _useForkRef.default)(menuItemRef, ref);
216
+ // Don't forward the 'root' class to the ButtonBase, as it will get duplicated with the one passed to the className prop.
217
+ const {
218
+ root,
219
+ ...forwardedClasses
220
+ } = classes;
216
221
  let tabIndex;
217
222
  if (!props.disabled) {
218
223
  tabIndex = tabIndexProp !== undefined ? tabIndexProp : -1;
@@ -228,7 +233,7 @@ const MenuItem = /*#__PURE__*/React.forwardRef(function MenuItem(inProps, ref) {
228
233
  className: (0, _clsx.default)(classes.root, className),
229
234
  ...other,
230
235
  ownerState: ownerState,
231
- classes: classes
236
+ classes: forwardedClasses
232
237
  })
233
238
  });
234
239
  });
@@ -150,8 +150,30 @@ const PopperTooltip = /*#__PURE__*/React.forwardRef(function PopperTooltip(props
150
150
  modifiers: popperModifiers
151
151
  });
152
152
  handlePopperRefRef.current(popper);
153
+ const popperElement = tooltipRef.current;
153
154
  return () => {
154
- popper.destroy();
155
+ // popper.destroy() clears all inline positioning via the applyStyles
156
+ // modifier cleanup, which causes the element to jump to its static
157
+ // position. Snapshot and restore only the positioning properties so the
158
+ // element stays in place during the destroy/recreate gap (prevents scroll
159
+ // jumps when a child focuses between the two).
160
+ // https://github.com/mui/mui-x/issues/21839
161
+ if (popperElement) {
162
+ const {
163
+ style
164
+ } = popperElement;
165
+ const position = style.position;
166
+ const top = style.top;
167
+ const left = style.left;
168
+ const transform = style.transform;
169
+ popper.destroy();
170
+ style.position = position;
171
+ style.top = top;
172
+ style.left = left;
173
+ style.transform = transform;
174
+ } else {
175
+ popper.destroy();
176
+ }
155
177
  handlePopperRefRef.current(null);
156
178
  };
157
179
  }, [resolvedAnchorElement, disablePortal, modifiers, open, popperOptions, rtlPlacement]);
@@ -20,6 +20,8 @@ var _visuallyHidden = _interopRequireDefault(require("@mui/utils/visuallyHidden"
20
20
  var _clamp = _interopRequireDefault(require("@mui/utils/clamp"));
21
21
  var _extractEventHandlers = _interopRequireDefault(require("@mui/utils/extractEventHandlers"));
22
22
  var _areArraysEqual = _interopRequireDefault(require("../utils/areArraysEqual"));
23
+ var _contains = _interopRequireDefault(require("../utils/contains"));
24
+ var _getActiveElement = _interopRequireDefault(require("../utils/getActiveElement"));
23
25
  const INTENTIONAL_DRAG_COUNT_THRESHOLD = 2;
24
26
  function getNewValue(currentValue, step, direction, min, max) {
25
27
  return direction === 1 ? Math.min(currentValue + step, max) : Math.max(currentValue - step, min);
@@ -99,8 +101,8 @@ function focusThumb({
99
101
  activeIndex,
100
102
  setActive
101
103
  }) {
102
- const doc = (0, _ownerDocument.default)(sliderRef.current);
103
- if (!sliderRef.current?.contains(doc.activeElement) || Number(doc?.activeElement?.getAttribute('data-index')) !== activeIndex) {
104
+ const activeElement = (0, _getActiveElement.default)((0, _ownerDocument.default)(sliderRef.current));
105
+ if (!(0, _contains.default)(sliderRef.current, activeElement) || Number(activeElement?.getAttribute('data-index')) !== activeIndex) {
104
106
  sliderRef.current?.querySelector(`[type="range"][data-index="${activeIndex}"]`).focus();
105
107
  }
106
108
  if (setActive) {
@@ -357,7 +359,8 @@ function useSlider(parameters) {
357
359
  otherHandlers?.onKeyDown?.(event);
358
360
  };
359
361
  (0, _useEnhancedEffect.default)(() => {
360
- if (disabled && sliderRef.current.contains(document.activeElement)) {
362
+ const activeElement = (0, _getActiveElement.default)((0, _ownerDocument.default)(sliderRef.current));
363
+ if (disabled && (0, _contains.default)(sliderRef.current, activeElement)) {
361
364
  // This is necessary because Firefox and Safari will keep focus
362
365
  // on a disabled element:
363
366
  // https://codesandbox.io/p/sandbox/mui-pr-22247-forked-h151h?file=/src/App.js
@@ -14,10 +14,11 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
14
14
  var _elementTypeAcceptingRef = _interopRequireDefault(require("@mui/utils/elementTypeAcceptingRef"));
15
15
  var _NoSsr = _interopRequireDefault(require("../NoSsr"));
16
16
  var _Drawer = _interopRequireWildcard(require("../Drawer/Drawer"));
17
- var _useForkRef = _interopRequireDefault(require("../utils/useForkRef"));
17
+ var _contains = _interopRequireDefault(require("../utils/contains"));
18
18
  var _ownerDocument = _interopRequireDefault(require("../utils/ownerDocument"));
19
19
  var _ownerWindow = _interopRequireDefault(require("../utils/ownerWindow"));
20
20
  var _useEventCallback = _interopRequireDefault(require("../utils/useEventCallback"));
21
+ var _useForkRef = _interopRequireDefault(require("../utils/useForkRef"));
21
22
  var _useEnhancedEffect = _interopRequireDefault(require("../utils/useEnhancedEffect"));
22
23
  var _zeroStyled = require("../zero-styled");
23
24
  var _DefaultPropsProvider = require("../DefaultPropsProvider");
@@ -299,7 +300,7 @@ const SwipeableDrawer = /*#__PURE__*/React.forwardRef(function SwipeableDrawer(i
299
300
  const horizontalSwipe = (0, _Drawer.isHorizontal)(anchor);
300
301
  const currentX = calculateCurrentX(anchorRtl, nativeEvent.touches, (0, _ownerDocument.default)(nativeEvent.currentTarget));
301
302
  const currentY = calculateCurrentY(anchorRtl, nativeEvent.touches, (0, _ownerWindow.default)(nativeEvent.currentTarget));
302
- if (open && paperRef.current.contains(nativeEvent.target) && claimedSwipeInstance === null) {
303
+ if (open && (0, _contains.default)(paperRef.current, nativeEvent.target) && claimedSwipeInstance === null) {
303
304
  const domTreeShapes = getDomTreeShapes(nativeEvent.target, paperRef.current);
304
305
  const hasNativeHandler = computeHasNativeHandler({
305
306
  domTreeShapes,
@@ -397,7 +398,7 @@ const SwipeableDrawer = /*#__PURE__*/React.forwardRef(function SwipeableDrawer(i
397
398
  }
398
399
 
399
400
  // At least one element clogs the drawer interaction zone.
400
- if (open && (hideBackdrop || !backdropRef.current.contains(nativeEvent.target)) && !paperRef.current.contains(nativeEvent.target)) {
401
+ if (open && (hideBackdrop || !(0, _contains.default)(backdropRef.current, nativeEvent.target)) && !(0, _contains.default)(paperRef.current, nativeEvent.target)) {
401
402
  return;
402
403
  }
403
404
  const anchorRtl = (0, _Drawer.getAnchor)(theme, anchor);
@@ -409,7 +410,7 @@ const SwipeableDrawer = /*#__PURE__*/React.forwardRef(function SwipeableDrawer(i
409
410
  // if disableSwipeToOpen
410
411
  // if target != swipeArea, and target is not a child of paper ref
411
412
  // if is a child of paper ref, and `allowSwipeInChildren` does not allow it
412
- if (disableSwipeToOpen || !(nativeEvent.target === swipeAreaRef.current || paperRef.current?.contains(nativeEvent.target) && (typeof allowSwipeInChildren === 'function' ? allowSwipeInChildren(nativeEvent, swipeAreaRef.current, paperRef.current) : allowSwipeInChildren))) {
413
+ if (disableSwipeToOpen || !(nativeEvent.target === swipeAreaRef.current || (0, _contains.default)(paperRef.current, nativeEvent.target) && (typeof allowSwipeInChildren === 'function' ? allowSwipeInChildren(nativeEvent, swipeAreaRef.current, paperRef.current) : allowSwipeInChildren))) {
413
414
  return;
414
415
  }
415
416
  if (horizontalSwipe) {
package/Switch/Switch.js CHANGED
@@ -20,6 +20,7 @@ var _zeroStyled = require("../zero-styled");
20
20
  var _memoTheme = _interopRequireDefault(require("../utils/memoTheme"));
21
21
  var _DefaultPropsProvider = require("../DefaultPropsProvider");
22
22
  var _switchClasses = _interopRequireWildcard(require("./switchClasses"));
23
+ var _utils = require("../utils");
23
24
  var _useSlot = _interopRequireDefault(require("../utils/useSlot"));
24
25
  var _jsxRuntime = require("react/jsx-runtime");
25
26
  const useUtilityClasses = ownerState => {
@@ -232,6 +233,7 @@ const Switch = /*#__PURE__*/React.forwardRef(function Switch(inProps, ref) {
232
233
  size
233
234
  };
234
235
  const classes = useUtilityClasses(ownerState);
236
+ const externalInputProps = slotProps.input;
235
237
  const externalForwardedProps = {
236
238
  slots,
237
239
  slotProps
@@ -285,11 +287,8 @@ const Switch = /*#__PURE__*/React.forwardRef(function Switch(inProps, ref) {
285
287
  ...(slotProps.switchBase && {
286
288
  root: typeof slotProps.switchBase === 'function' ? slotProps.switchBase(ownerState) : slotProps.switchBase
287
289
  }),
288
- input: {
290
+ input: (0, _utils.mergeSlotProps)(typeof externalInputProps === 'function' ? externalInputProps(ownerState) : externalInputProps, {
289
291
  role: 'switch'
290
- },
291
- ...(slotProps.input && {
292
- input: typeof slotProps.input === 'function' ? slotProps.input(ownerState) : slotProps.input
293
292
  })
294
293
  }
295
294
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(TrackSlot, {