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.

149 lines 7.46 kB
import _noop from "lodash/noop"; import _find from "lodash/find"; import _get from "lodash/get"; import _merge from "lodash/merge"; 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; }; /* eslint-disable react-hooks/exhaustive-deps */ import React, { useState, useEffect, useMemo } from 'react'; import { addClass, removeClass } from '@douyinfe/semi-foundation/lib/es/utils/classnames'; import { strings, numbers } from '@douyinfe/semi-foundation/lib/es/table/constants'; import { assignColumnKeys, findColumn, withResizeWidth } from '@douyinfe/semi-foundation/lib/es/table/utils'; import Table from './Table'; import { cloneDeep, mergeColumns } from './utils'; import getColumns from './getColumns'; import ResizableHeaderCell from './ResizableHeaderCell'; const ResizableTable = function () { let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; let ref = arguments.length > 1 ? arguments[1] : undefined; const { components: propComponents, columns: propColumns, resizable } = props, restProps = __rest(props, ["components", "columns", "resizable"]); const childrenColumnName = 'children'; const onResize = _get(resizable, 'onResize', _noop); const onResizeStart = _get(resizable, 'onResizeStart', _noop); const onResizeStop = _get(resizable, 'onResizeStop', _noop); /** * 此处关于 columns 有三个存储 * * 1. rawColumns 是根据 props.columns 或者 props.children 解析出来的原始 columns * 2. newColumns 是 rawColumns 的深拷贝,同时根据 props.expandedRowRender、props.hideExpandedColumn 和 props.rowSelection * 这三个参数加入了【选择列】以及【展开列】 * 3. columns 是当前组件中存储的 state,一般情况下与 newColumns 相等,但是会保存列当前伸缩的宽度 */ /** * There are three stores for columns here * * 1. rawColumns are the original columns parsed according to props.columns or props.children * 2. newColumns is a deep copy of rawColumns, based on props.expandedRowRender, props.hideExpandedColumn and props.rowSelection * These three parameters have been added [Select Column] and [Expand Column] * 3. columns is the state stored in the current component, which is generally equal to newColumns, but it will save the current stretched width of the column */ const parsedColumns = Array.isArray(propColumns) && propColumns.length ? propColumns : getColumns(props.children); const rawColumns = assignColumnKeys(cloneDeep(parsedColumns), childrenColumnName); const newColumns = assignColumnKeys(cloneDeep(parsedColumns), childrenColumnName); if (typeof props.expandedRowRender === 'function' && !props.hideExpandedColumn && !_find(rawColumns, item => item.key === strings.DEFAULT_KEY_COLUMN_EXPAND)) { newColumns.unshift({ key: strings.DEFAULT_KEY_COLUMN_EXPAND, width: numbers.DEFAULT_WIDTH_COLUMN_EXPAND }); } if (props.rowSelection && !_get(props.rowSelection, 'hidden') && !_find(rawColumns, item => item.key === strings.DEFAULT_KEY_COLUMN_SELECTION)) { newColumns.unshift({ width: _get(props, 'rowSelection.width', numbers.DEFAULT_WIDTH_COLUMN_SELECTION), key: strings.DEFAULT_KEY_COLUMN_SELECTION }); } const [columns, setColumns] = useState(newColumns); useEffect(() => { // If there is a resize value, the width does not use the default value fix#1072 const _newColumns = withResizeWidth(columns, newColumns); setColumns(mergeColumns(columns, _newColumns)); }, [propColumns, props.expandedRowRender, props.hideExpandedColumn, props.rowSelection]); const components = useMemo(() => _merge({ header: { cell: ResizableHeaderCell } }, propComponents), [propComponents]); const handlerClassName = _get(resizable, 'handlerClassName', 'resizing'); const handleResize = column => (e, _ref) => { let { size } = _ref; const nextColumns = cloneDeep(columns); const curColumn = findColumn(nextColumns, column, childrenColumnName); let nextColumn = Object.assign(Object.assign({}, curColumn), { width: size.width }); const customProps = onResize(nextColumn) || {}; nextColumn = Object.assign(Object.assign({}, nextColumn), customProps); Object.assign(curColumn, nextColumn); setColumns(nextColumns); }; const handleResizeStart = column => e => { const nextColumns = cloneDeep(columns); const curColumn = findColumn(nextColumns, column, childrenColumnName); let nextColumn = Object.assign(Object.assign({}, curColumn), { className: addClass(curColumn.className, handlerClassName) }); const customProps = onResizeStart(nextColumn) || {}; nextColumn = Object.assign(Object.assign({}, nextColumn), customProps); Object.assign(curColumn, nextColumn); setColumns(nextColumns); }; const handleResizeStop = column => e => { const nextColumns = cloneDeep(columns); const curColumn = findColumn(nextColumns, column, childrenColumnName); let nextColumn = Object.assign(Object.assign({}, curColumn), { className: removeClass(curColumn.className, handlerClassName) }); const customProps = onResizeStop(nextColumn) || {}; nextColumn = Object.assign(Object.assign({}, nextColumn), customProps); Object.assign(curColumn, nextColumn); setColumns(nextColumns); }; const resizableRender = function (col, index) { let level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; let originalHeaderCellProps = arguments.length > 3 ? arguments[3] : undefined; return Object.assign(Object.assign({}, col), { onHeaderCell: column => { return Object.assign(Object.assign({}, originalHeaderCellProps), { width: column.width, onResize: handleResize(column), onResizeStart: handleResizeStart(column), onResizeStop: handleResizeStop(column) }); } }); }; const assignResizableRender = function () { let columns = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; let level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return Array.isArray(columns) && columns.length ? columns.map((col, index) => { var _a, _b; const originalHeaderCellProps = (_b = (_a = col.onHeaderCell) === null || _a === void 0 ? void 0 : _a.call(col, col, index, level)) !== null && _b !== void 0 ? _b : {}; Object.assign(col, resizableRender(col, index, level, originalHeaderCellProps)); const children = col[childrenColumnName]; if (Array.isArray(children) && children.length) { col[childrenColumnName] = assignResizableRender(children, level + 1); } return col; }) : []; }; const finalColumns = useMemo(() => assignResizableRender(columns), [columns]); return /*#__PURE__*/React.createElement(Table, Object.assign({}, restProps, { columns: finalColumns, components: components, ref: ref })); }; export default /*#__PURE__*/React.forwardRef(ResizableTable);