"use client" import { Virtualizer } from "@tanstack/react-virtual" import React, { memo, useCallback, useState } from "react" import { useCallbackRef, useIntersected, useSynchronizedScroll, useVirtualPagination, } from "../../hooks" import { classNames } from "../../utils/classNames" import { CenterAligned } from "../CenterAligned" import { FlexColumn } from "../FlexColumn" import { RetryButton } from "../RetryButton" import { TABLE_SIZES, TableRowRenderProps, useTable } from "../Table" import { TableHeaderWrapper } from "../Table/TableHeader" import { DEFAULT_PAGINATION_THRESHOLD } from "./constants" import { VirtualizedTableProps } from "./VirtualizedTable" type Props = { rowVirtualizer: | Virtualizer | Virtualizer setTableRef: (ref: HTMLDivElement) => void tableRef: React.RefObject id?: string gap: number } & VirtualizedTableProps type VirtualizedTableRowProps = { index: number Row: Props["renderRow"] context: Props["context"] translateY: number item: Props["items"][number] } const VirtualizedTableRow = memo(function VirtualizedTableRow({ index, item, Row, context, translateY, }: VirtualizedTableRowProps) { return (
) }) export const VirtualizedTableView = ({ className, contentClassName, items, hasNext, loadNext, paginationThreshold = DEFAULT_PAGINATION_THRESHOLD, header, renderRow: Row, rowVirtualizer, setTableRef, tableRef, id, context, scrollMode, headerBorderOnScroll: headerBorderOnScrollProp = true, style, contentStyle, paginationError, gap, itemKey, }: Props) => { const [headerRef, setHeaderRef] = useCallbackRef() const { size, dividers } = useTable() const headerRefChild = headerRef.current ?.firstElementChild as HTMLDivElement | null useSynchronizedScroll(headerRefChild, tableRef.current) const virtualItems = rowVirtualizer.getVirtualItems() const [hasLocalError, setHasLocalError] = useState(false) const hasError = paginationError || hasLocalError const onError = useCallback(() => { setHasLocalError(true) }, []) useVirtualPagination({ items: virtualItems, count: items.length, loadNext, hasNext: hasNext && !hasError, paginationThreshold, onError, }) const isScrolledDown = useIntersected( tableRef, { current: headerRefChild }, (scrollMode === "table" && tableRef) || undefined, ) const showBorder = (isScrolledDown && headerBorderOnScrollProp) || dividers return ( {header && ( // Display contents to allow header to become sticky with parent. {header} )}
{virtualItems.map(({ index, start }) => { return ( > } context={context} index={index} item={items[index]} // virtual items default key is bugged key={itemKey?.(items[index], index) ?? index} translateY={start - (rowVirtualizer.options.scrollMargin ?? 0)} /> ) })}
{(paginationError || hasError) && ( { await loadNext?.() setHasLocalError(false) }} /> )}
) }