ExpandedRow.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /* eslint-disable max-len */
  2. import React, { PureComponent, isValidElement, ReactNode } from 'react';
  3. import PropTypes from 'prop-types';
  4. import classnames from 'classnames';
  5. import { get, set, isNull } from 'lodash';
  6. import { cssClasses, strings } from '@douyinfe/semi-foundation/table/constants';
  7. import { arrayAdd, filterColumns } from '@douyinfe/semi-foundation/table/utils';
  8. import Store from '@douyinfe/semi-foundation/utils/Store';
  9. import TableContext from '../table-context';
  10. import TableRow from './BaseRow';
  11. import { amendTableWidth } from '../utils';
  12. import { ColumnProps, ExpandIcon, TableComponents, Virtualized, Fixed } from '../interface';
  13. export interface TableExpandedRowProps {
  14. cellWidths: number[]; // required
  15. className?: string;
  16. columns?: ColumnProps[];
  17. components?: TableComponents;
  18. defaultExpandAllRows?: boolean;
  19. defaultExpandedRowKeys?: (string | number)[];
  20. expandIcon?: ExpandIcon;
  21. expandRowByClick?: boolean;
  22. expanded?: boolean;
  23. expandedRowKeys?: (string | number)[];
  24. expandedRowRender?: (record?: Record<string, any>, index?: number, expanded?: boolean) => ExpandedRowRenderReturnType;
  25. indentSize?: number;
  26. index?: number;
  27. prefixCls?: string;
  28. record?: Record<string, any>;
  29. renderExpandIcon?: (record?: Record<string, any>, isNested?: boolean) => ReactNode | null;
  30. store?: Store;
  31. style?: React.CSSProperties;
  32. virtualized?: Virtualized;
  33. }
  34. /**
  35. * Render expanded row
  36. */
  37. export default class TableExpandedRow extends PureComponent<TableExpandedRowProps> {
  38. static contextType = TableContext;
  39. static propTypes = {
  40. cellWidths: PropTypes.array.isRequired,
  41. className: PropTypes.string,
  42. columns: PropTypes.array,
  43. components: PropTypes.object,
  44. defaultExpandAllRows: PropTypes.bool,
  45. defaultExpandedRowKeys: PropTypes.array,
  46. expandIcon: PropTypes.oneOfType([PropTypes.object, PropTypes.node, PropTypes.func]),
  47. expandRowByClick: PropTypes.bool,
  48. expanded: PropTypes.bool,
  49. expandedRowKeys: PropTypes.array,
  50. expandedRowRender: PropTypes.func,
  51. indentSize: PropTypes.number,
  52. index: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  53. onExpand: PropTypes.func,
  54. onExpandedRowsChange: PropTypes.func,
  55. prefixCls: PropTypes.string,
  56. record: PropTypes.object,
  57. renderExpandIcon: PropTypes.func,
  58. store: PropTypes.object,
  59. style: PropTypes.object,
  60. virtualized: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
  61. };
  62. static defaultProps = {
  63. record: {},
  64. prefixCls: cssClasses.PREFIX,
  65. };
  66. render() {
  67. const {
  68. record,
  69. columns: propColumns = [],
  70. prefixCls,
  71. className,
  72. expanded,
  73. expandedRowRender,
  74. renderExpandIcon,
  75. index,
  76. store,
  77. components,
  78. style,
  79. virtualized,
  80. indentSize,
  81. cellWidths,
  82. } = this.props;
  83. const { tableWidth, anyColumnFixed, getCellWidths } = this.context;
  84. const cell: ExpandedRowRenderReturnType = expandedRowRender(record, index, expanded);
  85. let children: ReactNode = null;
  86. const props: { colSpan?: number; style?: Record<string, any> } = {};
  87. let column = {};
  88. if (isNull(cell)) {
  89. return null;
  90. } else if (isValidElement(cell)) {
  91. children = cell;
  92. } else if (cell && Object.prototype.toString.call(cell) === '[object Object]') {
  93. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  94. const { children: cellChildren, fixed, ...restProps } = cell as { children: ReactNode; fixed: Fixed };
  95. children = cellChildren;
  96. column = { ...restProps };
  97. }
  98. if (get(components, 'body.cell') !== strings.DEFAULT_COMPONENTS.body.cell) {
  99. if (virtualized) {
  100. set(props, 'style.height', '100%');
  101. }
  102. set(props, 'style.display', 'block');
  103. set(props, 'style.width', arrayAdd(cellWidths, 0, propColumns.length));
  104. } else {
  105. // Remove the row where the scroll bar is located
  106. props.colSpan = filterColumns(propColumns).length;
  107. }
  108. const columns = [
  109. {
  110. render: () => ({
  111. props,
  112. children: (
  113. <div
  114. className={classnames(`${prefixCls}-expand-inner`)}
  115. style={{
  116. width: anyColumnFixed ? amendTableWidth(tableWidth) : undefined,
  117. }}
  118. >
  119. {children}
  120. </div>
  121. ),
  122. }),
  123. ...column,
  124. },
  125. ];
  126. const rowCls = classnames(className, `${prefixCls}-row-expand`);
  127. const baseRowCellWidths = getCellWidths(columns);
  128. return (
  129. <TableRow
  130. style={style}
  131. components={components}
  132. className={rowCls}
  133. expandedRow={true}
  134. renderExpandIcon={renderExpandIcon}
  135. rowKey={`${record.key}-expanded-row`}
  136. columns={columns}
  137. store={store}
  138. virtualized={virtualized}
  139. indentSize={indentSize}
  140. cellWidths={baseRowCellWidths}
  141. />
  142. );
  143. }
  144. }
  145. export type ExpandedRowRenderReturnType = React.ReactNode | { children: ReactNode; fixed: Fixed } & ColumnProps;