Skip to content

Commit 3ecdff5

Browse files
committed
release v2.11.2 - row pinning fixes
1 parent 3d33091 commit 3ecdff5

File tree

12 files changed

+184
-158
lines changed

12 files changed

+184
-158
lines changed

apps/material-react-table-docs/pages/changelog.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ import Head from 'next/head';
77

88
## MRT V2 Changelog
99

10+
### Version 2.11.3 - 2024-02-08
11+
12+
- Fixed bugs with batch row selection and row pinning together
13+
- Fixed duplicate pinned rows when global filter is present for non-sticky row pinning modes
14+
- Fixed selected row count in toolbar alert banner with sub row selection
15+
1016
### Version 2.11.1 - 2024-02-05
1117

1218
- Fixed bug where new batch row selection feature did not account for `manualPagination`

apps/material-react-table-docs/pages/docs/guides/row-selection.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ const table = useMaterialReactTable({
176176
//clicking anywhere on the row will select it
177177
muiTableBodyRowProps: ({ row, staticRowIndex, table }) => ({
178178
onClick: (event) =>
179-
getMRT_RowSelectionHandler()({ event, row, staticRowIndex, table }), //import this helper function from material-react-table
179+
getMRT_RowSelectionHandler({ row, staticRowIndex, table })(event), //import this helper function from material-react-table
180180
sx: { cursor: 'pointer' },
181181
}),
182182
});

apps/material-react-table-docs/public/sitemap-0.xml

Lines changed: 101 additions & 101 deletions
Large diffs are not rendered by default.

packages/material-react-table/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "2.11.1",
2+
"version": "2.11.2",
33
"license": "MIT",
44
"name": "material-react-table",
55
"description": "A fully featured Material UI V5 implementation of TanStack React Table V8, written from the ground up in TypeScript.",

packages/material-react-table/src/components/body/MRT_TableBody.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export const MRT_TableBody = <TData extends MRT_RowData>({
6464
.map((r) => r.id);
6565
}, [rowPinning, getRowModel().rows]);
6666

67-
const rows = useMRT_Rows(table, pinnedRowIds);
67+
const rows = useMRT_Rows(table);
6868

6969
const rowVirtualizer = useMRT_RowVirtualizer(table, rows);
7070

packages/material-react-table/src/components/inputs/MRT_SelectCheckbox.tsx

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type ChangeEvent, type MouseEvent } from 'react';
1+
import { type MouseEvent } from 'react';
22
import Checkbox, { type CheckboxProps } from '@mui/material/Checkbox';
33
import Radio, { type RadioProps } from '@mui/material/Radio';
44
import Tooltip from '@mui/material/Tooltip';
@@ -11,6 +11,7 @@ import {
1111
import {
1212
getIsRowSelected,
1313
getMRT_RowSelectionHandler,
14+
getMRT_SelectAllHandler,
1415
} from '../../utils/row.utils';
1516
import { getCommonTooltipProps } from '../../utils/style.utils';
1617
import { parseFromValuesOrFunc } from '../../utils/utils';
@@ -32,22 +33,16 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
3233
getState,
3334
options: {
3435
enableMultiRowSelection,
35-
enableRowPinning,
3636
localization,
3737
muiSelectAllCheckboxProps,
3838
muiSelectCheckboxProps,
39-
rowPinningDisplayMode,
4039
selectAllMode,
4140
},
42-
refs: { lastSelectedRowId },
4341
} = table;
4442
const { density, isLoading } = getState();
4543

4644
const selectAll = !row;
4745

48-
const isStickySelection =
49-
enableRowPinning && rowPinningDisplayMode?.includes('select');
50-
5146
const allRowsSelected = selectAll
5247
? selectAllMode === 'page'
5348
? table.getIsAllPageRowsSelected()
@@ -68,17 +63,15 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
6863
...rest,
6964
};
7065

71-
const onSelectionChange = getMRT_RowSelectionHandler();
66+
const onSelectionChange = row
67+
? getMRT_RowSelectionHandler({
68+
row,
69+
staticRowIndex,
70+
table,
71+
})
72+
: undefined;
7273

73-
const onSelectAllChange = (event: ChangeEvent<HTMLInputElement>) => {
74-
selectAllMode === 'all'
75-
? table.getToggleAllRowsSelectedHandler()(event)
76-
: table.getToggleAllPageRowsSelectedHandler()(event);
77-
if (isStickySelection) {
78-
table.setRowPinning({ bottom: [], top: [] });
79-
}
80-
lastSelectedRowId.current = null;
81-
};
74+
const onSelectAllChange = getMRT_SelectAllHandler({ table });
8275

