import React from 'react' import ReactDOM from 'react-dom' import PropTypes from 'prop-types' import { connect } from 'mini-store' import TableCell from './TableCell' import { warningOnce } from './utils' class TableRow extends React.Component { static propTypes = { onRow: PropTypes.func, onRowClick: PropTypes.func, onRowDoubleClick: PropTypes.func, onRowContextMenu: PropTypes.func, onRowMouseEnter: PropTypes.func, onRowMouseLeave: PropTypes.func, record: PropTypes.object, prefixCls: PropTypes.string, onHover: PropTypes.func, columns: PropTypes.array, height: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, ]), index: PropTypes.number, rowKey: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, ]).isRequired, className: PropTypes.string, indent: PropTypes.number, indentSize: PropTypes.number, hasExpandIcon: PropTypes.func.isRequired, hovered: PropTypes.bool.isRequired, visible: PropTypes.bool.isRequired, store: PropTypes.object.isRequired, fixed: PropTypes.oneOfType([ PropTypes.string, PropTypes.bool, ]), renderExpandIcon: PropTypes.func, renderExpandIconCell: PropTypes.func, components: PropTypes.any, expandedRow: PropTypes.bool, isAnyColumnsFixed: PropTypes.bool, ancestorKeys: PropTypes.array.isRequired, } static defaultProps = { onRow () {}, expandIconColumnIndex: 0, expandRowByClick: false, onHover () {}, hasExpandIcon () {}, renderExpandIcon () {}, renderExpandIconCell () {}, } constructor (props) { super(props) this.shouldRender = props.visible } componentDidMount () { if (this.shouldRender) { this.saveRowRef() } } componentWillReceiveProps (nextProps) { if (this.props.visible || (!this.props.visible && nextProps.visible)) { this.shouldRender = true } } shouldComponentUpdate (nextProps) { return !!(this.props.visible || nextProps.visible) } componentDidUpdate () { if (this.shouldRender && !this.rowRef) { this.saveRowRef() } } onRowClick = (event) => { const { record, index, onRowClick } = this.props if (onRowClick) { onRowClick(record, index, event) } } onRowDoubleClick = (event) => { const { record, index, onRowDoubleClick } = this.props if (onRowDoubleClick) { onRowDoubleClick(record, index, event) } } onContextMenu = (event) => { const { record, index, onRowContextMenu } = this.props if (onRowContextMenu) { onRowContextMenu(record, index, event) } } onMouseEnter = (event) => { const { record, index, onRowMouseEnter, onHover, rowKey } = this.props onHover(true, rowKey) if (onRowMouseEnter) { onRowMouseEnter(record, index, event) } } onMouseLeave = (event) => { const { record, index, onRowMouseLeave, onHover, rowKey } = this.props onHover(false, rowKey) if (onRowMouseLeave) { onRowMouseLeave(record, index, event) } } setExpanedRowHeight () { const { store, rowKey } = this.props let { expandedRowsHeight } = store.getState() const height = this.rowRef.getBoundingClientRect().height expandedRowsHeight = { ...expandedRowsHeight, [rowKey]: height, } store.setState({ expandedRowsHeight }) } setRowHeight () { const { store, index } = this.props const fixedColumnsBodyRowsHeight = store.getState().fixedColumnsBodyRowsHeight.slice() const height = this.rowRef.getBoundingClientRect().height fixedColumnsBodyRowsHeight[index] = height store.setState({ fixedColumnsBodyRowsHeight }) } getStyle () { const { height, visible } = this.props if (height && height !== this.style.height) { this.style = { ...this.style, height } } if (!visible && !this.style.display) { this.style = { ...this.style, display: 'none' } } return this.style } saveRowRef () { this.rowRef = ReactDOM.findDOMNode(this) const { isAnyColumnsFixed, fixed, expandedRow, ancestorKeys } = this.props if (!isAnyColumnsFixed) { return } if (!fixed && expandedRow) { this.setExpanedRowHeight() } if (!fixed && ancestorKeys.length >= 0) { this.setRowHeight() } } render () { if (!this.shouldRender) { return null } const { prefixCls, columns, record, index, onRow, indent, indentSize, hovered, height, visible, components, hasExpandIcon, renderExpandIcon, renderExpandIconCell, } = this.props const BodyRow = components.body.row const BodyCell = components.body.cell let { className } = this.props if (hovered) { className += ` ${prefixCls}-hover` } const cells = [] renderExpandIconCell(cells) for (let i = 0; i < columns.length; i++) { const column = columns[i] warningOnce( column.onCellClick === undefined, 'column[onCellClick] is deprecated, please use column[onCell] instead.', ) cells.push( ) } const rowClassName = `${prefixCls} ${className} ${prefixCls}-level-${indent}`.trim() const rowProps = onRow(record, index) const customStyle = rowProps ? rowProps.style : {} let style = { height } if (!visible) { style.display = 'none' } style = { ...style, ...customStyle } return ( {cells} ) } } function getRowHeight (state, props) { const { expandedRowsHeight, fixedColumnsBodyRowsHeight } = state const { fixed, index, rowKey } = props if (!fixed) { return null } if (expandedRowsHeight[rowKey]) { return expandedRowsHeight[rowKey] } if (fixedColumnsBodyRowsHeight[index]) { return fixedColumnsBodyRowsHeight[index] } return null } export default connect((state, props) => { const { currentHoverKey, expandedRowKeys } = state const { rowKey, ancestorKeys } = props const visible = ancestorKeys.length === 0 || ancestorKeys.every(k => ~expandedRowKeys.indexOf(k)) return ({ visible, hovered: currentHoverKey === rowKey, height: getRowHeight(state, props), }) })(TableRow)