import { ComponentType, Ref, useCallback, useState, forwardRef } from 'react'; import { Row } from 'react-table'; import AutoSizer from 'react-virtualized-auto-sizer'; import { FixedSizeList, FixedSizeList as List, ListChildComponentProps, ListItemKeySelector, } from 'react-window'; import { convertRemToPixels, TableHeightKeyType, TableLocalType, tableRowHeight, } from './TableUtils'; import { useTableContext } from './Tablev2.component'; import useSyncedScroll from './useSyncedScroll'; import { CSSProperties } from 'styled-components'; import { UnsuccessfulResult } from '../UnsuccessfulResult.component'; const SmoothScrollDiv = forwardRef((props, ref) => (
)); type VirtualizedRowsType< DATA_ROW extends Record = Record, > = { rows: Row[]; RenderRow: ComponentType< React.PropsWithChildren[]>> >; rowHeight: TableHeightKeyType; setHasScrollbar: React.Dispatch>; hasScrollbar?: boolean; itemKey?: ListItemKeySelector[]>; onBottom?: (rowLength: number) => void; onBottomOffset?: number; listRef?: Ref[]>>; }; export const VirtualizedRows = < DATA_ROW extends Record = Record, >({ rows, rowHeight, setHasScrollbar, onBottom, onBottomOffset, RenderRow, listRef, itemKey, }: VirtualizedRowsType) => ( {({ height }) => { return ( { setHasScrollbar( visibleStopIndex - visibleStartIndex < overscanStopIndex, ); if ( onBottom && onBottomOffset != null && overscanStopIndex >= rows.length - 1 - onBottomOffset ) { onBottom(rows.length); } }} > {RenderRow} ); }} ); export const useTableScrollbar = () => { const { hasScrollbar, setHasScrollbar } = useTableContext(); const [scrollBarWidth, setScrollBarWidth] = useState(0); const handleScrollbarWidth = useCallback((node) => { if (node) { const scrollDiv = document.createElement('div'); scrollDiv.setAttribute( 'style', 'width: 100px; height: 100px; overflow: scroll; position:absolute; top:-9999px;', ); node.appendChild(scrollDiv); const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; node.removeChild(scrollDiv); setScrollBarWidth(scrollbarWidth); } }, []); return { hasScrollbar, setHasScrollbar, scrollBarWidth, handleScrollbarWidth, }; }; export type RenderRowType = { index: number; style: CSSProperties; }; type TableRowsProps< DATA_ROW extends Record = Record, > = { locale?: TableLocalType; children?: (children: JSX.Element) => JSX.Element; customItemKey?: (index: number, data: DATA_ROW) => string; RenderRow: React.MemoExoticComponent< ({ index, style }: RenderRowType) => JSX.Element >; listRef?: Ref[]>>; }; export function TableRows< DATA_ROW extends Record = Record, >({ locale, children, customItemKey, RenderRow, listRef: externalListRef, }: TableRowsProps) { const { setHasScrollbar } = useTableScrollbar(); const { rows, status, entityName, rowHeight, onBottom, onBottomOffset } = useTableContext(); const { bodyRef } = useSyncedScroll(); const listRef: Ref[]>> = externalListRef || bodyRef; function itemKey(index, data) { if (typeof customItemKey === 'function') { return customItemKey(index, data); } return index; } if (status === 'idle' || status === 'loading' || status === 'error') { return ( ); } if (status === 'success' || status === undefined) { if (typeof children === 'function') { if (rows.length) { return children( rows={rows} listRef={listRef} itemKey={itemKey} rowHeight={rowHeight} setHasScrollbar={setHasScrollbar} onBottom={onBottom} onBottomOffset={onBottomOffset} RenderRow={RenderRow} />, ); } else { return children( , ); } } else if (rows.length) { return ( rows={rows} listRef={listRef} setHasScrollbar={setHasScrollbar} onBottom={onBottom} onBottomOffset={onBottomOffset} itemKey={itemKey} rowHeight={rowHeight} RenderRow={RenderRow} /> ); } else { return ( ); } } return null; }