feat: add virtualized data table resizer

This commit is contained in:
moonrailgun 2024-08-08 00:51:22 +08:00
parent ad18666851
commit f1aaa7040e
3 changed files with 64 additions and 2 deletions

View File

@ -69,6 +69,7 @@ export function VirtualizedInfiniteDataTable<TData>(
const table = useReactTable({
data: flatData,
columns,
columnResizeMode: 'onChange',
getCoreRowModel: getCoreRowModel(),
});
@ -87,13 +88,32 @@ export function VirtualizedInfiniteDataTable<TData>(
overscan: 5,
});
/**
* Instead of calling `column.getSize()` on every render for every header
* and especially every data cell (very expensive),
* we will calculate all column sizes at once at the root table level in a useMemo
* and pass the column sizes down as CSS variables to the <table> element.
*/
const columnSizeVars = React.useMemo(() => {
const headers = table.getFlatHeaders();
const colSizes: { [key: string]: number } = {};
for (let i = 0; i < headers.length; i++) {
const header = headers[i]!;
colSizes[`--header-${header.id}-size`] = header.getSize();
colSizes[`--col-${header.column.id}-size`] = header.column.getSize();
}
return colSizes;
}, [table.getState().columnSizingInfo, table.getState().columnSizing]);
console.log('columnSizeVars', columnSizeVars);
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div
className="relative h-full overflow-auto"
className="virtualized-infinite-data-table relative h-full overflow-auto"
onScroll={(e) => fetchMoreOnBottomReached(e.target as HTMLDivElement)}
ref={tableContainerRef}
>
@ -101,6 +121,7 @@ export function VirtualizedInfiniteDataTable<TData>(
<table style={{ display: 'grid' }}>
<TableHeader
style={{
...columnSizeVars,
display: 'grid',
position: 'sticky',
top: 0,
@ -116,8 +137,9 @@ export function VirtualizedInfiniteDataTable<TData>(
return (
<TableHead
key={header.id}
className="relative pt-2.5"
style={{
width: header.getSize(),
width: `calc(var(--header-${header?.id}-size) * 1px)`,
}}
>
{header.isPlaceholder
@ -126,6 +148,17 @@ export function VirtualizedInfiniteDataTable<TData>(
header.column.columnDef.header,
header.getContext()
)}
<div
{...{
onDoubleClick: () => header.column.resetSize(),
onMouseDown: header.getResizeHandler(),
onTouchStart: header.getResizeHandler(),
className: `resizer ${
header.column.getIsResizing() ? 'isResizing' : ''
}`,
}}
/>
</TableHead>
);
})}

View File

@ -1,4 +1,5 @@
import './index.css';
import './styles/global.less';
import React from 'react';
import ReactDOM from 'react-dom/client';

View File

@ -0,0 +1,28 @@
.virtualized-infinite-data-table {
.resizer {
position: absolute;
top: 0;
height: 100%;
right: 0;
width: 2px;
cursor: col-resize;
user-select: none;
touch-action: none;
@apply dark:bg-muted bg-neutral-300 transition-all;
}
.resizer.isResizing {
@apply opacity-100 dark:bg-muted bg-neutral-300;
}
@media (hover: hover) {
.resizer {
opacity: 0;
}
*:hover > .resizer {
opacity: 1;
}
}
}