@mui/material 9.0.0-beta.0 → 9.0.0-beta.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 (138) hide show
  1. package/Accordion/Accordion.d.mts +1 -1
  2. package/Accordion/Accordion.d.ts +1 -1
  3. package/AccordionSummary/AccordionSummary.js +1 -0
  4. package/AccordionSummary/AccordionSummary.mjs +1 -0
  5. package/Backdrop/Backdrop.d.mts +1 -1
  6. package/Backdrop/Backdrop.d.ts +1 -1
  7. package/BottomNavigationAction/BottomNavigationAction.js +1 -0
  8. package/BottomNavigationAction/BottomNavigationAction.mjs +1 -0
  9. package/Breadcrumbs/BreadcrumbCollapsed.js +5 -1
  10. package/Breadcrumbs/BreadcrumbCollapsed.mjs +5 -1
  11. package/Button/Button.js +1 -0
  12. package/Button/Button.mjs +1 -0
  13. package/ButtonBase/ButtonBase.d.mts +5 -0
  14. package/ButtonBase/ButtonBase.d.ts +5 -0
  15. package/ButtonBase/ButtonBase.js +84 -85
  16. package/ButtonBase/ButtonBase.mjs +84 -85
  17. package/ButtonBase/useButtonBase.d.mts +91 -0
  18. package/ButtonBase/useButtonBase.d.ts +91 -0
  19. package/ButtonBase/useButtonBase.js +174 -0
  20. package/ButtonBase/useButtonBase.mjs +167 -0
  21. package/CHANGELOG.md +48 -0
  22. package/CardActionArea/CardActionArea.js +1 -0
  23. package/CardActionArea/CardActionArea.mjs +1 -0
  24. package/Chip/Chip.d.mts +7 -0
  25. package/Chip/Chip.d.ts +7 -0
  26. package/Chip/Chip.js +18 -1
  27. package/Chip/Chip.mjs +18 -1
  28. package/Dialog/Dialog.d.mts +8 -1
  29. package/Dialog/Dialog.d.ts +8 -1
  30. package/Dialog/Dialog.js +9 -1
  31. package/Dialog/Dialog.mjs +9 -1
  32. package/Divider/Divider.js +0 -8
  33. package/Divider/Divider.mjs +0 -8
  34. package/Drawer/Drawer.d.mts +1 -1
  35. package/Drawer/Drawer.d.ts +1 -1
  36. package/Fab/Fab.js +1 -0
  37. package/Fab/Fab.mjs +1 -0
  38. package/FilledInput/FilledInput.js +1 -1
  39. package/FilledInput/FilledInput.mjs +1 -1
  40. package/Grid/Grid.d.mts +8 -3
  41. package/Grid/Grid.d.ts +8 -3
  42. package/Grid/Grid.js +8 -3
  43. package/Grid/Grid.mjs +8 -3
  44. package/Grid/gridClasses.js +1 -1
  45. package/Grid/gridClasses.mjs +1 -1
  46. package/IconButton/IconButton.js +1 -0
  47. package/IconButton/IconButton.mjs +1 -0
  48. package/Input/Input.js +1 -1
  49. package/Input/Input.mjs +1 -1
  50. package/InputAdornment/inputAdornmentClasses.d.mts +2 -2
  51. package/InputAdornment/inputAdornmentClasses.d.ts +2 -2
  52. package/ListItemButton/ListItemButton.js +1 -0
  53. package/ListItemButton/ListItemButton.mjs +1 -0
  54. package/ListItemIcon/ListItemIcon.js +1 -1
  55. package/ListItemIcon/ListItemIcon.mjs +1 -1
  56. package/ListSubheader/ListSubheader.js +0 -3
  57. package/ListSubheader/ListSubheader.mjs +0 -3
  58. package/Menu/Menu.d.mts +1 -1
  59. package/Menu/Menu.d.ts +1 -1
  60. package/Menu/Menu.js +15 -32
  61. package/Menu/Menu.mjs +15 -32
  62. package/MenuItem/MenuItem.js +36 -26
  63. package/MenuItem/MenuItem.mjs +34 -26
  64. package/MenuList/MenuList.js +136 -101
  65. package/MenuList/MenuList.mjs +135 -100
  66. package/MenuList/MenuListContext.d.mts +11 -0
  67. package/MenuList/MenuListContext.d.ts +11 -0
  68. package/MenuList/MenuListContext.js +25 -0
  69. package/MenuList/MenuListContext.mjs +19 -0
  70. package/PaginationItem/PaginationItem.d.mts +5 -0
  71. package/PaginationItem/PaginationItem.d.ts +5 -0
  72. package/PaginationItem/PaginationItem.js +6 -0
  73. package/PaginationItem/PaginationItem.mjs +6 -0
  74. package/PigmentGrid/PigmentGrid.d.mts +1 -1
  75. package/PigmentGrid/PigmentGrid.d.ts +1 -1
  76. package/PigmentGrid/PigmentGrid.js +1 -1
  77. package/PigmentGrid/PigmentGrid.mjs +1 -1
  78. package/Popover/Popover.d.mts +1 -1
  79. package/Popover/Popover.d.ts +1 -1
  80. package/Popover/Popover.js +19 -7
  81. package/Popover/Popover.mjs +18 -6
  82. package/Snackbar/Snackbar.d.mts +1 -1
  83. package/Snackbar/Snackbar.d.ts +1 -1
  84. package/SpeedDial/SpeedDial.d.mts +1 -1
  85. package/SpeedDial/SpeedDial.d.ts +1 -1
  86. package/StepButton/StepButton.js +44 -14
  87. package/StepButton/StepButton.mjs +44 -14
  88. package/StepContent/StepContent.d.mts +1 -1
  89. package/StepContent/StepContent.d.ts +1 -1
  90. package/Stepper/Stepper.js +54 -22
  91. package/Stepper/Stepper.mjs +54 -22
  92. package/Stepper/StepperContext.d.mts +0 -5
  93. package/Stepper/StepperContext.d.ts +0 -5
  94. package/Stepper/StepperContext.js +1 -2
  95. package/Stepper/StepperContext.mjs +0 -1
  96. package/Tab/Tab.js +17 -1
  97. package/Tab/Tab.mjs +17 -1
  98. package/TabScrollButton/TabScrollButton.d.mts +1 -1
  99. package/TabScrollButton/TabScrollButton.d.ts +1 -1
  100. package/TabScrollButton/TabScrollButton.js +6 -2
  101. package/TabScrollButton/TabScrollButton.mjs +6 -2
  102. package/TableSortLabel/TableSortLabel.js +4 -1
  103. package/TableSortLabel/TableSortLabel.mjs +4 -1
  104. package/Tabs/Tabs.js +30 -21
  105. package/Tabs/Tabs.mjs +29 -20
  106. package/ToggleButton/ToggleButton.js +1 -0
  107. package/ToggleButton/ToggleButton.mjs +1 -0
  108. package/Tooltip/Tooltip.d.mts +1 -1
  109. package/Tooltip/Tooltip.d.ts +1 -1
  110. package/index.js +1 -1
  111. package/index.mjs +1 -1
  112. package/internal/SwitchBase.d.mts +2 -2
  113. package/internal/SwitchBase.d.ts +2 -2
  114. package/internal/SwitchBase.js +5 -1
  115. package/internal/SwitchBase.mjs +5 -1
  116. package/locale/psAF.js +1 -1
  117. package/locale/psAF.mjs +1 -1
  118. package/package.json +5 -5
  119. package/styles/createThemeWithVars.js +9 -9
  120. package/styles/createThemeWithVars.mjs +9 -9
  121. package/useAutocomplete/useAutocomplete.js +8 -0
  122. package/useAutocomplete/useAutocomplete.mjs +8 -0
  123. package/utils/focusWithVisible.js +24 -0
  124. package/utils/focusWithVisible.mjs +19 -0
  125. package/utils/index.d.mts +0 -1
  126. package/utils/index.d.ts +0 -1
  127. package/utils/index.js +0 -7
  128. package/utils/index.mjs +0 -1
  129. package/utils/useFocusableWhenDisabled.d.mts +30 -0
  130. package/utils/useFocusableWhenDisabled.d.ts +30 -0
  131. package/utils/useFocusableWhenDisabled.js +47 -0
  132. package/utils/useFocusableWhenDisabled.mjs +41 -0
  133. package/utils/useRovingTabIndex.d.mts +1 -2
  134. package/utils/useRovingTabIndex.d.ts +1 -2
  135. package/utils/useRovingTabIndex.js +25 -4
  136. package/utils/useRovingTabIndex.mjs +1 -2
  137. package/version/index.js +2 -2
  138. package/version/index.mjs +2 -2
