@mui/material 9.0.0 → 9.0.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 (130) hide show
  1. package/Autocomplete/Autocomplete.js +65 -11
  2. package/Autocomplete/Autocomplete.mjs +65 -11
  3. package/Avatar/Avatar.js +4 -0
  4. package/Avatar/Avatar.mjs +4 -0
  5. package/Badge/Badge.js +3 -0
  6. package/Badge/Badge.mjs +3 -0
  7. package/Button/Button.js +19 -2
  8. package/Button/Button.mjs +19 -2
  9. package/ButtonBase/ButtonBase.d.mts +7 -0
  10. package/ButtonBase/ButtonBase.d.ts +7 -0
  11. package/ButtonBase/ButtonBase.js +5 -2
  12. package/ButtonBase/ButtonBase.mjs +5 -2
  13. package/CHANGELOG.md +132 -1245
  14. package/Checkbox/Checkbox.js +2 -1
  15. package/Checkbox/Checkbox.mjs +2 -1
  16. package/CircularProgress/CircularProgress.d.mts +12 -2
  17. package/CircularProgress/CircularProgress.d.ts +12 -2
  18. package/CircularProgress/CircularProgress.js +33 -6
  19. package/CircularProgress/CircularProgress.mjs +33 -6
  20. package/ClickAwayListener/ClickAwayListener.js +3 -6
  21. package/ClickAwayListener/ClickAwayListener.mjs +3 -6
  22. package/Dialog/Dialog.js +11 -6
  23. package/Dialog/Dialog.mjs +11 -6
  24. package/Drawer/Drawer.js +18 -4
  25. package/Drawer/Drawer.mjs +18 -4
  26. package/Fab/Fab.js +7 -1
  27. package/Fab/Fab.mjs +7 -1
  28. package/FilledInput/FilledInput.d.mts +4 -0
  29. package/FilledInput/FilledInput.d.ts +4 -0
  30. package/FilledInput/FilledInput.js +18 -20
  31. package/FilledInput/FilledInput.mjs +18 -20
  32. package/FormControl/useFormControl.d.mts +12 -2
  33. package/FormControl/useFormControl.d.ts +12 -2
  34. package/FormControl/useFormControl.js +13 -0
  35. package/FormControl/useFormControl.mjs +12 -0
  36. package/FormControlLabel/FormControlLabel.js +5 -8
  37. package/FormControlLabel/FormControlLabel.mjs +5 -8
  38. package/FormGroup/FormGroup.js +2 -5
  39. package/FormGroup/FormGroup.mjs +2 -5
  40. package/FormHelperText/FormHelperText.js +2 -5
  41. package/FormHelperText/FormHelperText.mjs +2 -5
  42. package/FormLabel/FormLabel.js +2 -5
  43. package/FormLabel/FormLabel.mjs +2 -5
  44. package/IconButton/IconButton.js +1 -8
  45. package/IconButton/IconButton.mjs +1 -8
  46. package/Input/Input.d.mts +4 -0
  47. package/Input/Input.d.ts +4 -0
  48. package/Input/Input.js +6 -0
  49. package/Input/Input.mjs +6 -0
  50. package/InputBase/InputBase.d.mts +2 -1
  51. package/InputBase/InputBase.d.ts +2 -1
  52. package/InputBase/InputBase.js +50 -15
  53. package/InputBase/InputBase.mjs +50 -15
  54. package/InputLabel/InputLabel.js +5 -8
  55. package/InputLabel/InputLabel.mjs +5 -8
  56. package/LinearProgress/LinearProgress.d.mts +12 -2
  57. package/LinearProgress/LinearProgress.d.ts +12 -2
  58. package/LinearProgress/LinearProgress.js +42 -10
  59. package/LinearProgress/LinearProgress.mjs +42 -10
  60. package/List/List.js +2 -1
  61. package/List/List.mjs +2 -1
  62. package/ListItemButton/ListItemButton.js +7 -1
  63. package/ListItemButton/ListItemButton.mjs +7 -1
  64. package/MenuItem/MenuItem.js +7 -1
  65. package/MenuItem/MenuItem.mjs +7 -1
  66. package/MenuList/MenuList.js +2 -1
  67. package/MenuList/MenuList.mjs +2 -1
  68. package/NativeSelect/NativeSelect.js +2 -5
  69. package/NativeSelect/NativeSelect.mjs +2 -5
  70. package/OutlinedInput/OutlinedInput.js +13 -23
  71. package/OutlinedInput/OutlinedInput.mjs +13 -23
  72. package/PigmentContainer/PigmentContainer.js +0 -1
  73. package/PigmentContainer/PigmentContainer.mjs +0 -1
  74. package/Popper/BasePopper.js +23 -1
  75. package/Popper/BasePopper.mjs +23 -1
  76. package/Select/Select.js +2 -5
  77. package/Select/Select.mjs +2 -5
  78. package/Select/SelectInput.js +164 -2
  79. package/Select/SelectInput.mjs +164 -2
  80. package/Slide/Slide.js +48 -26
  81. package/Slide/Slide.mjs +49 -27
  82. package/Slider/Slider.js +10 -1
  83. package/Slider/Slider.mjs +10 -1
  84. package/Slider/useSlider.js +3 -2
  85. package/Slider/useSlider.mjs +3 -2
  86. package/SwipeableDrawer/SwipeableDrawer.js +7 -3
  87. package/SwipeableDrawer/SwipeableDrawer.mjs +7 -3
  88. package/Switch/Switch.js +7 -6
  89. package/Switch/Switch.mjs +7 -6
  90. package/Tabs/ScrollbarSize.js +2 -1
  91. package/Tabs/ScrollbarSize.mjs +2 -1
  92. package/Tabs/Tabs.js +2 -1
  93. package/Tabs/Tabs.mjs +2 -1
  94. package/Tooltip/Tooltip.js +26 -108
  95. package/Tooltip/Tooltip.mjs +26 -108
  96. package/Unstable_TrapFocus/FocusTrap.js +18 -14
  97. package/Unstable_TrapFocus/FocusTrap.mjs +18 -14
  98. package/index.js +1 -1
  99. package/index.mjs +1 -1
  100. package/package.json +49 -49
  101. package/styles/responsiveFontSizes.js +19 -8
  102. package/styles/responsiveFontSizes.mjs +19 -8
  103. package/styles/useThemeProps.d.mts +3 -3
  104. package/styles/useThemeProps.d.ts +3 -3
  105. package/transitions/utils.d.mts +17 -0
  106. package/transitions/utils.d.ts +17 -0
  107. package/transitions/utils.js +64 -0
  108. package/transitions/utils.mjs +63 -0
  109. package/useAutocomplete/useAutocomplete.d.mts +4 -5
  110. package/useAutocomplete/useAutocomplete.d.ts +4 -5
  111. package/useAutocomplete/useAutocomplete.js +166 -53
  112. package/useAutocomplete/useAutocomplete.mjs +166 -53
  113. package/utils/contains.d.mts +2 -0
  114. package/utils/contains.d.ts +2 -0
  115. package/utils/contains.js +9 -0
  116. package/utils/contains.mjs +2 -0
  117. package/utils/focusable.d.mts +7 -0
  118. package/utils/focusable.d.ts +7 -0
  119. package/utils/focusable.js +20 -0
  120. package/utils/focusable.mjs +13 -0
  121. package/utils/getEventTarget.d.mts +2 -0
  122. package/utils/getEventTarget.d.ts +2 -0
  123. package/utils/getEventTarget.js +9 -0
  124. package/utils/getEventTarget.mjs +2 -0
  125. package/utils/mergeSlotProps.js +2 -8
  126. package/utils/mergeSlotProps.mjs +1 -8
  127. package/version/index.js +2 -2
  128. package/version/index.mjs +2 -2
  129. package/FormControl/formControlState.js +0 -21
  130. package/FormControl/formControlState.mjs +0 -15
