@mui/material 6.3.1 → 6.4.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 (69) hide show
  1. package/Alert/Alert.d.ts +69 -0
  2. package/Alert/Alert.js +53 -21
  3. package/Autocomplete/Autocomplete.d.ts +1 -1
  4. package/Button/Button.d.ts +18 -0
  5. package/Button/Button.js +233 -15
  6. package/Button/buttonClasses.d.ts +14 -0
  7. package/Button/buttonClasses.js +1 -1
  8. package/CHANGELOG.md +49 -0
  9. package/CardHeader/CardHeader.d.ts +114 -1
  10. package/CardHeader/CardHeader.js +99 -32
  11. package/CircularProgress/CircularProgress.js +2 -2
  12. package/IconButton/IconButton.d.ts +12 -0
  13. package/IconButton/IconButton.js +69 -7
  14. package/IconButton/iconButtonClasses.d.ts +4 -0
  15. package/IconButton/iconButtonClasses.js +1 -1
  16. package/LinearProgress/LinearProgress.js +4 -4
  17. package/LinearProgress/linearProgressClasses.d.ts +31 -9
  18. package/LinearProgress/linearProgressClasses.js +1 -1
  19. package/Link/getTextDecoration.js +3 -2
  20. package/Select/Select.js +10 -1
  21. package/Select/SelectInput.js +1 -1
  22. package/Slider/useSlider.js +5 -2
  23. package/StepLabel/StepLabel.d.ts +1 -1
  24. package/Tooltip/Tooltip.d.ts +1 -1
  25. package/index.js +1 -1
  26. package/modern/Alert/Alert.js +53 -21
  27. package/modern/Button/Button.js +233 -15
  28. package/modern/Button/buttonClasses.js +1 -1
  29. package/modern/CardHeader/CardHeader.js +99 -32
  30. package/modern/CircularProgress/CircularProgress.js +2 -2
  31. package/modern/IconButton/IconButton.js +69 -7
  32. package/modern/IconButton/iconButtonClasses.js +1 -1
  33. package/modern/LinearProgress/LinearProgress.js +4 -4
  34. package/modern/LinearProgress/linearProgressClasses.js +1 -1
  35. package/modern/Link/getTextDecoration.js +3 -2
  36. package/modern/Select/Select.js +10 -1
  37. package/modern/Select/SelectInput.js +1 -1
  38. package/modern/Slider/useSlider.js +5 -2
  39. package/modern/index.js +1 -1
  40. package/modern/utils/index.js +1 -0
  41. package/modern/utils/mergeSlotProps.js +43 -0
  42. package/modern/utils/useSlot.js +5 -1
  43. package/modern/version/index.js +3 -3
  44. package/node/Alert/Alert.js +53 -21
  45. package/node/Button/Button.js +233 -15
  46. package/node/Button/buttonClasses.js +1 -1
  47. package/node/CardHeader/CardHeader.js +99 -32
  48. package/node/CircularProgress/CircularProgress.js +2 -2
  49. package/node/IconButton/IconButton.js +68 -6
  50. package/node/IconButton/iconButtonClasses.js +1 -1
  51. package/node/LinearProgress/LinearProgress.js +4 -4
  52. package/node/LinearProgress/linearProgressClasses.js +1 -1
  53. package/node/Link/getTextDecoration.js +3 -2
  54. package/node/Select/Select.js +10 -1
  55. package/node/Select/SelectInput.js +1 -1
  56. package/node/Slider/useSlider.js +5 -2
  57. package/node/index.js +1 -1
  58. package/node/utils/index.js +7 -0
  59. package/node/utils/mergeSlotProps.js +50 -0
  60. package/node/utils/useSlot.js +5 -1
  61. package/node/version/index.js +3 -3
  62. package/package.json +5 -5
  63. package/utils/index.d.ts +1 -0
  64. package/utils/index.js +1 -0
  65. package/utils/mergeSlotProps.d.ts +2 -0
  66. package/utils/mergeSlotProps.js +43 -0
  67. package/utils/useSlot.d.ts +8 -0
  68. package/utils/useSlot.js +5 -1
  69. package/version/index.js +3 -3
