Skip to content

Commit

Permalink
release v2.11.2 - row pinning fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinVandy committed Feb 9, 2024
1 parent 3d33091 commit 3ecdff5
Show file tree
Hide file tree
Showing 12 changed files with 184 additions and 158 deletions.
6 changes: 6 additions & 0 deletions apps/material-react-table-docs/pages/changelog.mdx
Expand Up @@ -7,6 +7,12 @@ import Head from 'next/head';

## MRT V2 Changelog

### Version 2.11.3 - 2024-02-08

- Fixed bugs with batch row selection and row pinning together
- Fixed duplicate pinned rows when global filter is present for non-sticky row pinning modes
- Fixed selected row count in toolbar alert banner with sub row selection

### Version 2.11.1 - 2024-02-05

- Fixed bug where new batch row selection feature did not account for `manualPagination`
Expand Down
Expand Up @@ -176,7 +176,7 @@ const table = useMaterialReactTable({
//clicking anywhere on the row will select it
muiTableBodyRowProps: ({ row, staticRowIndex, table }) => ({
onClick: (event) =>
getMRT_RowSelectionHandler()({ event, row, staticRowIndex, table }), //import this helper function from material-react-table
getMRT_RowSelectionHandler({ row, staticRowIndex, table })(event), //import this helper function from material-react-table
sx: { cursor: 'pointer' },
}),
});
Expand Down
202 changes: 101 additions & 101 deletions apps/material-react-table-docs/public/sitemap-0.xml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/material-react-table/package.json
@@ -1,5 +1,5 @@
{
"version": "2.11.1",
"version": "2.11.2",
"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 @@ -64,7 +64,7 @@ export const MRT_TableBody = <TData extends MRT_RowData>({
.map((r) => r.id);
}, [rowPinning, getRowModel().rows]);

const rows = useMRT_Rows(table, pinnedRowIds);
const rows = useMRT_Rows(table);

const rowVirtualizer = useMRT_RowVirtualizer(table, rows);

Expand Down
@@ -1,4 +1,4 @@
import { type ChangeEvent, type MouseEvent } from 'react';
import { type MouseEvent } from 'react';
import Checkbox, { type CheckboxProps } from '@mui/material/Checkbox';
import Radio, { type RadioProps } from '@mui/material/Radio';
import Tooltip from '@mui/material/Tooltip';
Expand All @@ -11,6 +11,7 @@ import {
import {
getIsRowSelected,
getMRT_RowSelectionHandler,
getMRT_SelectAllHandler,
} from '../../utils/row.utils';
import { getCommonTooltipProps } from '../../utils/style.utils';
import { parseFromValuesOrFunc } from '../../utils/utils';
Expand All @@ -32,22 +33,16 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
getState,
options: {
enableMultiRowSelection,
enableRowPinning,
localization,
muiSelectAllCheckboxProps,
muiSelectCheckboxProps,
rowPinningDisplayMode,
selectAllMode,
},
refs: { lastSelectedRowId },
} = table;
const { density, isLoading } = getState();

const selectAll = !row;

const isStickySelection =
enableRowPinning && rowPinningDisplayMode?.includes('select');

const allRowsSelected = selectAll
? selectAllMode === 'page'
? table.getIsAllPageRowsSelected()
Expand All @@ -68,17 +63,15 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
...rest,
};

const onSelectionChange = getMRT_RowSelectionHandler();
const onSelectionChange = row
? getMRT_RowSelectionHandler({
row,
staticRowIndex,
table,
})
: undefined;

const onSelectAllChange = (event: ChangeEvent<HTMLInputElement>) => {
selectAllMode === 'all'
? table.getToggleAllRowsSelectedHandler()(event)
: table.getToggleAllPageRowsSelectedHandler()(event);
if (isStickySelection) {
table.setRowPinning({ bottom: [], top: [] });
}
lastSelectedRowId.current = null;
};
const onSelectAllChange = getMRT_SelectAllHandler({ table });

