UNPKG

12.6 kBJavaScriptView Raw
1'use client';
2
3import * as React from 'react';
4import PropTypes from 'prop-types';
5import clsx from 'clsx';
6import composeClasses from '@mui/utils/composeClasses';
7import elementTypeAcceptingRef from '@mui/utils/elementTypeAcceptingRef';
8import chainPropTypes from '@mui/utils/chainPropTypes';
9import isHostComponent from "../utils/isHostComponent.js";
10import { styled } from "../zero-styled/index.js";
11import memoTheme from "../utils/memoTheme.js";
12import { useDefaultProps } from "../DefaultPropsProvider/index.js";
13import isMuiElement from "../utils/isMuiElement.js";
14import useForkRef from "../utils/useForkRef.js";
15import ListContext from "../List/ListContext.js";
16import { getListItemUtilityClass } from "./listItemClasses.js";
17import { listItemButtonClasses } from "../ListItemButton/index.js";
18import ListItemSecondaryAction from "../ListItemSecondaryAction/index.js";
19import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
20export const overridesResolver = (props, styles) => {
21 const {
22 ownerState
23 } = props;
24 return [styles.root, ownerState.dense && styles.dense, ownerState.alignItems === 'flex-start' && styles.alignItemsFlexStart, ownerState.divider && styles.divider, !ownerState.disableGutters && styles.gutters, !ownerState.disablePadding && styles.padding, ownerState.hasSecondaryAction && styles.secondaryAction];
25};
26const useUtilityClasses = ownerState => {
27 const {
28 alignItems,
29 classes,
30 dense,
31 disableGutters,
32 disablePadding,
33 divider,
34 hasSecondaryAction
35 } = ownerState;
36 const slots = {
37 root: ['root', dense && 'dense', !disableGutters && 'gutters', !disablePadding && 'padding', divider && 'divider', alignItems === 'flex-start' && 'alignItemsFlexStart', hasSecondaryAction && 'secondaryAction'],
38 container: ['container']
39 };
40 return composeClasses(slots, getListItemUtilityClass, classes);
41};
42export const ListItemRoot = styled('div', {
43 name: 'MuiListItem',
44 slot: 'Root',
45 overridesResolver
46})(memoTheme(({
47 theme
48}) => ({
49 display: 'flex',
50 justifyContent: 'flex-start',
51 alignItems: 'center',
52 position: 'relative',
53 textDecoration: 'none',
54 width: '100%',
55 boxSizing: 'border-box',
56 textAlign: 'left',
57 variants: [{
58 props: ({
59 ownerState
60 }) => !ownerState.disablePadding,
61 style: {
62 paddingTop: 8,
63 paddingBottom: 8
64 }
65 }, {
66 props: ({
67 ownerState
68 }) => !ownerState.disablePadding && ownerState.dense,
69 style: {
70 paddingTop: 4,
71 paddingBottom: 4
72 }
73 }, {
74 props: ({
75 ownerState
76 }) => !ownerState.disablePadding && !ownerState.disableGutters,
77 style: {
78 paddingLeft: 16,
79 paddingRight: 16
80 }
81 }, {
82 props: ({
83 ownerState
84 }) => !ownerState.disablePadding && !!ownerState.secondaryAction,
85 style: {
86 // Add some space to avoid collision as `ListItemSecondaryAction`
87 // is absolutely positioned.
88 paddingRight: 48
89 }
90 }, {
91 props: ({
92 ownerState
93 }) => !!ownerState.secondaryAction,
94 style: {
95 [`& > .${listItemButtonClasses.root}`]: {
96 paddingRight: 48
97 }
98 }
99 }, {
100 props: {
101 alignItems: 'flex-start'
102 },
103 style: {
104 alignItems: 'flex-start'
105 }
106 }, {
107 props: ({
108 ownerState
109 }) => ownerState.divider,
110 style: {
111 borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`,
112 backgroundClip: 'padding-box'
113 }
114 }, {
115 props: ({
116 ownerState
117 }) => ownerState.button,
118 style: {
119 transition: theme.transitions.create('background-color', {
120 duration: theme.transitions.duration.shortest
121 }),
122 '&:hover': {
123 textDecoration: 'none',
124 backgroundColor: (theme.vars || theme).palette.action.hover,
125 // Reset on touch devices, it doesn't add specificity
126 '@media (hover: none)': {
127 backgroundColor: 'transparent'
128 }
129 }
130 }
131 }, {
132 props: ({
133 ownerState
134 }) => ownerState.hasSecondaryAction,
135 style: {
136 // Add some space to avoid collision as `ListItemSecondaryAction`
137 // is absolutely positioned.
138 paddingRight: 48
139 }
140 }]
141})));
142const ListItemContainer = styled('li', {
143 name: 'MuiListItem',
144 slot: 'Container',
145 overridesResolver: (props, styles) => styles.container
146})({
147 position: 'relative'
148});
149
150/**
151 * Uses an additional container component if `ListItemSecondaryAction` is the last child.
152 */
153const ListItem = /*#__PURE__*/React.forwardRef(function ListItem(inProps, ref) {
154 const props = useDefaultProps({
155 props: inProps,
156 name: 'MuiListItem'
157 });
158 const {
159 alignItems = 'center',
160 children: childrenProp,
161 className,
162 component: componentProp,
163 components = {},
164 componentsProps = {},
165 ContainerComponent = 'li',
166 ContainerProps: {
167 className: ContainerClassName,
168 ...ContainerProps
169 } = {},
170 dense = false,
171 disableGutters = false,
172 disablePadding = false,
173 divider = false,
174 secondaryAction,
175 slotProps = {},
176 slots = {},
177 ...other
178 } = props;
179 const context = React.useContext(ListContext);
180 const childContext = React.useMemo(() => ({
181 dense: dense || context.dense || false,
182 alignItems,
183 disableGutters
184 }), [alignItems, context.dense, dense, disableGutters]);
185 const listItemRef = React.useRef(null);
186 const children = React.Children.toArray(childrenProp);
187
188 // v4 implementation, deprecated in v6, will be removed in v7
189 const hasSecondaryAction = children.length && isMuiElement(children[children.length - 1], ['ListItemSecondaryAction']);
190 const ownerState = {
191 ...props,
192 alignItems,
193 dense: childContext.dense,
194 disableGutters,
195 disablePadding,
196 divider,
197 hasSecondaryAction
198 };
199 const classes = useUtilityClasses(ownerState);
200 const handleRef = useForkRef(listItemRef, ref);
201 const Root = slots.root || components.Root || ListItemRoot;
202 const rootProps = slotProps.root || componentsProps.root || {};
203 const componentProps = {
204 className: clsx(classes.root, rootProps.className, className),
205 ...other
206 };
207 let Component = componentProp || 'li';
208
209 // v4 implementation, deprecated in v6, will be removed in v7
210 if (hasSecondaryAction) {
211 // Use div by default.
212 Component = !componentProps.component && !componentProp ? 'div' : Component;
213
214 // Avoid nesting of li > li.
215 if (ContainerComponent === 'li') {
216 if (Component === 'li') {
217 Component = 'div';
218 } else if (componentProps.component === 'li') {
219 componentProps.component = 'div';
220 }
221 }
222 return /*#__PURE__*/_jsx(ListContext.Provider, {
223 value: childContext,
224 children: /*#__PURE__*/_jsxs(ListItemContainer, {
225 as: ContainerComponent,
226 className: clsx(classes.container, ContainerClassName),
227 ref: handleRef,
228 ownerState: ownerState,
229 ...ContainerProps,
230 children: [/*#__PURE__*/_jsx(Root, {
231 ...rootProps,
232 ...(!isHostComponent(Root) && {
233 as: Component,
234 ownerState: {
235 ...ownerState,
236 ...rootProps.ownerState
237 }
238 }),
239 ...componentProps,
240 children: children
241 }), children.pop()]
242 })
243 });
244 }
245 return /*#__PURE__*/_jsx(ListContext.Provider, {
246 value: childContext,
247 children: /*#__PURE__*/_jsxs(Root, {
248 ...rootProps,
249 as: Component,
250 ref: handleRef,
251 ...(!isHostComponent(Root) && {
252 ownerState: {
253 ...ownerState,
254 ...rootProps.ownerState
255 }
256 }),
257 ...componentProps,
258 children: [children, secondaryAction && /*#__PURE__*/_jsx(ListItemSecondaryAction, {
259 children: secondaryAction
260 })]
261 })
262 });
263});
264process.env.NODE_ENV !== "production" ? ListItem.propTypes /* remove-proptypes */ = {
265 // ┌────────────────────────────── Warning ──────────────────────────────┐
266 // │ These PropTypes are generated from the TypeScript type definitions. │
267 // │ To update them, edit the d.ts file and run `pnpm proptypes`. │
268 // └─────────────────────────────────────────────────────────────────────┘
269 /**
270 * Defines the `align-items` style property.
271 * @default 'center'
272 */
273 alignItems: PropTypes.oneOf(['center', 'flex-start']),
274 /**
275 * The content of the component if a `ListItemSecondaryAction` is used it must
276 * be the last child.
277 */
278 children: chainPropTypes(PropTypes.node, props => {
279 const children = React.Children.toArray(props.children);
280
281 // React.Children.toArray(props.children).findLastIndex(isListItemSecondaryAction)
282 let secondaryActionIndex = -1;
283 for (let i = children.length - 1; i >= 0; i -= 1) {
284 const child = children[i];
285 if (isMuiElement(child, ['ListItemSecondaryAction'])) {
286 secondaryActionIndex = i;
287 break;
288 }
289 }
290
291 // is ListItemSecondaryAction the last child of ListItem
292 if (secondaryActionIndex !== -1 && secondaryActionIndex !== children.length - 1) {
293 return new Error('MUI: You used an element after ListItemSecondaryAction. ' + 'For ListItem to detect that it has a secondary action ' + 'you must pass it as the last child to ListItem.');
294 }
295 return null;
296 }),
297 /**
298 * Override or extend the styles applied to the component.
299 */
300 classes: PropTypes.object,
301 /**
302 * @ignore
303 */
304 className: PropTypes.string,
305 /**
306 * The component used for the root node.
307 * Either a string to use a HTML element or a component.
308 */
309 component: PropTypes.elementType,
310 /**
311 * The components used for each slot inside.
312 *
313 * @deprecated Use the `slots` prop instead. This prop will be removed in v7. See [Migrating from deprecated APIs](https://mui.com/material-ui/migration/migrating-from-deprecated-apis/) for more details.
314 * @default {}
315 */
316 components: PropTypes.shape({
317 Root: PropTypes.elementType
318 }),
319 /**
320 * The extra props for the slot components.
321 * You can override the existing props or add new ones.
322 *
323 * @deprecated Use the `slotProps` prop instead. This prop will be removed in v7. See [Migrating from deprecated APIs](https://mui.com/material-ui/migration/migrating-from-deprecated-apis/) for more details.
324 * @default {}
325 */
326 componentsProps: PropTypes.shape({
327 root: PropTypes.object
328 }),
329 /**
330 * The container component used when a `ListItemSecondaryAction` is the last child.
331 * @default 'li'
332 * @deprecated Use the `component` or `slots.root` prop instead. This prop will be removed in v7. See [Migrating from deprecated APIs](https://mui.com/material-ui/migration/migrating-from-deprecated-apis/) for more details.
333 */
334 ContainerComponent: elementTypeAcceptingRef,
335 /**
336 * Props applied to the container component if used.
337 * @default {}
338 * @deprecated Use the `slotProps.root` prop instead. This prop will be removed in v7. See [Migrating from deprecated APIs](https://mui.com/material-ui/migration/migrating-from-deprecated-apis/) for more details.
339 */
340 ContainerProps: PropTypes.object,
341 /**
342 * If `true`, compact vertical padding designed for keyboard and mouse input is used.
343 * The prop defaults to the value inherited from the parent List component.
344 * @default false
345 */
346 dense: PropTypes.bool,
347 /**
348 * If `true`, the left and right padding is removed.
349 * @default false
350 */
351 disableGutters: PropTypes.bool,
352 /**
353 * If `true`, all padding is removed.
354 * @default false
355 */
356 disablePadding: PropTypes.bool,
357 /**
358 * If `true`, a 1px light border is added to the bottom of the list item.
359 * @default false
360 */
361 divider: PropTypes.bool,
362 /**
363 * The element to display at the end of ListItem.
364 */
365 secondaryAction: PropTypes.node,
366 /**
367 * The extra props for the slot components.
368 * You can override the existing props or add new ones.
369 *
370 * @default {}
371 */
372 slotProps: PropTypes.shape({
373 root: PropTypes.object
374 }),
375 /**
376 * The components used for each slot inside.
377 *
378 * @default {}
379 */
380 slots: PropTypes.shape({
381 root: PropTypes.elementType
382 }),
383 /**
384 * The system prop that allows defining system overrides as well as additional CSS styles.
385 */
386 sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object])
387} : void 0;
388export default ListItem;
\No newline at end of file