@@ -9,18 +9,52 @@ import clsx from 'clsx';
9
9
  import composeClasses from '@mui/utils/composeClasses';
10
10
  import useId from '@mui/utils/useId';
11
11
  import refType from '@mui/utils/refType';
12
+ import useTimeout from '@mui/utils/useTimeout';
12
13
  import ownerDocument from "../utils/ownerDocument.mjs";
13
14
  import Menu from "../Menu/Menu.mjs";
14
15
  import { StyledSelectSelect, StyledSelectIcon } from "../NativeSelect/NativeSelectInput.mjs";
15
16
  import { isFilled } from "../InputBase/utils.mjs";
16
17
  import { styled } from "../zero-styled/index.mjs";
17
18
  import slotShouldForwardProp from "../styles/slotShouldForwardProp.mjs";
19
+ import useEnhancedEffect from "../utils/useEnhancedEffect.mjs";
20
+ import useEventCallback from "../utils/useEventCallback.mjs";
18
21
  import useForkRef from "../utils/useForkRef.mjs";
19
22
  import useControlled from "../utils/useControlled.mjs";
20
23
  import selectClasses, { getSelectUtilityClasses } from "./selectClasses.mjs";
21
24
  import { areEqualValues, isEmpty, getOpenInteractionType } from "./utils/index.mjs";
22
25
  import { SelectFocusSourceProvider } from "./utils/SelectFocusSourceContext.mjs";