const commonProps = {
'aria-label': selectAll
Expand All @@ -94,9 +87,7 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
},
onChange: (event) => {
event.stopPropagation();
row
? onSelectionChange({ event, row, staticRowIndex, table })
: onSelectAllChange(event);
row ? onSelectionChange!(event) : onSelectAllChange(event);
},
size: (density === 'compact' ? 'small' : 'medium') as 'medium' | 'small',
...checkboxProps,
Expand Down
Expand Up @@ -7,6 +7,7 @@ import Chip from '@mui/material/Chip';
import Collapse from '@mui/material/Collapse';
import Stack from '@mui/material/Stack';
import { type MRT_RowData, type MRT_TableInstance } from '../../types';
import { getMRT_SelectAllHandler } from '../../utils/row.utils';
import { parseFromValuesOrFunc } from '../../utils/utils';
import { MRT_SelectCheckbox } from '../inputs/MRT_SelectCheckbox';

Expand Down Expand Up @@ -36,7 +37,7 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
renderToolbarAlertBannerContent,
rowCount,
},
refs: { lastSelectedRowId, tablePaperRef },
refs: { tablePaperRef },
} = table;
const { density, grouping, rowSelection, showAlertBanner } = getState();

Expand All @@ -51,7 +52,7 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
table,
});

const totalRowCount = rowCount ?? getPrePaginationRowModel().rows.length;
const totalRowCount = rowCount ?? getPrePaginationRowModel().flatRows.length;

const selectedRowCount = useMemo(
() =>
Expand All @@ -67,10 +68,7 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
?.replace('{selectedCount}', selectedRowCount.toLocaleString())
?.replace('{rowCount}', totalRowCount.toString())}
<Button
onClick={() => {
table.toggleAllRowsSelected(false);
lastSelectedRowId.current = null;
}}
onClick={(event) => getMRT_SelectAllHandler({ table })(event, false)}
size="small"
sx={{ p: '2px' }}
>
Expand Down
3 changes: 1 addition & 2 deletions packages/material-react-table/src/hooks/useMRT_Rows.ts
Expand Up @@ -8,7 +8,6 @@ import { getMRT_Rows } from '../utils/row.utils';