8376
const commonProps = {
8477
'aria-label': selectAll
@@ -94,9 +87,7 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
9487
},
9588
onChange: (event) => {
9689
event.stopPropagation();
97-
row
98-
? onSelectionChange({ event, row, staticRowIndex, table })
99-
: onSelectAllChange(event);
90+
row ? onSelectionChange!(event) : onSelectAllChange(event);
10091
},
10192
size: (density === 'compact' ? 'small' : 'medium') as 'medium' | 'small',
10293
...checkboxProps,

packages/material-react-table/src/components/toolbar/MRT_ToolbarAlertBanner.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Chip from '@mui/material/Chip';
77
import Collapse from '@mui/material/Collapse';
88
import Stack from '@mui/material/Stack';
99
import { type MRT_RowData, type MRT_TableInstance } from '../../types';
10+
import { getMRT_SelectAllHandler } from '../../utils/row.utils';
1011
import { parseFromValuesOrFunc } from '../../utils/utils';
1112
import { MRT_SelectCheckbox } from '../inputs/MRT_SelectCheckbox';
1213

@@ -36,7 +37,7 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
3637
renderToolbarAlertBannerContent,
3738
rowCount,
3839
},
39-
refs: { lastSelectedRowId, tablePaperRef },
40+
refs: { tablePaperRef },
4041
} = table;
4142
const { density, grouping, rowSelection, showAlertBanner } = getState();
4243

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

54-
const totalRowCount = rowCount ?? getPrePaginationRowModel().rows.length;
55+
const totalRowCount = rowCount ?? getPrePaginationRowModel().flatRows.length;
5556

5657
const selectedRowCount = useMemo(
5758
() =>
@@ -67,10 +68,7 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
6768
?.replace('{selectedCount}', selectedRowCount.toLocaleString())
6869
?.replace('{rowCount}', totalRowCount.toString())}
6970
<Button
70-
onClick={() => {
71-
table.toggleAllRowsSelected(false);
72-
lastSelectedRowId.current = null;
73-
}}
71+
onClick={(event) => getMRT_SelectAllHandler({ table })(event, false)}
7472
size="small"
7573
sx={{ p: '2px' }}
7674
>

packages/material-react-table/src/hooks/useMRT_Rows.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { getMRT_Rows } from '../utils/row.utils';
88