@@ -0,0 +1,91 @@
1
+ import * as React from 'react';
2
+ export interface UseButtonBaseParameters {
3
+ /**
4
+ * Whether the root should be treated as a native `<button>` for render-time semantics.
5
+ */
6
+ nativeButton: boolean;
7
+ /**
8
+ * The explicit `nativeButton` value provided by the caller, if any.
9
+ */
10
+ nativeButtonProp?: boolean | undefined;
11
+ /**
12
+ * Whether the default rendered element is expected to be a native button when
13
+ * `nativeButton` was not explicitly provided.
14
+ * @default nativeButton
15
+ */
16
+ internalNativeButton?: boolean | undefined;
17
+ /**
18
+ * Whether to perform additional checks in dev mode on whether the resolved element
19
+ * matches the default native or non-native button expectation.
20
+ * Set to `true` to allow hook callers bypass this check, e.g. when the `component`
21
+ * prop is a string.
22
+ * @default false
23
+ */
24
+ allowInferredHostMismatch?: boolean | undefined;
25
+ /**
26
+ * The disabled state of the component.
27
+ */
28
+ disabled: boolean;
29
+ /**
30
+ * The `type` attribute for the element.
31
+ */
32
+ type?: string | undefined;
33
+ /**
34
+ * Whether the element has a `formAction` attribute. When true, the hook
35
+ * will not default `type` to `'button'` for native buttons so the browser
36
+ * can use its natural submit behaviour.
37
+ * @default false
38
+ */
39
+ hasFormAction?: boolean | undefined;
40
+ /**
41
+ * The `tabIndex` attribute for the element.
42
+ * @default 0
43
+ */
44
+ tabIndex?: number | undefined;
45
+ /**
46
+ * When `true`, a disabled root can remain focusable.
47
+ * When `undefined`, the feature is not enabled.
48
+ */
49
+ focusableWhenDisabled?: boolean | undefined;
50
+ /**
51
+ * When `true`, calls `event.stopPropagation()` on click before the disabled guard runs.
52
+ * @default false
53
+ */
54
+ stopEventPropagation?: boolean | undefined;
55
+ /**
56
+ * An additional function that will run before the user's `onKeyDown`, e.g.
57
+ * to trigger the ripple effect in `<ButtonBase>`.
58
+ */
59
+ onBeforeKeyDown?: React.KeyboardEventHandler<HTMLElement> | undefined;
60
+ /**
61
+ * An additional function that will run before the user's `onKeyUp`, e.g.
62
+ * to control the ripple effect in `<ButtonBase>`.
63
+ */
64
+ onBeforeKeyUp?: React.KeyboardEventHandler<HTMLElement> | undefined;
65
+ }
66
+ export interface ButtonBaseButtonProps {
67
+ role?: string | undefined;
68
+ 'aria-disabled'?: boolean | undefined;
69
+ type?: string | undefined;
70
+ disabled?: boolean | undefined;
71
+ tabIndex: number;
72
+ }
73
+ export interface ButtonBaseExternalProps extends React.HTMLAttributes<any> {
74
+ 'aria-disabled'?: boolean | undefined;
75
+ disabled?: boolean | undefined;
76
+ type?: string | undefined;
77
+ }
78
+ export interface ButtonBaseEventHandlers {
79
+ onClick: React.MouseEventHandler<HTMLElement>;
80
+ onKeyDown: React.KeyboardEventHandler<HTMLElement>;
81
+ onKeyUp: React.KeyboardEventHandler<HTMLElement>;
82
+ }
83
+ export interface UseButtonBaseReturnValue {
84
+ /**
85
+ * @param externalProps additional props for the button
86
+ * @returns props that should be spread on the button
87
+ */
88
+ getButtonProps: <ExternalProps extends ButtonBaseExternalProps = ButtonBaseExternalProps>(externalProps?: ExternalProps) => Omit<ExternalProps, keyof ButtonBaseEventHandlers> & ButtonBaseButtonProps & ButtonBaseEventHandlers;
89
+ rootRef: React.RefObject<HTMLElement | null>;
90
+ }
91
+ export default function useButtonBase(parameters: UseButtonBaseParameters): UseButtonBaseReturnValue;
@@ -0,0 +1,91 @@
1
+ import * as React from 'react';
2
+ export interface UseButtonBaseParameters {
3
+ /**
4
+ * Whether the root should be treated as a native `<button>` for render-time semantics.
5
+ */
6
+ nativeButton: boolean;
7
+ /**
8
+ * The explicit `nativeButton` value provided by the caller, if any.
9
+ */
10
+ nativeButtonProp?: boolean | undefined;
11
+ /**
12
+ * Whether the default rendered element is expected to be a native button when
13
+ * `nativeButton` was not explicitly provided.
14
+ * @default nativeButton
15
+ */
16
+ internalNativeButton?: boolean | undefined;
17
+ /**
18
+ * Whether to perform additional checks in dev mode on whether the resolved element
19
+ * matches the default native or non-native button expectation.
20
+ * Set to `true` to allow hook callers bypass this check, e.g. when the `component`
21
+ * prop is a string.
22
+ * @default false
23
+ */
24
+ allowInferredHostMismatch?: boolean | undefined;
25
+ /**
26
+ * The disabled state of the component.
27
+ */
28
+ disabled: boolean;
29
+ /**
30
+ * The `type` attribute for the element.
31
+ */
32
+ type?: string | undefined;
33
+ /**
34
+ * Whether the element has a `formAction` attribute. When true, the hook
35
+ * will not default `type` to `'button'` for native buttons so the browser
36
+ * can use its natural submit behaviour.
37
+ * @default false
38
+ */
39
+ hasFormAction?: boolean | undefined;
40
+ /**
41
+ * The `tabIndex` attribute for the element.
42
+ * @default 0
43
+ */
44
+ tabIndex?: number | undefined;
45
+ /**
46
+ * When `true`, a disabled root can remain focusable.
47
+ * When `undefined`, the feature is not enabled.
48
+ */
49
+ focusableWhenDisabled?: boolean | undefined;
50
+ /**
51
+ * When `true`, calls `event.stopPropagation()` on click before the disabled guard runs.
52
+ * @default false
53
+ */
54
+ stopEventPropagation?: boolean | undefined;
55
+ /**
56
+ * An additional function that will run before the user's `onKeyDown`, e.g.
57
+ * to trigger the ripple effect in `<ButtonBase>`.
58
+ */
59
+ onBeforeKeyDown?: React.KeyboardEventHandler<HTMLElement> | undefined;
60
+ /**
61
+ * An additional function that will run before the user's `onKeyUp`, e.g.
62
+ * to control the ripple effect in `<ButtonBase>`.
63
+ */
64
+ onBeforeKeyUp?: React.KeyboardEventHandler<HTMLElement> | undefined;
65
+ }
66
+ export interface ButtonBaseButtonProps {
67
+ role?: string | undefined;
68
+ 'aria-disabled'?: boolean | undefined;
69
+ type?: string | undefined;
70
+ disabled?: boolean | undefined;
71
+ tabIndex: number;
72
+ }
73
+ export interface ButtonBaseExternalProps extends React.HTMLAttributes<any> {
74
+ 'aria-disabled'?: boolean | undefined;
75
+ disabled?: boolean | undefined;
76
+ type?: string | undefined;
77
+ }
78
+ export interface ButtonBaseEventHandlers {
79
+ onClick: React.MouseEventHandler<HTMLElement>;
80
+ onKeyDown: React.KeyboardEventHandler<HTMLElement>;
81
+ onKeyUp: React.KeyboardEventHandler<HTMLElement>;
82
+ }
83
+ export interface UseButtonBaseReturnValue {
84
+ /**
85
+ * @param externalProps additional props for the button
86
+ * @returns props that should be spread on the button
87
+ */
88
+ getButtonProps: <ExternalProps extends ButtonBaseExternalProps = ButtonBaseExternalProps>(externalProps?: ExternalProps) => Omit<ExternalProps, keyof ButtonBaseEventHandlers> & ButtonBaseButtonProps & ButtonBaseEventHandlers;
89
+ rootRef: React.RefObject<HTMLElement | null>;
90
+ }
91
+ export default function useButtonBase(parameters: UseButtonBaseParameters): UseButtonBaseReturnValue;
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ 'use client';
3
+
4
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
5
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ exports.default = useButtonBase;
10
+ var React = _interopRequireWildcard(require("react"));
11
+ var _useFocusableWhenDisabled = _interopRequireDefault(require("../utils/useFocusableWhenDisabled"));
12
+ const EMPTY = {};
13
+ function useButtonBase(parameters) {
14
+ const {
15
+ nativeButton,
16
+ nativeButtonProp,
17
+ internalNativeButton = nativeButton,
18
+ allowInferredHostMismatch = false,
19
+ disabled,
20
+ type,
21
+ hasFormAction = false,
22
+ tabIndex = 0,
23
+ focusableWhenDisabled: focusableWhenDisabledParam,
24
+ stopEventPropagation = false,
25
+ onBeforeKeyDown,
26
+ onBeforeKeyUp
27
+ } = parameters;
28
+ const rootRef = React.useRef(null);
29
+ const focusableWhenDisabled = focusableWhenDisabledParam === true;
30
+ const focusableWhenDisabledProps = (0, _useFocusableWhenDisabled.default)({
31
+ focusableWhenDisabled,
32
+ disabled,
33
+ isNativeButton: nativeButton,
34
+ tabIndex
35
+ });
36
+ if (process.env.NODE_ENV !== 'production') {
37
+ // eslint-disable-next-line react-hooks/rules-of-hooks
38
+ React.useEffect(() => {
39
+ const root = rootRef.current;
40
+ if (root == null) {
41
+ return;
42
+ }
43
+ const isButtonTag = root.tagName === 'BUTTON';
44
+ if (nativeButtonProp !== undefined) {
45
+ if (nativeButtonProp && !isButtonTag) {
46
+ const message = 'MUI: A component that acts as a button expected a native <button> because the ' + '`nativeButton` prop is true. Rendering a non-<button> removes native button ' + 'semantics, which can impact forms and accessibility. Render a real <button> ' + 'or set `nativeButton` to `false`.';
47
+ console.error(message);
48
+ }
49
+ if (!nativeButtonProp && isButtonTag) {
50
+ const message = 'MUI: A component that acts as a button expected a non-<button> because the `nativeButton` ' + 'prop is false. Rendering a <button> keeps native behavior while additionally applies ' + 'non-native attributes and handlers, which can add unintended extra attributes (such ' + 'as `role` or `aria-disabled`). Render a non-<button> such as <div>, or set ' + '`nativeButton` to `true`.';
51
+ console.error(message);
52
+ }
53
+ return;
54
+ }
55
+ if (allowInferredHostMismatch) {
56
+ return;
57
+ }
58
+
59
+ // warn when expecting a native <button> element but a non-string `component` prop resolved to a non-button element
60
+ if (internalNativeButton && !isButtonTag) {
61
+ const message = 'MUI: A component rendering a native <button> resolved to a non-<button> element, ' + 'but `nativeButton={false}` was not specified and the resolved root is a non-<button>. ' + 'When rendering a custom component, set `nativeButton={false}` explicitly or render a <button> element.';
62
+ console.error(message);
63
+ }
64
+
65
+ // warn when expecting a non-button but a non-string `component` prop resolved to a native <button> element
66
+ if (!internalNativeButton && isButtonTag) {
67
+ const message = 'MUI: A component that acts as a non-native button resolved to a native <button> element, ' + 'but `nativeButton={true}` was not specified. ' + 'When rendering a custom component, set `nativeButton={true}` explicitly or render a non-<button> element.';
68
+ console.error(message);
69
+ }
70
+ }, [allowInferredHostMismatch, internalNativeButton, nativeButtonProp]);
71
+ }
72
+
73
+ // A helper for event handlers to determine whether to use browser-defined keyboard activation
74
+ // for native elements like <button> and <a href>, or synthesize Enter/Space clicks for non-native
75
+ // elements like `<div role="button">`.
76
+ // This is UNSAFE TO USE outside of event handers, e.g. in render.
77
+ const hasNativeKeyboardActivation = React.useCallback(() => {
78
+ const root = rootRef.current;
79
+ if (root == null) {
80
+ return nativeButton;
81
+ }
82
+ if (root.tagName === 'BUTTON') {
83
+ return true;
84
+ }
85
+
86
+ // Although this hook is not intended for links, this check is for
87
+ // backward compatibility with `<ButtonBase href="#" />` since ButtonBase
88
+ // uses the returned event handlers.
89
+ return Boolean(root.tagName === 'A' && root.href);
90
+ }, [nativeButton]);
91
+ const buttonProps = React.useMemo(() => {
92
+ const resolvedButtonProps = focusableWhenDisabled ? {} : {
93
+ tabIndex: disabled ? -1 : tabIndex
94
+ };
95
+ if (nativeButton) {
96
+ resolvedButtonProps.type = type === undefined && !hasFormAction ? 'button' : type;
97
+ if (!focusableWhenDisabled) {
98
+ resolvedButtonProps.disabled = disabled;
99
+ }
100
+ } else {
101
+ resolvedButtonProps.role = 'button';
102
+ if (!focusableWhenDisabled && disabled) {
103
+ resolvedButtonProps['aria-disabled'] = disabled;
104
+ }
105
+ }
106
+ if (focusableWhenDisabled) {
107
+ return {
108
+ ...resolvedButtonProps,
109
+ ...focusableWhenDisabledProps
110
+ };
111
+ }
112
+ return resolvedButtonProps;
113
+ }, [disabled, focusableWhenDisabled, focusableWhenDisabledProps, hasFormAction, nativeButton, tabIndex, type]);
114
+ const getButtonProps = React.useCallback((externalProps = EMPTY) => {
115
+ const {
116
+ onClick: externalOnClick,
117
+ onKeyDown: externalOnKeyDown,
118
+ onKeyUp: externalOnKeyUp,
119
+ ...otherExternalProps
120
+ } = externalProps;
121
+ const handleClick = event => {
122
+ if (stopEventPropagation) {
123
+ event.stopPropagation();
124
+ }
125
+ if (disabled) {
126
+ event.preventDefault();
127
+ return;
128
+ }
129
+ externalOnClick?.(event);
130
+ };
131
+ const handleKeyDown = event => {
132
+ if (focusableWhenDisabled) {
133
+ focusableWhenDisabledProps.onKeyDown(event);
134
+ }
135
+ if (disabled) {
136
+ return;
137
+ }
138
+ onBeforeKeyDown?.(event);
139
+ externalOnKeyDown?.(event);
140
+ if (event.target !== event.currentTarget || hasNativeKeyboardActivation()) {
141
+ return;
142
+ }
143
+ if (event.key === ' ') {
144
+ event.preventDefault();
145
+ return;
146
+ }
147
+ if (event.key === 'Enter') {
148
+ event.preventDefault();
149
+ event.currentTarget.click();
150
+ }
151
+ };
152
+ const handleKeyUp = event => {
153
+ if (disabled) {
154
+ return;
155
+ }
156
+ onBeforeKeyUp?.(event);
157
+ externalOnKeyUp?.(event);
158
+ if (event.target === event.currentTarget && !hasNativeKeyboardActivation() && event.key === ' ' && !event.defaultPrevented) {
159
+ event.currentTarget.click();
160
+ }
161
+ };
162
+ return {
163
+ ...buttonProps,
164
+ ...otherExternalProps,
165
+ onClick: handleClick,
166
+ onKeyDown: handleKeyDown,
167
+ onKeyUp: handleKeyUp
168
+ };
169
+ }, [buttonProps, disabled, focusableWhenDisabled, focusableWhenDisabledProps, hasNativeKeyboardActivation, onBeforeKeyDown, onBeforeKeyUp, stopEventPropagation]);
170
+ return {
171
+ getButtonProps,
172
+ rootRef
173
+ };
174
+ }
@@ -0,0 +1,167 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import useFocusableWhenDisabled from "../utils/useFocusableWhenDisabled.mjs";
5
+ const EMPTY = {};
6
+ export default function useButtonBase(parameters) {
7
+ const {
8
+ nativeButton,
9
+ nativeButtonProp,
10
+ internalNativeButton = nativeButton,
11
+ allowInferredHostMismatch = false,
12
+ disabled,
13
+ type,
14
+ hasFormAction = false,
15
+ tabIndex = 0,
16
+ focusableWhenDisabled: focusableWhenDisabledParam,
17
+ stopEventPropagation = false,
18
+ onBeforeKeyDown,
19
+ onBeforeKeyUp
20
+ } = parameters;
21
+ const rootRef = React.useRef(null);
22
+ const focusableWhenDisabled = focusableWhenDisabledParam === true;
23
+ const focusableWhenDisabledProps = useFocusableWhenDisabled({
24
+ focusableWhenDisabled,
25
+ disabled,
26
+ isNativeButton: nativeButton,
27
+ tabIndex
28
+ });
29
+ if (process.env.NODE_ENV !== 'production') {
30
+ // eslint-disable-next-line react-hooks/rules-of-hooks
31
+ React.useEffect(() => {
32
+ const root = rootRef.current;
33
+ if (root == null) {
34
+ return;
35
+ }
36
+ const isButtonTag = root.tagName === 'BUTTON';
37
+ if (nativeButtonProp !== undefined) {
38
+ if (nativeButtonProp && !isButtonTag) {
39
+ const message = 'MUI: A component that acts as a button expected a native <button> because the ' + '`nativeButton` prop is true. Rendering a non-<button> removes native button ' + 'semantics, which can impact forms and accessibility. Render a real <button> ' + 'or set `nativeButton` to `false`.';
40
+ console.error(message);
41
+ }
42
+ if (!nativeButtonProp && isButtonTag) {
43
+ const message = 'MUI: A component that acts as a button expected a non-<button> because the `nativeButton` ' + 'prop is false. Rendering a <button> keeps native behavior while additionally applies ' + 'non-native attributes and handlers, which can add unintended extra attributes (such ' + 'as `role` or `aria-disabled`). Render a non-<button> such as <div>, or set ' + '`nativeButton` to `true`.';
44
+ console.error(message);
45
+ }
46
+ return;
47
+ }
48
+ if (allowInferredHostMismatch) {
49
+ return;
50
+ }
51
+
52
+ // warn when expecting a native <button> element but a non-string `component` prop resolved to a non-button element
53
+ if (internalNativeButton && !isButtonTag) {
54
+ const message = 'MUI: A component rendering a native <button> resolved to a non-<button> element, ' + 'but `nativeButton={false}` was not specified and the resolved root is a non-<button>. ' + 'When rendering a custom component, set `nativeButton={false}` explicitly or render a <button> element.';
55
+ console.error(message);
56
+ }
57
+
58
+ // warn when expecting a non-button but a non-string `component` prop resolved to a native <button> element
59
+ if (!internalNativeButton && isButtonTag) {
60
+ const message = 'MUI: A component that acts as a non-native button resolved to a native <button> element, ' + 'but `nativeButton={true}` was not specified. ' + 'When rendering a custom component, set `nativeButton={true}` explicitly or render a non-<button> element.';
61
+ console.error(message);
62
+ }
63
+ }, [allowInferredHostMismatch, internalNativeButton, nativeButtonProp]);
64
+ }
65
+
66
+ // A helper for event handlers to determine whether to use browser-defined keyboard activation
67
+ // for native elements like <button> and <a href>, or synthesize Enter/Space clicks for non-native
68
+ // elements like `<div role="button">`.
69
+ // This is UNSAFE TO USE outside of event handers, e.g. in render.
70
+ const hasNativeKeyboardActivation = React.useCallback(() => {
71
+ const root = rootRef.current;
72
+ if (root == null) {
73
+ return nativeButton;
74
+ }
75
+ if (root.tagName === 'BUTTON') {
76
+ return true;
77
+ }
78
+
79
+ // Although this hook is not intended for links, this check is for
80
+ // backward compatibility with `<ButtonBase href="#" />` since ButtonBase
81
+ // uses the returned event handlers.
82
+ return Boolean(root.tagName === 'A' && root.href);
83
+ }, [nativeButton]);
84
+ const buttonProps = React.useMemo(() => {
85
+ const resolvedButtonProps = focusableWhenDisabled ? {} : {
86
+ tabIndex: disabled ? -1 : tabIndex
87
+ };
88
+ if (nativeButton) {
89
+ resolvedButtonProps.type = type === undefined && !hasFormAction ? 'button' : type;
90
+ if (!focusableWhenDisabled) {
91
+ resolvedButtonProps.disabled = disabled;
92
+ }
93
+ } else {
94
+ resolvedButtonProps.role = 'button';
95
+ if (!focusableWhenDisabled && disabled) {
96
+ resolvedButtonProps['aria-disabled'] = disabled;
97
+ }
98
+ }
99
+ if (focusableWhenDisabled) {
100
+ return {
101
+ ...resolvedButtonProps,
102
+ ...focusableWhenDisabledProps
103
+ };
104
+ }
105
+ return resolvedButtonProps;
106
+ }, [disabled, focusableWhenDisabled, focusableWhenDisabledProps, hasFormAction, nativeButton, tabIndex, type]);
107
+ const getButtonProps = React.useCallback((externalProps = EMPTY) => {
108
+ const {
109
+ onClick: externalOnClick,
110
+ onKeyDown: externalOnKeyDown,
111
+ onKeyUp: externalOnKeyUp,
112
+ ...otherExternalProps
113
+ } = externalProps;
114
+ const handleClick = event => {
115
+ if (stopEventPropagation) {
116
+ event.stopPropagation();
117
+ }
118
+ if (disabled) {
119
+ event.preventDefault();
120
+ return;
121
+ }
122
+ externalOnClick?.(event);
123
+ };
124
+ const handleKeyDown = event => {
125
+ if (focusableWhenDisabled) {
126
+ focusableWhenDisabledProps.onKeyDown(event);
127
+ }
128
+ if (disabled) {
129
+ return;
130
+ }
131
+ onBeforeKeyDown?.(event);
132
+ externalOnKeyDown?.(event);
133
+ if (event.target !== event.currentTarget || hasNativeKeyboardActivation()) {
134
+ return;
135
+ }
136
+ if (event.key === ' ') {
137
+ event.preventDefault();
138
+ return;
139
+ }
140
+ if (event.key === 'Enter') {
141
+ event.preventDefault();
142
+ event.currentTarget.click();
143
+ }
144
+ };
145
+ const handleKeyUp = event => {
146
+ if (disabled) {
147
+ return;
148
+ }
149
+ onBeforeKeyUp?.(event);
150
+ externalOnKeyUp?.(event);
151
+ if (event.target === event.currentTarget && !hasNativeKeyboardActivation() && event.key === ' ' && !event.defaultPrevented) {
152
+ event.currentTarget.click();
153
+ }
154
+ };
155
+ return {
156
+ ...buttonProps,
157
+ ...otherExternalProps,
158
+ onClick: handleClick,
159
+ onKeyDown: handleKeyDown,
160
+ onKeyUp: handleKeyUp
161
+ };
162
+ }, [buttonProps, disabled, focusableWhenDisabled, focusableWhenDisabledProps, hasNativeKeyboardActivation, onBeforeKeyDown, onBeforeKeyUp, stopEventPropagation]);
163
+ return {
164
+ getButtonProps,
165
+ rootRef
166
+ };
167
+ }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,53 @@
1
1
  # [Versions](https://mui.com/versions/)