23
26
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
27
+ const OPENING_MOUSE_UP_BOUNDARY_OFFSET = 2;
28
+ // The initial mouseup may land on an item when the menu opens over the trigger.
29
+ const SELECTED_MOUSE_UP_DELAY = 400;
30
+ const UNSELECTED_MOUSE_UP_DELAY = 200;
31
+
32
+ /**
33
+ * Returns true when a native mouse event should be treated as happening inside
34
+ * the element, even if a portal or backdrop retargeted the event away from it.
35
+ *
36
+ * Select uses this for the opening mouseup: when the menu opens over the
37
+ * trigger, the release can target the backdrop or portaled menu even though the
38
+ * pointer is still inside the trigger or menu bounds.
39
+ */
40
+ function isMouseEventInsideElement(event, element) {
41
+ if (!element) {
42
+ return false;
43
+ }
44
+ const eventPath = event.composedPath();
45
+ if (eventPath.includes(element)) {
46
+ return true;
47
+ }
48
+ if (event.target?.nodeType && element.contains(event.target)) {
49
+ return true;
50
+ }
51
+ const rect = element.getBoundingClientRect();
52
+ if (rect.width === 0 && rect.height === 0) {
53
+ // Hidden or transition-mounted elements do not have useful bounds to hit-test.
54
+ return false;
55
+ }
56
+ return event.clientX >= rect.left - OPENING_MOUSE_UP_BOUNDARY_OFFSET && event.clientX <= rect.right + OPENING_MOUSE_UP_BOUNDARY_OFFSET && event.clientY >= rect.top - OPENING_MOUSE_UP_BOUNDARY_OFFSET && event.clientY <= rect.bottom + OPENING_MOUSE_UP_BOUNDARY_OFFSET;
57
+ }
24
58
  const SelectSelect = styled(StyledSelectSelect, {
25
59
  name: 'MuiSelect',
26
60
  slot: 'Select',
@@ -147,6 +181,17 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
147
181
  });
148
182
  const inputRef = React.useRef(null);
149
183
  const displayRef = React.useRef(null);
184
+ const paperRef = React.useRef(null);
185
+ const openRef = React.useRef(false);
186
+ const hasSelectedItemInListRef = React.useRef(false);
187
+ const openingMouseUpListenerCleanupRef = React.useRef(null);
188
+ const didPointerDownOnItemRef = React.useRef(false);
189
+ const selectionRef = React.useRef({
190
+ allowSelectedMouseUp: false,
191
+ allowUnselectedMouseUp: false
192
+ });
193
+ const selectedMouseUpTimer = useTimeout();
194
+ const unselectedMouseUpTimer = useTimeout();
150
195
  const [displayNode, setDisplayNode] = React.useState(null);
151
196
  const {
152
197
  current: isOpenControlled
@@ -169,6 +214,42 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
169
214
  value
170
215
  }), [value]);
171
216
  const open = displayNode !== null && openState;
217
+ useEnhancedEffect(() => {
218
+ openRef.current = open;
219
+ }, [open]);
220
+ const clearSelectionTimers = React.useCallback(() => {
221
+ selectedMouseUpTimer.clear();
222
+ unselectedMouseUpTimer.clear();
223
+ }, [selectedMouseUpTimer, unselectedMouseUpTimer]);
224
+ const resetMouseUpSelection = React.useCallback(() => {
225
+ clearSelectionTimers();
226
+ didPointerDownOnItemRef.current = false;
227
+ selectionRef.current = {
228
+ allowSelectedMouseUp: false,
229
+ allowUnselectedMouseUp: false
230
+ };
231
+ }, [clearSelectionTimers]);
232
+ const clearOpeningMouseUpListener = React.useCallback(() => {
233
+ if (openingMouseUpListenerCleanupRef.current) {
234
+ openingMouseUpListenerCleanupRef.current();
235
+ openingMouseUpListenerCleanupRef.current = null;
236
+ }
237
+ }, []);
238
+ React.useEffect(() => {
239
+ if (!open) {
240
+ resetMouseUpSelection();
241
+ clearOpeningMouseUpListener();
242
+ }
243
+ }, [open, resetMouseUpSelection, clearOpeningMouseUpListener]);
244
+
245
+ // Keep unmount cleanup separate from the `open` effect. Effect cleanups also run
246
+ // before the next effect, which would clear the opening mouseup listener while opening.
247
+ React.useEffect(() => {
248
+ return () => {
249
+ resetMouseUpSelection();
250
+ clearOpeningMouseUpListener();
251
+ };
252
+ }, [resetMouseUpSelection, clearOpeningMouseUpListener]);
172
253
  React.useEffect(() => {
173
254
  if (!open || !anchorElement || autoWidth) {
174
255
  return undefined;
@@ -219,7 +300,11 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
219
300
  }
220
301
  return undefined;
221
302
  }, [labelId]);
