src/list/list-item.tsx (100 lines of code) (raw):

/* Copyright (c) Uber Technologies, Inc. This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. */ import React from 'react'; import { getOverrides } from '../helpers/overrides'; import { ARTWORK_SIZES, SHAPE } from './constants'; import { StyledRoot, StyledContent, StyledEndEnhancerContainer, StyledArtworkContainer, } from './styled-components'; import type { ListProps } from './types'; import { artworkSizeToValue } from './utils'; const ListItem = React.forwardRef<HTMLLIElement, ListProps>((props: ListProps, ref) => { const { overrides = {} } = props; const Artwork = props.artwork; const EndEnhancer = props.endEnhancer; const [Root, rootProps] = getOverrides(overrides.Root, StyledRoot); const [ArtworkContainer, artworkContainerProps] = getOverrides( overrides.ArtworkContainer, StyledArtworkContainer ); const [Content, contentProps] = getOverrides(overrides.Content, StyledContent); const [EndEnhancerContainer, endEnhancerContainerProps] = getOverrides( overrides.EndEnhancerContainer, StyledEndEnhancerContainer ); const artworkSize = React.useMemo(() => { if (props.sublist) { let size = props.artworkSize || ARTWORK_SIZES.SMALL; if (props.artworkSize === ARTWORK_SIZES.MEDIUM) { size = ARTWORK_SIZES.SMALL; if (__DEV__) { console.warn( 'When ListItem sublist prop is true, artworkSize MEDIUM is aliased to SMALL' ); } } return size; } else { return props.artworkSize || ARTWORK_SIZES.MEDIUM; } }, [props.artworkSize, props.sublist]); const isTapTarget = Boolean(props.onClick); const getMainTextFromChild = (child: React.ReactNode | React.ReactNode[] | string) => { if (typeof child === 'string') { return child; } else if (React.isValidElement(child)) { return getMainTextFromChild(child.props.children); } else { return 'List item'; } }; const listItemName = React.Children.count(props.children) === 0 ? ['List item'] : React.Children.map(props.children, (child) => { return getMainTextFromChild(child); }); const ariaLabel = props.hasOwnProperty('aria-label') ? props['aria-label'] : listItemName[0]; return ( <Root // eslint-disable-next-line @typescript-eslint/no-explicit-any ref={ref as any} $shape={props.shape || SHAPE.DEFAULT} $as={isTapTarget ? 'button' : 'li'} $isTapTarget={isTapTarget} aria-label={props.role !== 'presentation' ? ariaLabel : null} aria-selected={props['aria-selected']} id={props.id} role={props.role} onClick={props.onClick} {...rootProps} > {Artwork && ( <ArtworkContainer $artworkSize={artworkSize} $sublist={Boolean(props.sublist)} {...artworkContainerProps} > <Artwork size={ typeof artworkSize === 'number' ? artworkSize : artworkSizeToValue(artworkSize, Boolean(props.sublist)) } /> </ArtworkContainer> )} <Content $mLeft={!Artwork} $sublist={!!props.sublist} {...contentProps}> {props.children} {EndEnhancer && // @ts-expect-error todo(flow->ts) it is not expected to be a number EndEnhancer !== 0 && ( <EndEnhancerContainer {...endEnhancerContainerProps}> <EndEnhancer /> </EndEnhancerContainer> )} </Content> </Root> ); }); ListItem.displayName = 'ListItem'; export default ListItem;