2
2
 
3
+ ## 9.0.0-beta.1
4
+
5
+ <!-- generated comparing v9.0.0-beta.0..master -->
6
+
7
+ _Apr 2, 2026_
8
+
9
+ A big thanks to the 11 contributors who made this release possible.
10
+
11
+ ### `@mui/material@9.0.0-beta.1`
12
+
13
+ #### Breaking Changes
14
+
15
+ - [grid] Remove 'column' and 'column-reverse' options from `direction` prop (#47564) @sai6855
16
+ - [icons] Remove legacy `*Outline` icons (#48116) @mj12albert
17
+ - [list-item-icon] Use theme spacing instead of hardcoded minWidth (#46597) @adiitxa
18
+
19
+ #### Changes
20
+
21
+ - [all components] Fix `slotProps.transition` types (#48153) @mj12albert
22
+ - [alert][dialog] Accessibility improvements (#48113) @silviuaavram
23
+ - [autocomplete] Fix helper text focusing input when clicked (#48156) @mj12albert
24
+ - [button-base] Add `nativeButton` prop (#47989) @mj12albert
25
+ - [input] Fix high contrast cutoff on first character (#48150) @silviuaavram
26
+ - [menu] Fix empty roving focus container (#48114) @mj12albert
27
+ - [utils] Explicitly register roving tab items with parent (#48122) @mj12albert
28
+
29
+ ### Docs
30
+
31
+ - Fix HTML validation errors (#48107) @Janpot
32
+ - Fix duplicate IDs and HTML validation issues (#48095) @Janpot
33
+ - Fix the dark mode footer row shadow for the Data Grid on the advanced components page (#48149) @arminmeh
34
+ - Improve jsdom section (#48098) @oliviertassinari
35
+ - Update "Deprecated APIs removed" section to h2 in "Upgrade to v9" docs (#48115) @ZeeshanTamboli
36
+ - [docs][progress] Label all demo components (#48143) @mj12albert
37
+ - [docs-infra] Add x-scheduler to component API URL resolver (#48097) @rita-codes
38
+ - [docs-infra] Resolve some redirects (#48165) @Janpot
39
+ - [docs-infra] Update v9 Search Index (#48028) @dav-is
40
+
41
+ ### Core
42
+
43
+ - [code-infra] Discover exports for bundle size report (#48170) @Janpot
44
+ - [internal] Fix use of ellipsis (#48096) @oliviertassinari
45
+ - [test] Add screenshot test for Virtualized Table (#47947) @mnajdova
46
+ - [test] Remove `componentsProp` from `describeConformance` tests (#48142) @ZeeshanTamboli
47
+ - [theme] Do not create channel tokens for custom colors when `nativeColor` is used (#47765) @ZeeshanTamboli
48
+
49
+ All contributors of this release in alphabetical order: @adiitxa, @arminmeh, @dav-is, @Janpot, @mj12albert, @mnajdova, @oliviertassinari, @rita-codes, @sai6855, @silviuaavram, @ZeeshanTamboli
50
+
3
51
  ## 9.0.0-beta.0
4
52
 
5
53
  <!-- generated comparing v9.0.0-alpha.4..master -->
@@ -99,6 +99,7 @@ const CardActionArea = /*#__PURE__*/React.forwardRef(function CardActionArea(inP
99
99
  ref,
100
100
  className: (0, _clsx.default)(classes.root, className),
101
101
  additionalProps: {
102
+ internalNativeButton: true,
102
103
  focusVisibleClassName: (0, _clsx.default)(focusVisibleClassName, classes.focusVisible)
103
104
  }
104
105
  });
@@ -92,6 +92,7 @@ const CardActionArea = /*#__PURE__*/React.forwardRef(function CardActionArea(inP
92
92
  ref,
93
93
  className: clsx(classes.root, className),
94
94
  additionalProps: {
95
+ internalNativeButton: true,
95
96
  focusVisibleClassName: clsx(focusVisibleClassName, classes.focusVisible)
96
97
  }
97
98
  });
package/Chip/Chip.d.mts CHANGED
@@ -90,6 +90,13 @@ export interface ChipOwnProps {
90
90
  * @default 'medium'
91
91
  */
92
92
  size?: OverridableStringUnion<'small' | 'medium', ChipPropsSizeOverrides> | undefined;
93
+ /**
94
+ * If `true`, the component is expected to resolve to a native `<button>` element.
95
+ * When omitted, custom components inherit the default button semantics of the current wrapper.
96
+ * Set to `true` when a custom component resolves to a native `<button>`, or `false`
97
+ * when it resolves to a non-button host.
98
+ */
99
+ nativeButton?: boolean | undefined;
93
100
  /**
94
101
  * If `true`, allows the disabled chip to escape focus.
95
102
  * If `false`, allows the disabled chip to receive focus.
package/Chip/Chip.d.ts CHANGED
@@ -90,6 +90,13 @@ export interface ChipOwnProps {
90
90
  * @default 'medium'
91
91
  */
92
92
  size?: OverridableStringUnion<'small' | 'medium', ChipPropsSizeOverrides> | undefined;
93
+ /**
94
+ * If `true`, the component is expected to resolve to a native `<button>` element.
95
+ * When omitted, custom components inherit the default button semantics of the current wrapper.
96
+ * Set to `true` when a custom component resolves to a native `<button>`, or `false`
97
+ * when it resolves to a non-button host.
98
+ */
99
+ nativeButton?: boolean | undefined;
93
100
  /**
94
101
  * If `true`, allows the disabled chip to escape focus.
95
102
  * If `false`, allows the disabled chip to receive focus.