mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-20 21:55:03 -04:00
Convert Table to TypeScript
(cherry picked from commit 699120a8fd54be9e70fb9a83298f94c8cb6a80bb)
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
import React, { ReactNode, useEffect, useRef } from 'react';
|
||||
import { Grid, GridCellProps, WindowScroller } from 'react-virtualized';
|
||||
import ModelBase from 'App/ModelBase';
|
||||
import Scroller from 'Components/Scroller/Scroller';
|
||||
import useMeasure from 'Helpers/Hooks/useMeasure';
|
||||
import usePrevious from 'Helpers/Hooks/usePrevious';
|
||||
import { scrollDirections } from 'Helpers/Props';
|
||||
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
|
||||
import styles from './VirtualTable.css';
|
||||
|
||||
const ROW_HEIGHT = 38;
|
||||
|
||||
function overscanIndicesGetter(options: {
|
||||
cellCount: number;
|
||||
overscanCellsCount: number;
|
||||
startIndex: number;
|
||||
stopIndex: number;
|
||||
}) {
|
||||
const { cellCount, overscanCellsCount, startIndex, stopIndex } = options;
|
||||
|
||||
// The default getter takes the scroll direction into account,
|
||||
// but that can cause issues. Ignore the scroll direction and
|
||||
// always over return more items.
|
||||
|
||||
const overscanStartIndex = startIndex - overscanCellsCount;
|
||||
const overscanStopIndex = stopIndex + overscanCellsCount;
|
||||
|
||||
return {
|
||||
overscanStartIndex: Math.max(0, overscanStartIndex),
|
||||
overscanStopIndex: Math.min(cellCount - 1, overscanStopIndex),
|
||||
};
|
||||
}
|
||||
|
||||
interface VirtualTableProps<T extends ModelBase> {
|
||||
isSmallScreen: boolean;
|
||||
className?: string;
|
||||
items: T[];
|
||||
scrollIndex?: number;
|
||||
scrollTop?: number;
|
||||
scroller: Element;
|
||||
header: React.ReactNode;
|
||||
headerHeight?: number;
|
||||
rowRenderer: (rowProps: GridCellProps) => ReactNode;
|
||||
rowHeight?: number;
|
||||
}
|
||||
|
||||
function VirtualTable<T extends ModelBase>({
|
||||
isSmallScreen,
|
||||
className = styles.tableContainer,
|
||||
items,
|
||||
scroller,
|
||||
scrollIndex,
|
||||
scrollTop,
|
||||
header,
|
||||
headerHeight = 38,
|
||||
rowHeight = ROW_HEIGHT,
|
||||
rowRenderer,
|
||||
...otherProps
|
||||
}: VirtualTableProps<T>) {
|
||||
const [measureRef, bounds] = useMeasure();
|
||||
const gridRef = useRef<Grid>(null);
|
||||
const scrollRestored = useRef(false);
|
||||
const previousScrollIndex = usePrevious(scrollIndex);
|
||||
const previousItems = usePrevious(items);
|
||||
|
||||
const width = bounds.width;
|
||||
|
||||
const gridStyle = {
|
||||
boxSizing: undefined,
|
||||
direction: undefined,
|
||||
height: undefined,
|
||||
position: undefined,
|
||||
willChange: undefined,
|
||||
overflow: undefined,
|
||||
width: undefined,
|
||||
};
|
||||
|
||||
const containerStyle = {
|
||||
position: undefined,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (gridRef.current && width > 0) {
|
||||
gridRef.current.recomputeGridSize();
|
||||
}
|
||||
}, [width]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
gridRef.current &&
|
||||
previousItems &&
|
||||
hasDifferentItemsOrOrder(previousItems, items)
|
||||
) {
|
||||
gridRef.current.recomputeGridSize();
|
||||
}
|
||||
}, [items, previousItems]);
|
||||
|
||||
useEffect(() => {
|
||||
if (gridRef.current && scrollTop && !scrollRestored.current) {
|
||||
gridRef.current.scrollToPosition({ scrollLeft: 0, scrollTop });
|
||||
scrollRestored.current = true;
|
||||
}
|
||||
}, [scrollTop]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
gridRef.current &&
|
||||
scrollIndex != null &&
|
||||
scrollIndex !== previousScrollIndex
|
||||
) {
|
||||
gridRef.current.scrollToCell({
|
||||
rowIndex: scrollIndex,
|
||||
columnIndex: 0,
|
||||
});
|
||||
}
|
||||
}, [scrollIndex, previousScrollIndex]);
|
||||
|
||||
return (
|
||||
<WindowScroller scrollElement={isSmallScreen ? undefined : scroller}>
|
||||
{({ height, registerChild, onChildScroll, scrollTop }) => {
|
||||
if (!height) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div ref={measureRef}>
|
||||
<Scroller
|
||||
className={className}
|
||||
scrollDirection={scrollDirections.HORIZONTAL}
|
||||
>
|
||||
{header}
|
||||
|
||||
{/* @ts-expect-error - ref type is incompatible */}
|
||||
<div ref={registerChild}>
|
||||
<Grid
|
||||
{...otherProps}
|
||||
ref={gridRef}
|
||||
autoContainerWidth={true}
|
||||
autoHeight={true}
|
||||
autoWidth={true}
|
||||
width={width}
|
||||
height={height}
|
||||
headerHeight={height - headerHeight}
|
||||
rowHeight={rowHeight}
|
||||
rowCount={items.length}
|
||||
columnCount={1}
|
||||
columnWidth={width}
|
||||
scrollTop={scrollTop}
|
||||
overscanRowCount={2}
|
||||
cellRenderer={rowRenderer}
|
||||
overscanIndicesGetter={overscanIndicesGetter}
|
||||
scrollToAlignment="start"
|
||||
isScrollingOptout={true}
|
||||
className={styles.tableBodyContainer}
|
||||
style={gridStyle}
|
||||
containerStyle={containerStyle}
|
||||
onScroll={onChildScroll}
|
||||
/>
|
||||
</div>
|
||||
</Scroller>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</WindowScroller>
|
||||
);
|
||||
}
|
||||
|
||||
export default VirtualTable;
|
||||
Reference in New Issue
Block a user