UNPKG

9.11 kBJavaScriptView Raw
1import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
2import _extends from "@babel/runtime/helpers/esm/extends";
3const _excluded = ["autoFocus", "component", "dense", "divider", "disableGutters", "focusVisibleClassName", "role", "tabIndex"];
4import * as React from 'react';
5import PropTypes from 'prop-types';
6import clsx from 'clsx';
7import { unstable_composeClasses as composeClasses } from '@mui/base';
8import { alpha } from '@mui/system';
9import styled, { rootShouldForwardProp } from '../styles/styled';
10import useThemeProps from '../styles/useThemeProps';
11import ListContext from '../List/ListContext';
12import ButtonBase from '../ButtonBase';
13import useEnhancedEffect from '../utils/useEnhancedEffect';
14import useForkRef from '../utils/useForkRef';
15import { dividerClasses } from '../Divider';
16import { listItemIconClasses } from '../ListItemIcon';
17import { listItemTextClasses } from '../ListItemText';
18import menuItemClasses, { getMenuItemUtilityClass } from './menuItemClasses';
19import { jsx as _jsx } from "react/jsx-runtime";
20export const overridesResolver = (props, styles) => {
21 const {
22 ownerState
23 } = props;
24 return [styles.root, ownerState.dense && styles.dense, ownerState.divider && styles.divider, !ownerState.disableGutters && styles.gutters];
25};
26
27const useUtilityClasses = ownerState => {
28 const {
29 disabled,
30 dense,
31 divider,
32 disableGutters,
33 selected,
34 classes
35 } = ownerState;
36 const slots = {
37 root: ['root', dense && 'dense', disabled && 'disabled', !disableGutters && 'gutters', divider && 'divider', selected && 'selected']
38 };
39 const composedClasses = composeClasses(slots, getMenuItemUtilityClass, classes);
40 return _extends({}, classes, composedClasses);
41};
42
43const MenuItemRoot = styled(ButtonBase, {
44 shouldForwardProp: prop => rootShouldForwardProp(prop) || prop === 'classes',
45 name: 'MuiMenuItem',
46 slot: 'Root',
47 overridesResolver
48})(({
49 theme,
50 ownerState
51}) => _extends({}, theme.typography.body1, {
52 display: 'flex',
53 justifyContent: 'flex-start',
54 alignItems: 'center',
55 position: 'relative',
56 textDecoration: 'none',
57 minHeight: 48,
58 paddingTop: 6,
59 paddingBottom: 6,
60 boxSizing: 'border-box',
61 whiteSpace: 'nowrap'
62}, !ownerState.disableGutters && {
63 paddingLeft: 16,
64 paddingRight: 16
65}, ownerState.divider && {
66 borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`,
67 backgroundClip: 'padding-box'
68}, {
69 '&:hover': {
70 textDecoration: 'none',
71 backgroundColor: (theme.vars || theme).palette.action.hover,
72 // Reset on touch devices, it doesn't add specificity
73 '@media (hover: none)': {
74 backgroundColor: 'transparent'
75 }
76 },
77 [`&.${menuItemClasses.selected}`]: {
78 backgroundColor: theme.vars ? `rgba(${theme.vars.palette.primary.mainChannel} / ${theme.vars.palette.action.selectedOpacity})` : alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity),
79 [`&.${menuItemClasses.focusVisible}`]: {
80 backgroundColor: theme.vars ? `rgba(${theme.vars.palette.primary.mainChannel} / calc(${theme.vars.palette.action.selectedOpacity} + ${theme.vars.palette.action.focusOpacity}))` : alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity + theme.palette.action.focusOpacity)
81 }
82 },
83 [`&.${menuItemClasses.selected}:hover`]: {
84 backgroundColor: theme.vars ? `rgba(${theme.vars.palette.primary.mainChannel} / calc(${theme.vars.palette.action.selectedOpacity} + ${theme.vars.palette.action.hoverOpacity}))` : alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity + theme.palette.action.hoverOpacity),
85 // Reset on touch devices, it doesn't add specificity
86 '@media (hover: none)': {
87 backgroundColor: theme.vars ? `rgba(${theme.vars.palette.primary.mainChannel} / ${theme.vars.palette.action.selectedOpacity})` : alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity)
88 }
89 },
90 [`&.${menuItemClasses.focusVisible}`]: {
91 backgroundColor: (theme.vars || theme).palette.action.focus
92 },
93 [`&.${menuItemClasses.disabled}`]: {
94 opacity: (theme.vars || theme).palette.action.disabledOpacity
95 },
96 [`& + .${dividerClasses.root}`]: {
97 marginTop: theme.spacing(1),
98 marginBottom: theme.spacing(1)
99 },
100 [`& + .${dividerClasses.inset}`]: {
101 marginLeft: 52
102 },
103 [`& .${listItemTextClasses.root}`]: {
104 marginTop: 0,
105 marginBottom: 0
106 },
107 [`& .${listItemTextClasses.inset}`]: {
108 paddingLeft: 36
109 },
110 [`& .${listItemIconClasses.root}`]: {
111 minWidth: 36
112 }
113}, !ownerState.dense && {
114 [theme.breakpoints.up('sm')]: {
115 minHeight: 'auto'
116 }
117}, ownerState.dense && _extends({
118 minHeight: 32,
119 // https://material.io/components/menus#specs > Dense
120 paddingTop: 4,
121 paddingBottom: 4
122}, theme.typography.body2, {
123 [`& .${listItemIconClasses.root} svg`]: {
124 fontSize: '1.25rem'
125 }
126})));
127const MenuItem = /*#__PURE__*/React.forwardRef(function MenuItem(inProps, ref) {
128 const props = useThemeProps({
129 props: inProps,
130 name: 'MuiMenuItem'
131 });
132
133 const {
134 autoFocus = false,
135 component = 'li',
136 dense = false,
137 divider = false,
138 disableGutters = false,
139 focusVisibleClassName,
140 role = 'menuitem',
141 tabIndex: tabIndexProp
142 } = props,
143 other = _objectWithoutPropertiesLoose(props, _excluded);
144
145 const context = React.useContext(ListContext);
146 const childContext = {
147 dense: dense || context.dense || false,
148 disableGutters
149 };
150 const menuItemRef = React.useRef(null);
151 useEnhancedEffect(() => {
152 if (autoFocus) {
153 if (menuItemRef.current) {
154 menuItemRef.current.focus();
155 } else if (process.env.NODE_ENV !== 'production') {
156 console.error('MUI: Unable to set focus to a MenuItem whose component has not been rendered.');
157 }
158 }
159 }, [autoFocus]);
160
161 const ownerState = _extends({}, props, {
162 dense: childContext.dense,
163 divider,
164 disableGutters
165 });
166
167 const classes = useUtilityClasses(props);
168 const handleRef = useForkRef(menuItemRef, ref);
169 let tabIndex;
170
171 if (!props.disabled) {
172 tabIndex = tabIndexProp !== undefined ? tabIndexProp : -1;
173 }
174
175 return /*#__PURE__*/_jsx(ListContext.Provider, {
176 value: childContext,
177 children: /*#__PURE__*/_jsx(MenuItemRoot, _extends({
178 ref: handleRef,
179 role: role,
180 tabIndex: tabIndex,
181 component: component,
182 focusVisibleClassName: clsx(classes.focusVisible, focusVisibleClassName)
183 }, other, {
184 ownerState: ownerState,
185 classes: classes
186 }))
187 });
188});
189process.env.NODE_ENV !== "production" ? MenuItem.propTypes
190/* remove-proptypes */
191= {
192 // ----------------------------- Warning --------------------------------
193 // | These PropTypes are generated from the TypeScript type definitions |
194 // | To update them edit the d.ts file and run "yarn proptypes" |
195 // ----------------------------------------------------------------------
196
197 /**
198 * If `true`, the list item is focused during the first mount.
199 * Focus will also be triggered if the value changes from false to true.
200 * @default false
201 */
202 autoFocus: PropTypes.bool,
203
204 /**
205 * The content of the component.
206 */
207 children: PropTypes.node,
208
209 /**
210 * Override or extend the styles applied to the component.
211 */
212 classes: PropTypes.object,
213
214 /**
215 * The component used for the root node.
216 * Either a string to use a HTML element or a component.
217 */
218 component: PropTypes.elementType,
219
220 /**
221 * If `true`, compact vertical padding designed for keyboard and mouse input is used.
222 * The prop defaults to the value inherited from the parent Menu component.
223 * @default false
224 */
225 dense: PropTypes.bool,
226
227 /**
228 * @ignore
229 */
230 disabled: PropTypes.bool,
231
232 /**
233 * If `true`, the left and right padding is removed.
234 * @default false
235 */
236 disableGutters: PropTypes.bool,
237
238 /**
239 * If `true`, a 1px light border is added to the bottom of the menu item.
240 * @default false
241 */
242 divider: PropTypes.bool,
243
244 /**
245 * This prop can help identify which element has keyboard focus.
246 * The class name will be applied when the element gains the focus through keyboard interaction.
247 * It's a polyfill for the [CSS :focus-visible selector](https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo).
248 * The rationale for using this feature [is explained here](https://github.com/WICG/focus-visible/blob/HEAD/explainer.md).
249 * A [polyfill can be used](https://github.com/WICG/focus-visible) to apply a `focus-visible` class to other components
250 * if needed.
251 */
252 focusVisibleClassName: PropTypes.string,
253
254 /**
255 * @ignore
256 */
257 role: PropTypes
258 /* @typescript-to-proptypes-ignore */
259 .string,
260
261 /**
262 * @ignore
263 */
264 selected: PropTypes.bool,
265
266 /**
267 * The system prop that allows defining system overrides as well as additional CSS styles.
268 */
269 sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object]),
270
271 /**
272 * @default 0
273 */
274 tabIndex: PropTypes.number
275} : void 0;
276export default MenuItem;
\No newline at end of file