@mui/material 9.0.1 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/Accordion/Accordion.d.mts +2 -2
  2. package/Accordion/Accordion.d.ts +2 -2
  3. package/Accordion/Accordion.js +3 -2
  4. package/Accordion/Accordion.mjs +3 -2
  5. package/AccordionSummary/AccordionSummary.js +27 -29
  6. package/AccordionSummary/AccordionSummary.mjs +27 -29
  7. package/Autocomplete/Autocomplete.js +8 -6
  8. package/Autocomplete/Autocomplete.mjs +8 -6
  9. package/Backdrop/Backdrop.d.mts +2 -2
  10. package/Backdrop/Backdrop.d.ts +2 -2
  11. package/Badge/Badge.js +28 -24
  12. package/Badge/Badge.mjs +28 -24
  13. package/BottomNavigationAction/BottomNavigationAction.js +6 -2
  14. package/BottomNavigationAction/BottomNavigationAction.mjs +6 -2
  15. package/Button/Button.js +11 -15
  16. package/Button/Button.mjs +11 -15
  17. package/ButtonBase/Ripple.js +21 -11
  18. package/ButtonBase/Ripple.mjs +21 -11
  19. package/ButtonBase/TouchRipple.js +252 -116
  20. package/ButtonBase/TouchRipple.mjs +253 -117
  21. package/CHANGELOG.md +84 -0
  22. package/CardActionArea/CardActionArea.js +2 -1
  23. package/CardActionArea/CardActionArea.mjs +2 -1
  24. package/Chip/Chip.js +2 -1
  25. package/Chip/Chip.mjs +2 -1
  26. package/CircularProgress/CircularProgress.js +85 -55
  27. package/CircularProgress/CircularProgress.mjs +84 -55
  28. package/Collapse/Collapse.d.mts +15 -3
  29. package/Collapse/Collapse.d.ts +15 -3
  30. package/Collapse/Collapse.js +44 -31
  31. package/Collapse/Collapse.mjs +43 -30
  32. package/Dialog/Dialog.d.mts +2 -2
  33. package/Dialog/Dialog.d.ts +2 -2
  34. package/Dialog/Dialog.js +2 -0
  35. package/Dialog/Dialog.mjs +2 -0
  36. package/Drawer/Drawer.d.mts +2 -2
  37. package/Drawer/Drawer.d.ts +2 -2
  38. package/Fab/Fab.js +2 -1
  39. package/Fab/Fab.mjs +2 -1
  40. package/Fade/Fade.d.mts +15 -2
  41. package/Fade/Fade.d.ts +15 -2
  42. package/Fade/Fade.js +46 -19
  43. package/Fade/Fade.mjs +45 -18
  44. package/FilledInput/FilledInput.js +4 -3
  45. package/FilledInput/FilledInput.mjs +4 -3
  46. package/Grow/Grow.d.mts +15 -2
  47. package/Grow/Grow.d.ts +15 -2
  48. package/Grow/Grow.js +45 -28
  49. package/Grow/Grow.mjs +44 -27
  50. package/IconButton/IconButton.js +2 -1
  51. package/IconButton/IconButton.mjs +2 -1
  52. package/Input/Input.js +3 -2
  53. package/Input/Input.mjs +3 -2
  54. package/InputBase/InputBase.js +2 -1
  55. package/InputBase/InputBase.mjs +2 -1
  56. package/InputLabel/InputLabel.js +2 -1
  57. package/InputLabel/InputLabel.mjs +2 -1
  58. package/LICENSE +1 -1
  59. package/LinearProgress/LinearProgress.js +187 -120
  60. package/LinearProgress/LinearProgress.mjs +186 -120
  61. package/ListItem/ListItem.js +2 -1
  62. package/ListItem/ListItem.mjs +2 -1
  63. package/ListItemButton/ListItemButton.js +2 -1
  64. package/ListItemButton/ListItemButton.mjs +2 -1
  65. package/Menu/Menu.d.mts +1 -1
  66. package/Menu/Menu.d.ts +1 -1
  67. package/MobileStepper/MobileStepper.js +2 -1
  68. package/MobileStepper/MobileStepper.mjs +2 -1
  69. package/OutlinedInput/NotchedOutline.js +4 -3
  70. package/OutlinedInput/NotchedOutline.mjs +4 -3
  71. package/PaginationItem/PaginationItem.js +2 -1
  72. package/PaginationItem/PaginationItem.mjs +2 -1
  73. package/Paper/Paper.js +2 -1
  74. package/Paper/Paper.mjs +2 -1
  75. package/Popover/Popover.d.mts +1 -1
  76. package/Popover/Popover.d.ts +1 -1
  77. package/README.md +3 -2
  78. package/Radio/RadioButtonIcon.js +3 -2
  79. package/Radio/RadioButtonIcon.mjs +3 -2
  80. package/Rating/Rating.js +2 -1
  81. package/Rating/Rating.mjs +2 -1
  82. package/Select/SelectInput.js +115 -25
  83. package/Select/SelectInput.mjs +115 -25
  84. package/Select/utils/closedTypeahead.js +73 -0
  85. package/Select/utils/closedTypeahead.mjs +63 -0
  86. package/Skeleton/Skeleton.js +22 -2
  87. package/Skeleton/Skeleton.mjs +22 -2
  88. package/Slide/Slide.d.mts +15 -2
  89. package/Slide/Slide.d.ts +15 -2
  90. package/Slide/Slide.js +53 -25
  91. package/Slide/Slide.mjs +52 -24
  92. package/Slider/Slider.js +4 -3
  93. package/Slider/Slider.mjs +4 -3
  94. package/Slider/useSlider.js +1 -1
  95. package/Slider/useSlider.mjs +1 -1
  96. package/Snackbar/Snackbar.d.mts +2 -2
  97. package/Snackbar/Snackbar.d.ts +2 -2
  98. package/SpeedDial/SpeedDial.d.mts +1 -1
  99. package/SpeedDial/SpeedDial.d.ts +1 -1
  100. package/SpeedDial/SpeedDial.js +6 -2
  101. package/SpeedDial/SpeedDial.mjs +6 -2
  102. package/SpeedDialAction/SpeedDialAction.js +11 -2
  103. package/SpeedDialAction/SpeedDialAction.mjs +12 -3
  104. package/SpeedDialIcon/SpeedDialIcon.js +40 -37
  105. package/SpeedDialIcon/SpeedDialIcon.mjs +40 -37
  106. package/Step/Step.js +47 -15
  107. package/Step/Step.mjs +47 -15
  108. package/StepButton/StepButton.js +9 -3
  109. package/StepButton/StepButton.mjs +9 -3
  110. package/StepConnector/StepConnector.js +10 -0
  111. package/StepConnector/StepConnector.mjs +10 -0
  112. package/StepContent/StepContent.d.mts +2 -2
  113. package/StepContent/StepContent.d.ts +2 -2
  114. package/StepContent/StepContent.js +26 -2
  115. package/StepContent/StepContent.mjs +26 -2
  116. package/StepIcon/StepIcon.js +2 -1
  117. package/StepIcon/StepIcon.mjs +2 -1
  118. package/StepLabel/StepLabel.js +52 -7
  119. package/StepLabel/StepLabel.mjs +52 -7
  120. package/Stepper/Stepper.d.mts +2 -0
  121. package/Stepper/Stepper.d.ts +2 -0
  122. package/Stepper/Stepper.js +18 -0
  123. package/Stepper/Stepper.mjs +18 -0
  124. package/SvgIcon/SvgIcon.js +2 -1
  125. package/SvgIcon/SvgIcon.mjs +2 -1
  126. package/SwipeableDrawer/SwipeableDrawer.js +14 -3
  127. package/SwipeableDrawer/SwipeableDrawer.mjs +14 -3
  128. package/Switch/Switch.js +3 -2
  129. package/Switch/Switch.mjs +3 -2
  130. package/TableSortLabel/TableSortLabel.js +2 -1
  131. package/TableSortLabel/TableSortLabel.mjs +2 -1
  132. package/Tabs/Tabs.js +14 -3
  133. package/Tabs/Tabs.mjs +14 -3
  134. package/Tooltip/Tooltip.d.mts +2 -2
  135. package/Tooltip/Tooltip.d.ts +2 -2
  136. package/Tooltip/Tooltip.js +3 -0
  137. package/Tooltip/Tooltip.mjs +3 -0
  138. package/Unstable_TrapFocus/FocusTrap.js +42 -8
  139. package/Unstable_TrapFocus/FocusTrap.mjs +42 -8
  140. package/Zoom/Zoom.d.mts +15 -2
  141. package/Zoom/Zoom.d.ts +15 -2
  142. package/Zoom/Zoom.js +43 -16
  143. package/Zoom/Zoom.mjs +42 -15
  144. package/index.js +1 -1
  145. package/index.mjs +1 -1
  146. package/internal/Transition.d.mts +34 -0
  147. package/internal/Transition.d.ts +34 -0
  148. package/internal/Transition.js +444 -0
  149. package/internal/Transition.mjs +436 -0
  150. package/internal/react-transition-group.d.mts +8 -0
  151. package/internal/react-transition-group.d.ts +8 -0
  152. package/package.json +6 -6
  153. package/styles/createMotion.d.mts +8 -0
  154. package/styles/createMotion.d.ts +8 -0
  155. package/styles/createMotion.js +13 -0
  156. package/styles/createMotion.mjs +7 -0
  157. package/styles/createThemeFoundation.d.mts +2 -0
  158. package/styles/createThemeFoundation.d.ts +2 -0
  159. package/styles/createThemeNoVars.d.mts +3 -0
  160. package/styles/createThemeNoVars.d.ts +3 -0
  161. package/styles/createThemeNoVars.js +5 -0
  162. package/styles/createThemeNoVars.mjs +5 -0
  163. package/styles/createTransitions.d.mts +6 -2
  164. package/styles/createTransitions.d.ts +6 -2
  165. package/styles/createTransitions.js +12 -4
  166. package/styles/createTransitions.mjs +12 -4
  167. package/styles/enhanceHighContrast.d.mts +70 -0
  168. package/styles/enhanceHighContrast.d.ts +70 -0
  169. package/styles/enhanceHighContrast.js +502 -0
  170. package/styles/enhanceHighContrast.mjs +495 -0
  171. package/styles/index.d.mts +2 -0
  172. package/styles/index.d.ts +2 -0
  173. package/styles/index.js +8 -0
  174. package/styles/index.mjs +1 -0
  175. package/styles/reducedMotion.d.mts +7 -0
  176. package/styles/reducedMotion.d.ts +7 -0
  177. package/styles/reducedMotion.js +21 -0
  178. package/styles/reducedMotion.mjs +14 -0
  179. package/styles/shouldSkipGeneratingVar.js +1 -1
  180. package/styles/shouldSkipGeneratingVar.mjs +1 -1
  181. package/styles/stringifyTheme.js +1 -0
  182. package/styles/stringifyTheme.mjs +1 -0
  183. package/transitions/index.d.mts +1 -1
  184. package/transitions/index.d.ts +1 -1
  185. package/transitions/index.js +0 -11
  186. package/transitions/index.mjs +1 -1
  187. package/transitions/transition.d.mts +1 -12
  188. package/transitions/transition.d.ts +1 -12
  189. package/transitions/types.d.mts +73 -0
  190. package/transitions/types.d.ts +73 -0
  191. package/transitions/useReducedMotion.d.mts +14 -0
  192. package/transitions/useReducedMotion.d.ts +14 -0
  193. package/transitions/useReducedMotion.js +117 -0
  194. package/transitions/useReducedMotion.mjs +110 -0
  195. package/transitions/utils.d.mts +34 -2
  196. package/transitions/utils.d.ts +34 -2
  197. package/transitions/utils.js +33 -4
  198. package/transitions/utils.mjs +31 -4
  199. package/useAutocomplete/useAutocomplete.d.mts +8 -1
  200. package/useAutocomplete/useAutocomplete.d.ts +8 -1
  201. package/useAutocomplete/useAutocomplete.js +66 -4
  202. package/useAutocomplete/useAutocomplete.mjs +66 -4
  203. package/version/index.js +3 -3
  204. package/version/index.mjs +3 -3
  205. /package/transitions/{transition.js → types.js} +0 -0
  206. /package/transitions/{transition.mjs → types.mjs} +0 -0
