UNPKG

material-react-table

Version:

A fully featured Material UI V6 implementation of TanStack React Table V8, written from the ground up in TypeScript.

125 lines (108 loc) 3.77 kB
import { useCallback, useMemo } from 'react'; import { type Range, useVirtualizer } from '@tanstack/react-virtual'; import { type MRT_ColumnVirtualizer, type MRT_RowData, type MRT_TableInstance, } from '../types'; import { parseFromValuesOrFunc } from '../utils/utils'; import { extraIndexRangeExtractor } from '../utils/virtualization.utils'; export const useMRT_ColumnVirtualizer = < TData extends MRT_RowData, TScrollElement extends Element | Window = HTMLDivElement, TItemElement extends Element = HTMLTableCellElement, >( table: MRT_TableInstance<TData>, ): MRT_ColumnVirtualizer | undefined => { const { getState, options: { columnVirtualizerInstanceRef, columnVirtualizerOptions, enableColumnPinning, enableColumnVirtualization, }, refs: { tableContainerRef }, } = table; const { columnPinning, columnVisibility, draggingColumn } = getState(); if (!enableColumnVirtualization) return undefined; const columnVirtualizerProps = parseFromValuesOrFunc( columnVirtualizerOptions, { table, }, ); const visibleColumns = table.getVisibleLeafColumns(); const [leftPinnedIndexes, rightPinnedIndexes] = useMemo( () => enableColumnPinning ? [ table.getLeftVisibleLeafColumns().map((c) => c.getPinnedIndex()), table .getRightVisibleLeafColumns() .map( (column) => visibleColumns.length - column.getPinnedIndex() - 1, ) .sort((a, b) => a - b), ] : [[], []], [columnPinning, columnVisibility, enableColumnPinning], ); const numPinnedLeft = leftPinnedIndexes.length; const numPinnedRight = rightPinnedIndexes.length; const draggingColumnIndex = useMemo( () => draggingColumn?.id ? visibleColumns.findIndex((c) => c.id === draggingColumn?.id) : undefined, [draggingColumn?.id], ); const columnVirtualizer = useVirtualizer({ count: visibleColumns.length, estimateSize: (index) => visibleColumns[index].getSize(), getScrollElement: () => tableContainerRef.current, horizontal: true, overscan: 3, rangeExtractor: useCallback( (range: Range) => { const newIndexes = extraIndexRangeExtractor(range, draggingColumnIndex); if (!numPinnedLeft && !numPinnedRight) { return newIndexes; } return [ ...new Set([ ...leftPinnedIndexes, ...newIndexes, ...rightPinnedIndexes, ]), ]; }, [leftPinnedIndexes, rightPinnedIndexes, draggingColumnIndex], ), ...columnVirtualizerProps, }) as unknown as MRT_ColumnVirtualizer<TScrollElement, TItemElement>; const virtualColumns = columnVirtualizer.getVirtualItems(); columnVirtualizer.virtualColumns = virtualColumns as any; const numColumns = virtualColumns.length; if (numColumns) { const totalSize = columnVirtualizer.getTotalSize(); const leftNonPinnedStart = virtualColumns[numPinnedLeft]?.start || 0; const leftNonPinnedEnd = virtualColumns[leftPinnedIndexes.length - 1]?.end || 0; const rightNonPinnedStart = virtualColumns[numColumns - numPinnedRight]?.start || 0; const rightNonPinnedEnd = virtualColumns[numColumns - numPinnedRight - 1]?.end || 0; columnVirtualizer.virtualPaddingLeft = leftNonPinnedStart - leftNonPinnedEnd; columnVirtualizer.virtualPaddingRight = totalSize - rightNonPinnedEnd - (numPinnedRight ? totalSize - rightNonPinnedStart : 0); } if (columnVirtualizerInstanceRef) { //@ts-expect-error columnVirtualizerInstanceRef.current = columnVirtualizer; } return columnVirtualizer as any; };