222
- const update = (openParam, event) => {
303
+ const update = useEventCallback((openParam, event) => {
304
+ if (!openParam) {
305
+ resetMouseUpSelection();
306
+ clearOpeningMouseUpListener();
307
+ }
223
308
  if (openParam) {
224
309
  setOpenInteractionType(getOpenInteractionType(event));
225
310
  if (onOpen) {
@@ -232,9 +317,33 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
232
317
  }
233
318
  }
234
319
  if (!isOpenControlled) {
320
+ openRef.current = openParam;
235
321
  setMenuMinWidthState(autoWidth ? null : anchorElement.clientWidth);
236
322
  setOpenState(openParam);
237
323
  }
324
+ });
325
+ const scheduleMouseUpSelection = () => {
326
+ resetMouseUpSelection();
327
+
328
+ // When there is no selected item in the list, a mousedown
329
+ // on the trigger followed by a quick mouseup over the first option can accidentally select
330
+ // within 200ms. Delay unselected mouseup to match the safer 400ms window.
331
+ if (!hasSelectedItemInListRef.current) {
332
+ selectedMouseUpTimer.start(SELECTED_MOUSE_UP_DELAY, () => {
333
+ selectionRef.current.allowSelectedMouseUp = true;
334
+ selectionRef.current.allowUnselectedMouseUp = true;
335
+ });
336
+ } else {
337
+ // mousedown -> move to unselected item -> mouseup should not select within 200ms.
338
+ unselectedMouseUpTimer.start(UNSELECTED_MOUSE_UP_DELAY, () => {
339
+ selectionRef.current.allowUnselectedMouseUp = true;
340
+
341
+ // mousedown -> mouseup on selected item should not select within 400ms.
342
+ selectedMouseUpTimer.start(UNSELECTED_MOUSE_UP_DELAY, () => {
343
+ selectionRef.current.allowSelectedMouseUp = true;
344
+ });
345
+ });
346
+ }
238
347
  };
239
348
  const handleMouseDown = event => {
240
349
  onMouseDown?.(event);
@@ -245,6 +354,29 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
245
354
  // Hijack the default focus behavior.
246
355
  event.preventDefault();
247
356
  displayRef.current.focus();
357
+ const doc = ownerDocument(event.currentTarget);
358
+ scheduleMouseUpSelection();
359
+ clearOpeningMouseUpListener();
360
+ const handleMouseUp = mouseEvent => {
361
+ openingMouseUpListenerCleanupRef.current = null;
362
+ if (!displayRef.current) {
363
+ return;
364
+ }
365
+ if (isMouseEventInsideElement(mouseEvent, displayRef.current) || isMouseEventInsideElement(mouseEvent, paperRef.current)) {
366
+ return;
367
+ }
368
+ if (!openRef.current && isOpenControlled) {
369
+ return;
370
+ }
371
+ update(false, mouseEvent);
372
+ };
373
+ doc.addEventListener('mouseup', handleMouseUp, {
374
+ capture: true,
375
+ once: true
376
+ });
377
+ openingMouseUpListenerCleanupRef.current = () => {
378
+ doc.removeEventListener('mouseup', handleMouseUp, true);
379
+ };
248
380
  update(true, event);
249
381
  };
250
382
  const handleClose = event => {
@@ -264,6 +396,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
264
396
  }
265
397
  };
266
398
  const handleItemClick = child => event => {
399
+ didPointerDownOnItemRef.current = false;
267
400
  let newValue;
268
401
 
269
402
  // We use the tabindex attribute to signal the available options.
@@ -307,6 +440,19 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
307
440
  update(false, event);
308
441
  }
309
442
  };