export const useMRT_Rows = <TData extends MRT_RowData>(
table: MRT_TableInstance<TData>,
pinnedRowIds: string[] = [],
): MRT_Row<TData>[] => {
const {
getRowModel,
Expand All @@ -25,7 +24,7 @@ export const useMRT_Rows = <TData extends MRT_RowData>(
} = getState();

const rows = useMemo(
() => getMRT_Rows(table, pinnedRowIds),
() => getMRT_Rows(table),
[
creatingRow,
data,
Expand Down
80 changes: 56 additions & 24 deletions packages/material-react-table/src/utils/row.utils.ts
Expand Up @@ -9,11 +9,9 @@ import { parseFromValuesOrFunc } from './utils';

export const getMRT_Rows = <TData extends MRT_RowData>(
table: MRT_TableInstance<TData>,
pinnedRowIds: string[] = [],
all?: boolean,
): MRT_Row<TData>[] => {
const {
getBottomRows,
getCenterRows,
getPrePaginationRowModel,
getRowModel,
Expand Down Expand Up @@ -41,21 +39,31 @@ export const getMRT_Rows = <TData extends MRT_RowData>(
: getRowModel().rows
: getCenterRows();
} else {
// fuzzy ranking adjustments
rows = getPrePaginationRowModel().rows.sort((a, b) =>
rankGlobalFuzzy(a, b),
);
if (enablePagination && !manualPagination && !all) {
const start = pagination.pageIndex * pagination.pageSize;
rows = rows.slice(start, start + pagination.pageSize);
}
if (enableRowPinning && !rowPinningDisplayMode?.includes('sticky')) {
// "re-center-ize" the rows (no top or bottom pinned rows unless sticky)
rows = rows.filter((row) => !row.getIsPinned());
}
}
// row pinning adjustments
if (enableRowPinning && rowPinningDisplayMode?.includes('sticky')) {
const centerPinnedRowIds = rows
.filter((row) => row.getIsPinned())
.map((r) => r.id);

rows = [
...getTopRows().filter((row) => !pinnedRowIds.includes(row.id)),
...getTopRows().filter((row) => !centerPinnedRowIds.includes(row.id)),
...rows,
...getBottomRows().filter((row) => !pinnedRowIds.includes(row.id)),
];
}
// blank inserted creating row adjustments
if (
positionCreatingRow !== undefined &&
creatingRow &&
Expand Down Expand Up @@ -135,18 +143,19 @@ export const getIsRowSelected = <TData extends MRT_RowData>({
};

export const getMRT_RowSelectionHandler =
() =>
<TData extends MRT_RowData>({
event,
row,
staticRowIndex = 0,
table,
}: {
event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLTableRowElement>;
row: MRT_Row<TData>;
staticRowIndex?: number;
table: MRT_TableInstance<TData>;
}) => {
}) =>
(
event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLTableRowElement>,
value?: boolean,
) => {
const {
getState,
options: {
Expand All @@ -164,13 +173,12 @@ export const getMRT_RowSelectionHandler =

const paginationOffset = manualPagination ? 0 : pageSize * pageIndex;

const isCurrentRowChecked = getIsRowSelected({ row, table });

const isStickySelection =
enableRowPinning && rowPinningDisplayMode?.includes('select');
const wasCurrentRowChecked = getIsRowSelected({ row, table });

// toggle selection of this row
row.getToggleSelectedHandler()(event);
row.toggleSelected(value ?? !wasCurrentRowChecked);

const changedRowIds = new Set<string>([row.id]);

// if shift key is pressed, select all rows between last selected and this one
if (
Expand All @@ -179,7 +187,7 @@ export const getMRT_RowSelectionHandler =
(event as any).nativeEvent.shiftKey &&
lastSelectedRowId.current !== null
) {
const rows = getMRT_Rows(table, undefined, true);
const rows = getMRT_Rows(table, true);

const lastIndex = rows.findIndex(
(r) => r.id === lastSelectedRowId.current,
Expand All @@ -199,9 +207,10 @@ export const getMRT_RowSelectionHandler =

// toggle selection of all rows between last selected and this one
// but only if the last selected row is not the same as the current one
if (isCurrentRowChecked !== isLastIndexChecked) {
if (wasCurrentRowChecked !== isLastIndexChecked) {
for (let i = start; i <= end; i++) {
rows[i].toggleSelected(!isCurrentRowChecked);
rows[i].toggleSelected(!wasCurrentRowChecked);
changedRowIds.add(rows[i].id);
}
}
}
Expand All @@ -215,13 +224,36 @@ export const getMRT_RowSelectionHandler =
row.subRows?.forEach((r) => r.toggleSelected(false));
}

if (isStickySelection) {
row.pin(
!row.getIsPinned() && isCurrentRowChecked
? rowPinningDisplayMode?.includes('bottom')
? 'bottom'
: 'top'
: false,
);
if (enableRowPinning && rowPinningDisplayMode?.includes('select')) {
changedRowIds.forEach((rowId) => {
const rowToTogglePin = table.getRow(rowId);
rowToTogglePin.pin(
!wasCurrentRowChecked //was not previously pinned or selected
? rowPinningDisplayMode?.includes('bottom')
? 'bottom'
: 'top'
: false,
);
});
}
};

export const getMRT_SelectAllHandler =
<TData extends MRT_RowData>({ table }: { table: MRT_TableInstance<TData> }) =>
(
event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLButtonElement>,
value?: boolean,
) => {
const {
options: { enableRowPinning, rowPinningDisplayMode, selectAllMode },
refs: { lastSelectedRowId },
} = table;

selectAllMode === 'all'
? table.toggleAllRowsSelected(value ?? (event as any).target.checked)
: table.toggleAllPageRowsSelected(value ?? (event as any).target.checked);
if (enableRowPinning && rowPinningDisplayMode?.includes('select')) {
table.setRowPinning({ bottom: [], top: [] });
}
lastSelectedRowId.current = null;
};
Expand Up @@ -295,7 +295,6 @@ export const GroupingColumnsSetState = () => {
columns={columns}
data={data}
enableGrouping
state={{ columnOrder: columns.map((c) => c.accessorKey as string) }}
/>
);
};
Expand Down
Expand Up @@ -137,6 +137,7 @@ export const RowPinningTopMode = () => (
data={data}
enablePagination={false}
enableRowPinning
keepPinnedRows={false}
muiTableContainerProps={{
sx: {
maxHeight: '600px',
Expand Down
Expand Up @@ -117,7 +117,7 @@ export const SelectionEnabledWithRowClick = () => (
enableRowSelection
muiTableBodyRowProps={({ row, staticRowIndex, table }) => ({
onClick: (event) =>
getMRT_RowSelectionHandler()({ event, row, staticRowIndex, table }),
getMRT_RowSelectionHandler({ row, staticRowIndex, table })(event),
style: {
cursor: 'pointer',
userSelect: 'none',
Expand Down

0 comments on commit 3ecdff5

Please sign in to comment.