import React, { forwardRef, useContext, useCallback, CSSProperties, } from "react"; import classNames from "classnames"; import { Text } from "../text"; import { TableBox } from "./TableBox"; import { TableProps } from "./TableProps"; import { useMiddleware } from "./util/use-middleware"; import { isCallable } from "../_util/is-callable"; import { useConfig } from "../_util/config-context"; import { TableVirtualizedBodyProps } from "./TableVirtualizedBody"; import { getFixedOffset, getFixedEndColumn, CellResizeObserver, } from "./TableBody"; import { TableContext } from "./TableContext"; import { TableGroupableHeadItem } from "./addons/groupable"; import { DragContext } from "./addons/draggable/DraggableTable"; import { ResizeContext } from "./addons/resizable/ResizableTable"; export const TableHead = forwardRef(function TableHead( props: TableProps & { tableBoxStyle?: React.CSSProperties; // `scrollable` 开启虚拟滚动式注入该 props virtualizedOptions?: TableVirtualizedBodyProps; // `columnsDraggable` 开启时注入该 props columnsDraggable?: boolean; // `resizable` 开启时注入该 props columnsResizable?: boolean; // 固定列计算宽度 onResize?: React.Dispatch>; headerRows?: TableGroupableHeadItem[][]; }, ref: React.Ref ) { const { classPrefix } = useConfig(); const { scrollStatus, columnsWidths } = useContext(TableContext); const { dragEventHandlers, draggableColumns } = useContext(DragContext); const { isResizing } = useContext(ResizeContext); const { columns, records, addons, tableBoxStyle, disableTextOverflow, hideHeader, virtualizedOptions, headerRows, columnsDraggable, columnsResizable, onResize, } = props; const hasFixedColumn = columns.find(column => !!column.fixed); const renderColumn = useMiddleware( addons, "onInjectColumn" )((record, rowKey, recordIndex, column, columnIndex) => { const { key, header } = column; let children: React.ReactNode = header; // pass a render function if (isCallable(header)) { children = header(column); } // forgot to pass, use a key as a reminder if (header === undefined) { children = key; } // plain values if (typeof children === "string" || typeof children === "number") { children = ( {children} ); } return { props: {}, children, }; }); const tableHeaders = columns.map((column, index) => { const { props, children } = renderColumn(null, null, -1, column, index); const cKey = column.key; if (props.colSpan === 0) { return null; } if (virtualizedOptions) { props.style = { ...(props.style || {}), display: "inline-block", overflow: "hidden", boxSizing: "border-box", flex: column.width ? undefined : 1, flexBasis: column.width || 1, }; } // 固定列 if ( (column.fixed === "left" || column.fixed === "right") && column.fixed !== scrollStatus && scrollStatus !== "no-scroll" ) { const end = getFixedEndColumn(columns); props.className = classNames( props.className, `${classPrefix}-table__td--fixed`, { [`${classPrefix}-table__td--fixed-${column.fixed}`]: end[column.fixed] === index, } ); props.style = { ...(props.style || {}), position: "sticky", [column.fixed]: getFixedOffset( columns, index, columnsWidths, column.fixed ), }; } // 列拖拽排序 if (!column.fixed && columnsDraggable && !("ignore" in column)) { const { onDragEnter, onDragOver, onDrop, onDragStart, onDrag, onDragLeave, onDragEnd, onMouseEnter, onMouseLeave, } = dragEventHandlers; props["data-column"] = column.key; props.onDragEnter = onDragEnter; props.onDragOver = onDragOver; props.onDrop = onDrop; if (draggableColumns === "all" || draggableColumns.includes(cKey)) { props.draggable = true; props.onDragStart = onDragStart; props.onDrag = onDrag; props.onDragLeave = onDragLeave; props.onDragEnd = onDragEnd; props.onMouseEnter = onMouseEnter; props.onMouseLeave = onMouseLeave; props.className = classNames(props.className, "is-draggable"); } } const childrenStyle: CSSProperties = columnsResizable && isResizing ? { pointerEvents: "none" } : {}; const cell = (
{children}
); // 无数据时通过头确定列宽 if ((records || []).length === 0 && hasFixedColumn) { return ( { onResize(widths => { const columnsWidths = [...widths]; columnsWidths[index] = width; return columnsWidths; }); }} > {cell} ); } return cell; }); const renderGroupingHeader = useCallback( heads => { return headerRows.map(row => ( i.key).join("-")}> {row.map(({ key, isLeaf, title, align = "left", colSpan }) => { if (isLeaf) { const index = columns.findIndex(i => i.key === key); return heads[index]; } return (
{title}
); })} )); }, [columns, headerRows] ); return useMiddleware( addons, "onInjectHead" )(props => (
{headerRows ? ( renderGroupingHeader(tableHeaders) ) : ( {tableHeaders} )}
))(props); }); TableHead.displayName = "TableHead";