443
+ const handleItemMouseUp = (child, selected) => event => {
444
+ child.props.onMouseUp?.(event);
445
+ if (didPointerDownOnItemRef.current) {
446
+ didPointerDownOnItemRef.current = false;
447
+ return;
448
+ }
449
+ const disallowSelectedMouseUp = !selectionRef.current.allowSelectedMouseUp && selected;
450
+ const disallowUnselectedMouseUp = !selectionRef.current.allowUnselectedMouseUp && !selected;
451
+ if (disallowSelectedMouseUp || disallowUnselectedMouseUp) {
452
+ return;
453
+ }
454
+ event.currentTarget.click();
455
+ };
310
456
  const handleKeyDown = event => {
311
457
  if (!readOnly) {
312
458
  const validKeys = [' ', 'ArrowUp', 'ArrowDown',
@@ -380,7 +526,16 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
380
526
  }
381
527
  return /*#__PURE__*/React.cloneElement(child, {
382
528
  'aria-selected': selected ? 'true' : 'false',
529
+ onMouseDown: event => {
530
+ didPointerDownOnItemRef.current = true;
531
+ child.props.onMouseDown?.(event);
532
+ },
533
+ onPointerDown: event => {
534
+ didPointerDownOnItemRef.current = true;
535
+ child.props.onPointerDown?.(event);
536
+ },
383
537
  onClick: handleItemClick(child),
538
+ onMouseUp: handleItemMouseUp(child, selected),
384
539
  onKeyUp: event => {
385
540
  if (event.key === ' ') {
386
541
  // otherwise our MenuItems dispatches a click event
@@ -399,6 +554,11 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
399
554
  'data-value': child.props.value // Instead, we provide it as a data attribute.
400
555
  });
401
556
  });
557
+
558
+ // Keep the opening mouseup guard current without mutating refs during render.
559
+ useEnhancedEffect(() => {
560
+ hasSelectedItemInListRef.current = foundMatch;
561
+ }, [foundMatch]);
402
562
  if (process.env.NODE_ENV !== 'production') {
403
563
  // TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
404
564
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -448,6 +608,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
448
608
  };
449
609
  const classes = useUtilityClasses(ownerState);
450
610
  const menuPaperSlotProps = typeof MenuProps.slotProps?.paper === 'function' ? MenuProps.slotProps.paper(ownerState) : MenuProps.slotProps?.paper;
611
+ const handlePaperRef = useForkRef(menuPaperSlotProps?.ref, paperRef);
451
612
  const menuListSlotProps = typeof MenuProps.slotProps?.list === 'function' ? MenuProps.slotProps.list(ownerState) : MenuProps.slotProps?.list;
452
613
  const listboxId = useId();
453
614
  const nativeInputId = useId();
@@ -462,7 +623,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
462
623
  "aria-expanded": open ? 'true' : 'false',
463
624
  "aria-haspopup": "listbox",
464
625
  "aria-label": ariaLabel,
465
- "aria-labelledby": [labelId, buttonId].filter(Boolean).join(' ') || undefined,
626
+ "aria-labelledby": labelId,
466
627
  "aria-describedby": ariaDescribedby,
467
628
  "aria-required": required ? 'true' : undefined,
468
629
  "aria-invalid": error ? 'true' : undefined,
@@ -529,6 +690,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
529
690
  },
530
691
  paper: {
531
692
  ...menuPaperSlotProps,
693
+ ref: handlePaperRef,
532
694
  style: {
533
695
  minWidth: menuMinWidth,
534
696
  ...menuPaperSlotProps?.style
package/Slide/Slide.js CHANGED
@@ -26,33 +26,46 @@ const hiddenStyles = {
26
26
  visibility: 'hidden'
27
27
  };
28
28
 
29
+ /**
30
+ * Detects SwipeableDrawer's active-swipe `translate(x, y)` transform.
31
+ * Keep this in sync with SwipeableDrawer.setPosition.
32
+ */
33
+ function isGestureTranslate(transform) {
34
+ return typeof transform === 'string' && /^translate\(.+,\s*.+\)$/.test(transform);
35
+ }
36
+
29
37
  // Translate the node so it can't be seen on the screen.
30
38
  // Later, we're going to translate the node back to its original location with `none`.
31
- function getTranslateValue(direction, node, resolvedContainer) {
39
+ function getTranslateValue(direction, node, resolvedContainer, options = {}) {
40
+ const {
41
+ resetInlineTransform = true
42
+ } = options;
32
43
  const containerRect = resolvedContainer && resolvedContainer.getBoundingClientRect();
33
44
  const containerWindow = (0, _utils2.ownerWindow)(node);
34
-
35
- // Clear the inline transform and transition before reading layout and computed
36
- // style so we compute from the element's natural position, not its previous
37
- // off-screen translation. The transition must also be cleared, otherwise the
38
- // browser may report an animated intermediate value from a still-running
39
- // enter transition when reading getComputedStyle during exit.
40
- const previousTransform = node.style.transform;
41
- const previousTransition = node.style.transition;
42
- node.style.transition = '';
43
- node.style.transform = '';
44
- const rect = node.getBoundingClientRect();
45
- const computedStyle = containerWindow.getComputedStyle(node);
46
- const transform = computedStyle.getPropertyValue('transform');
47
- node.style.transform = previousTransform;
48
- node.style.transition = previousTransition;
49
- let offsetX = 0;
50
- let offsetY = 0;
51
- if (transform && transform !== 'none' && typeof transform === 'string') {
52
- const transformValues = transform.split('(')[1].split(')')[0].split(',');
53
- offsetX = parseInt(transformValues[4], 10);
54
- offsetY = parseInt(transformValues[5], 10);
45
+ let rect;
46
+ let transform;
47
+ if (resetInlineTransform) {
48
+ // Clear the inline transform and transition before reading layout and computed
49
+ // style so we compute from the element's natural position, not its previous
50
+ // off-screen translation.
51
+ const previousTransform = node.style.transform;
52
+ const previousTransition = node.style.transition;
53
+ node.style.transition = '';
54
+ node.style.transform = '';
55
+ rect = node.getBoundingClientRect();
56
+ const computedStyle = containerWindow.getComputedStyle(node);
57
+ transform = computedStyle.getPropertyValue('transform');
58
+ node.style.transform = previousTransform;
59
+ node.style.transition = previousTransition;
60
+ } else {
61
+ rect = node.getBoundingClientRect();
62
+ const computedStyle = containerWindow.getComputedStyle(node);
63
+ transform = computedStyle.getPropertyValue('transform');
55
64
  }
65
+ const {
66
+ offsetX,
67
+ offsetY
68
+ } = (0, _utils.getTranslateOffsets)(transform);
56
69
  if (direction === 'left') {
57
70
  if (containerRect) {
58
71
  return `translateX(${containerRect.right + offsetX - rect.left}px)`;
@@ -81,9 +94,9 @@ function getTranslateValue(direction, node, resolvedContainer) {
81
94
  function resolveContainer(containerPropProp) {
82
95
  return typeof containerPropProp === 'function' ? containerPropProp() : containerPropProp;
83
96
  }
84
- function setTranslateValue(direction, node, containerProp) {
97
+ function setTranslateValue(direction, node, containerProp, options) {
85
98
  const resolvedContainer = resolveContainer(containerProp);
86
- const transform = getTranslateValue(direction, node, resolvedContainer);
99
+ const transform = getTranslateValue(direction, node, resolvedContainer, options);
87
100
  if (transform) {
88
101
  node.style.transform = transform;
89
102
  }
@@ -122,6 +135,7 @@ const Slide = /*#__PURE__*/React.forwardRef(function Slide(props, ref) {
122
135
  ...other
123
136
  } = props;
124
137
  const childrenRef = React.useRef(null);
138
+ const preserveInlineTransformRef = React.useRef(false);
125
139
  const handleRef = (0, _useForkRef.default)((0, _getReactElementRef.default)(children), childrenRef, ref);
126
140
  const handleEnter = (0, _utils.normalizedTransitionCallback)(childrenRef, (node, isAppearing) => {
127
141
  setTranslateValue(direction, node, containerProp);
@@ -155,12 +169,20 @@ const Slide = /*#__PURE__*/React.forwardRef(function Slide(props, ref) {
155
169
  mode: 'exit'
156
170
  });
157
171
  node.style.transition = theme.transitions.create('transform', transitionProps);
158
- setTranslateValue(direction, node, containerProp);
172
+ const preserveInlineTransform = isGestureTranslate(node.style.transform);
173
+ preserveInlineTransformRef.current = preserveInlineTransform;
174
+
175
+ // Preserve SwipeableDrawer's inline gesture transform during exit. Slide's
176
+ // own off-screen translateX/Y transforms still use the reset path.
177
+ setTranslateValue(direction, node, containerProp, {
178
+ resetInlineTransform: !preserveInlineTransform
179
+ });
159
180
  if (onExit) {
160
181
  onExit(node);
161
182
  }
162
183
  });
163
184
  const handleExited = (0, _utils.normalizedTransitionCallback)(childrenRef, node => {
185
+ preserveInlineTransformRef.current = false;
164
186
  // No need for transitions when the component is hidden
165
187
  node.style.transition = '';
166
188
  if (onExited) {
@@ -196,7 +218,7 @@ const Slide = /*#__PURE__*/React.forwardRef(function Slide(props, ref) {
196
218
  };
197
219
  }, [direction, inProp, containerProp]);
198
220
  React.useEffect(() => {
199
- if (!inProp) {
221
+ if (!inProp && !preserveInlineTransformRef.current) {
200
222
  // We need to update the position of the drawer when the direction change and
201
223
  // when it's hidden.
202
224
  updatePosition();
package/Slide/Slide.mjs CHANGED
@@ -11,40 +11,53 @@ import isLayoutSupported from "../utils/isLayoutSupported.mjs";
11
11
  import debounce from "../utils/debounce.mjs";
12
12
  import useForkRef from "../utils/useForkRef.mjs";
13
13
  import { useTheme } from "../zero-styled/index.mjs";
14
- import { normalizedTransitionCallback, reflow, getTransitionProps } from "../transitions/utils.mjs";
14
+ import { normalizedTransitionCallback, reflow, getTransitionProps, getTranslateOffsets } from "../transitions/utils.mjs";
15
15
  import { ownerWindow } from "../utils/index.mjs";
16
16
  import { jsx as _jsx } from "react/jsx-runtime";
17
17
  const hiddenStyles = {
18
18
  visibility: 'hidden'
19
19
  };
20
20
 
21
+ /**
22
+ * Detects SwipeableDrawer's active-swipe `translate(x, y)` transform.
23
+ * Keep this in sync with SwipeableDrawer.setPosition.
24
+ */
25
+ function isGestureTranslate(transform) {
26
+ return typeof transform === 'string' && /^translate\(.+,\s*.+\)$/.test(transform);
27
+ }
28
+
21
29
  // Translate the node so it can't be seen on the screen.
22
30
  // Later, we're going to translate the node back to its original location with `none`.
23
- function getTranslateValue(direction, node, resolvedContainer) {
31
+ function getTranslateValue(direction, node, resolvedContainer, options = {}) {
32
+ const {
33
+ resetInlineTransform = true
34
+ } = options;
24
35
  const containerRect = resolvedContainer && resolvedContainer.getBoundingClientRect();
25
36
  const containerWindow = ownerWindow(node);
26
-
27
- // Clear the inline transform and transition before reading layout and computed
28
- // style so we compute from the element's natural position, not its previous
29
- // off-screen translation. The transition must also be cleared, otherwise the
30
- // browser may report an animated intermediate value from a still-running
31
- // enter transition when reading getComputedStyle during exit.
32
- const previousTransform = node.style.transform;
33
- const previousTransition = node.style.transition;
34
- node.style.transition = '';
35
- node.style.transform = '';
36
- const rect = node.getBoundingClientRect();
37
- const computedStyle = containerWindow.getComputedStyle(node);
38
- const transform = computedStyle.getPropertyValue('transform');
39
- node.style.transform = previousTransform;
40
- node.style.transition = previousTransition;
41
- let offsetX = 0;
42
- let offsetY = 0;
43
- if (transform && transform !== 'none' && typeof transform === 'string') {
44
- const transformValues = transform.split('(')[1].split(')')[0].split(',');
45
- offsetX = parseInt(transformValues[4], 10);
46
- offsetY = parseInt(transformValues[5], 10);
37
+ let rect;
38
+ let transform;
39
+ if (resetInlineTransform) {
40
+ // Clear the inline transform and transition before reading layout and computed
41
+ // style so we compute from the element's natural position, not its previous
42
+ // off-screen translation.
43
+ const previousTransform = node.style.transform;
44
+ const previousTransition = node.style.transition;
45
+ node.style.transition = '';
46
+ node.style.transform = '';
47
+ rect = node.getBoundingClientRect();
48
+ const computedStyle = containerWindow.getComputedStyle(node);
49
+ transform = computedStyle.getPropertyValue('transform');
50
+ node.style.transform = previousTransform;
51
+ node.style.transition = previousTransition;
52
+ } else {
53
+ rect = node.getBoundingClientRect();
54
+ const computedStyle = containerWindow.getComputedStyle(node);
55
+ transform = computedStyle.getPropertyValue('transform');
47
56
  }
57
+ const {
58
+ offsetX,
59
+ offsetY
60
+ } = getTranslateOffsets(transform);
48
61
  if (direction === 'left') {
49
62
  if (containerRect) {
50
63
  return `translateX(${containerRect.right + offsetX - rect.left}px)`;
@@ -73,9 +86,9 @@ function getTranslateValue(direction, node, resolvedContainer) {
73
86
  function resolveContainer(containerPropProp) {
74
87
  return typeof containerPropProp === 'function' ? containerPropProp() : containerPropProp;
75
88
  }
76
- export function setTranslateValue(direction, node, containerProp) {
89
+ export function setTranslateValue(direction, node, containerProp, options) {
77
90
  const resolvedContainer = resolveContainer(containerProp);
78
- const transform = getTranslateValue(direction, node, resolvedContainer);
91
+ const transform = getTranslateValue(direction, node, resolvedContainer, options);
79
92
  if (transform) {
80
93
  node.style.transform = transform;
81
94
  }
@@ -114,6 +127,7 @@ const Slide = /*#__PURE__*/React.forwardRef(function Slide(props, ref) {
114
127
  ...other
115
128
  } = props;
116
129
  const childrenRef = React.useRef(null);
130
+ const preserveInlineTransformRef = React.useRef(false);
117
131
  const handleRef = useForkRef(getReactElementRef(children), childrenRef, ref);
118
132
  const handleEnter = normalizedTransitionCallback(childrenRef, (node, isAppearing) => {
119
133
  setTranslateValue(direction, node, containerProp);
@@ -147,12 +161,20 @@ const Slide = /*#__PURE__*/React.forwardRef(function Slide(props, ref) {
147
161
  mode: 'exit'
148
162
  });
149
163
  node.style.transition = theme.transitions.create('transform', transitionProps);
150
- setTranslateValue(direction, node, containerProp);
164
+ const preserveInlineTransform = isGestureTranslate(node.style.transform);
165
+ preserveInlineTransformRef.current = preserveInlineTransform;
166
+
167
+ // Preserve SwipeableDrawer's inline gesture transform during exit. Slide's
168
+ // own off-screen translateX/Y transforms still use the reset path.
169
+ setTranslateValue(direction, node, containerProp, {
170
+ resetInlineTransform: !preserveInlineTransform
171
+ });
151
172
  if (onExit) {
152
173
  onExit(node);
153
174
  }
154
175
  });
155
176
  const handleExited = normalizedTransitionCallback(childrenRef, node => {
177
+ preserveInlineTransformRef.current = false;
156
178
  // No need for transitions when the component is hidden
157
179
  node.style.transition = '';
158
180
  if (onExited) {
@@ -188,7 +210,7 @@ const Slide = /*#__PURE__*/React.forwardRef(function Slide(props, ref) {
188
210
  };
189
211
  }, [direction, inProp, containerProp]);
190
212
  React.useEffect(() => {
191
- if (!inProp) {
213
+ if (!inProp && !preserveInlineTransformRef.current) {
192
214
  // We need to update the position of the drawer when the direction change and
193
215
  // when it's hidden.
194
216
  updatePosition();
package/Slider/Slider.js CHANGED
@@ -138,6 +138,10 @@ const SliderRail = exports.SliderRail = (0, _zeroStyled.styled)('span', {
138
138
  borderRadius: 'inherit',
139
139
  backgroundColor: 'currentColor',
140
140
  opacity: 0.38,
141
+ '@media (forced-colors: active)': {
142
+ border: '1px solid transparent',
143
+ boxSizing: 'border-box'
144
+ },
141
145
  variants: [{
142
146
  props: {
143
147
  orientation: 'horizontal'
@@ -187,7 +191,9 @@ const SliderTrack = exports.SliderTrack = (0, _zeroStyled.styled)('span', {
187
191
  size: 'small'
188
192
  },
189
193
  style: {
190
- border: 'none'
194
+ '@media (forced-colors: none)': {
195
+ border: 'none'
196
+ }
191
197
  }
192
198
  }, {
193
199
  props: {
@@ -256,6 +262,9 @@ const SliderThumb = exports.SliderThumb = (0, _zeroStyled.styled)('span', {
256
262
  transition: theme.transitions.create(['box-shadow', 'left', 'bottom'], {
257
263
  duration: theme.transitions.duration.shortest
258
264
  }),
265
+ '@media (forced-colors: active)': {
266
+ border: '1px solid ButtonBorder'
267
+ },
259
268
  '&::before': {
260
269
  position: 'absolute',
261
270
  content: '""',
package/Slider/Slider.mjs CHANGED
@@ -131,6 +131,10 @@ export const SliderRail = styled('span', {
131
131
  borderRadius: 'inherit',
132
132
  backgroundColor: 'currentColor',
133
133
  opacity: 0.38,
134
+ '@media (forced-colors: active)': {
135
+ border: '1px solid transparent',
136
+ boxSizing: 'border-box'
137
+ },
134
138
  variants: [{
135
139
  props: {
136
140
  orientation: 'horizontal'
@@ -180,7 +184,9 @@ export const SliderTrack = styled('span', {
180
184
  size: 'small'
181
185
  },
182
186
  style: {
183
- border: 'none'
187
+ '@media (forced-colors: none)': {
188
+ border: 'none'
189
+ }
184
190
  }
185
191
  }, {
186
192
  props: {
@@ -249,6 +255,9 @@ export const SliderThumb = styled('span', {
249
255
  transition: theme.transitions.create(['box-shadow', 'left', 'bottom'], {
250
256
  duration: theme.transitions.duration.shortest
251
257
  }),
258
+ '@media (forced-colors: active)': {
259
+ border: '1px solid ButtonBorder'
260
+ },
252
261
  '&::before': {
253
262
  position: 'absolute',
254
263
  content: '""',
@@ -20,6 +20,7 @@ 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"));
23
24
  var _getActiveElement = _interopRequireDefault(require("../utils/getActiveElement"));
24
25
  const INTENTIONAL_DRAG_COUNT_THRESHOLD = 2;
25
26
  const EMPTY_MARKS = [];
@@ -103,7 +104,7 @@ function setValueIndex(values, newValue, index) {
103
104
  function focusThumb(sliderRef, activeIndex, setActive, focusVisible) {
104
105
  const doc = (0, _ownerDocument.default)(sliderRef.current);
105
106
  const activeElement = (0, _getActiveElement.default)(doc);
106
- if (!sliderRef.current?.contains(activeElement) || Number(activeElement?.getAttribute('data-index')) !== activeIndex) {
107
+ if (!(0, _contains.default)(sliderRef.current, activeElement) || Number(activeElement?.getAttribute('data-index')) !== activeIndex) {
107
108
  const input = sliderRef.current?.querySelector(`[type="range"][data-index="${activeIndex}"]`);
108
109
  if (input != null) {
109
110
  if (focusVisible == null) {
@@ -388,7 +389,7 @@ function useSlider(parameters) {
388
389
  };
389
390
  (0, _useEnhancedEffect.default)(() => {
390
391
  const activeElement = (0, _getActiveElement.default)((0, _ownerDocument.default)(sliderRef.current));
391
- if (disabled && sliderRef.current?.contains(activeElement)) {
392
+ if (disabled && (0, _contains.default)(sliderRef.current, activeElement)) {
392
393
  // This is necessary because Firefox and Safari will keep focus
393
394
  // on a disabled element:
394
395
  // https://codesandbox.io/p/sandbox/mui-pr-22247-forked-h151h?file=/src/App.js
@@ -11,6 +11,7 @@ import visuallyHidden from '@mui/utils/visuallyHidden';
11
11
  import clamp from '@mui/utils/clamp';
12
12
  import extractEventHandlers from '@mui/utils/extractEventHandlers';
13
13
  import areArraysEqual from "../utils/areArraysEqual.mjs";
14
+ import contains from "../utils/contains.mjs";
14
15
  import getActiveElement from "../utils/getActiveElement.mjs";
15
16
  const INTENTIONAL_DRAG_COUNT_THRESHOLD = 2;
16
17
  const EMPTY_MARKS = [];
@@ -94,7 +95,7 @@ function setValueIndex(values, newValue, index) {
94
95
  function focusThumb(sliderRef, activeIndex, setActive, focusVisible) {
95
96
  const doc = ownerDocument(sliderRef.current);
96
97
  const activeElement = getActiveElement(doc);
97
- if (!sliderRef.current?.contains(activeElement) || Number(activeElement?.getAttribute('data-index')) !== activeIndex) {
98
+ if (!contains(sliderRef.current, activeElement) || Number(activeElement?.getAttribute('data-index')) !== activeIndex) {
98
99
  const input = sliderRef.current?.querySelector(`[type="range"][data-index="${activeIndex}"]`);
99
100
  if (input != null) {
100
101
  if (focusVisible == null) {
@@ -378,7 +379,7 @@ export function useSlider(parameters) {
378
379
  };
379
380
  useEnhancedEffect(() => {
380
381
  const activeElement = getActiveElement(ownerDocument(sliderRef.current));
381
- if (disabled && sliderRef.current?.contains(activeElement)) {
382
+ if (disabled && contains(sliderRef.current, activeElement)) {
382
383
  // This is necessary because Firefox and Safari will keep focus
383
384
  // on a disabled element:
384
385
  // https://codesandbox.io/p/sandbox/mui-pr-22247-forked-h151h?file=/src/App.js