1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-06-04 01:18:20 +02:00
unleash.unleash/frontend/src/component/common/Table/VirtualizedTable/VirtualizedTable.tsx
2023-06-15 14:11:04 +02:00

120 lines
4.0 KiB
TypeScript

import { RefObject, useMemo } from 'react';
import { useTheme, TableBody, TableRow } from '@mui/material';
import { SortableTableHeader } from 'component/common/Table/SortableTableHeader/SortableTableHeader';
import { TableCell } from 'component/common/Table/TableCell/TableCell';
import { Table } from 'component/common/Table/Table/Table';
import { useVirtualizedRange } from 'hooks/useVirtualizedRange';
import { HeaderGroup, Row } from 'react-table';
/**
* READ BEFORE USE
*
* Virtualized tables require some setup.
* With this component all but one columns are fixed width, and one fills remaining space.
* Add `maxWidth` to columns that will be static in width, and `minWidth` to the one that should grow.
*
* Remember to add `useFlexLayout` to `useTable`
* (more at: https://react-table-v7.tanstack.com/docs/api/useFlexLayout)
*/
export const VirtualizedTable = <T extends object>({
rowHeight: rowHeightOverride,
headerGroups,
rows,
prepareRow,
parentRef,
}: {
rowHeight?: number;
headerGroups: HeaderGroup<T>[];
rows: Row<T>[];
prepareRow: (row: Row<T>) => void;
parentRef?: RefObject<HTMLElement | null>;
}) => {
const theme = useTheme();
const rowHeight = useMemo(
() => rowHeightOverride || theme.shape.tableRowHeight,
[rowHeightOverride, theme.shape.tableRowHeight]
);
const [firstRenderedIndex, lastRenderedIndex] = useVirtualizedRange(
rowHeight,
40,
5,
parentRef?.current
);
const tableHeight = useMemo(
() => rowHeight * rows.length + theme.shape.tableRowHeightCompact,
[rowHeight, rows.length, theme.shape.tableRowHeightCompact]
);
return (
<Table
role="table"
rowHeight={rowHeight}
style={{ height: tableHeight }}
>
<SortableTableHeader headerGroups={headerGroups} flex />
<TableBody
role="rowgroup"
sx={{
'& tr': {
position: 'absolute',
width: '100%',
'&:hover': {
'.show-row-hover': {
opacity: 1,
},
},
},
'& tr td': {
alignItems: 'center',
display: 'flex',
flexShrink: 0,
'& > *': {
flexGrow: 1,
},
},
}}
>
{rows.map((row, index) => {
const top =
index * rowHeight + theme.shape.tableRowHeightCompact;
const isVirtual =
index < firstRenderedIndex || index > lastRenderedIndex;
if (isVirtual) {
return null;
}
prepareRow(row);
return (
<TableRow
hover
{...row.getRowProps({
style: { display: 'flex', top },
})}
key={row.id}
>
{row.cells.map(cell => (
<TableCell
{...cell.getCellProps({
style: {
flex: cell.column.minWidth
? '1 0 auto'
: undefined,
},
})}
>
{cell.render('Cell')}
</TableCell>
))}
</TableRow>
);
})}
</TableBody>
</Table>
);
};