material-react-table 2.11.0 → 2.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.11.0",
2
+ "version": "2.11.2",
3
3
  "license": "MIT",
4
4
  "name": "material-react-table",
5
5
  "description": "A fully featured Material UI V5 implementation of TanStack React Table V8, written from the ground up in TypeScript.",
@@ -64,7 +64,7 @@ export const MRT_TableBody = <TData extends MRT_RowData>({
64
64
  .map((r) => r.id);
65
65
  }, [rowPinning, getRowModel().rows]);
66
66
 
67
- const rows = useMRT_Rows(table, pinnedRowIds);
67
+ const rows = useMRT_Rows(table);
68
68
 
69
69
  const rowVirtualizer = useMRT_RowVirtualizer(table, rows);
70
70
 
@@ -1,4 +1,4 @@
1
- import { type ChangeEvent, type MouseEvent } from 'react';
1
+ import { type MouseEvent } from 'react';
2
2
  import Checkbox, { type CheckboxProps } from '@mui/material/Checkbox';
3
3
  import Radio, { type RadioProps } from '@mui/material/Radio';
4
4
  import Tooltip from '@mui/material/Tooltip';
@@ -11,6 +11,7 @@ import {
11
11
  import {
12
12
  getIsRowSelected,
13
13
  getMRT_RowSelectionHandler,
14
+ getMRT_SelectAllHandler,
14
15
  } from '../../utils/row.utils';
15
16
  import { getCommonTooltipProps } from '../../utils/style.utils';
16
17
  import { parseFromValuesOrFunc } from '../../utils/utils';
@@ -32,22 +33,16 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
32
33
  getState,
33
34
  options: {
34
35
  enableMultiRowSelection,
35
- enableRowPinning,
36
36
  localization,
37
37
  muiSelectAllCheckboxProps,
38
38
  muiSelectCheckboxProps,
39
- rowPinningDisplayMode,
40
39
  selectAllMode,
41
40
  },
42
- refs: { lastSelectedRowId },
43
41
  } = table;
44
42
  const { density, isLoading } = getState();
45
43
 
46
44
  const selectAll = !row;
47
45
 
48
- const isStickySelection =
49
- enableRowPinning && rowPinningDisplayMode?.includes('select');
50
-
51
46
  const allRowsSelected = selectAll
52
47
  ? selectAllMode === 'page'
53
48
  ? table.getIsAllPageRowsSelected()
@@ -68,17 +63,15 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
68
63
  ...rest,
69
64
  };
70
65
 
71
- const onSelectionChange = getMRT_RowSelectionHandler();
66
+ const onSelectionChange = row
67
+ ? getMRT_RowSelectionHandler({
68
+ row,
69
+ staticRowIndex,
70
+ table,
71
+ })
72
+ : undefined;
72
73
 
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 });
82
75
 
83
76
  const commonProps = {
84
77
  'aria-label': selectAll
@@ -94,9 +87,7 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
94
87
  },
95
88
  onChange: (event) => {
96
89
  event.stopPropagation();
97
- row
98
- ? onSelectionChange({ event, row, staticRowIndex, table })
99
- : onSelectAllChange(event);
90
+ row ? onSelectionChange!(event) : onSelectAllChange(event);
100
91
  },
101
92
  size: (density === 'compact' ? 'small' : 'medium') as 'medium' | 'small',
102
93
  ...checkboxProps,
@@ -129,8 +120,8 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
129
120
  ) : (
130
121
  <Checkbox
131
122
  indeterminate={
132
- selectAll
133
- ? table.getIsSomeRowsSelected() && !allRowsSelected
123
+ !isChecked && selectAll
124
+ ? table.getIsSomeRowsSelected()
134
125
  : row?.getIsSomeSelected() && row.getCanSelectSubRows()
135
126
  }
136
127
  {...commonProps}
@@ -7,6 +7,7 @@ import Chip from '@mui/material/Chip';
7
7
  import Collapse from '@mui/material/Collapse';
8
8
  import Stack from '@mui/material/Stack';
9
9
  import { type MRT_RowData, type MRT_TableInstance } from '../../types';
10
+ import { getMRT_SelectAllHandler } from '../../utils/row.utils';
10
11
  import { parseFromValuesOrFunc } from '../../utils/utils';
11
12
  import { MRT_SelectCheckbox } from '../inputs/MRT_SelectCheckbox';
12
13
 
@@ -36,7 +37,7 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
36
37
  renderToolbarAlertBannerContent,
37
38
  rowCount,
38
39
  },
