semantic-ui-react
Version:
The official Semantic-UI-React integration.
183 lines (159 loc) • 4.88 kB
JavaScript
import cx from 'clsx'
import _ from 'lodash'
import PropTypes from 'prop-types'
import React, { Component, isValidElement } from 'react'
import {
childrenUtils,
createShorthandFactory,
customPropTypes,
getElementType,
getUnhandledProps,
useKeyOnly,
} from '../../lib'
import Image from '../Image'
import ListContent from './ListContent'
import ListDescription from './ListDescription'
import ListHeader from './ListHeader'
import ListIcon from './ListIcon'
/**
* A list item can contain a set of items.
*/
class ListItem extends Component {
handleClick = (e) => {
const { disabled } = this.props
if (!disabled) _.invoke(this.props, 'onClick', e, this.props)
}
render() {
const {
active,
children,
className,
content,
description,
disabled,
header,
icon,
image,
value,
} = this.props
const ElementType = getElementType(ListItem, this.props)
const classes = cx(
useKeyOnly(active, 'active'),
useKeyOnly(disabled, 'disabled'),
useKeyOnly(ElementType !== 'li', 'item'),
className,
)
const rest = getUnhandledProps(ListItem, this.props)
const valueProp = ElementType === 'li' ? { value } : { 'data-value': value }
if (!childrenUtils.isNil(children)) {
return (
<ElementType
{...valueProp}
role='listitem'
className={classes}
onClick={this.handleClick}
{...rest}
>
{children}
</ElementType>
)
}
const iconElement = ListIcon.create(icon, { autoGenerateKey: false })
const imageElement = Image.create(image, { autoGenerateKey: false })
// See description of `content` prop for explanation about why this is necessary.
if (!isValidElement(content) && _.isPlainObject(content)) {
return (
<ElementType
{...valueProp}
role='listitem'
className={classes}
onClick={this.handleClick}
{...rest}
>
{iconElement || imageElement}
{ListContent.create(content, {
autoGenerateKey: false,
defaultProps: { header, description },
})}
</ElementType>
)
}
const headerElement = ListHeader.create(header, { autoGenerateKey: false })
const descriptionElement = ListDescription.create(description, { autoGenerateKey: false })
if (iconElement || imageElement) {
return (
<ElementType
{...valueProp}
role='listitem'
className={classes}
onClick={this.handleClick}
{...rest}
>
{iconElement || imageElement}
{(content || headerElement || descriptionElement) && (
<ListContent>
{headerElement}
{descriptionElement}
{content}
</ListContent>
)}
</ElementType>
)
}
return (
<ElementType
{...valueProp}
role='listitem'
className={classes}
onClick={this.handleClick}
{...rest}
>
{headerElement}
{descriptionElement}
{content}
</ElementType>
)
}
}
ListItem.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
/** A list item can active. */
active: PropTypes.bool,
/** Primary content. */
children: PropTypes.node,
/** Additional classes. */
className: PropTypes.string,
/**
* Shorthand for primary content.
*
* Heads up!
*
* This is handled slightly differently than the typical `content` prop since
* the wrapping ListContent is not used when there's no icon or image.
*
* If you pass content as:
* - an element/literal, it's treated as the sibling node to
* header/description (whether wrapped in Item.Content or not).
* - a props object, it forces the presence of Item.Content and passes those
* props to it. If you pass a content prop within that props object, it
* will be treated as the sibling node to header/description.
*/
content: customPropTypes.itemShorthand,
/** Shorthand for ListDescription. */
description: customPropTypes.itemShorthand,
/** A list item can disabled. */
disabled: PropTypes.bool,
/** Shorthand for ListHeader. */
header: customPropTypes.itemShorthand,
/** Shorthand for ListIcon. */
icon: customPropTypes.every([customPropTypes.disallow(['image']), customPropTypes.itemShorthand]),
/** Shorthand for Image. */
image: customPropTypes.every([customPropTypes.disallow(['icon']), customPropTypes.itemShorthand]),
/** A ListItem can be clicked */
onClick: PropTypes.func,
/** A value for an ordered list. */
value: PropTypes.string,
}
ListItem.create = createShorthandFactory(ListItem, (content) => ({ content }))
export default ListItem