material-react-table 2.13.2 → 3.0.0-beta.0

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,8 +1,8 @@
1
1
  {
2
- "version": "2.13.2",
2
+ "version": "3.0.0-beta.0",
3
3
  "license": "MIT",
4
4
  "name": "material-react-table",
5
- "description": "A fully featured Material UI V5 implementation of TanStack React Table V8, written from the ground up in TypeScript.",
5
+ "description": "A fully featured Material UI V6 implementation of TanStack React Table V8, written from the ground up in TypeScript.",
6
6
  "author": "KevinVandy",
7
7
  "keywords": [
8
8
  "react-table",
@@ -65,9 +65,9 @@
65
65
  "@emotion/react": "^11.13.3",
66
66
  "@emotion/styled": "^11.13.0",
67
67
  "@faker-js/faker": "^8.4.1",
68
- "@mui/icons-material": "^5.16.5",
69
- "@mui/material": "^5.16.5",
70
- "@mui/x-date-pickers": "^7.11.1",
68
+ "@mui/icons-material": "^6.0.1",
69
+ "@mui/material": "^6.0.1",
70
+ "@mui/x-date-pickers": "^7.15.0",
71
71
  "@rollup/plugin-typescript": "^11.1.6",
72
72
  "@size-limit/preset-small-lib": "^11.1.4",
73
73
  "@storybook/addon-a11y": "^8.2.9",
@@ -105,11 +105,11 @@
105
105
  "vite": "^5.4.2"
106
106
  },
107
107
  "peerDependencies": {
108
- "@emotion/react": ">=11.11",
109
- "@emotion/styled": ">=11.11",
110
- "@mui/icons-material": ">=5.11",
111
- "@mui/material": ">=5.13",
112
- "@mui/x-date-pickers": ">=6.15.0",
108
+ "@emotion/react": ">=11.13",
109
+ "@emotion/styled": ">=11.13",
110
+ "@mui/icons-material": ">=6",
111
+ "@mui/material": ">=6",
112
+ "@mui/x-date-pickers": ">=7.15",
113
113
  "react": ">=17.0",
114
114
  "react-dom": ">=17.0"
115
115
  },
@@ -16,7 +16,11 @@ import {
16
16
  type MRT_RowData,
17
17
  type MRT_TableInstance,
18
18
  } from '../../types';
19
- import { isCellEditable, openEditingCell } from '../../utils/cell.utils';
19
+ import {
20
+ isCellEditable,
21
+ cellNavigation,
22
+ openEditingCell,
23
+ } from '../../utils/cell.utils';
20
24
  import { getCommonMRTCellStyles } from '../../utils/style.utils';
21
25
  import { parseFromValuesOrFunc } from '../../utils/utils';
22
26
  import { MRT_CopyButton } from '../buttons/MRT_CopyButton';
@@ -54,6 +58,7 @@ export const MRT_TableBodyCell = <TData extends MRT_RowData>({
54
58
  enableColumnOrdering,
55
59
  enableColumnPinning,
56
60
  enableGrouping,
61
+ enableCellNavigation,
57
62
  layoutMode,
58
63
  mrtTheme: { draggingBorderColor },
59
64
  muiSkeletonProps,
@@ -227,12 +232,21 @@ export const MRT_TableBodyCell = <TData extends MRT_RowData>({
227
232
  }
228
233
  };
229
234
 
235
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLTableCellElement>) => {
236
+ if (enableCellNavigation) {
237
+ cellNavigation(e);
238
+ }
239
+ tableCellProps?.onKeyDown?.(e);
240
+ };
241
+
230
242
  return (
231
243
  <TableCell
232
244
  align={theme.direction === 'rtl' ? 'right' : 'left'}
233
245
  data-index={staticColumnIndex}
234
246
  data-pinned={!!isColumnPinned || undefined}
247
+ tabIndex={enableCellNavigation ? 0 : undefined}
235
248
  {...tableCellProps}
249
+ onKeyDown={handleKeyDown}
236
250
  onContextMenu={handleContextMenu}
237
251
  onDoubleClick={handleDoubleClick}
238
252
  onDragEnter={handleDragEnter}
@@ -248,6 +248,7 @@ export const MRT_TableBodyRow = <TData extends MRT_RowData>({
248
248
  staticRowIndex,
249
249
  table,
250
250
  };
251
+ const key = `${cell.id}-${staticRowIndex}`;
251
252
  return cell ? (
252
253
  memoMode === 'cells' &&
253
254
  cell.column.columnDef.columnDefType === 'data' &&
@@ -255,9 +256,9 @@ export const MRT_TableBodyRow = <TData extends MRT_RowData>({
255
256
  !draggingRow &&
256
257
  editingCell?.id !== cell.id &&
257
258
  editingRow?.id !== row.id ? (
258
- <Memo_MRT_TableBodyCell key={cell.id} {...props} />
259
+ <Memo_MRT_TableBodyCell key={key} {...props} />
259
260
  ) : (
260
- <MRT_TableBodyCell key={cell.id} {...props} />
261
+ <MRT_TableBodyCell key={key} {...props} />
261
262
  )
262
263
  ) : null;
263
264
  },
@@ -94,7 +94,11 @@ export const MRT_ToggleRowActionMenuButton = <TData extends MRT_RowData>({
94
94
  <EditIcon />
95
95
  </IconButton>
96
96
  </Tooltip>
97
- ) : renderRowActionMenuItems ? (
97
+ ) : renderRowActionMenuItems?.({
98
+ row,
99
+ staticRowIndex,
100
+ table,
101
+ } as any)?.length ? (
98
102
  <>
99
103
  <Tooltip {...getCommonTooltipProps()} title={localization.rowActions}>
100
104
  <IconButton
@@ -19,7 +19,6 @@ export const MRT_TableFooter = <TData extends MRT_RowData>({
19
19
  ...rest
20
20
  }: MRT_TableFooterProps<TData>) => {
21
21
  const {
22
- getFooterGroups,
23
22
  getState,
24
23
  options: { enableStickyFooter, layoutMode, muiTableFooterProps },
25
24
  refs: { tableFooterRef },
@@ -36,6 +35,22 @@ export const MRT_TableFooter = <TData extends MRT_RowData>({
36
35
  const stickFooter =
37
36
  (isFullScreen || enableStickyFooter) && enableStickyFooter !== false;
38
37
 
38
+ const footerGroups = table.getFooterGroups();
39
+
40
+ //if no footer cells at all, skip footer
41
+ if (
42
+ !footerGroups.some((footerGroup) =>
43
+ footerGroup.headers?.some(
44
+ (header) =>
45
+ (typeof header.column.columnDef.footer === 'string' &&
46
+ !!header.column.columnDef.footer) ||
47
+ header.column.columnDef.Footer,
48
+ ),
49
+ )
50
+ ) {
51
+ return null;
52
+ }
53
+
39
54
  return (
40
55
  <TableFooter
41
56
  {...tableFooterProps}
@@ -60,7 +75,7 @@ export const MRT_TableFooter = <TData extends MRT_RowData>({
60
75
  ...(parseFromValuesOrFunc(tableFooterProps?.sx, theme) as any),
61
76
  })}
62
77
  >
63
- {getFooterGroups().map((footerGroup) => (
78
+ {footerGroups.map((footerGroup) => (
64
79
  <MRT_TableFooterRow
65
80
  columnVirtualizer={columnVirtualizer}
66
81
  footerGroup={footerGroup as any}
@@ -7,6 +7,7 @@ import {
7
7
  } from '../../types';
8
8
  import { getCommonMRTCellStyles } from '../../utils/style.utils';
9
9
  import { parseFromValuesOrFunc } from '../../utils/utils';
10
+ import { cellNavigation } from '../../utils/cell.utils';
10
11
 
11
12
  export interface MRT_TableFooterCellProps<TData extends MRT_RowData>
12
13
  extends TableCellProps {
@@ -24,7 +25,11 @@ export const MRT_TableFooterCell = <TData extends MRT_RowData>({
24
25
  const theme = useTheme();
25
26
  const {
26
27
  getState,
27
- options: { enableColumnPinning, muiTableFooterCellProps },
28
+ options: {
29
+ enableColumnPinning,
30
+ muiTableFooterCellProps,
31
+ enableCellNavigation,
32
+ },
28
33
  } = table;
29
34
  const { density } = getState();
30
35
  const { column } = footer;
@@ -43,6 +48,13 @@ export const MRT_TableFooterCell = <TData extends MRT_RowData>({
43
48
  ...rest,
44
49
  };
45
50
 
51
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLTableCellElement>) => {
52
+ if (enableCellNavigation) {
53
+ cellNavigation(e);
54
+ }
55
+ tableCellProps?.onKeyDown?.(e);
56
+ };
57
+
46
58
  return (
47
59
  <TableCell
48
60
  align={
@@ -57,6 +69,7 @@ export const MRT_TableFooterCell = <TData extends MRT_RowData>({
57
69
  data-pinned={!!isColumnPinned || undefined}
58
70
  variant="footer"
59
71
  {...tableCellProps}
72
+ onKeyDown={handleKeyDown}
60
73
  sx={(theme) => ({
61
74
  fontWeight: 'bold',
62
75
  p:
@@ -17,6 +17,7 @@ import {
17
17
  } from '../../types';
18
18
  import { getCommonMRTCellStyles } from '../../utils/style.utils';
19
19
  import { parseFromValuesOrFunc } from '../../utils/utils';
20
+ import { cellNavigation } from '../../utils/cell.utils';
20
21
 
21
22
  export interface MRT_TableHeadCellProps<TData extends MRT_RowData>
22
23
  extends TableCellProps {
@@ -45,6 +46,7 @@ export const MRT_TableHeadCell = <TData extends MRT_RowData>({
45
46
  enableColumnOrdering,
46
47
  enableColumnPinning,
47
48
  enableGrouping,
49
+ enableCellNavigation,
48
50
  enableMultiSort,
49
51
  layoutMode,
50
52
  mrtTheme: { draggingBorderColor },
@@ -147,6 +149,13 @@ export const MRT_TableHeadCell = <TData extends MRT_RowData>({
147
149
  }
148
150
  };
149
151
 
152
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLTableCellElement>) => {
153
+ if (enableCellNavigation) {
154
+ cellNavigation(e);
155
+ }
156
+ tableCellProps?.onKeyDown?.(e);
157
+ };
158
+
150
159
  const HeaderElement =
151
160
  parseFromValuesOrFunc(columnDef.Header, {
152
161
  column,
@@ -185,7 +194,9 @@ export const MRT_TableHeadCell = <TData extends MRT_RowData>({
185
194
  }
186
195
  }
187
196
  }}
197
+ tabIndex={enableCellNavigation ? 0 : undefined}
188
198
  {...tableCellProps}
199
+ onKeyDown={handleKeyDown}
189
200
  sx={(theme: Theme) => ({
190
201
  '& :hover': {
191
202
  '.MuiButtonBase-root': {
@@ -1,4 +1,4 @@
1
- import { type MouseEvent } from 'react';
1
+ import { ReactNode, useMemo, type MouseEvent } from 'react';
2
2
  import Menu, { type MenuProps } from '@mui/material/Menu';
3
3
  import { MRT_ActionMenuItem } from './MRT_ActionMenuItem';
4
4
  import {
@@ -40,6 +40,30 @@ export const MRT_RowActionMenu = <TData extends MRT_RowData>({
40
40
  } = table;
41
41
  const { density } = getState();
42
42
 
43
+ const menuItems = useMemo(() => {
44
+ const items: ReactNode[] = [];
45
+ const editItem = parseFromValuesOrFunc(enableEditing, row) &&
46
+ ['modal', 'row'].includes(editDisplayMode!) && (
47
+ <MRT_ActionMenuItem
48
+ icon={<EditIcon />}
49
+ label={localization.edit}
50
+ onClick={handleEdit}
51
+ table={table}
52
+ />
53
+ );
54
+ if (editItem) items.push(editItem);
55
+ const rowActionMenuItems = renderRowActionMenuItems?.({
56
+ closeMenu: () => setAnchorEl(null),
57
+ row,
58
+ staticRowIndex,
59
+ table,
60
+ });
61
+ if (rowActionMenuItems?.length) items.push(...rowActionMenuItems);
62
+ return items;
63
+ }, [renderRowActionMenuItems, row, staticRowIndex, table]);
64
+
65
+ if (!menuItems.length) return null;
66
+
43
67
  return (
44
68
  <Menu
45
69
  MenuListProps={{
@@ -55,21 +79,7 @@ export const MRT_RowActionMenu = <TData extends MRT_RowData>({
55
79
  open={!!anchorEl}
56
80
  {...rest}
57
81
  >
58
- {parseFromValuesOrFunc(enableEditing, row) &&
59
- ['modal', 'row'].includes(editDisplayMode!) && (
60
- <MRT_ActionMenuItem
61
- icon={<EditIcon />}
62
- label={localization.edit}
63
- onClick={handleEdit}
64
- table={table}
65
- />
66
- )}
67
- {renderRowActionMenuItems?.({
68
- closeMenu: () => setAnchorEl(null),
69
- row,
70
- staticRowIndex,
71
- table,
72
- })}
82
+ {menuItems}
73
83
  </Menu>
74
84
  );
75
85
  };
@@ -11,10 +11,14 @@ const fuzzy = <TData extends MRT_RowData>(
11
11
  columnId: string,
12
12
  filterValue: number | string,
13
13
  addMeta: (item: RankingInfo) => void,
14
- ) => {
15
- const itemRank = rankItem(row.getValue(columnId), filterValue as string, {
16
- threshold: rankings.MATCHES,
17
- });
14
+ ): boolean => {
15
+ const itemRank = rankItem(
16
+ row.getValue<string | number | null>(columnId),
17
+ filterValue as string,
18
+ {
19
+ threshold: rankings.MATCHES,
20
+ },
21
+ );
18
22
  addMeta(itemRank);
19
23
  return itemRank.passed;
20
24
  };
@@ -25,10 +29,10 @@ const contains = <TData extends MRT_RowData>(
25
29
  row: Row<TData>,
26
30
  id: string,
27
31
  filterValue: number | string,
28
- ) =>
29
- row
30
- .getValue<number | string>(id)
31
- .toString()
32
+ ): boolean =>
33
+ !!row
34
+ .getValue<number | string | null>(id)
35
+ ?.toString()
32
36
  .toLowerCase()
33
37
  .trim()
34
38
  .includes(filterValue.toString().toLowerCase().trim());
@@ -39,10 +43,10 @@ const startsWith = <TData extends MRT_RowData>(
39
43
  row: Row<TData>,
40
44
  id: string,
41
45
  filterValue: number | string,
42
- ) =>
43
- row
44
- .getValue<number | string>(id)
45
- .toString()
46
+ ): boolean =>
47
+ !!row
48
+ .getValue<number | string | null>(id)
49
+ ?.toString()
46
50
  .toLowerCase()
47
51
  .trim()
48
52
  .startsWith(filterValue.toString().toLowerCase().trim());
@@ -53,10 +57,10 @@ const endsWith = <TData extends MRT_RowData>(
53
57
  row: Row<TData>,
54
58
  id: string,
55
59
  filterValue: number | string,
56
- ) =>
57
- row
58
- .getValue<number | string>(id)
59
- .toString()
60
+ ): boolean =>
61
+ !!row
62
+ .getValue<number | string | null>(id)
63
+ ?.toString()
60
64
  .toLowerCase()
61
65
  .trim()
62
66
  .endsWith(filterValue.toString().toLowerCase().trim());
@@ -67,9 +71,9 @@ const equals = <TData extends MRT_RowData>(
67
71
  row: Row<TData>,
68
72
  id: string,
69
73
  filterValue: number | string,
70
- ) =>
71
- row.getValue<number | string>(id).toString().toLowerCase().trim() ===
72
- filterValue?.toString().toLowerCase().trim();
74
+ ): boolean =>
75
+ row.getValue<number | string | null>(id)?.toString().toLowerCase().trim() ===
76
+ filterValue.toString().toLowerCase().trim();
73
77
 
74
78
  equals.autoRemove = (val: any) => !val;
75
79
 
@@ -77,8 +81,8 @@ const notEquals = <TData extends MRT_RowData>(
77
81
  row: Row<TData>,
78
82
  id: string,
79
83
  filterValue: number | string,
80
- ) =>
81
- row.getValue<number | string>(id).toString().toLowerCase().trim() !==
84
+ ): boolean =>
85
+ row.getValue<number | string | null>(id)?.toString().toLowerCase().trim() !==
82
86
  filterValue.toString().toLowerCase().trim();
83
87
 
84
88
  notEquals.autoRemove = (val: any) => !val;
@@ -87,11 +91,13 @@ const greaterThan = <TData extends MRT_RowData>(
87
91
  row: Row<TData>,
88
92
  id: string,
89
93
  filterValue: number | string,
90
- ) =>
94
+ ): boolean =>
91
95
  !isNaN(+filterValue) && !isNaN(+row.getValue<number | string>(id))
92
- ? +row.getValue<number | string>(id) > +filterValue
93
- : row.getValue<number | string>(id).toString().toLowerCase().trim() >
94
- filterValue?.toString().toLowerCase().trim();
96
+ ? +(row.getValue<number | string | null>(id) ?? 0) > +filterValue
97
+ : (row.getValue<number | string | null>(id) ?? '')
98
+ ?.toString()
99
+ .toLowerCase()
100
+ .trim() > filterValue.toString().toLowerCase().trim();
95
101
 
96
102
  greaterThan.autoRemove = (val: any) => !val;
97
103
 
@@ -99,7 +105,7 @@ const greaterThanOrEqualTo = <TData extends MRT_RowData>(
99
105
  row: Row<TData>,
100
106
  id: string,
101
107
  filterValue: number | string,
102
- ) => equals(row, id, filterValue) || greaterThan(row, id, filterValue);
108
+ ): boolean => equals(row, id, filterValue) || greaterThan(row, id, filterValue);
103
109
 
104
110
  greaterThanOrEqualTo.autoRemove = (val: any) => !val;
105
111
 
@@ -107,11 +113,13 @@ const lessThan = <TData extends MRT_RowData>(
107
113
  row: Row<TData>,
108
114
  id: string,
109
115
  filterValue: number | string,
110
- ) =>
116
+ ): boolean =>
111
117
  !isNaN(+filterValue) && !isNaN(+row.getValue<number | string>(id))
112
- ? +row.getValue<number | string>(id) < +filterValue
113
- : row.getValue<number | string>(id).toString().toLowerCase().trim() <
114
- filterValue?.toString().toLowerCase().trim();
118
+ ? +(row.getValue<number | string | null>(id) ?? 0) < +filterValue
119
+ : (row.getValue<number | string | null>(id) ?? '')
120
+ ?.toString()
121
+ .toLowerCase()
122
+ .trim() < filterValue.toString().toLowerCase().trim();
115
123
 
116
124
  lessThan.autoRemove = (val: any) => !val;
117
125
 
@@ -119,7 +127,7 @@ const lessThanOrEqualTo = <TData extends MRT_RowData>(
119
127
  row: Row<TData>,
120
128
  id: string,
121
129
  filterValue: number | string,
122
- ) => equals(row, id, filterValue) || lessThan(row, id, filterValue);
130
+ ): boolean => equals(row, id, filterValue) || lessThan(row, id, filterValue);
123
131
 
124
132
  lessThanOrEqualTo.autoRemove = (val: any) => !val;
125
133
 
@@ -127,7 +135,7 @@ const between = <TData extends MRT_RowData>(
127
135
  row: Row<TData>,
128
136
  id: string,
129
137
  filterValues: [number | string, number | string],
130
- ) =>
138
+ ): boolean =>
131
139
  ((['', undefined] as any[]).includes(filterValues[0]) ||
132
140
  greaterThan(row, id, filterValues[0])) &&
133
141
  ((!isNaN(+filterValues[0]) &&
@@ -142,7 +150,7 @@ const betweenInclusive = <TData extends MRT_RowData>(
142
150
  row: Row<TData>,
143
151
  id: string,
144
152
  filterValues: [number | string, number | string],
145
- ) =>
153
+ ): boolean =>
146
154
  ((['', undefined] as any[]).includes(filterValues[0]) ||
147
155
  greaterThanOrEqualTo(row, id, filterValues[0])) &&
148
156
  ((!isNaN(+filterValues[0]) &&
@@ -157,7 +165,7 @@ const empty = <TData extends MRT_RowData>(
157
165
  row: Row<TData>,
158
166
  id: string,
159
167
  _filterValue: number | string,
160
- ) => !row.getValue<number | string>(id).toString().trim();
168
+ ): boolean => !row.getValue<number | string | null>(id)?.toString().trim();
161
169
 
162
170
  empty.autoRemove = (val: any) => !val;
163
171
 
@@ -165,7 +173,7 @@ const notEmpty = <TData extends MRT_RowData>(
165
173
  row: Row<TData>,
166
174
  id: string,
167
175
  _filterValue: number | string,
168
- ) => !!row.getValue<number | string>(id).toString().trim();
176
+ ): boolean => !!row.getValue<number | string | null>(id)?.toString().trim();
169
177
 
170
178
  notEmpty.autoRemove = (val: any) => !val;
171
179
 
@@ -76,6 +76,7 @@ export const useMRT_TableOptions: <TData extends MRT_RowData>(
76
76
  enableGlobalFilterRankedResults = true,
77
77
  enableGrouping = false,
78
78
  enableHiding = true,
79
+ enableCellNavigation = true,
79
80
  enableMultiRowSelection = true,
80
81
  enableMultiSort = true,
81
82
  enablePagination = true,
@@ -203,6 +204,7 @@ export const useMRT_TableOptions: <TData extends MRT_RowData>(
203
204
  enableGlobalFilterRankedResults,
204
205
  enableGrouping,
205
206
  enableHiding,
207
+ enableCellNavigation,
206
208
  enableMultiRowSelection,
207
209
  enableMultiSort,
208
210
  enablePagination,