import React, { PureComponent, ReactNode, CSSProperties } from 'react'; import { omit, isString } from 'lodash'; import PropTypes from 'prop-types'; import { cssClasses, strings } from '@douyinfe/semi-foundation/card/constants'; import '@douyinfe/semi-foundation/card/card.scss'; import Meta from './meta'; import cls from 'classnames'; import Skeleton from '../skeleton'; import Typography from '../typography'; import Space from '../space'; const prefixcls = cssClasses.PREFIX; export type Shadows = 'hover' | 'always'; export type { MetaProps } from './meta'; export type { CardGroupProps } from './cardGroup'; export interface CardProps { /** Operation group at the bottom of the card content area */ actions?: ReactNode[]; /** Card content area inline style */ bodyStyle?: CSSProperties; /** Whether there is an outer border */ bordered?: boolean; /** Style class name */ className?: string; children?: React.ReactNode; /** Cover */ cover?: ReactNode; /** Additional additions to the right of the title */ headerExtraContent?: ReactNode; /** Custom end of page */ footer?: ReactNode; /** Whether there is an edge between the bottom of the page and the content area */ footerLine?: boolean; /** Inline style at the end of the page */ footerStyle?: CSSProperties; /** Custom head */ header?: ReactNode; /** Whether there is an edge line between the head and the content area */ headerLine?: boolean; /** Head inline style */ headerStyle?: CSSProperties; /** Whether to preload */ loading?: boolean; /** Set shadow */ shadows?: Shadows; /** Card inline style */ style?: CSSProperties; /** Title */ title?: ReactNode; /** aria label */ 'aria-label'?: string; } class Card extends PureComponent { static Meta = Meta; static propTypes = { actions: PropTypes.array, bodyStyle: PropTypes.object, bordered: PropTypes.bool, children: PropTypes.node, className: PropTypes.string, cover: PropTypes.node, footer: PropTypes.node, footerLine: PropTypes.bool, footerStyle: PropTypes.object, header: PropTypes.node, headerExtraContent: PropTypes.node, headerLine: PropTypes.bool, headerStyle: PropTypes.object, loading: PropTypes.bool, shadows: PropTypes.oneOf(strings.SHADOWS), style: PropTypes.object, title: PropTypes.node, 'aria-label': PropTypes.string, }; static defaultProps = { bordered: true, footerLine: false, headerLine: true, loading: false }; renderHeader = (): ReactNode => { const { title, headerExtraContent, header, headerLine, headerStyle } = this.props; const headerCls = cls(`${prefixcls}-header`, { [`${prefixcls}-header-bordered`]: Boolean(headerLine) }); const headerWrapperCls = cls(`${prefixcls}-header-wrapper`); const titleCls = cls(`${prefixcls}-header-wrapper-title`, { [`${prefixcls}-header-wrapper-spacing`]: Boolean(headerExtraContent) }); if (header || headerExtraContent || title) { return (
{header || ( // Priority of header over title and headerExtraContent
{headerExtraContent && (
{headerExtraContent}
)} {title && (
{isString(title) ? ( {title} ) : ( title )}
)}
)}
); } return null; }; renderCover = (): ReactNode => { const { cover } = this.props; const coverCls = cls(`${prefixcls}-cover`); return ( cover && (
{cover}
) ); }; renderBody = (): ReactNode => { const { bodyStyle, children, actions, loading } = this.props; const bodyCls = cls(`${prefixcls}-body`); const actionsCls = cls(`${prefixcls}-body-actions`); const actionsItemCls = cls(`${prefixcls}-body-actions-item`); const placeholder = (

); return (
{children && ( {children} )} { Array.isArray(actions) && (
{actions.map((item, idx) => (
{item}
))}
) }
); }; renderFooter = (): ReactNode => { const { footer, footerLine, footerStyle } = this.props; const footerCls = cls(`${prefixcls}-footer`, { [`${prefixcls}-footer-bordered`]: footerLine }); return ( footer && (
{footer}
) ); }; render(): ReactNode { const { bordered, shadows, style, className, ...otherProps } = this.props; const others = omit(otherProps, [ // Remove APIs in otherProps that do not need to be hung on the outer node 'actions', 'bodyStyle', 'cover', 'headerExtraContent', 'footer', 'footerLine', 'footerStyle', 'header', 'headerLine', 'headerStyle', 'loading', 'title' ]); const cardCls = cls(prefixcls, className, { [`${prefixcls}-bordered`]: bordered, [`${prefixcls}-shadows`]: shadows, [`${prefixcls}-shadows-${shadows}`]: shadows }); return (
{this.renderHeader()} {this.renderCover()} {this.renderBody()} {this.renderFooter()}
); } } export default Card;