Skip to content

Commit

Permalink
initial row pinning feature
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinVandy committed Oct 1, 2023
1 parent aa86d88 commit ba6242a
Show file tree
Hide file tree
Showing 19 changed files with 734 additions and 95 deletions.
6 changes: 3 additions & 3 deletions packages/material-react-table/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "2.0.0-alpha.0",
"version": "2.0.0-alpha.1",
"license": "MIT",
"name": "material-react-table",
"description": "A fully featured Material UI V5 implementation of TanStack React Table V8, written from the ground up in TypeScript.",
Expand Down Expand Up @@ -34,11 +34,11 @@
"size-limit": [
{
"path": "dist/cjs/index.js",
"limit": "54 KB"
"limit": "59 KB"
},
{
"path": "dist/esm/material-react-table.esm.js",
"limit": "50 KB"
"limit": "55 KB"
}
],
"engines": {
Expand Down
236 changes: 173 additions & 63 deletions packages/material-react-table/src/body/MRT_TableBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,20 @@ export const MRT_TableBody = <TData extends Record<string, any>>({
virtualPaddingRight,
}: Props<TData>) => {
const {
getRowModel,
getBottomRows,
getCenterRows,
getPrePaginationRowModel,
getRowModel,
getState,
getIsSomeRowsPinned,
getTopRows,
options: {
enableGlobalFilterRankedResults,
enablePagination,
enableRowPinning,
enableRowVirtualization,
enableStickyHeader,
enableStickyFooter,
layoutMode,
localization,
manualExpanding,
Expand All @@ -44,10 +51,11 @@ export const MRT_TableBody = <TData extends Record<string, any>>({
memoMode,
muiTableBodyProps,
renderEmptyRowsFallback,
rowPinningDisplayMode,
rowVirtualizerInstanceRef,
rowVirtualizerOptions,
},
refs: { tableContainerRef, tablePaperRef },
refs: { tableContainerRef, tablePaperRef, tableFooterRef, tableHeadRef },
} = table;
const {
columnFilters,
Expand All @@ -57,13 +65,22 @@ export const MRT_TableBody = <TData extends Record<string, any>>({
globalFilterFn,
pagination,
sorting,
rowPinning,
isFullScreen,
} = getState();

const tableBodyProps = parseFromValuesOrFunc(muiTableBodyProps, { table });
const rowVirtualizerProps = parseFromValuesOrFunc(rowVirtualizerOptions, {
table,
});

const tableHeadHeight =
((enableStickyHeader || isFullScreen) &&
tableHeadRef.current?.clientHeight) ||
0;
const tableFooterHeight =
(enableStickyFooter && tableFooterRef.current?.clientHeight) || 0;

const shouldRankResults = useMemo(
() =>
!manualExpanding &&
Expand All @@ -88,21 +105,45 @@ export const MRT_TableBody = <TData extends Record<string, any>>({
],
);

const pinnedRowIds = useMemo(
() =>
getRowModel()
.rows.filter((row) => row.getIsPinned())
.map((r) => r.id),
[rowPinning, table.getRowModel().rows],
);

const rows = useMemo(() => {
if (!shouldRankResults) return getRowModel().rows;
const rankedRows = getPrePaginationRowModel().rows.sort((a, b) =>
rankGlobalFuzzy(a, b),
);
if (enablePagination && !manualPagination) {
const start = pagination.pageIndex * pagination.pageSize;
return rankedRows.slice(start, start + pagination.pageSize);
let rows = [];
if (!shouldRankResults) {
rows =
!enableRowPinning || rowPinningDisplayMode?.includes('sticky')
? getRowModel().rows
: getCenterRows();
} else {
rows = getPrePaginationRowModel().rows.sort((a, b) =>
rankGlobalFuzzy(a, b),
);
if (enablePagination && !manualPagination) {
const start = pagination.pageIndex * pagination.pageSize;
rows = rows.slice(start, start + pagination.pageSize);
}
}
if (enableRowPinning && rowPinningDisplayMode?.includes('sticky')) {
rows = [
...getTopRows().filter((row) => !pinnedRowIds.includes(row.id)),
...rows,
...getBottomRows().filter((row) => !pinnedRowIds.includes(row.id)),
];
}
return rankedRows;

return rows;
}, [
shouldRankResults,
shouldRankResults ? getPrePaginationRowModel().rows : getRowModel().rows,
pagination.pageIndex,
pagination.pageSize,
rowPinning,
]);

const rowVirtualizer:
Expand Down Expand Up @@ -132,76 +173,145 @@ export const MRT_TableBody = <TData extends Record<string, any>>({
: undefined;

return (
<TableBody
{...tableBodyProps}
sx={(theme) => ({
display: layoutMode === 'grid' ? 'grid' : 'table-row-group',
height: rowVirtualizer
? `${rowVirtualizer.getTotalSize()}px`
: 'inherit',
minHeight: !rows.length ? '100px' : undefined,
position: 'relative',
...(parseFromValuesOrFunc(tableBodyProps?.sx, theme) as any),
})}
>
{tableBodyProps?.children ??
(!rows.length ? (
<tr style={{ display: layoutMode === 'grid' ? 'grid' : 'table-row' }}>
<td
colSpan={table.getVisibleLeafColumns().length}
style={{
display: layoutMode === 'grid' ? 'grid' : 'table-cell',
}}
<>
{!rowPinningDisplayMode?.includes('sticky') &&
getIsSomeRowsPinned('top') && (
<TableBody
{...tableBodyProps}
sx={(theme) => ({
display: layoutMode === 'grid' ? 'grid' : 'table-row-group',
position: 'sticky',
top: tableHeadHeight - 1,
zIndex: 1,
...(parseFromValuesOrFunc(tableBodyProps?.sx, theme) as any),
})}
>
{getTopRows().map((row, rowIndex) => {
const props = {
columnVirtualizer,
measureElement: rowVirtualizer?.measureElement,
numRows: rows.length,
row,
rowIndex,
table,
virtualColumns,
virtualPaddingLeft,
virtualPaddingRight,
};
return memoMode === 'rows' ? (
<Memo_MRT_TableBodyRow key={row.id} {...props} />
) : (
<MRT_TableBodyRow key={row.id} {...props} />
);
})}
</TableBody>
)}
<TableBody
{...tableBodyProps}
sx={(theme) => ({
display: layoutMode === 'grid' ? 'grid' : 'table-row-group',
height: rowVirtualizer
? `${rowVirtualizer.getTotalSize()}px`
: 'inherit',
minHeight: !rows.length ? '100px' : undefined,
position: 'relative',
...(parseFromValuesOrFunc(tableBodyProps?.sx, theme) as any),
})}
>
{tableBodyProps?.children ??
(!rows.length ? (
<tr
style={{ display: layoutMode === 'grid' ? 'grid' : 'table-row' }}
>
{renderEmptyRowsFallback?.({ table }) ?? (
<Typography
sx={{
color: 'text.secondary',
fontStyle: 'italic',
maxWidth: `min(100vw, ${
tablePaperRef.current?.clientWidth ?? 360
}px)`,
py: '2rem',
textAlign: 'center',
width: '100%',
}}
>
{globalFilter || columnFilters.length
? localization.noResultsFound
: localization.noRecordsToDisplay}
</Typography>
)}
</td>
</tr>
) : (
<>
{(virtualRows ?? rows).map((rowOrVirtualRow, rowIndex) => {
const row = rowVirtualizer
? rows[rowOrVirtualRow.index]
: (rowOrVirtualRow as MRT_Row<TData>);
<td
colSpan={table.getVisibleLeafColumns().length}
style={{
display: layoutMode === 'grid' ? 'grid' : 'table-cell',
}}
>
{renderEmptyRowsFallback?.({ table }) ?? (
<Typography
sx={{
color: 'text.secondary',
fontStyle: 'italic',
maxWidth: `min(100vw, ${
tablePaperRef.current?.clientWidth ?? 360
}px)`,
py: '2rem',
textAlign: 'center',
width: '100%',
}}
>
{globalFilter || columnFilters.length
? localization.noResultsFound
: localization.noRecordsToDisplay}
</Typography>
)}
</td>
</tr>
) : (
<>
{(virtualRows ?? rows).map((rowOrVirtualRow, rowIndex) => {
const row = rowVirtualizer
? rows[rowOrVirtualRow.index]
: (rowOrVirtualRow as MRT_Row<TData>);
const props = {
columnVirtualizer,
measureElement: rowVirtualizer?.measureElement,
numRows: rows.length,
pinnedRowIds,
row,
rowIndex: rowVirtualizer ? rowOrVirtualRow.index : rowIndex,
table,
virtualColumns,
virtualPaddingLeft,
virtualPaddingRight,
virtualRow: rowVirtualizer
? (rowOrVirtualRow as VirtualItem)
: undefined,
};
return memoMode === 'rows' ? (
<Memo_MRT_TableBodyRow key={row.id} {...props} />
) : (
<MRT_TableBodyRow key={row.id} {...props} />
);
})}
</>
))}
</TableBody>
{!rowPinningDisplayMode?.includes('sticky') &&
getIsSomeRowsPinned('bottom') && (
<TableBody
{...tableBodyProps}
sx={(theme) => ({
display: layoutMode === 'grid' ? 'grid' : 'table-row-group',
position: 'sticky',
bottom: tableFooterHeight - 1,
zIndex: 1,
...(parseFromValuesOrFunc(tableBodyProps?.sx, theme) as any),
})}
>
{getBottomRows().map((row, rowIndex) => {
const props = {
columnVirtualizer,
measureElement: rowVirtualizer?.measureElement,
numRows: rows.length,
row,
rowIndex: rowVirtualizer ? rowOrVirtualRow.index : rowIndex,
rowIndex,
table,
virtualColumns,
virtualPaddingLeft,
virtualPaddingRight,
virtualRow: rowVirtualizer
? (rowOrVirtualRow as VirtualItem)
: undefined,
};
return memoMode === 'rows' ? (
<Memo_MRT_TableBodyRow key={row.id} {...props} />
) : (
<MRT_TableBodyRow key={row.id} {...props} />
);
})}
</>
))}
</TableBody>
</TableBody>
)}
</>
);
};

Expand Down
3 changes: 2 additions & 1 deletion packages/material-react-table/src/body/MRT_TableBodyCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ export const MRT_TableBodyCell = <TData extends Record<string, any>>({
}rem`
: undefined,
textOverflow: columnDefType !== 'display' ? 'ellipsis' : undefined,
whiteSpace: density === 'compact' ? 'nowrap' : 'normal',
whiteSpace:
row.getIsPinned() || density === 'compact' ? 'nowrap' : 'normal',
zIndex:
draggingColumn?.id === column.id ? 2 : column.getIsPinned() ? 1 : 0,
'&:hover': {
Expand Down
Loading

0 comments on commit ba6242a

Please sign in to comment.