99
export const useMRT_Rows = <TData extends MRT_RowData>(
1010
table: MRT_TableInstance<TData>,
11-
pinnedRowIds: string[] = [],
1211
): MRT_Row<TData>[] => {
1312
const {
1413
getRowModel,
@@ -25,7 +24,7 @@ export const useMRT_Rows = <TData extends MRT_RowData>(
2524
} = getState();
2625

2726
const rows = useMemo(
28-
() => getMRT_Rows(table, pinnedRowIds),
27+
() => getMRT_Rows(table),
2928
[
3029
creatingRow,
3130
data,

packages/material-react-table/src/utils/row.utils.ts

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ import { parseFromValuesOrFunc } from './utils';
99

1010
export const getMRT_Rows = <TData extends MRT_RowData>(
1111
table: MRT_TableInstance<TData>,
12-
pinnedRowIds: string[] = [],
1312
all?: boolean,
1413
): MRT_Row<TData>[] => {
1514
const {
16-
getBottomRows,
1715
getCenterRows,
1816
getPrePaginationRowModel,
1917
getRowModel,
@@ -41,21 +39,31 @@ export const getMRT_Rows = <TData extends MRT_RowData>(
4139
: getRowModel().rows
4240
: getCenterRows();
4341
} else {
42+
// fuzzy ranking adjustments
4443
rows = getPrePaginationRowModel().rows.sort((a, b) =>
4544
rankGlobalFuzzy(a, b),
4645
);
4746
if (enablePagination && !manualPagination && !all) {
4847
const start = pagination.pageIndex * pagination.pageSize;
4948
rows = rows.slice(start, start + pagination.pageSize);
5049
}
50+
if (enableRowPinning && !rowPinningDisplayMode?.includes('sticky')) {
51+
// "re-center-ize" the rows (no top or bottom pinned rows unless sticky)
52+
rows = rows.filter((row) => !row.getIsPinned());
53+
}
5154
}
55+
// row pinning adjustments
5256
if (enableRowPinning && rowPinningDisplayMode?.includes('sticky')) {
57+
const centerPinnedRowIds = rows
58+
.filter((row) => row.getIsPinned())
59+
.map((r) => r.id);
60+
5361
rows = [
54-
...getTopRows().filter((row) => !pinnedRowIds.includes(row.id)),
62+
...getTopRows().filter((row) => !centerPinnedRowIds.includes(row.id)),
5563
...rows,
56-
...getBottomRows().filter((row) => !pinnedRowIds.includes(row.id)),
5764
];
5865
}
66+
// blank inserted creating row adjustments
5967
if (
6068
positionCreatingRow !== undefined &&
6169
creatingRow &&
@@ -135,18 +143,19 @@ export const getIsRowSelected = <TData extends MRT_RowData>({
135143
};
136144

137145
export const getMRT_RowSelectionHandler =
138-
() =>
139146
<TData extends MRT_RowData>({
140-
event,
141147
row,
142148
staticRowIndex = 0,
143149
table,
144150
}: {
145-
event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLTableRowElement>;
146151
row: MRT_Row<TData>;
147152
staticRowIndex?: number;
148153
table: MRT_TableInstance<TData>;
149-
}) => {
154+
}) =>
155+
(
156+
event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLTableRowElement>,
157+
value?: boolean,
158+
) => {
150159
const {
151160
getState,
152161
options: {
@@ -164,13 +173,12 @@ export const getMRT_RowSelectionHandler =
164173

165174
const paginationOffset = manualPagination ? 0 : pageSize * pageIndex;
166175

167-
const isCurrentRowChecked = getIsRowSelected({ row, table });
168-
169-
const isStickySelection =
170-
enableRowPinning && rowPinningDisplayMode?.includes('select');
176+
const wasCurrentRowChecked = getIsRowSelected({ row, table });
171177

172178
// toggle selection of this row
173-
row.getToggleSelectedHandler()(event);
179+
row.toggleSelected(value ?? !wasCurrentRowChecked);
180+
181+
const changedRowIds = new Set<string>([row.id]);
174182

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

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

200208
// toggle selection of all rows between last selected and this one
201209
// but only if the last selected row is not the same as the current one
202-
if (isCurrentRowChecked !== isLastIndexChecked) {
210+
if (wasCurrentRowChecked !== isLastIndexChecked) {
203211
for (let i = start; i <= end; i++) {
204-
rows[i].toggleSelected(!isCurrentRowChecked);
212+
rows[i].toggleSelected(!wasCurrentRowChecked);
213+
changedRowIds.add(rows[i].id);
205214
}
206215
}
207216
}
@@ -215,13 +224,36 @@ export const getMRT_RowSelectionHandler =
215224
row.subRows?.forEach((r) => r.toggleSelected(false));
216225
}
217226

218-
if (isStickySelection) {
219-
row.pin(
220-
!row.getIsPinned() && isCurrentRowChecked
221-
? rowPinningDisplayMode?.includes('bottom')
222-
? 'bottom'
223-
: 'top'
224-
: false,
225-
);
227+
if (enableRowPinning && rowPinningDisplayMode?.includes('select')) {
228+
changedRowIds.forEach((rowId) => {
229+
const rowToTogglePin = table.getRow(rowId);
230+
rowToTogglePin.pin(
231+
!wasCurrentRowChecked //was not previously pinned or selected
232+
? rowPinningDisplayMode?.includes('bottom')
233+
? 'bottom'
234+
: 'top'
235+
: false,
236+
);
237+
});
238+
}
239+
};
240+
241+
export const getMRT_SelectAllHandler =
242+
<TData extends MRT_RowData>({ table }: { table: MRT_TableInstance<TData> }) =>
243+
(
244+
event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLButtonElement>,
245+
value?: boolean,
246+
) => {
247+
const {
248+
options: { enableRowPinning, rowPinningDisplayMode, selectAllMode },
249+
refs: { lastSelectedRowId },
250+
} = table;
251+
252+
selectAllMode === 'all'
253+
? table.toggleAllRowsSelected(value ?? (event as any).target.checked)
254+
: table.toggleAllPageRowsSelected(value ?? (event as any).target.checked);
255+
if (enableRowPinning && rowPinningDisplayMode?.includes('select')) {
256+
table.setRowPinning({ bottom: [], top: [] });
226257
}
258+
lastSelectedRowId.current = null;
227259
};

packages/material-react-table/stories/features/ColumnGrouping.stories.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,6 @@ export const GroupingColumnsSetState = () => {
295295
columns={columns}
296296
data={data}
297297
enableGrouping
298-
state={{ columnOrder: columns.map((c) => c.accessorKey as string) }}
299298
/>
300299
);
301300
};

0 commit comments

Comments
 (0)