| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 | 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 { MetaProps } from './meta';export { 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<CardProps> {    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 (                <div style={headerStyle} className={headerCls}>                    {header || ( // Priority of header over title and headerExtraContent                        <div className={headerWrapperCls}>                            {headerExtraContent && (                                <div                                    className={`${prefixcls}-header-wrapper-extra`}                                    x-semi-prop="headerExtraContent"                                >                                    {headerExtraContent}                                </div>                            )}                            {title && (                                <div className={titleCls}>                                    {isString(title) ? (                                        <Typography.Title                                            heading={6}                                            ellipsis={{ showTooltip: true, rows: 1 }}                                            x-semi-prop="title"                                        >                                            {title}                                        </Typography.Title>                                    ) : (                                        title                                    )}                                </div>                            )}                        </div>                    )}                </div>            );        }        return null;    };    renderCover = (): ReactNode => {        const {            cover        } = this.props;        const coverCls = cls(`${prefixcls}-cover`);        return (            cover && (                <div className={coverCls} x-semi-prop="cover">                    {cover}                </div>            )        );    };    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 = (            <div>                <Skeleton.Title />                <br />                <Skeleton.Paragraph rows={3} />            </div>        );        return (            <div style={bodyStyle} className={bodyCls}>                {children && (                    <Skeleton placeholder={placeholder} loading={loading} active>                        {children}                    </Skeleton>                )}                {                    Array.isArray(actions) &&                    (                        <div className={actionsCls}>                            <Space spacing={12}>                                {actions.map((item, idx) => (                                    <div key={idx} className={actionsItemCls} x-semi-prop={`actions.${idx}`}>{item}</div>                                ))}                            </Space>                        </div>                    )                }            </div>        );    };    renderFooter = (): ReactNode => {        const {            footer,            footerLine,            footerStyle        } = this.props;        const footerCls = cls(`${prefixcls}-footer`, {            [`${prefixcls}-footer-bordered`]: footerLine        });        return (            footer && (                <div style={footerStyle} className={footerCls} x-semi-prop="footer">                    {footer}                </div>            )        );    };    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 (            <div {...others} aria-busy={this.props.loading} className={cardCls} style={style}>                {this.renderHeader()}                {this.renderCover()}                {this.renderBody()}                {this.renderFooter()}            </div>        );    }}export default Card;
 |