@@ -6,7 +6,7 @@ import { Theme } from "../styles/index.js";
6
6
  import { InternalStandardProps as StandardProps } from "../internal/index.js";
7
7
  import { PaperProps } from "../Paper/index.js";
8
8
  import { ModalProps } from "../Modal/index.js";
9
- import { TransitionProps } from "../transitions/transition.js";
9
+ import { TransitionProps } from "../transitions/types.js";
10
10
  import { PopoverClasses } from "./popoverClasses.js";
11
11
  import { CreateSlotsAndSlotProps, SlotProps } from "../utils/types.js";
12
12
  export interface PopoverSlots {
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  <!-- #host-reference -->
2
- <!-- markdownlint-disable-next-line -->
2
+ <!-- lint disable mui-first-block-heading -->
3
+
3
4
  <p align="center">
4
- <a href="https://mui.com/material-ui/" rel="noopener" target="_blank"><img width="150" height="133" src="https://mui.com/static/logo.svg" alt="Material UI logo"></a>
5
+ <a href="https://mui.com/material-ui/" target="_blank"><img width="150" height="133" src="https://mui.com/static/logo.svg" alt="Material UI logo"></a>
5
6
  </p>
6
7
 
7
8
  <h1 align="center">Material UI</h1>
@@ -12,6 +12,7 @@ var _RadioButtonChecked = _interopRequireDefault(require("../internal/svg-icons/
12
12
  var _rootShouldForwardProp = _interopRequireDefault(require("../styles/rootShouldForwardProp"));
13
13
  var _zeroStyled = require("../zero-styled");
14
14
  var _memoTheme = _interopRequireDefault(require("../utils/memoTheme"));
15
+ var _utils = require("../transitions/utils");
15
16
  var _jsxRuntime = require("react/jsx-runtime");
16
17
  const RadioButtonIconRoot = (0, _zeroStyled.styled)('span', {
17
18
  name: 'MuiRadioButtonIcon',
@@ -34,7 +35,7 @@ const RadioButtonIconDot = (0, _zeroStyled.styled)(_RadioButtonChecked.default,
34
35
  left: 0,
35
36
  position: 'absolute',
36
37
  transform: 'scale(0)',
37
- transition: theme.transitions.create('transform', {
38
+ ...(0, _utils.getTransitionStyles)(theme, 'transform', {
38
39
  easing: theme.transitions.easing.easeIn,
39
40
  duration: theme.transitions.duration.shortest
40
41
  }),
@@ -44,7 +45,7 @@ const RadioButtonIconDot = (0, _zeroStyled.styled)(_RadioButtonChecked.default,
44
45
  },
45
46
  style: {
46
47
  transform: 'scale(1)',
47
- transition: theme.transitions.create('transform', {
48
+ ...(0, _utils.getTransitionStyles)(theme, 'transform', {
48
49
  easing: theme.transitions.easing.easeOut,
49
50
  duration: theme.transitions.duration.shortest
50
51
  })
@@ -6,6 +6,7 @@ import RadioButtonCheckedIcon from "../internal/svg-icons/RadioButtonChecked.mjs
6
6
  import rootShouldForwardProp from "../styles/rootShouldForwardProp.mjs";
7
7
  import { styled } from "../zero-styled/index.mjs";
8
8
  import memoTheme from "../utils/memoTheme.mjs";
9
+ import { getTransitionStyles } from "../transitions/utils.mjs";
9
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
11
  const RadioButtonIconRoot = styled('span', {
11
12
  name: 'MuiRadioButtonIcon',
@@ -28,7 +29,7 @@ const RadioButtonIconDot = styled(RadioButtonCheckedIcon, {
28
29
  left: 0,
29
30
  position: 'absolute',
30
31
  transform: 'scale(0)',
31
- transition: theme.transitions.create('transform', {
32
+ ...getTransitionStyles(theme, 'transform', {
32
33
  easing: theme.transitions.easing.easeIn,
33
34
  duration: theme.transitions.duration.shortest
34
35
  }),
@@ -38,7 +39,7 @@ const RadioButtonIconDot = styled(RadioButtonCheckedIcon, {
38
39
  },
39
40
  style: {
40
41
  transform: 'scale(1)',
41
- transition: theme.transitions.create('transform', {
42
+ ...getTransitionStyles(theme, 'transform', {
42
43
  easing: theme.transitions.easing.easeOut,
43
44
  duration: theme.transitions.duration.shortest
44
45
  })
package/Rating/Rating.js CHANGED
@@ -26,6 +26,7 @@ var _DefaultPropsProvider = require("../DefaultPropsProvider");
26
26
  var _slotShouldForwardProp = _interopRequireDefault(require("../styles/slotShouldForwardProp"));
27
27
  var _ratingClasses = _interopRequireWildcard(require("./ratingClasses"));
28
28
  var _useSlot = _interopRequireDefault(require("../utils/useSlot"));
29
+ var _utils2 = require("../transitions/utils");
29
30
  var _jsxRuntime = require("react/jsx-runtime");
30
31
  function getDecimalPrecision(num) {
31
32
  const decimalPart = num.toString().split('.')[1];
@@ -152,7 +153,7 @@ const RatingIcon = (0, _zeroStyled.styled)('span', {
152
153
  }) => ({
153
154
  // Fit wrapper to actual icon size.
154
155
  display: 'flex',
155
- transition: theme.transitions.create('transform', {
156
+ ...(0, _utils2.getTransitionStyles)(theme, 'transform', {
156
157
  duration: theme.transitions.duration.shortest
157
158
  }),
158
159
  // Fix mouseLeave issue.
package/Rating/Rating.mjs CHANGED
@@ -18,6 +18,7 @@ import { useDefaultProps } from "../DefaultPropsProvider/index.mjs";
18
18
  import slotShouldForwardProp from "../styles/slotShouldForwardProp.mjs";
19
19
  import ratingClasses, { getRatingUtilityClass } from "./ratingClasses.mjs";
20
20
  import useSlot from "../utils/useSlot.mjs";
21
+ import { getTransitionStyles } from "../transitions/utils.mjs";
21
22
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
22
23
  import { createElement as _createElement } from "react";
23
24
  function getDecimalPrecision(num) {
@@ -145,7 +146,7 @@ const RatingIcon = styled('span', {
145
146
  }) => ({
146
147
  // Fit wrapper to actual icon size.
147
148
  display: 'flex',
148
- transition: theme.transitions.create('transform', {
149
+ ...getTransitionStyles(theme, 'transform', {
149
150
  duration: theme.transitions.duration.shortest
150
151
  }),
151
152
  // Fix mouseLeave issue.
@@ -28,6 +28,7 @@ var _useForkRef = _interopRequireDefault(require("../utils/useForkRef"));
28
28
  var _useControlled = _interopRequireDefault(require("../utils/useControlled"));
29
29
  var _selectClasses = _interopRequireWildcard(require("./selectClasses"));
30
30
  var _utils2 = require("./utils");
31
+ var _closedTypeahead = require("./utils/closedTypeahead");
31
32
  var _SelectFocusSourceContext = require("./utils/SelectFocusSourceContext");
32
33
  var _jsxRuntime = require("react/jsx-runtime");
33
34
  var _span;
@@ -35,6 +36,11 @@ const OPENING_MOUSE_UP_BOUNDARY_OFFSET = 2;
35
36
  // The initial mouseup may land on an item when the menu opens over the trigger.
36
37
  const SELECTED_MOUSE_UP_DELAY = 400;
37
38
  const UNSELECTED_MOUSE_UP_DELAY = 200;
39
+ const TYPEAHEAD_RESET_MS = 750;
40
+ const SPACE = ' ';
41
+ const ARROW_UP = 'ArrowUp';
42
+ const ARROW_DOWN = 'ArrowDown';
43
+ const ENTER = 'Enter';
38
44
 
39
45
  /**
40
46
  * Returns true when a native mouse event should be treated as happening inside
@@ -197,8 +203,14 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
197
203
  allowSelectedMouseUp: false,
198
204
  allowUnselectedMouseUp: false
199
205
  });
206
+ const closedTypeaheadRef = React.useRef({
207
+ buffer: '',
208
+ previousSearchIndex: null,
209
+ matchedIndex: null
210
+ });
200
211
  const selectedMouseUpTimer = (0, _useTimeout.default)();
201
212
  const unselectedMouseUpTimer = (0, _useTimeout.default)();
213
+ const typeaheadResetTimer = (0, _useTimeout.default)();
202
214
  const [displayNode, setDisplayNode] = React.useState(null);
203
215
  const {
204
216
  current: isOpenControlled
@@ -221,9 +233,18 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
221
233
  value
222
234
  }), [value]);
223
235
  const open = displayNode !== null && openState;
236
+ const resetClosedTypeahead = React.useCallback(() => {
237
+ typeaheadResetTimer.clear();
238
+ closedTypeaheadRef.current.buffer = '';
239
+ closedTypeaheadRef.current.previousSearchIndex = null;
240
+ closedTypeaheadRef.current.matchedIndex = null;
241
+ }, [typeaheadResetTimer]);
224
242
  (0, _useEnhancedEffect.default)(() => {
225
243
  openRef.current = open;
226
- }, [open]);
244
+ if (open) {
245
+ resetClosedTypeahead();
246
+ }
247
+ }, [open, resetClosedTypeahead]);
227
248
  const clearSelectionTimers = React.useCallback(() => {
228
249
  selectedMouseUpTimer.clear();
229
250
  unselectedMouseUpTimer.clear();
@@ -255,8 +276,9 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
255
276
  return () => {
256
277
  resetMouseUpSelection();
257
278
  clearOpeningMouseUpListener();
279
+ resetClosedTypeahead();
258
280
  };
259
- }, [resetMouseUpSelection, clearOpeningMouseUpListener]);
281
+ }, [resetMouseUpSelection, clearOpeningMouseUpListener, resetClosedTypeahead]);
260
282
  React.useEffect(() => {
261
283
  if (!open || !anchorElement || autoWidth) {
262
284
  return undefined;
@@ -313,6 +335,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
313
335
  clearOpeningMouseUpListener();
314
336
  }
315
337
  if (openParam) {
338
+ resetClosedTypeahead();
316
339
  setOpenInteractionType((0, _utils2.getOpenInteractionType)(event));
317
340
  if (onOpen) {
318
341
  onOpen(event);
@@ -402,6 +425,25 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
402
425
  onChange(event, child);
403
426
  }
404
427
  };
428
+ const handleValueChange = (event, child, newValue) => {
429
+ setValueState(newValue);
430
+ if (onChange) {
431
+ // Redefine target to allow name and value to be read.
432
+ // This allows seamless integration with the most popular form libraries.
433
+ // https://github.com/mui/material-ui/issues/13485#issuecomment-676048492
434
+ // Clone the event to not override `target` of the original event.
435
+ const nativeEvent = event.nativeEvent || event;
436
+ const clonedEvent = new nativeEvent.constructor(nativeEvent.type, nativeEvent);
437
+ Object.defineProperty(clonedEvent, 'target', {
438
+ writable: true,
439
+ value: {
440
+ value: newValue,
441
+ name
442
+ }
443
+ });
444
+ onChange(clonedEvent, child);
445
+ }
446
+ };
405
447
  const handleItemClick = child => event => {
406
448
  didPointerDownOnItemRef.current = false;
407
449
  let newValue;
@@ -425,23 +467,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
425
467
  child.props.onClick(event);
426
468
  }
427
469
  if (value !== newValue) {
428
- setValueState(newValue);
429
- if (onChange) {
430
- // Redefine target to allow name and value to be read.
431
- // This allows seamless integration with the most popular form libraries.
432
- // https://github.com/mui/material-ui/issues/13485#issuecomment-676048492
433
- // Clone the event to not override `target` of the original event.
434
- const nativeEvent = event.nativeEvent || event;
435
- const clonedEvent = new nativeEvent.constructor(nativeEvent.type, nativeEvent);
436
- Object.defineProperty(clonedEvent, 'target', {
437
- writable: true,
438
- value: {
439
- value: newValue,
440
- name
441
- }
442
- });
443
- onChange(clonedEvent, child);
444
- }
470
+ handleValueChange(event, child, newValue);
445
471
  }
446
472
  if (!multiple) {
447
473
  update(false, event);
@@ -460,13 +486,57 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
460
486
  }
461
487
  event.currentTarget.click();
462
488
  };
489
+ const handleClosedTypeahead = event => {
490
+ const state = closedTypeaheadRef.current;
491
+ const hasActiveBuffer = state.buffer !== '';
492
+ if (open || multiple || disabled || event.defaultPrevented || event.nativeEvent?.isComposing || event.key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey || event.key === SPACE && !hasActiveBuffer) {
493
+ return false;
494
+ }
495
+ if (event.key === SPACE) {
496
+ event.preventDefault();
497
+ }
498
+ const isNewSession = state.buffer === '';
499
+ const {
500
+ options: searchableOptions,
501
+ selectedIndex
502
+ } = (0, _closedTypeahead.getTypeaheadOptions)(childrenArray, value);
503
+ if (searchableOptions.length === 0) {
504
+ if (event.key !== SPACE) {
505
+ resetClosedTypeahead();
506
+ }
507
+ return true;
508
+ }
509
+ if (isNewSession) {
510
+ state.previousSearchIndex = selectedIndex;
511
+ }
512
+ const key = event.key.toLowerCase();
513
+ if (state.buffer === key && (0, _closedTypeahead.canCycleRepeatedCharacter)(searchableOptions, key)) {
514
+ state.buffer = '';
515
+ state.previousSearchIndex = state.matchedIndex;
516
+ }
517
+ state.buffer += key;
518
+ typeaheadResetTimer.start(TYPEAHEAD_RESET_MS, resetClosedTypeahead);
519
+ const matchingIndex = (0, _closedTypeahead.getMatchingOptionIndex)(searchableOptions, state.buffer, (state.previousSearchIndex ?? -1) + 1);
520
+ if (matchingIndex !== -1) {
521
+ const matchedOption = searchableOptions[matchingIndex];
522
+ state.matchedIndex = matchingIndex;
523
+ if (!(0, _utils2.areEqualValues)(value, matchedOption.value)) {
524
+ handleValueChange(event, matchedOption.child, matchedOption.value);
525
+ }
526
+ return true;
527
+ }
528
+ if (event.key !== SPACE) {
529
+ resetClosedTypeahead();
530
+ }
531
+ return true;
532
+ };
463
533
  const handleKeyDown = event => {
464
534
  if (!readOnly) {
465
- const validKeys = [' ', 'ArrowUp', 'ArrowDown',
466
- // The native select doesn't respond to enter on macOS, but it's recommended by
535
+ const isClosedTypeaheadHandled = handleClosedTypeahead(event);
536
+ // The native select doesn't respond to Enter on macOS, but it's recommended by
467
537
  // https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/
468
- 'Enter'];
469
- if (validKeys.includes(event.key)) {
538
+ const isOpenKey = event.key === SPACE || event.key === ARROW_UP || event.key === ARROW_DOWN || event.key === ENTER;
539
+ if (!isClosedTypeaheadHandled && isOpenKey) {
470
540
  event.preventDefault();
471
541
  update(true, event);
472
542
  }
@@ -474,6 +544,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
474
544
  }
475
545
  };
476
546
  const handleBlur = event => {
547
+ resetClosedTypeahead();
477
548
  // if open event.stopImmediatePropagation
478
549
  if (!open && onBlur) {
479
550
  // Preact support, target is read only property on a native event.
@@ -487,6 +558,19 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
487
558
  onBlur(event);
488
559
  }
489
560
  };
561
+ const handleItemKeyDown = child => event => {
562
+ child?.props?.onKeyDown?.(event);
563
+ if (event.key === SPACE && event.target === event.currentTarget && !event.defaultPrevented) {
564
+ // Prevent the browser from scrolling the page
565
+ event.preventDefault();
566
+ // Ignore auto-repeated keydowns to avoid toggling multiple times
567
+ if (!event.repeat) {
568
+ // Trigger via click so that onClick receives a click event,
569
+ // consistent with Enter and pointer interactions.
570
+ event.currentTarget.click();
571
+ }
572
+ }
573
+ };
490
574
  delete other['aria-invalid'];
491
575
  let display;
492
576
  let displaySingle;
@@ -544,7 +628,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
544
628
  onClick: handleItemClick(child),
545
629
  onMouseUp: handleItemMouseUp(child, selected),
546
630
  onKeyUp: event => {
547
- if (event.key === ' ') {
631
+ if (event.key === SPACE) {
548
632
  // otherwise our MenuItems dispatches a click event
549
633
  // it's not behavior of the native <option> and causes
550
634
  // the select to close immediately since we open on space keydown
@@ -554,6 +638,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
554
638
  child.props.onKeyUp(event);
555
639
  }
556
640
  },
641
+ onKeyDown: handleItemKeyDown(child),
557
642
  role: 'option',
558
643
  selected,
559
644
  value: undefined,
@@ -565,7 +650,10 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
565
650
  // Keep the opening mouseup guard current without mutating refs during render.
566
651
  (0, _useEnhancedEffect.default)(() => {
567
652
  hasSelectedItemInListRef.current = foundMatch;
568
- }, [foundMatch]);
653
+ if (!open && !multiple && !foundMatch) {
654
+ resetClosedTypeahead();
655
+ }
656
+ }, [foundMatch, multiple, open, resetClosedTypeahead]);
569
657
  if (process.env.NODE_ENV !== 'production') {
570
658
  // TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
571
659
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -629,6 +717,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
629
717
  "aria-disabled": disabled ? 'true' : undefined,
630
718
  "aria-expanded": open ? 'true' : 'false',
631
719
  "aria-haspopup": "listbox",
720
+ "aria-readonly": readOnly ? 'true' : undefined,
632
721
  "aria-label": ariaLabel,
633
722
  "aria-labelledby": labelId,
634
723
  "aria-describedby": ariaDescribedby,
@@ -659,6 +748,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
659
748
  onChange: handleChange,
660
749
  tabIndex: -1,
661
750
  disabled: disabled,
751
+ readOnly: readOnly,
662
752
  className: classes.nativeInput,
663
753
  autoFocus: autoFocus,
664
754
  required: required,
@@ -22,12 +22,18 @@ import useForkRef from "../utils/useForkRef.mjs";
22
22
  import useControlled from "../utils/useControlled.mjs";
23
23
  import selectClasses, { getSelectUtilityClasses } from "./selectClasses.mjs";
24
24
  import { areEqualValues, isEmpty, getOpenInteractionType } from "./utils/index.mjs";
25
+ import { canCycleRepeatedCharacter, getMatchingOptionIndex, getTypeaheadOptions } from "./utils/closedTypeahead.mjs";
25
26
  import { SelectFocusSourceProvider } from "./utils/SelectFocusSourceContext.mjs";
26
27
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
27
28
  const OPENING_MOUSE_UP_BOUNDARY_OFFSET = 2;
28
29
  // The initial mouseup may land on an item when the menu opens over the trigger.
29
30
  const SELECTED_MOUSE_UP_DELAY = 400;
30
31
  const UNSELECTED_MOUSE_UP_DELAY = 200;
32
+ const TYPEAHEAD_RESET_MS = 750;
33
+ const SPACE = ' ';
34
+ const ARROW_UP = 'ArrowUp';
35
+ const ARROW_DOWN = 'ArrowDown';
36
+ const ENTER = 'Enter';
31
37
 
32
38
  /**
33
39
  * Returns true when a native mouse event should be treated as happening inside
@@ -190,8 +196,14 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
190
196
  allowSelectedMouseUp: false,
191
197
  allowUnselectedMouseUp: false
192
198
  });
199
+ const closedTypeaheadRef = React.useRef({
200
+ buffer: '',
201
+ previousSearchIndex: null,
202
+ matchedIndex: null
203
+ });
193
204
  const selectedMouseUpTimer = useTimeout();
194
205
  const unselectedMouseUpTimer = useTimeout();
206
+ const typeaheadResetTimer = useTimeout();
195
207
  const [displayNode, setDisplayNode] = React.useState(null);
196
208
  const {
197
209
  current: isOpenControlled
@@ -214,9 +226,18 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
214
226
  value
215
227
  }), [value]);
216
228
  const open = displayNode !== null && openState;
229
+ const resetClosedTypeahead = React.useCallback(() => {
230
+ typeaheadResetTimer.clear();
231
+ closedTypeaheadRef.current.buffer = '';
232
+ closedTypeaheadRef.current.previousSearchIndex = null;
233
+ closedTypeaheadRef.current.matchedIndex = null;
234
+ }, [typeaheadResetTimer]);
217
235
  useEnhancedEffect(() => {
218
236
  openRef.current = open;
219
- }, [open]);
237
+ if (open) {
238
+ resetClosedTypeahead();
239
+ }
240
+ }, [open, resetClosedTypeahead]);
220
241
  const clearSelectionTimers = React.useCallback(() => {
221
242
  selectedMouseUpTimer.clear();
222
243
  unselectedMouseUpTimer.clear();
@@ -248,8 +269,9 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
248
269
  return () => {
249
270
  resetMouseUpSelection();
250
271
  clearOpeningMouseUpListener();
272
+ resetClosedTypeahead();
251
273
  };
252
- }, [resetMouseUpSelection, clearOpeningMouseUpListener]);
274
+ }, [resetMouseUpSelection, clearOpeningMouseUpListener, resetClosedTypeahead]);
253
275
  React.useEffect(() => {
254
276
  if (!open || !anchorElement || autoWidth) {
255
277
  return undefined;
@@ -306,6 +328,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
306
328
  clearOpeningMouseUpListener();
307
329
  }
308
330
  if (openParam) {
331
+ resetClosedTypeahead();
309
332
  setOpenInteractionType(getOpenInteractionType(event));
310
333
  if (onOpen) {
311
334
  onOpen(event);
@@ -395,6 +418,25 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
395
418
  onChange(event, child);
396
419
  }
397
420
  };
421
+ const handleValueChange = (event, child, newValue) => {
422
+ setValueState(newValue);
423
+ if (onChange) {
424
+ // Redefine target to allow name and value to be read.
425
+ // This allows seamless integration with the most popular form libraries.
426
+ // https://github.com/mui/material-ui/issues/13485#issuecomment-676048492
427
+ // Clone the event to not override `target` of the original event.
428
+ const nativeEvent = event.nativeEvent || event;
429
+ const clonedEvent = new nativeEvent.constructor(nativeEvent.type, nativeEvent);
430
+ Object.defineProperty(clonedEvent, 'target', {
431
+ writable: true,
432
+ value: {
433
+ value: newValue,
434
+ name
435
+ }
436
+ });
437
+ onChange(clonedEvent, child);
438
+ }
439
+ };
398
440
  const handleItemClick = child => event => {
399
441
  didPointerDownOnItemRef.current = false;
400
442
  let newValue;
@@ -418,23 +460,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
418
460
  child.props.onClick(event);
419
461
  }
420
462
  if (value !== newValue) {
421
- setValueState(newValue);
422
- if (onChange) {
423
- // Redefine target to allow name and value to be read.
424
- // This allows seamless integration with the most popular form libraries.
425
- // https://github.com/mui/material-ui/issues/13485#issuecomment-676048492
426
- // Clone the event to not override `target` of the original event.
427
- const nativeEvent = event.nativeEvent || event;
428
- const clonedEvent = new nativeEvent.constructor(nativeEvent.type, nativeEvent);
429
- Object.defineProperty(clonedEvent, 'target', {
430
- writable: true,
431
- value: {
432
- value: newValue,
433
- name
434
- }
435
- });
436
- onChange(clonedEvent, child);
437
- }
463
+ handleValueChange(event, child, newValue);
438
464
  }
439
465
  if (!multiple) {
440
466
  update(false, event);
@@ -453,13 +479,57 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
453
479
  }
454
480
  event.currentTarget.click();
455
481
  };
482
+ const handleClosedTypeahead = event => {
483
+ const state = closedTypeaheadRef.current;
484
+ const hasActiveBuffer = state.buffer !== '';
485
+ if (open || multiple || disabled || event.defaultPrevented || event.nativeEvent?.isComposing || event.key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey || event.key === SPACE && !hasActiveBuffer) {
486
+ return false;
487
+ }
488
+ if (event.key === SPACE) {
489
+ event.preventDefault();
490
+ }
491
+ const isNewSession = state.buffer === '';
492
+ const {
493
+ options: searchableOptions,
494
+ selectedIndex
495
+ } = getTypeaheadOptions(childrenArray, value);
496
+ if (searchableOptions.length === 0) {
497
+ if (event.key !== SPACE) {
498
+ resetClosedTypeahead();
499
+ }
500
+ return true;
501
+ }
502
+ if (isNewSession) {
503
+ state.previousSearchIndex = selectedIndex;
504
+ }
505
+ const key = event.key.toLowerCase();
506
+ if (state.buffer === key && canCycleRepeatedCharacter(searchableOptions, key)) {
507
+ state.buffer = '';
508
+ state.previousSearchIndex = state.matchedIndex;
509
+ }
510
+ state.buffer += key;
511
+ typeaheadResetTimer.start(TYPEAHEAD_RESET_MS, resetClosedTypeahead);
512
+ const matchingIndex = getMatchingOptionIndex(searchableOptions, state.buffer, (state.previousSearchIndex ?? -1) + 1);
513
+ if (matchingIndex !== -1) {
514
+ const matchedOption = searchableOptions[matchingIndex];
515
+ state.matchedIndex = matchingIndex;
516
+ if (!areEqualValues(value, matchedOption.value)) {
517
+ handleValueChange(event, matchedOption.child, matchedOption.value);
518
+ }
519
+ return true;
520
+ }
521
+ if (event.key !== SPACE) {
522
+ resetClosedTypeahead();
523
+ }
524
+ return true;
525
+ };
456
526
  const handleKeyDown = event => {
457
527
  if (!readOnly) {
458
- const validKeys = [' ', 'ArrowUp', 'ArrowDown',
459
- // The native select doesn't respond to enter on macOS, but it's recommended by
528
+ const isClosedTypeaheadHandled = handleClosedTypeahead(event);
529
+ // The native select doesn't respond to Enter on macOS, but it's recommended by
460
530
  // https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/
461
- 'Enter'];
462
- if (validKeys.includes(event.key)) {
531
+ const isOpenKey = event.key === SPACE || event.key === ARROW_UP || event.key === ARROW_DOWN || event.key === ENTER;
532
+ if (!isClosedTypeaheadHandled && isOpenKey) {
463
533
  event.preventDefault();
464
534
  update(true, event);
465
535
  }
@@ -467,6 +537,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
467
537
  }
468
538
  };
469
539
  const handleBlur = event => {
540
+ resetClosedTypeahead();
470
541
  // if open event.stopImmediatePropagation
471
542
  if (!open && onBlur) {
472
543
  // Preact support, target is read only property on a native event.
@@ -480,6 +551,19 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
480
551
  onBlur(event);
481
552
  }
482
553
  };
554
+ const handleItemKeyDown = child => event => {
555
+ child?.props?.onKeyDown?.(event);
556
+ if (event.key === SPACE && event.target === event.currentTarget && !event.defaultPrevented) {
557
+ // Prevent the browser from scrolling the page
558
+ event.preventDefault();
559
+ // Ignore auto-repeated keydowns to avoid toggling multiple times
560
+ if (!event.repeat) {
561
+ // Trigger via click so that onClick receives a click event,
562
+ // consistent with Enter and pointer interactions.
563
+ event.currentTarget.click();
564
+ }
565
+ }
566
+ };
483
567
  delete other['aria-invalid'];
484
568
  let display;
485
569
  let displaySingle;
@@ -537,7 +621,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
537
621
  onClick: handleItemClick(child),
538
622
  onMouseUp: handleItemMouseUp(child, selected),
539
623
  onKeyUp: event => {
540
- if (event.key === ' ') {
624
+ if (event.key === SPACE) {
541
625
  // otherwise our MenuItems dispatches a click event
542
626
  // it's not behavior of the native <option> and causes
543
627
  // the select to close immediately since we open on space keydown
@@ -547,6 +631,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
547
631
  child.props.onKeyUp(event);
548
632
  }
549
633
  },
634
+ onKeyDown: handleItemKeyDown(child),
550
635
  role: 'option',
551
636
  selected,
552
637
  value: undefined,
@@ -558,7 +643,10 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
558
643
  // Keep the opening mouseup guard current without mutating refs during render.
559
644
  useEnhancedEffect(() => {
560
645
  hasSelectedItemInListRef.current = foundMatch;
561
- }, [foundMatch]);
646
+ if (!open && !multiple && !foundMatch) {
647
+ resetClosedTypeahead();
648
+ }
649
+ }, [foundMatch, multiple, open, resetClosedTypeahead]);
562
650
  if (process.env.NODE_ENV !== 'production') {
563
651
  // TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
564
652
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -622,6 +710,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
622
710
  "aria-disabled": disabled ? 'true' : undefined,
623
711
  "aria-expanded": open ? 'true' : 'false',
624
712
  "aria-haspopup": "listbox",
713
+ "aria-readonly": readOnly ? 'true' : undefined,
625
714
  "aria-label": ariaLabel,
626
715
  "aria-labelledby": labelId,
627
716
  "aria-describedby": ariaDescribedby,
@@ -652,6 +741,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
652
741
  onChange: handleChange,
653
742
  tabIndex: -1,
654
743
  disabled: disabled,
744
+ readOnly: readOnly,
655
745
  className: classes.nativeInput,
656
746
  autoFocus: autoFocus,
657
747
  required: required,