ExpandedRow.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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, { TableContextProps } 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. context: TableContextProps;
  67. render() {
  68. const {
  69. record,
  70. columns: propColumns = [],
  71. prefixCls,
  72. className,
  73. expanded,
  74. expandedRowRender,
  75. renderExpandIcon,
  76. index,
  77. store,
  78. components,
  79. style,
  80. virtualized,
  81. indentSize,
  82. cellWidths,
  83. } = this.props;
  84. const { tableWidth, anyColumnFixed, getCellWidths } = this.context;
  85. const cell: ExpandedRowRenderReturnType = expandedRowRender(record, index, expanded);
  86. let children: ReactNode = null;
  87. const props: { colSpan?: number; style?: Record<string, any> } = {};
  88. let column = {};
  89. if (isNull(cell)) {
  90. return null;
  91. } else if (isValidElement(cell)) {
  92. children = cell;
  93. } else if (cell && Object.prototype.toString.call(cell) === '[object Object]') {
  94. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  95. const { children: cellChildren, fixed, ...restProps } = cell as { children: ReactNode; fixed: Fixed };
  96. children = cellChildren;
  97. column = { ...restProps };
  98. }
  99. if (get(components, 'body.cell') !== strings.DEFAULT_COMPONENTS.body.cell) {
  100. if (virtualized) {
  101. set(props, 'style.height', '100%');
  102. }
  103. set(props, 'style.display', 'block');
  104. set(props, 'style.width', arrayAdd(cellWidths, 0, propColumns.length));
  105. } else {
  106. // Remove the row where the scroll bar is located
  107. props.colSpan = filterColumns(propColumns).length;
  108. }
  109. const columns = [
  110. {
  111. render: () => ({
  112. props,
  113. children: (
  114. <div
  115. className={classnames(`${prefixCls}-expand-inner`)}
  116. style={{
  117. width: anyColumnFixed ? amendTableWidth(tableWidth) : undefined,
  118. }}
  119. >
  120. {children}
  121. </div>
  122. ),
  123. }),
  124. ...column,
  125. },
  126. ];
  127. const rowCls = classnames(className, `${prefixCls}-row-expand`);
  128. const baseRowCellWidths = getCellWidths(columns);
  129. return (
  130. <TableRow
  131. style={style}
  132. components={components}
  133. className={rowCls}
  134. expandedRow={true}
  135. renderExpandIcon={renderExpandIcon}
  136. rowKey={`${record.key}-expanded-row`}
  137. columns={columns}
  138. store={store}
  139. virtualized={virtualized}
  140. indentSize={indentSize}
  141. cellWidths={baseRowCellWidths}
  142. />
  143. );
  144. }
  145. }
  146. export type ExpandedRowRenderReturnType = React.ReactNode | { children: ReactNode; fixed: Fixed } & ColumnProps;