UNPKG

@douyinfe/semi-ui

Version:

A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.

331 lines 11.5 kB
import _pick from "lodash/pick"; import _isEqual from "lodash/isEqual"; import _omit from "lodash/omit"; import _stubTrue from "lodash/stubTrue"; import _get from "lodash/get"; import _noop from "lodash/noop"; import _each from "lodash/each"; var __rest = this && this.__rest || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import React from 'react'; import classnames from 'classnames'; import PropTypes from 'prop-types'; import { strings, cssClasses } from '@douyinfe/semi-foundation/lib/es/table/constants'; import shallowEqualObjects from '@douyinfe/semi-foundation/lib/es/utils/shallowEqualObjects'; import TableRowFoundation from '@douyinfe/semi-foundation/lib/es/table/tableRowFoundation'; import { isLastLeftFixed, arrayAdd, isFixedLeft, isFixedRight, isScrollbarColumn, isFirstFixedRight, isInnerColumnKey, isExpandedColumn } from '@douyinfe/semi-foundation/lib/es/table/utils'; import BaseComponent from '../../_base/baseComponent'; import TableCell from '../TableCell'; /** * avoid affected by https://www.npmjs.com/package/babel-plugin-transform-react-remove-prop-types */ export const baseRowPropTypes = { anyColumnFixed: PropTypes.bool, cellWidths: PropTypes.array.isRequired, className: PropTypes.string, columns: PropTypes.array.isRequired, components: PropTypes.object.isRequired, disabled: PropTypes.bool, expandIcon: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.node]), expandableRow: PropTypes.bool, expanded: PropTypes.bool, displayNone: PropTypes.bool, expandedRow: PropTypes.bool, fixed: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), hideExpandedColumn: PropTypes.bool, hovered: PropTypes.bool.isRequired, indent: PropTypes.number, indentSize: PropTypes.number, index: PropTypes.number, isSection: PropTypes.bool, level: PropTypes.number, onDidUpdate: PropTypes.func, onHover: PropTypes.func, onRow: PropTypes.func, onRowClick: PropTypes.func, onRowContextMenu: PropTypes.func, onRowDoubleClick: PropTypes.func, onRowMouseEnter: PropTypes.func, onRowMouseLeave: PropTypes.func, prefixCls: PropTypes.string, record: PropTypes.object, renderExpandIcon: PropTypes.func, replaceClassName: PropTypes.string, rowExpandable: PropTypes.func, rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, selected: PropTypes.bool, store: PropTypes.object, style: PropTypes.object, virtualized: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]), visible: PropTypes.bool.isRequired }; export default class TableRow extends BaseComponent { get adapter() { var _this = this; return Object.assign(Object.assign({}, super.adapter), { notifyClick: function () { return _this.props.onRowClick(...arguments); }, notifyDoubleClick: function () { return _this.props.onRowDoubleClick(...arguments); }, notifyMouseLeave: function () { _this.props.onHover(false, _this.props.rowKey); _this.props.onRowMouseEnter(...arguments); }, notifyMouseEnter: function () { _this.props.onHover(true, _this.props.rowKey); _this.props.onRowMouseEnter(...arguments); } }); } constructor(props) { super(props); // Pass true to render the tree-shaped expand button this.renderExpandIcon = record => { const { renderExpandIcon } = this.props; return renderExpandIcon(record, true); }; this.handleMouseEnter = e => { this.foundation.handleMouseEnter(e); const customRowProps = this.adapter.getCache('customRowProps'); if (typeof (customRowProps === null || customRowProps === void 0 ? void 0 : customRowProps.onMouseEnter) === 'function') { customRowProps.onMouseEnter(e); } }; this.handleMouseLeave = e => { this.foundation.handleMouseLeave(e); const customRowProps = this.adapter.getCache('customRowProps'); if (typeof (customRowProps === null || customRowProps === void 0 ? void 0 : customRowProps.onMouseLeave) === 'function') { customRowProps.onMouseLeave(e); } }; this.handleClick = e => { this.foundation.handleClick(e); const customRowProps = this.adapter.getCache('customRowProps'); if (customRowProps && typeof customRowProps.onClick === 'function') { customRowProps.onClick(e); } }; this.foundation = new TableRowFoundation(this.adapter); } componentDidMount() { // fix #745 // didmount/willUnmount may be called twice when React.StrictMode is true in React 18, we need to ensure that this.cache.customRowProps is correct const { onRow, index, record } = this.props; const customRowProps = this.adapter.getCache('customRowProps'); if (typeof customRowProps === 'undefined') { const _a = onRow(record, index) || {}, { className: customClassName, style: customStyle } = _a, rowProps = __rest(_a, ["className", "style"]); this.adapter.setCache('customRowProps', Object.assign({}, rowProps)); } } shouldComponentUpdate(nextProps) { /** * Shallow comparison of incoming props to simulate PureComponent * Deep comparison cellWidths * * 浅层对比传入的 props,模拟 PureComponent * 深比较 cellWidths */ const omitProps = ['cellWidths']; const isPropsShallowEqual = shallowEqualObjects(_omit(nextProps, omitProps), _omit(this.props, omitProps)); if (!isPropsShallowEqual || !_isEqual(_pick(nextProps, omitProps), _pick(this.props, omitProps))) { return true; } return false; } renderCells() { const { columns, record, index, prefixCls, fixed, components, expandableRow, level, expandIcon, rowExpandable, isSection, expandedRow, virtualized, indentSize, hideExpandedColumn, cellWidths, selected, expanded, disabled, onDidUpdate } = this.props; const BodyCell = _get(components, 'body.cell', strings.DEFAULT_COMPONENTS.body.cell); const cells = []; const displayExpandedColumn = rowExpandable(record); let firstIndex = 0; // const dataColumns = getDataColumns(columns); _each(columns, (column, columnIndex) => { const columnKey = _get(column, 'key'); const expandableProps = {}; if (fixed !== 'right') { if (isInnerColumnKey(columnKey)) { firstIndex++; } if (expandableRow && columnIndex === firstIndex) { expandableProps.renderExpandIcon = this.renderExpandIcon; if (hideExpandedColumn || isSection) { expandableProps.expandIcon = expandIcon != null ? expandIcon : true; } } // Only the first data row will be indented if (level != null && columnIndex === firstIndex) { expandableProps.indent = level; const isBool = typeof expandIcon === 'boolean'; const hasExpandIcon = expandIcon !== false || !isBool && expandIcon !== null; // 如果 expandIcon 为空,不需要 indent if (!expandableRow && hideExpandedColumn && hasExpandIcon) { expandableProps.indent = level + 1; } } } if (isExpandedColumn(column) && !displayExpandedColumn) { cells.push(/*#__PURE__*/React.createElement(TableCell, { key: columnIndex, colIndex: columnIndex, isSection: isSection })); } else if (!isScrollbarColumn(column)) { const diyProps = {}; if (BodyCell !== strings.DEFAULT_COMPONENTS.body.cell && virtualized && !expandedRow) { diyProps.width = _get(cellWidths, columnIndex); } cells.push(/*#__PURE__*/React.createElement(TableCell, Object.assign({ colIndex: columnIndex }, expandableProps, diyProps, { hideExpandedColumn: hideExpandedColumn, indentSize: indentSize, isSection: isSection, prefixCls: `${prefixCls}`, column: column, key: columnIndex, index: index, record: record, component: BodyCell, fixedLeft: isFixedLeft(column) && arrayAdd(cellWidths, 0, columnIndex), lastFixedLeft: isLastLeftFixed(columns, column), fixedRight: isFixedRight(column) && arrayAdd(cellWidths, columnIndex + 1), firstFixedRight: isFirstFixedRight(columns, column), selected: selected, expanded: expanded, disabled: disabled, onDidUpdate: onDidUpdate }))); } }); return cells; } render() { const { style } = this.props; const { components, prefixCls, selected, onRow, index, className, replaceClassName, record, hovered, expanded, displayNone, expandableRow, level, expandedRow, isSection, rowKey } = this.props; const BodyRow = components.body.row; const _a = onRow(record, index) || {}, { className: customClassName, style: customStyle } = _a, rowProps = __rest(_a, ["className", "style"]); this.adapter.setCache('customRowProps', Object.assign({}, rowProps)); const baseRowStyle = Object.assign(Object.assign({}, style), customStyle); const rowCls = typeof replaceClassName === 'string' && replaceClassName.length ? classnames(replaceClassName, customClassName) : classnames(className, `${prefixCls}-row`, { [`${prefixCls}-row-selected`]: selected, [`${prefixCls}-row-expanded`]: expanded, [`${prefixCls}-row-hovered`]: hovered, [`${prefixCls}-row-hidden`]: displayNone }, customClassName); const ariaProps = {}; if (typeof index === 'number') { ariaProps['aria-rowindex'] = index + 1; } if (expandableRow) { ariaProps['aria-expanded'] = expanded; } // if row is expandedRow, set it's level to 2 if (expanded || expandedRow) { ariaProps['aria-level'] = 2; } if (typeof level === 'number') { ariaProps['aria-level'] = level + 1; } if (isSection) { ariaProps['aria-level'] = 1; } return /*#__PURE__*/React.createElement(BodyRow, Object.assign({ role: "row" }, ariaProps, rowProps, { style: baseRowStyle, className: rowCls, "data-row-key": rowKey, onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave, onClick: this.handleClick }), this.renderCells()); } } TableRow.propTypes = baseRowPropTypes; TableRow.defaultProps = { columns: [], rowExpandable: _stubTrue, components: { body: { row: 'tr', cell: 'td' } }, prefixCls: cssClasses.PREFIX, onRow: _noop, onRowClick: _noop, onRowDoubleClick: _noop, onRowMouseEnter: _noop, onRowMouseLeave: _noop, onHover: _noop, onDidUpdate: _noop, visible: true, hovered: false, selected: false, disabled: false };