/** * @file 单元格 */ import cns from 'classnames' import React, { useContext, useState, CSSProperties } from 'react' import { concat } from '../utils' import { InternalColumnOptions, InternalRecord } from './defs' import { dataTableCtx } from './context' import { Sorter } from './sort' import { Filter } from './filter' import { useColumnWidth, useColumnWidthReporter } from './column-width' import { useHorizontalScroll } from './horizontal-scroll' export function BodyCell({ column, record, recordIdx }: { column: InternalColumnOptions record: InternalRecord recordIdx: number }) { const { baseCls } = useContext(dataTableCtx) const { style, className } = useCellFixColumn(column, concat(baseCls, 'body', 'td')) const value = column.accessor != null ? (record.data as any)[column.accessor] : undefined return ( {column.render(value, record.data, recordIdx)} ) } export function MeasureCell({ column }: { column: InternalColumnOptions }) { const { baseCls } = useContext(dataTableCtx) const className = cns( concat(baseCls, 'body', 'td'), concat(baseCls, 'measure-cell') ) const [wrapper, setWrapper] = useState(null) useColumnWidthReporter(column.internalId, wrapper) return } export function HeadCell({ column }: { column: InternalColumnOptions }) { const { baseCls } = useContext(dataTableCtx) const thCls = concat(baseCls, 'head', 'th') const [wrapper, setWrapper] = useState(null) const { style, className } = useCellFixColumn(column, thCls) return ( {column.title} {column.sort && } {column.filter && } ) } function useCellFixColumn(column: InternalColumnOptions, className: string) { const { columns } = useContext(dataTableCtx) const { widths } = useColumnWidth() const { scrollLeft, scrollRight } = useHorizontalScroll() let style: CSSProperties | undefined let hasRightShadow = false let hasLeftShadow = false if (column.fixed != null) { style = { background: 'inherit', zIndex: 1, position: 'sticky' } let columnIdx = -1 let lastFixLeftIdx = -1 let firstFixRightIdx = -1 for (let i = 0; i < columns.length; i++) { const c = columns[i] if (c.fixed === 'left') lastFixLeftIdx = i if (c === column) columnIdx = i if (firstFixRightIdx === -1 && c.fixed === 'right') firstFixRightIdx = i } if (column.fixed === 'left') { const prevColumns = columns.slice(0, columnIdx) const prevColumnsWidth = sum(prevColumns.map(c => widths[c.internalId])) style.left = prevColumnsWidth + 'px' hasRightShadow = columnIdx === lastFixLeftIdx && scrollLeft > 0 } if (column.fixed === 'right') { const nextColumns = columns.slice(columnIdx + 1) const nextColumnsWidth = sum(nextColumns.map(c => widths[c.internalId])) style.right = nextColumnsWidth + 'px' hasLeftShadow = columnIdx === firstFixRightIdx && scrollRight > 0 } } const { baseCls } = useContext(dataTableCtx) className = cns( className, hasRightShadow && concat(baseCls, 'cell-right-shadow'), hasLeftShadow && concat(baseCls, 'cell-left-shadow') ) return { style, className } } function sum(nums: Array) { return nums.reduce((s, n) => s + (n ?? 0), 0) }