import type { CellProps, HoverRange } from '../../interfaces' import { isLeafNode, makeRecursiveMapper, mergeCellProps } from '../../utils' import { TablePipeline } from '../pipeline' const EMPTY_RANGE: HoverRange = { start: -1, end: -1, } as const export interface ColumnRangeHoverFeatureOptions { /** 鼠标悬停时单元格的背景色,默认为 'var(--hover-bgcolor)' */ hoverColor?: string /** 鼠标悬停时表头的背景色,默认为 'var(--header-hover-bgcolor)' */ headerHoverColor?: string /** 非受控用法:默认的悬停范围 */ defaultHoverRange?: HoverRange /** 受控用法:当前悬停范围 */ hoverRange?: HoverRange /** 受控用法:悬停渲染改变的回调 */ onChangeHoverRange?(nextColIndexRange: HoverRange): void } export function columnRangeHover(opts: ColumnRangeHoverFeatureOptions = {}) { const stateKey = 'columnHover' return function columnRangeHoverStep(pipeline: TablePipeline) { const hoverRange = opts.hoverRange ?? pipeline.getStateAtKey(stateKey) ?? opts.defaultHoverRange ?? EMPTY_RANGE const hoverColor = opts.hoverColor ?? 'var(--hover-bgcolor)' const headerHoverColor = opts.headerHoverColor ?? 'var(--header-hover-bgcolor)' const onChangeHoverRange = (nextColIndexRange: HoverRange) => { pipeline.setStateAtKey(stateKey, nextColIndexRange) opts.onChangeHoverRange?.(nextColIndexRange) } return pipeline.mapColumns( makeRecursiveMapper((col, { startIndex, endIndex }) => { const colRange = { start: startIndex, end: endIndex } const match = colRange.end > hoverRange.start && hoverRange.end > colRange.start if (!isLeafNode(col)) { if (headerHoverColor == null) { return col } return { ...col, headerCellProps: mergeCellProps(col.headerCellProps, { onMouseEnter() { onChangeHoverRange(colRange) }, onMouseLeave() { onChangeHoverRange(EMPTY_RANGE) }, style: { '--header-bgcolor': match ? headerHoverColor : undefined } as any, }), } } const prevGetCellProps = col.getCellProps return { ...col, headerCellProps: mergeCellProps(col.headerCellProps, { onMouseEnter() { onChangeHoverRange(colRange) }, onMouseLeave() { onChangeHoverRange(EMPTY_RANGE) }, style: { '--header-bgcolor': match ? headerHoverColor : undefined } as any, }), getCellProps(value: any, record: any, rowIndex: number): CellProps { const prevCellProps = prevGetCellProps?.(value, record, rowIndex) return mergeCellProps(prevCellProps, { onMouseEnter() { onChangeHoverRange(colRange) }, onMouseLeave() { onChangeHoverRange(EMPTY_RANGE) }, style: { '--bgcolor': match ? hoverColor : undefined } as any, }) }, } }), ) } }