39
- refs: { lastSelectedRowId, tablePaperRef },
40
+ refs: { tablePaperRef },
40
41
  } = table;
41
42
  const { density, grouping, rowSelection, showAlertBanner } = getState();
42
43
 
@@ -51,7 +52,7 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
51
52
  table,
52
53
  });
53
54
 
54
- const totalRowCount = rowCount ?? getPrePaginationRowModel().rows.length;
55
+ const totalRowCount = rowCount ?? getPrePaginationRowModel().flatRows.length;
55
56
 
56
57
  const selectedRowCount = useMemo(
57
58
  () =>
@@ -67,10 +68,7 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
67
68
  ?.replace('{selectedCount}', selectedRowCount.toLocaleString())
68
69
  ?.replace('{rowCount}', totalRowCount.toString())}
69
70
  <Button
70
- onClick={() => {
71
- table.toggleAllRowsSelected(false);
72
- lastSelectedRowId.current = null;
73
- }}
71
+ onClick={(event) => getMRT_SelectAllHandler({ table })(event, false)}
74
72
  size="small"
75
73
  sx={{ p: '2px' }}
76
74
  >
@@ -8,7 +8,6 @@ import { getMRT_Rows } from '../utils/row.utils';
8
8
 
9
9
  export const useMRT_Rows = <TData extends MRT_RowData>(
10
10
  table: MRT_TableInstance<TData>,
11
- pinnedRowIds: string[] = [],
12
11
  ): MRT_Row<TData>[] => {
13
12
  const {
14
13
  getRowModel,
@@ -25,7 +24,7 @@ export const useMRT_Rows = <TData extends MRT_RowData>(
25
24
  } = getState();
26
25
 
27
26
  const rows = useMemo(
28
- () => getMRT_Rows(table, pinnedRowIds),
27
+ () => getMRT_Rows(table),
29
28
  [
30
29
  creatingRow,
31
30
  data,
@@ -9,11 +9,9 @@ import { parseFromValuesOrFunc } from './utils';
9
9
 
10
10
  export const getMRT_Rows = <TData extends MRT_RowData>(
11
11
  table: MRT_TableInstance<TData>,
12
- pinnedRowIds: string[] = [],
13
12
  all?: boolean,
14
13
  ): MRT_Row<TData>[] => {
15
14
  const {
16
- getBottomRows,
17
15
  getCenterRows,
18
16
  getPrePaginationRowModel,
19
17
  getRowModel,
@@ -41,6 +39,7 @@ export const getMRT_Rows = <TData extends MRT_RowData>(
41
39
  : getRowModel().rows
42
40
  : getCenterRows();
43
41
  } else {
42
+ // fuzzy ranking adjustments
44
43
  rows = getPrePaginationRowModel().rows.sort((a, b) =>
45
44
  rankGlobalFuzzy(a, b),
46
45
  );
@@ -48,14 +47,23 @@ export const getMRT_Rows = <TData extends MRT_RowData>(
48
47
  const start = pagination.pageIndex * pagination.pageSize;
49
48
  rows = rows.slice(start, start + pagination.pageSize);
50
49
  }
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
+ }
51
54
  }
55
+ // row pinning adjustments
52
56
  if (enableRowPinning && rowPinningDisplayMode?.includes('sticky')) {
57
+ const centerPinnedRowIds = rows
58
+ .filter((row) => row.getIsPinned())
59
+ .map((r) => r.id);
60
+
53
61
  rows = [
54
- ...getTopRows().filter((row) => !pinnedRowIds.includes(row.id)),
62
+ ...getTopRows().filter((row) => !centerPinnedRowIds.includes(row.id)),
55
63
  ...rows,
56
- ...getBottomRows().filter((row) => !pinnedRowIds.includes(row.id)),
57
64
  ];
58
65
  }
66
+ // blank inserted creating row adjustments
59
67
  if (
60
68
  positionCreatingRow !== undefined &&
61
69
  creatingRow &&
@@ -135,23 +143,26 @@ export const getIsRowSelected = <TData extends MRT_RowData>({
135
143
  };
136
144
 
137
145
  export const getMRT_RowSelectionHandler =
138
- () =>
139
146
  <TData extends MRT_RowData>({
140
- event,
141
147
  row,
142
148
  staticRowIndex = 0,
143
149
  table,
144
150
  }: {
145
- event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLTableRowElement>;
146
151
  row: MRT_Row<TData>;
147
152
  staticRowIndex?: number;
148
153
  table: MRT_TableInstance<TData>;
149
- }) => {
154
+ }) =>
155
+ (
156
+ event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLTableRowElement>,
157
+ value?: boolean,
158
+ ) => {
150
159
  const {
151
160
  getState,
152
161
  options: {
153
162
  enableBatchRowSelection,
163
+ enableMultiRowSelection,
154
164
  enableRowPinning,
165
+ manualPagination,
155
166
  rowPinningDisplayMode,
156
167
  },
157
168
  refs: { lastSelectedRowId: lastSelectedRowId },
@@ -160,35 +171,52 @@ export const getMRT_RowSelectionHandler =
160
171
  pagination: { pageIndex, pageSize },
161
172
  } = getState();
162
173
 
163
- const isChecked = getIsRowSelected({ row, table });
174
+ const paginationOffset = manualPagination ? 0 : pageSize * pageIndex;
164
175
 
165
- const isStickySelection =
166
- enableRowPinning && rowPinningDisplayMode?.includes('select');
176
+ const wasCurrentRowChecked = getIsRowSelected({ row, table });
167
177
 
168
- // toggle selected of this row
169
- row.getToggleSelectedHandler()(event);
178
+ // toggle selection of this row
179
+ row.toggleSelected(value ?? !wasCurrentRowChecked);
180
+
181
+ const changedRowIds = new Set<string>([row.id]);
170
182
 
171
183
  // if shift key is pressed, select all rows between last selected and this one
172
184
  if (
173
185
  enableBatchRowSelection &&
186
+ enableMultiRowSelection &&
174
187
  (event as any).nativeEvent.shiftKey &&
175
188
  lastSelectedRowId.current !== null
176
189
  ) {
177
- const rows = getMRT_Rows(table, undefined, true);
190
+ const rows = getMRT_Rows(table, true);
191
+
178
192
  const lastIndex = rows.findIndex(
179
193
  (r) => r.id === lastSelectedRowId.current,
180
194
  );
195
+
181
196
  if (lastIndex !== -1) {
182
- const currentIndex = staticRowIndex + pageSize * pageIndex;
197
+ const isLastIndexChecked = getIsRowSelected({
198
+ row: rows?.[lastIndex],
199
+ table,
200
+ });
201
+
202
+ const currentIndex = staticRowIndex + paginationOffset;
183
203
  const [start, end] =
184
204
  lastIndex < currentIndex
185
205
  ? [lastIndex, currentIndex]
186
206
  : [currentIndex, lastIndex];
187
- for (let i = start; i <= end; i++) {
188
- rows[i].toggleSelected(!isChecked);
207
+
208
+ // toggle selection of all rows between last selected and this one
209
+ // but only if the last selected row is not the same as the current one
210
+ if (wasCurrentRowChecked !== isLastIndexChecked) {
211
+ for (let i = start; i <= end; i++) {
212
+ rows[i].toggleSelected(!wasCurrentRowChecked);
213
+ changedRowIds.add(rows[i].id);
214
+ }
189
215
  }
190
216
  }
191
217
  }
218
+
219
+ // record the last selected row id
192
220
  lastSelectedRowId.current = row.id;
193
221
 
194
222
  // if all sub rows were selected, unselect them
@@ -196,13 +224,36 @@ export const getMRT_RowSelectionHandler =
196
224
  row.subRows?.forEach((r) => r.toggleSelected(false));
197
225
  }
198
226
 
199
- if (isStickySelection) {
200
- row.pin(
201
- !row.getIsPinned() && isChecked
202
- ? rowPinningDisplayMode?.includes('bottom')
203
- ? 'bottom'
204
- : 'top'
205
- : false,
206
- );
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: [] });
207
257
  }
258
+ lastSelectedRowId.current = null;
208
259
  };