package/Select/Select.js CHANGED
@@ -4,6 +4,7 @@ import * as React from 'react';
4
4
  import PropTypes from 'prop-types';
5
5
  import clsx from 'clsx';
6
6
  import deepmerge from '@mui/utils/deepmerge';
7
+ import composeClasses from '@mui/utils/composeClasses';
7
8
  import getReactElementRef from '@mui/utils/getReactElementRef';
8
9
  import SelectInput from "./SelectInput.js";
9
10
  import formControlState from "../FormControl/formControlState.js";
@@ -17,12 +18,20 @@ import { useDefaultProps } from "../DefaultPropsProvider/index.js";
17
18
  import useForkRef from "../utils/useForkRef.js";
18
19
  import { styled } from "../zero-styled/index.js";
19
20
  import rootShouldForwardProp from "../styles/rootShouldForwardProp.js";
21
+ import { getSelectUtilityClasses } from "./selectClasses.js";
20
22
  import { jsx as _jsx } from "react/jsx-runtime";
21
23
  const useUtilityClasses = ownerState => {
22
24
  const {
23
25
  classes
24
26
  } = ownerState;
25
- return classes;
27
+ const slots = {
28
+ root: ['root']
29
+ };
30
+ const composedClasses = composeClasses(slots, getSelectUtilityClasses, classes);
31
+ return {
32
+ ...classes,
33
+ ...composedClasses
34
+ };
26
35
  };
