import * as React from 'react'; import classNames from 'classnames'; import addEventListener from 'rc-util/lib/Dom/addEventListener'; import omit from 'omit.js'; import Grid from './Grid'; import Meta from './Meta'; import Tabs from '../tabs'; import Row from '../row'; import Col from '../col'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame'; import warning from '../_util/warning'; import { Omit } from '../_util/type'; export { CardGridProps } from './Grid'; export { CardMetaProps } from './Meta'; export type CardType = 'inner'; export interface CardTabListType { key: string; tab: React.ReactNode; disabled?: boolean; } export interface CardProps extends Omit, 'title'> { prefixCls?: string; title?: React.ReactNode; extra?: React.ReactNode; bordered?: boolean; headStyle?: React.CSSProperties; bodyStyle?: React.CSSProperties; style?: React.CSSProperties; loading?: boolean; noHovering?: boolean; hoverable?: boolean; children?: React.ReactNode; id?: string; className?: string; type?: CardType; cover?: React.ReactNode; actions?: React.ReactNode[]; tabList?: CardTabListType[]; onTabChange?: (key: string) => void; activeTabKey?: string; defaultActiveTabKey?: string; } export interface CardState { widerPadding: boolean; } export default class Card extends React.Component { static Grid: typeof Grid = Grid; static Meta: typeof Meta = Meta; state = { widerPadding: false, }; private resizeEvent: any; private updateWiderPaddingCalled: boolean = false; private container: HTMLDivElement; componentDidMount() { this.updateWiderPadding(); this.resizeEvent = addEventListener(window, 'resize', this.updateWiderPadding); if ('noHovering' in this.props) { warning( !this.props.noHovering, '`noHovering` of Card is deprecated, you can remove it safely or use `hoverable` instead.', ); warning( !!this.props.noHovering, '`noHovering={false}` of Card is deprecated, use `hoverable` instead.', ); } } componentWillUnmount() { if (this.resizeEvent) { this.resizeEvent.remove(); } (this.updateWiderPadding as any).cancel(); } @throttleByAnimationFrameDecorator() updateWiderPadding() { if (!this.container) { return; } // 936 is a magic card width pixel number indicated by designer const WIDTH_BOUNDARY_PX = 936; if (this.container.offsetWidth >= WIDTH_BOUNDARY_PX && !this.state.widerPadding) { this.setState({ widerPadding: true }, () => { this.updateWiderPaddingCalled = true; // first render without css transition }); } if (this.container.offsetWidth < WIDTH_BOUNDARY_PX && this.state.widerPadding) { this.setState({ widerPadding: false }, () => { this.updateWiderPaddingCalled = true; // first render without css transition }); } } onTabChange = (key: string) => { if (this.props.onTabChange) { this.props.onTabChange(key); } }; saveRef = (node: HTMLDivElement) => { this.container = node; }; isContainGrid() { let containGrid; React.Children.forEach(this.props.children, (element: JSX.Element) => { if (element && element.type && element.type === Grid) { containGrid = true; } }); return containGrid; } getAction(actions: React.ReactNode[]) { if (!actions || !actions.length) { return null; } const actionList = actions.map((action, index) => (
  • {action}
  • )); return actionList; } // For 2.x compatible getCompatibleHoverable() { const { noHovering, hoverable } = this.props; if ('noHovering' in this.props) { return !noHovering || hoverable; } return !!hoverable; } renderCard = ({ getPrefixCls }: ConfigConsumerProps) => { const { prefixCls: customizePrefixCls, className, extra, headStyle = {}, bodyStyle = {}, noHovering, hoverable, title, loading, bordered = true, type, cover, actions, tabList, children, activeTabKey, defaultActiveTabKey, ...others } = this.props; const prefixCls = getPrefixCls('card', customizePrefixCls); const classString = classNames(prefixCls, className, { [`${prefixCls}-loading`]: loading, [`${prefixCls}-bordered`]: bordered, [`${prefixCls}-hoverable`]: this.getCompatibleHoverable(), [`${prefixCls}-wider-padding`]: this.state.widerPadding, [`${prefixCls}-padding-transition`]: this.updateWiderPaddingCalled, [`${prefixCls}-contain-grid`]: this.isContainGrid(), [`${prefixCls}-contain-tabs`]: tabList && tabList.length, [`${prefixCls}-type-${type}`]: !!type, }); const loadingBlockStyle = bodyStyle.padding === 0 || bodyStyle.padding === '0px' ? { padding: 24 } : undefined; const loadingBlock = (
    ); const hasActiveTabKey = activeTabKey !== undefined; const extraProps = { [hasActiveTabKey ? 'activeKey' : 'defaultActiveKey']: hasActiveTabKey ? activeTabKey : defaultActiveTabKey, }; let head; const tabs = tabList && tabList.length ? ( {tabList.map(item => ( ))} ) : null; if (title || extra || tabs) { head = (
    {title &&
    {title}
    } {extra &&
    {extra}
    }
    {tabs}
    ); } const coverDom = cover ?
    {cover}
    : null; const body = (
    {loading ? loadingBlock : children}
    ); const actionDom = actions && actions.length ? (
      {this.getAction(actions)}
    ) : null; const divProps = omit(others, ['onTabChange']); return (
    {head} {coverDom} {body} {actionDom}
    ); }; render() { return {this.renderCard}; } }