27
36
  const styledRootConfig = {
28
37
  name: 'MuiSelect',
@@ -443,7 +443,7 @@ const SelectInput = /*#__PURE__*/React.forwardRef(function SelectInput(props, re
443
443
  ref: handleDisplayRef,
444
444
  tabIndex: tabIndex,
445
445
  role: "combobox",
446
- "aria-controls": listboxId,
446
+ "aria-controls": open ? listboxId : undefined,
447
447
  "aria-disabled": disabled ? 'true' : undefined,
448
448
  "aria-expanded": open ? 'true' : 'false',
449
449
  "aria-haspopup": "listbox",
@@ -188,6 +188,8 @@ export function useSlider(parameters) {
188
188
  const [open, setOpen] = React.useState(-1);
189
189
  const [dragging, setDragging] = React.useState(false);
190
190
  const moveCount = React.useRef(0);
191
+ // lastChangedValue is updated whenever onChange is triggered.
192
+ const lastChangedValue = React.useRef(null);
191
193
  const [valueDerived, setValueState] = useControlled({
192
194
  controlled: valueProp,
193
195
  default: defaultValue ?? min,
@@ -208,6 +210,7 @@ export function useSlider(parameters) {
208
210
  name
209
211
  }
210
212
  });
213
+ lastChangedValue.current = value;
211
214
  onChange(clonedEvent, value, thumbIndex);
212
215
  });
213
216
  const range = Array.isArray(valueDerived);
@@ -279,7 +282,7 @@ export function useSlider(parameters) {
279
282
  handleChange(event, newValue, index);
280
283
  }
281
284
  if (onChangeCommitted) {
282
- onChangeCommitted(event, newValue);
285
+ onChangeCommitted(event, lastChangedValue.current ?? newValue);
283
286
  }
284
287
  };
285
288
  const createHandleHiddenInputKeyDown = otherHandlers => event => {
@@ -484,7 +487,7 @@ export function useSlider(parameters) {
484
487
  setOpen(-1);
485
488
  }
486
489
  if (onChangeCommitted) {
487
- onChangeCommitted(nativeEvent, newValue);
490
+ onChangeCommitted(nativeEvent, lastChangedValue.current ?? newValue);
488
491
  }
489
492
  touchId.current = undefined;
490
493
 
@@ -15,7 +15,7 @@ export interface StepLabelSlots {
15
15
  /**
16
16
  * The component to render in place of the [`StepIcon`](https://mui.com/material-ui/api/step-icon/).
17
17
  */
18
- stepIcon: React.ElementType<StepIconProps>;
18
+ stepIcon: React.ElementType;
19
19
  }
20
20
 
21
21
  export type StepLabelSlotsAndSlotProps = CreateSlotsAndSlotProps<
@@ -21,7 +21,7 @@ export interface TooltipSlots {
21
21
  * The component used for the popper.
22
22
  * @default Popper
23
23
  */
24
- popper: React.ElementType<PopperProps>;
24
+ popper: React.ElementType;
25
25
  /**
26
26
  * The component used for the transition.
27
27
  * [Follow this guide](https://mui.com/material-ui/transitions/#transitioncomponent-prop) to learn more about the requirements for this component.
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/material v6.3.1
2
+ * @mui/material v6.4.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -187,6 +187,39 @@ const Alert = /*#__PURE__*/React.forwardRef(function Alert(inProps, ref) {
187
187
  ...slotProps
188
188
  }
189
189
  };
190
+ const [RootSlot, rootSlotProps] = useSlot('root', {
191
+ ref,
192
+ shouldForwardComponentProp: true,
193
+ className: clsx(classes.root, className),
194
+ elementType: AlertRoot,
195
+ externalForwardedProps: {
196
+ ...externalForwardedProps,
197
+ ...other
198
+ },
199
+ ownerState,
200
+ additionalProps: {
201
+ role,
202
+ elevation: 0
203
+ }
204
+ });
205
+ const [IconSlot, iconSlotProps] = useSlot('icon', {
206
+ className: classes.icon,
207
+ elementType: AlertIcon,
208
+ externalForwardedProps,
209
+ ownerState
210
+ });
211
+ const [MessageSlot, messageSlotProps] = useSlot('message', {
212
+ className: classes.message,
213
+ elementType: AlertMessage,
214
+ externalForwardedProps,
215
+ ownerState
216
+ });
217
+ const [ActionSlot, actionSlotProps] = useSlot('action', {
218
+ className: classes.action,
219
+ elementType: AlertAction,
220
+ externalForwardedProps,
221
+ ownerState
222
+ });
190
223
  const [CloseButtonSlot, closeButtonProps] = useSlot('closeButton', {
191
224
  elementType: IconButton,
192
225
  externalForwardedProps,
@@ -197,28 +230,19 @@ const Alert = /*#__PURE__*/React.forwardRef(function Alert(inProps, ref) {
197
230
  externalForwardedProps,
198
231
  ownerState
199
232
  });
200
- return /*#__PURE__*/_jsxs(AlertRoot, {
201
- role: role,
202
- elevation: 0,
203
- ownerState: ownerState,
204
- className: clsx(classes.root, className),
205
- ref: ref,
206
- ...other,
207
- children: [icon !== false ? /*#__PURE__*/_jsx(AlertIcon, {
208
- ownerState: ownerState,
209
- className: classes.icon,
233
+ return /*#__PURE__*/_jsxs(RootSlot, {
234
+ ...rootSlotProps,
235
+ children: [icon !== false ? /*#__PURE__*/_jsx(IconSlot, {
236
+ ...iconSlotProps,
210
237
  children: icon || iconMapping[severity] || defaultIconMapping[severity]
211
- }) : null, /*#__PURE__*/_jsx(AlertMessage, {
212
- ownerState: ownerState,
213
- className: classes.message,
238
+ }) : null, /*#__PURE__*/_jsx(MessageSlot, {
239
+ ...messageSlotProps,
214
240
  children: children
215
- }), action != null ? /*#__PURE__*/_jsx(AlertAction, {
216
- ownerState: ownerState,
217
- className: classes.action,
241
+ }), action != null ? /*#__PURE__*/_jsx(ActionSlot, {
242
+ ...actionSlotProps,
218
243
  children: action
219
- }) : null, action == null && onClose ? /*#__PURE__*/_jsx(AlertAction, {
220
- ownerState: ownerState,
221
- className: classes.action,
244
+ }) : null, action == null && onClose ? /*#__PURE__*/_jsx(ActionSlot, {
245
+ ...actionSlotProps,
222
246
  children: /*#__PURE__*/_jsx(CloseButtonSlot, {
223
247
  size: "small",
224
248
  "aria-label": closeText,
@@ -330,16 +354,24 @@ process.env.NODE_ENV !== "production" ? Alert.propTypes /* remove-proptypes */ =
330
354
  * @default {}
331
355
  */
332
356
  slotProps: PropTypes.shape({
357
+ action: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
333
358
  closeButton: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
334
- closeIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object])
359
+ closeIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
360
+ icon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
361
+ message: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
362
+ root: PropTypes.oneOfType([PropTypes.func, PropTypes.object])
335
363
  }),
336
364
  /**
337
365
  * The components used for each slot inside.
338
366
  * @default {}
339
367
  */
340
368
  slots: PropTypes.shape({
369
+ action: PropTypes.elementType,
341
370
  closeButton: PropTypes.elementType,
342
- closeIcon: PropTypes.elementType
371
+ closeIcon: PropTypes.elementType,
372
+ icon: PropTypes.elementType,
373
+ message: PropTypes.elementType,
374
+ root: PropTypes.elementType
343
375
  }),
344
376
  /**
345
377
  * The system prop that allows defining system overrides as well as additional CSS styles.
@@ -6,11 +6,13 @@ import clsx from 'clsx';
6
6
  import resolveProps from '@mui/utils/resolveProps';
7
7
  import composeClasses from '@mui/utils/composeClasses';
8
8
  import { alpha } from '@mui/system/colorManipulator';
9
+ import { unstable_useId as useId } from '@mui/material/utils';
9
10
  import rootShouldForwardProp from "../styles/rootShouldForwardProp.js";
10
11
  import { styled } from "../zero-styled/index.js";
11
12
  import memoTheme from "../utils/memoTheme.js";
12
13
  import { useDefaultProps } from "../DefaultPropsProvider/index.js";
13
14
  import ButtonBase from "../ButtonBase/index.js";
15
+ import CircularProgress from "../CircularProgress/index.js";
14
16
  import capitalize from "../utils/capitalize.js";
15
17
  import createSimplePaletteValueFilter from "../utils/createSimplePaletteValueFilter.js";
16
18
  import buttonClasses, { getButtonUtilityClass } from "./buttonClasses.js";
@@ -24,13 +26,16 @@ const useUtilityClasses = ownerState => {
24
26
  fullWidth,
25
27
  size,
26
28
  variant,
29
+ loading,
30
+ loadingPosition,
27
31
  classes
28
32
  } = ownerState;
29
33
  const slots = {
30
- root: ['root', variant, `${variant}${capitalize(color)}`, `size${capitalize(size)}`, `${variant}Size${capitalize(size)}`, `color${capitalize(color)}`, disableElevation && 'disableElevation', fullWidth && 'fullWidth'],
31
- label: ['label'],
34
+ root: ['root', loading && 'loading', variant, `${variant}${capitalize(color)}`, `size${capitalize(size)}`, `${variant}Size${capitalize(size)}`, `color${capitalize(color)}`, disableElevation && 'disableElevation', fullWidth && 'fullWidth', loading && `loadingPosition${capitalize(loadingPosition)}`],
32
35
  startIcon: ['icon', 'startIcon', `iconSize${capitalize(size)}`],
33
- endIcon: ['icon', 'endIcon', `iconSize${capitalize(size)}`]
36
+ endIcon: ['icon', 'endIcon', `iconSize${capitalize(size)}`],
37
+ loadingIndicator: ['loadingIndicator'],
38
+ loadingWrapper: ['loadingWrapper']
34
39
  };
35
40
  const composedClasses = composeClasses(slots, getButtonUtilityClass, classes);
36
41
  return {
@@ -75,7 +80,7 @@ const ButtonRoot = styled(ButtonBase, {
75
80
  const {
76
81
  ownerState
77
82
  } = props;
78
- return [styles.root, styles[ownerState.variant], styles[`${ownerState.variant}${capitalize(ownerState.color)}`], styles[`size${capitalize(ownerState.size)}`], styles[`${ownerState.variant}Size${capitalize(ownerState.size)}`], ownerState.color === 'inherit' && styles.colorInherit, ownerState.disableElevation && styles.disableElevation, ownerState.fullWidth && styles.fullWidth];
83
+ return [styles.root, styles[ownerState.variant], styles[`${ownerState.variant}${capitalize(ownerState.color)}`], styles[`size${capitalize(ownerState.size)}`], styles[`${ownerState.variant}Size${capitalize(ownerState.size)}`], ownerState.color === 'inherit' && styles.colorInherit, ownerState.disableElevation && styles.disableElevation, ownerState.fullWidth && styles.fullWidth, ownerState.loading && styles.loading];
79
84
  }
80
85
  })(memoTheme(({
81
86
  theme
@@ -262,6 +267,18 @@ const ButtonRoot = styled(ButtonBase, {
262
267
  style: {
263
268
  width: '100%'
264
269
  }
270
+ }, {
271
+ props: {
272
+ loadingPosition: 'center'
273
+ },
274
+ style: {
275
+ transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color'], {
276
+ duration: theme.transitions.duration.short
277
+ }),
278
+ [`&.${buttonClasses.loading}`]: {
279
+ color: 'transparent'
280
+ }
281
+ }
265
282
  }]
266
283
  };
267
284
  }));
@@ -272,9 +289,11 @@ const ButtonStartIcon = styled('span', {
272
289
  const {
273
290
  ownerState
274
291
  } = props;
275
- return [styles.startIcon, styles[`iconSize${capitalize(ownerState.size)}`]];
292
+ return [styles.startIcon, ownerState.loading && styles.startIconLoadingStart, styles[`iconSize${capitalize(ownerState.size)}`]];
276
293
  }
277
- })({
294
+ })(({
295
+ theme
296
+ }) => ({
278
297
  display: 'inherit',
279
298
  marginRight: 8,
280
299
  marginLeft: -4,
@@ -285,8 +304,28 @@ const ButtonStartIcon = styled('span', {
285
304
  style: {
286
305
  marginLeft: -2
287
306
  }
307
+ }, {
308
+ props: {
309
+ loadingPosition: 'start',
310
+ loading: true
311
+ },
312
+ style: {
313
+ transition: theme.transitions.create(['opacity'], {
314
+ duration: theme.transitions.duration.short
315
+ }),
316
+ opacity: 0
317
+ }
318
+ }, {
319
+ props: {
320
+ loadingPosition: 'start',
321
+ loading: true,
322
+ fullWidth: true
323
+ },
324
+ style: {
325
+ marginRight: -8
326
+ }
288
327
  }, ...commonIconStyles]
289
- });
328
+ }));
290
329
  const ButtonEndIcon = styled('span', {
291
330
  name: 'MuiButton',
292
331
  slot: 'EndIcon',
@@ -294,9 +333,11 @@ const ButtonEndIcon = styled('span', {
294
333
  const {
295
334
  ownerState
296
335
  } = props;
297
- return [styles.endIcon, styles[`iconSize${capitalize(ownerState.size)}`]];
336
+ return [styles.endIcon, ownerState.loading && styles.endIconLoadingEnd, styles[`iconSize${capitalize(ownerState.size)}`]];
298
337
  }
299
- })({
338
+ })(({
339
+ theme
340
+ }) => ({
300
341
  display: 'inherit',
301
342
  marginRight: -4,
302
343
  marginLeft: 8,
@@ -307,7 +348,128 @@ const ButtonEndIcon = styled('span', {
307
348
  style: {
308
349
  marginRight: -2
309
350
  }
351
+ }, {
352
+ props: {
353
+ loadingPosition: 'end',
354
+ loading: true
355
+ },
356
+ style: {
357
+ transition: theme.transitions.create(['opacity'], {
358
+ duration: theme.transitions.duration.short
359
+ }),
360
+ opacity: 0
361
+ }
362
+ }, {
363
+ props: {
364
+ loadingPosition: 'end',
365
+ loading: true,
366
+ fullWidth: true
367
+ },
368
+ style: {
369
+ marginLeft: -8
370
+ }
310
371
  }, ...commonIconStyles]
372
+ }));
373
+ const ButtonLoadingIndicator = styled('span', {
374
+ name: 'MuiButton',
375
+ slot: 'LoadingIndicator',
376
+ overridesResolver: (props, styles) => styles.loadingIndicator
377
+ })(({
378
+ theme
379
+ }) => ({
380
+ display: 'none',
381
+ position: 'absolute',
382
+ visibility: 'visible',
383
+ variants: [{
384
+ props: {
385
+ loading: true
386
+ },
387
+ style: {
388
+ display: 'flex'
389
+ }
390
+ }, {
391
+ props: {
392
+ loadingPosition: 'start'
393
+ },
394
+ style: {
395
+ left: 14
396
+ }
397
+ }, {
398
+ props: {
399
+ loadingPosition: 'start',
400
+ size: 'small'
401
+ },
402
+ style: {
403
+ left: 10
404
+ }
405
+ }, {
406
+ props: {
407
+ variant: 'text',
408
+ loadingPosition: 'start'
409
+ },
410
+ style: {
411
+ left: 6
412
+ }
413
+ }, {
414
+ props: {
415
+ loadingPosition: 'center'
416
+ },
417
+ style: {
418
+ left: '50%',
419
+ transform: 'translate(-50%)',
420
+ color: (theme.vars || theme).palette.action.disabled
421
+ }
422
+ }, {
423
+ props: {
424
+ loadingPosition: 'end'
425
+ },
426
+ style: {
427
+ right: 14
428
+ }
429
+ }, {
430
+ props: {
431
+ loadingPosition: 'end',
432
+ size: 'small'
433
+ },
434
+ style: {
435
+ right: 10
436
+ }
437
+ }, {
438
+ props: {
439
+ variant: 'text',
440
+ loadingPosition: 'end'
441
+ },
442
+ style: {
443
+ right: 6
444
+ }
445
+ }, {
446
+ props: {
447
+ loadingPosition: 'start',
448
+ fullWidth: true
449
+ },
450
+ style: {
451
+ position: 'relative',
452
+ left: -10
453
+ }
454
+ }, {
455
+ props: {
456
+ loadingPosition: 'end',
457
+ fullWidth: true
458
+ },
459
+ style: {
460
+ position: 'relative',
461
+ right: -10
462
+ }
463
+ }]
464
+ }));
465
+ const ButtonLoadingIconPlaceholder = styled('span', {
466
+ name: 'MuiButton',
467
+ slot: 'LoadingIconPlaceholder',
468
+ overridesResolver: (props, styles) => styles.loadingIconPlaceholder
469
+ })({
470
+ display: 'inline-block',
471
+ width: '1em',
472
+ height: '1em'
311
473
  });
312
474
  const Button = /*#__PURE__*/React.forwardRef(function Button(inProps, ref) {
313
475
  // props priority: `inProps` > `contextProps` > `themeDefaultProps`
@@ -329,12 +491,22 @@ const Button = /*#__PURE__*/React.forwardRef(function Button(inProps, ref) {
329
491
  endIcon: endIconProp,
330
492
  focusVisibleClassName,
331
493
  fullWidth = false,
494
+ id: idProp,
495
+ loading = null,
496
+ loadingIndicator: loadingIndicatorProp,
497
+ loadingPosition = 'center',
332
498
  size = 'medium',
333
499
  startIcon: startIconProp,
334
500
  type,
335
501
  variant = 'text',
336
502
  ...other
337
503
  } = props;
504
+ const id = useId(idProp);
505
+ const loadingIndicator = loadingIndicatorProp ?? /*#__PURE__*/_jsx(CircularProgress, {
506
+ "aria-labelledby": id,
507
+ color: "inherit",
508
+ size: 16
509
+ });
338
510
  const ownerState = {
339
511
  ...props,
340
512
  color,
@@ -343,34 +515,58 @@ const Button = /*#__PURE__*/React.forwardRef(function Button(inProps, ref) {
343
515
  disableElevation,
344
516
  disableFocusRipple,
345
517
  fullWidth,
518
+ loading,
519
+ loadingIndicator,
520
+ loadingPosition,
346
521
  size,
347
522
  type,
348
523
  variant
349
524
  };
350
525
  const classes = useUtilityClasses(ownerState);
351
- const startIcon = startIconProp && /*#__PURE__*/_jsx(ButtonStartIcon, {
526
+ const startIcon = (startIconProp || loading && loadingPosition === 'start') && /*#__PURE__*/_jsx(ButtonStartIcon, {
352
527
  className: classes.startIcon,
353
528
  ownerState: ownerState,
354
- children: startIconProp
529
+ children: startIconProp || /*#__PURE__*/_jsx(ButtonLoadingIconPlaceholder, {
530
+ className: classes.loadingIconPlaceholder,
531
+ ownerState: ownerState
532
+ })
355
533
  });
356
- const endIcon = endIconProp && /*#__PURE__*/_jsx(ButtonEndIcon, {
534
+ const endIcon = (endIconProp || loading && loadingPosition === 'end') && /*#__PURE__*/_jsx(ButtonEndIcon, {
357
535
  className: classes.endIcon,
358
536
  ownerState: ownerState,
359
- children: endIconProp
537
+ children: endIconProp || /*#__PURE__*/_jsx(ButtonLoadingIconPlaceholder, {
538
+ className: classes.loadingIconPlaceholder,
539
+ ownerState: ownerState
540
+ })
360
541
  });
361
542
  const positionClassName = buttonGroupButtonContextPositionClassName || '';
543
+ const loader = typeof loading === 'boolean' ?
544
+ /*#__PURE__*/
545
+ // use plain HTML span to minimize the runtime overhead
546
+ _jsx("span", {
547
+ className: classes.loadingWrapper,
548
+ style: {
549
+ display: 'contents'
550
+ },
551
+ children: loading && /*#__PURE__*/_jsx(ButtonLoadingIndicator, {
552
+ className: classes.loadingIndicator,
553
+ ownerState: ownerState,
554
+ children: loadingIndicator
555
+ })
556
+ }) : null;
362
557
  return /*#__PURE__*/_jsxs(ButtonRoot, {
363
558
  ownerState: ownerState,
364
559
  className: clsx(contextProps.className, classes.root, className, positionClassName),
365
560
  component: component,
366
- disabled: disabled,
561
+ disabled: disabled || loading,
367
562
  focusRipple: !disableFocusRipple,
368
563
  focusVisibleClassName: clsx(classes.focusVisible, focusVisibleClassName),
369
564
  ref: ref,
370
565
  type: type,
566
+ id: id,
371
567
  ...other,
372
568
  classes: classes,
373
- children: [startIcon, children, endIcon]
569
+ children: [startIcon, loadingPosition !== 'end' && loader, children, loadingPosition === 'end' && loader, endIcon]
374
570
  });
375
571
  });
376
572
  process.env.NODE_ENV !== "production" ? Button.propTypes /* remove-proptypes */ = {
@@ -443,6 +639,28 @@ process.env.NODE_ENV !== "production" ? Button.propTypes /* remove-proptypes */
443
639
  * If defined, an `a` element will be used as the root node.
444
640
  */
445
641
  href: PropTypes.string,
642
+ /**
643
+ * @ignore
644
+ */
645
+ id: PropTypes.string,
646
+ /**
647
+ * If `true`, the loading indicator is visible and the button is disabled.
648
+ * If `true | false`, the loading wrapper is always rendered before the children to prevent [Google Translation Crash](https://github.com/mui/material-ui/issues/27853).
649
+ * @default null
650
+ */
651
+ loading: PropTypes.bool,
652
+ /**
653
+ * Element placed before the children if the button is in loading state.
654
+ * The node should contain an element with `role="progressbar"` with an accessible name.
655
+ * By default, it renders a `CircularProgress` that is labeled by the button itself.
656
+ * @default <CircularProgress color="inherit" size={16} />
657
+ */
658
+ loadingIndicator: PropTypes.node,
659
+ /**
660
+ * The loading indicator can be positioned on the start, end, or the center of the button.
661
+ * @default 'center'
662
+ */
663
+ loadingPosition: PropTypes.oneOf(['center', 'end', 'start']),
446
664
  /**
447
665
  * The size of the component.
448
666
  * `small` is equivalent to the dense button styling.
@@ -3,5 +3,5 @@ import generateUtilityClass from '@mui/utils/generateUtilityClass';
3
3
  export function getButtonUtilityClass(slot) {
4
4
  return generateUtilityClass('MuiButton', slot);
5
5
  }
6
- const buttonClasses = generateUtilityClasses('MuiButton', ['root', 'text', 'textInherit', 'textPrimary', 'textSecondary', 'textSuccess', 'textError', 'textInfo', 'textWarning', 'outlined', 'outlinedInherit', 'outlinedPrimary', 'outlinedSecondary', 'outlinedSuccess', 'outlinedError', 'outlinedInfo', 'outlinedWarning', 'contained', 'containedInherit', 'containedPrimary', 'containedSecondary', 'containedSuccess', 'containedError', 'containedInfo', 'containedWarning', 'disableElevation', 'focusVisible', 'disabled', 'colorInherit', 'colorPrimary', 'colorSecondary', 'colorSuccess', 'colorError', 'colorInfo', 'colorWarning', 'textSizeSmall', 'textSizeMedium', 'textSizeLarge', 'outlinedSizeSmall', 'outlinedSizeMedium', 'outlinedSizeLarge', 'containedSizeSmall', 'containedSizeMedium', 'containedSizeLarge', 'sizeMedium', 'sizeSmall', 'sizeLarge', 'fullWidth', 'startIcon', 'endIcon', 'icon', 'iconSizeSmall', 'iconSizeMedium', 'iconSizeLarge']);
6
+ const buttonClasses = generateUtilityClasses('MuiButton', ['root', 'text', 'textInherit', 'textPrimary', 'textSecondary', 'textSuccess', 'textError', 'textInfo', 'textWarning', 'outlined', 'outlinedInherit', 'outlinedPrimary', 'outlinedSecondary', 'outlinedSuccess', 'outlinedError', 'outlinedInfo', 'outlinedWarning', 'contained', 'containedInherit', 'containedPrimary', 'containedSecondary', 'containedSuccess', 'containedError', 'containedInfo', 'containedWarning', 'disableElevation', 'focusVisible', 'disabled', 'colorInherit', 'colorPrimary', 'colorSecondary', 'colorSuccess', 'colorError', 'colorInfo', 'colorWarning', 'textSizeSmall', 'textSizeMedium', 'textSizeLarge', 'outlinedSizeSmall', 'outlinedSizeMedium', 'outlinedSizeLarge', 'containedSizeSmall', 'containedSizeMedium', 'containedSizeLarge', 'sizeMedium', 'sizeSmall', 'sizeLarge', 'fullWidth', 'startIcon', 'endIcon', 'icon', 'iconSizeSmall', 'iconSizeMedium', 'iconSizeLarge', 'loading', 'loadingWrapper', 'loadingIconPlaceholder', 'loadingIndicator', 'loadingPositionCenter', 'loadingPositionStart', 'loadingPositionEnd']);
7
7
  export default buttonClasses;