material-react-table 0.7.2 → 0.7.5

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.
@@ -1,7 +1,7 @@
1
1
  import React, { FC, useMemo } from 'react';
2
2
  import { Menu, MenuItem } from '@mui/material';
3
- import type { MRT_FilterType, MRT_Header, MRT_TableInstance } from '..';
4
- import { MRT_FILTER_TYPE } from '../enums';
3
+ import type { MRT_FilterFn, MRT_Header, MRT_TableInstance } from '..';
4
+ import { MRT_FILTER_OPTION } from '../enums';
5
5
  import {
6
6
  bestMatch,
7
7
  bestMatchFirst,
@@ -30,7 +30,7 @@ interface Props {
30
30
  tableInstance: MRT_TableInstance;
31
31
  }
32
32
 
33
- export const MRT_FilterTypeMenu: FC<Props> = ({
33
+ export const MRT_FilterOptionMenu: FC<Props> = ({
34
34
  anchorEl,
35
35
  header,
36
36
  onSelect,
@@ -39,16 +39,16 @@ export const MRT_FilterTypeMenu: FC<Props> = ({
39
39
  }) => {
40
40
  const {
41
41
  getState,
42
- options: { enabledGlobalFilterTypes, localization },
43
- setCurrentFilterTypes,
44
- setCurrentGlobalFilterType,
42
+ options: { enabledGlobalFilterOptions, localization },
43
+ setCurrentFilterFns,
44
+ setCurrentGlobalFilterFn,
45
45
  } = tableInstance;
46
46
 
47
- const { isDensePadding, currentFilterTypes, currentGlobalFilterType } =
47
+ const { isDensePadding, currentFilterFns, currentGlobalFilterFn } =
48
48
  getState();
49
49
 
50
- const filterTypes: {
51
- type: MRT_FILTER_TYPE;
50
+ const filterOptions: {
51
+ type: MRT_FILTER_OPTION;
52
52
  label: string;
53
53
  divider: boolean;
54
54
  fn: Function;
@@ -56,104 +56,106 @@ export const MRT_FilterTypeMenu: FC<Props> = ({
56
56
  () =>
57
57
  [
58
58
  {
59
- type: MRT_FILTER_TYPE.BEST_MATCH_FIRST,
59
+ type: MRT_FILTER_OPTION.BEST_MATCH_FIRST,
60
60
  label: localization.filterBestMatchFirst,
61
61
  divider: false,
62
62
  fn: bestMatchFirst,
63
63
  },
64
64
  {
65
- type: MRT_FILTER_TYPE.BEST_MATCH,
65
+ type: MRT_FILTER_OPTION.BEST_MATCH,
66
66
  label: localization.filterBestMatch,
67
67
  divider: !!header,
68
68
  fn: bestMatch,
69
69
  },
70
70
  {
71
- type: MRT_FILTER_TYPE.CONTAINS,
71
+ type: MRT_FILTER_OPTION.CONTAINS,
72
72
  label: localization.filterContains,
73
73
  divider: false,
74
74
  fn: contains,
75
75
  },
76
76
  {
77
- type: MRT_FILTER_TYPE.STARTS_WITH,
77
+ type: MRT_FILTER_OPTION.STARTS_WITH,
78
78
  label: localization.filterStartsWith,
79
79
  divider: false,
80
80
  fn: startsWith,
81
81
  },
82
82
  {
83
- type: MRT_FILTER_TYPE.ENDS_WITH,
83
+ type: MRT_FILTER_OPTION.ENDS_WITH,
84
84
  label: localization.filterEndsWith,
85
85
  divider: true,
86
86
  fn: endsWith,
87
87
  },
88
88
  {
89
- type: MRT_FILTER_TYPE.EQUALS,
89
+ type: MRT_FILTER_OPTION.EQUALS,
90
90
  label: localization.filterEquals,
91
91
  divider: false,
92
92
  fn: equals,
93
93
  },
94
94
  {
95
- type: MRT_FILTER_TYPE.NOT_EQUALS,
95
+ type: MRT_FILTER_OPTION.NOT_EQUALS,
96
96
  label: localization.filterNotEquals,
97
97
  divider: true,
98
98
  fn: notEquals,
99
99
  },
100
100
  {
101
- type: MRT_FILTER_TYPE.GREATER_THAN,
101
+ type: MRT_FILTER_OPTION.GREATER_THAN,
102
102
  label: localization.filterGreaterThan,
103
103
  divider: false,
104
104
  fn: greaterThan,
105
105
  },
106
106
  {
107
- type: MRT_FILTER_TYPE.LESS_THAN,
107
+ type: MRT_FILTER_OPTION.LESS_THAN,
108
108
  label: localization.filterLessThan,
109
109
  divider: true,
110
110
  fn: lessThan,
111
111
  },
112
112
  {
113
- type: MRT_FILTER_TYPE.EMPTY,
113
+ type: MRT_FILTER_OPTION.EMPTY,
114
114
  label: localization.filterEmpty,
115
115
  divider: false,
116
116
  fn: empty,
117
117
  },
118
118
  {
119
- type: MRT_FILTER_TYPE.NOT_EMPTY,
119
+ type: MRT_FILTER_OPTION.NOT_EMPTY,
120
120
  label: localization.filterNotEmpty,
121
121
  divider: false,
122
122
  fn: notEmpty,
123
123
  },
124
124
  ].filter((filterType) =>
125
125
  header
126
- ? !header.column.enabledColumnFilterTypes ||
127
- header.column.enabledColumnFilterTypes.includes(filterType.type)
128
- : (!enabledGlobalFilterTypes ||
129
- enabledGlobalFilterTypes.includes(filterType.type)) &&
126
+ ? !header.column.enabledColumnFilterOptions ||
127
+ header.column.enabledColumnFilterOptions.includes(filterType.type)
128
+ : (!enabledGlobalFilterOptions ||
129
+ enabledGlobalFilterOptions.includes(filterType.type)) &&
130
130
  [
131
- MRT_FILTER_TYPE.BEST_MATCH_FIRST,
132
- MRT_FILTER_TYPE.BEST_MATCH,
131
+ MRT_FILTER_OPTION.BEST_MATCH_FIRST,
132
+ MRT_FILTER_OPTION.BEST_MATCH,
133
133
  ].includes(filterType.type),
134
134
  ),
135
135
  [],
136
136
  );
137
137
 
138
- const handleSelectFilterType = (value: MRT_FILTER_TYPE) => {
138
+ const handleSelectFilterType = (value: MRT_FILTER_OPTION) => {
139
139
  if (header) {
140
- setCurrentFilterTypes((prev: { [key: string]: MRT_FilterType }) => ({
140
+ setCurrentFilterFns((prev: { [key: string]: MRT_FilterFn }) => ({
141
141
  ...prev,
142
142
  [header.id]: value,
143
143
  }));
144
- if ([MRT_FILTER_TYPE.EMPTY, MRT_FILTER_TYPE.NOT_EMPTY].includes(value)) {
144
+ if (
145
+ [MRT_FILTER_OPTION.EMPTY, MRT_FILTER_OPTION.NOT_EMPTY].includes(value)
146
+ ) {
145
147
  header.column.setColumnFilterValue(' ');
146
148
  }
147
149
  } else {
148
- setCurrentGlobalFilterType(value);
150
+ setCurrentGlobalFilterFn(value);
149
151
  }
150
152
  setAnchorEl(null);
151
153
  onSelect?.();
152
154
  };
153
155
 
154
156
  const filterType = !!header
155
- ? currentFilterTypes[header.id]
156
- : currentGlobalFilterType;
157
+ ? currentFilterFns[header.id]
158
+ : currentGlobalFilterFn;
157
159
 
158
160
  return (
159
161
  <Menu
@@ -165,7 +167,7 @@ export const MRT_FilterTypeMenu: FC<Props> = ({
165
167
  dense: isDensePadding,
166
168
  }}
167
169
  >
168
- {filterTypes.map(({ type, label, divider, fn }, index) => (
170
+ {filterOptions.map(({ type, label, divider, fn }, index) => (
169
171
  <MenuItem
170
172
  divider={divider}
171
173
  key={index}
@@ -13,8 +13,16 @@ import {
13
13
  useTableInstance,
14
14
  getCoreRowModelSync,
15
15
  ColumnDef,
16
+ FilterFn,
16
17
  } from '@tanstack/react-table';
17
- import { MRT_ColumnDef, MRT_FilterType, MRT_Row, MRT_TableInstance } from '..';
18
+ import {
19
+ MRT_Cell,
20
+ MRT_ColumnDef,
21
+ MRT_FilterFn,
22
+ MRT_Row,
23
+ MRT_TableInstance,
24
+ MRT_TableState,
25
+ } from '..';
18
26
  import { MRT_ExpandAllButton } from '../buttons/MRT_ExpandAllButton';
19
27
  import { MRT_ExpandButton } from '../buttons/MRT_ExpandButton';
20
28
  import { MRT_ToggleRowActionMenuButton } from '../buttons/MRT_ToggleRowActionMenuButton';
@@ -28,7 +36,7 @@ import {
28
36
  getAllLeafColumnDefs,
29
37
  } from '../utils';
30
38
  import { defaultFilterFNs } from '../filtersFNs';
31
- import { MRT_FILTER_TYPE } from '../enums';
39
+ import { MRT_FILTER_OPTION } from '../enums';
32
40
  import { Box, Dialog, Grow } from '@mui/material';
33
41
 
34
42
  export const MRT_TableRoot = <D extends Record<string, any> = {}>(
@@ -41,53 +49,83 @@ export const MRT_TableRoot = <D extends Record<string, any> = {}>(
41
49
  [props.idPrefix],
42
50
  );
43
51
 
44
- const [currentEditingRow, setCurrentEditingRow] = useState<MRT_Row | null>(
45
- null,
52
+ const initialState: Partial<MRT_TableState<D>> = useMemo(() => {
53
+ if (!props.enablePersistentState || !props.idPrefix) {
54
+ return props.initialState;
55
+ }
56
+ if (typeof window === 'undefined') {
57
+ if (process.env.NODE_ENV !== 'production') {
58
+ console.error(
59
+ 'The MRT Persistent Table State feature is not supported if using SSR, but you can wrap your <MaterialReactTable /> in a MUI <NoSsr> tags to let it work',
60
+ );
61
+ }
62
+ return props.initialState;
63
+ }
64
+ const storedState =
65
+ props.persistentStateMode === 'localStorage'
66
+ ? localStorage.getItem(`mrt-${idPrefix}-table-state`)
67
+ : props.persistentStateMode === 'sessionStorage'
68
+ ? sessionStorage.getItem(`mrt-${idPrefix}-table-state`)
69
+ : '{}';
70
+ if (storedState) {
71
+ const parsedState = JSON.parse(storedState);
72
+ if (parsedState) {
73
+ return { ...props.initialState, ...parsedState };
74
+ }
75
+ }
76
+ return props.initialState;
77
+ }, []);
78
+
79
+ const [currentEditingCell, setCurrentEditingCell] =
80
+ useState<MRT_Cell<D> | null>(initialState?.currentEditingCell ?? null);
81
+ const [currentEditingRow, setCurrentEditingRow] = useState<MRT_Row<D> | null>(
82
+ initialState?.currentEditingRow ?? null,
46
83
  );
47
84
  const [isDensePadding, setIsDensePadding] = useState(
48
- props.initialState?.isDensePadding ?? false,
85
+ initialState?.isDensePadding ?? false,
49
86
  );
50
87
  const [isFullScreen, setIsFullScreen] = useState(
51
- props.initialState?.isFullScreen ?? false,
88
+ initialState?.isFullScreen ?? false,
52
89
  );
53
90
  const [showFilters, setShowFilters] = useState(
54
- props.initialState?.showFilters ?? false,
91
+ initialState?.showFilters ?? false,
55
92
  );
56
93
  const [showGlobalFilter, setShowGlobalFilter] = useState(
57
- props.initialState?.showGlobalFilter ?? false,
94
+ initialState?.showGlobalFilter ?? false,
58
95
  );
59
96
  const [pagination, setPagination] = useState<PaginationState>({
60
- pageIndex: props.initialState?.pagination?.pageIndex ?? 0,
61
- pageSize: props.initialState?.pagination?.pageSize ?? 10,
62
- pageCount: props.initialState?.pagination?.pageCount ?? -1,
97
+ pageIndex: initialState?.pagination?.pageIndex ?? 0,
98
+ pageSize: initialState?.pagination?.pageSize ?? 10,
99
+ pageCount: initialState?.pagination?.pageCount ?? -1,
63
100
  });
64
101
 
65
- const [currentFilterTypes, setCurrentFilterTypes] = useState<{
66
- [key: string]: MRT_FilterType;
102
+ const [currentFilterFns, setCurrentFilterFns] = useState<{
103
+ [key: string]: MRT_FilterFn;
67
104
  }>(() =>
68
105
  Object.assign(
69
106
  {},
70
107
  ...getAllLeafColumnDefs(props.columns as MRT_ColumnDef[]).map((c) => ({
71
108
  [c.id as string]:
72
- c.filter ??
73
- props?.initialState?.columnFilters?.find((cf) => cf.id === c.id) ??
109
+ c.filterFn ??
110
+ initialState?.currentFilterFns?.[c.id] ??
74
111
  (!!c.filterSelectOptions?.length
75
- ? MRT_FILTER_TYPE.EQUALS
76
- : MRT_FILTER_TYPE.BEST_MATCH),
112
+ ? MRT_FILTER_OPTION.EQUALS
113
+ : MRT_FILTER_OPTION.BEST_MATCH),
77
114
  })),
78
115
  ),
79
116
  );
80
117
 
81
- const [currentGlobalFilterType, setCurrentGlobalFilterType] = useState(
82
- props.globalFilterType ?? MRT_FILTER_TYPE.BEST_MATCH_FIRST,
83
- );
118
+ const [currentGlobalFilterFn, setCurrentGlobalFilterFn] = useState<
119
+ MRT_FILTER_OPTION | FilterFn<D> | string | number | symbol
120
+ >(props.globalFilterFn ?? MRT_FILTER_OPTION.BEST_MATCH_FIRST);
84
121
 
85
122
  const table = useMemo(() => createTable() as unknown as Table<D>, []);
86
123
 
87
124
  const displayColumns = useMemo(
88
125
  () =>
89
126
  [
90
- (props.enableRowActions || props.enableEditing) &&
127
+ (props.enableRowActions ||
128
+ (props.enableEditing && props.editingMode === 'row')) &&
91
129
  createDisplayColumn(table, {
92
130
  Cell: ({ cell }) => (
93
131
  <MRT_ToggleRowActionMenuButton
@@ -146,6 +184,7 @@ export const MRT_TableRoot = <D extends Record<string, any> = {}>(
146
184
  }),
147
185
  ].filter(Boolean),
148
186
  [
187
+ props.editingMode,
149
188
  props.enableEditing,
150
189
  props.enableExpandAll,
151
190
  props.enableExpanded,
@@ -165,11 +204,11 @@ export const MRT_TableRoot = <D extends Record<string, any> = {}>(
165
204
  ...displayColumns,
166
205
  ...props.columns.map((column) =>
167
206
  column.columns
168
- ? createGroup(table, column, currentFilterTypes)
169
- : createDataColumn(table, column, currentFilterTypes),
207
+ ? createGroup(table, column, currentFilterFns)
208
+ : createDataColumn(table, column, currentFilterFns),
170
209
  ),
171
210
  ] as ColumnDef<D>[]),
172
- [table, props.columns, currentFilterTypes],
211
+ [table, props.columns, currentFilterFns],
173
212
  );
174
213
 
175
214
  const data: D['Row'][] = useMemo(
@@ -193,7 +232,7 @@ export const MRT_TableRoot = <D extends Record<string, any> = {}>(
193
232
  const tableInstance: MRT_TableInstance<{}> = {
194
233
  ...useTableInstance(table, {
195
234
  //@ts-ignore
196
- filterTypes: defaultFilterFNs,
235
+ filterFns: defaultFilterFNs,
197
236
  getColumnFilteredRowModel: getColumnFilteredRowModelSync(),
198
237
  getCoreRowModel: getCoreRowModelSync(),
199
238
  getExpandedRowModel: getExpandedRowModel(),
@@ -202,17 +241,20 @@ export const MRT_TableRoot = <D extends Record<string, any> = {}>(
202
241
  getPaginationRowModel: getPaginationRowModel(),
203
242
  getSortedRowModel: getSortedRowModelSync(),
204
243
  getSubRows: (originalRow: D) => originalRow.subRows,
205
- globalFilterType: currentGlobalFilterType,
206
- idPrefix,
244
+ globalFilterFn: currentGlobalFilterFn,
207
245
  onPaginationChange: (updater: any) =>
208
246
  setPagination((old) => functionalUpdate(updater, old)),
209
247
  ...props,
210
248
  columns,
211
249
  data,
250
+ idPrefix,
251
+ //@ts-ignore
252
+ initialState,
212
253
  state: {
254
+ currentEditingCell,
213
255
  currentEditingRow,
214
- currentFilterTypes,
215
- currentGlobalFilterType,
256
+ currentFilterFns,
257
+ currentGlobalFilterFn,
216
258
  isDensePadding,
217
259
  isFullScreen,
218
260
  //@ts-ignore
@@ -222,32 +264,60 @@ export const MRT_TableRoot = <D extends Record<string, any> = {}>(
222
264
  ...props.state,
223
265
  },
224
266
  }),
267
+ //@ts-ignore
268
+ setCurrentEditingCell,
269
+ //@ts-ignore
225
270
  setCurrentEditingRow,
226
- setCurrentFilterTypes,
227
- setCurrentGlobalFilterType,
271
+ setCurrentFilterFns,
272
+ //@ts-ignore
273
+ setCurrentGlobalFilterFn,
228
274
  setIsDensePadding,
229
275
  setIsFullScreen,
230
276
  setShowFilters,
231
277
  setShowGlobalFilter,
232
278
  };
233
279
 
280
+ useEffect(() => {
281
+ if (typeof window === 'undefined' || !props.enablePersistentState) {
282
+ return;
283
+ }
284
+ if (!props.idPrefix && process.env.NODE_ENV !== 'production') {
285
+ console.warn(
286
+ 'a unique idPrefix prop is required for persistent table state to work',
287
+ );
288
+ return;
289
+ }
290
+ const itemArgs: [string, string] = [
291
+ `mrt-${idPrefix}-table-state`,
292
+ JSON.stringify(tableInstance.getState()),
293
+ ];
294
+ if (props.persistentStateMode === 'localStorage') {
295
+ localStorage.setItem(...itemArgs);
296
+ } else if (props.persistentStateMode === 'sessionStorage') {
297
+ sessionStorage.setItem(...itemArgs);
298
+ }
299
+ }, [
300
+ props.enablePersistentState,
301
+ props.idPrefix,
302
+ props.persistentStateMode,
303
+ tableInstance,
304
+ ]);
305
+
234
306
  return (
235
307
  <>
236
308
  <Dialog
237
- TransitionComponent={Grow}
238
309
  PaperComponent={Box}
310
+ TransitionComponent={Grow}
239
311
  disablePortal
240
312
  fullScreen
241
313
  keepMounted={false}
242
- onClose={() => tableInstance.setIsFullScreen(false)}
243
- open={tableInstance.getState().isFullScreen}
314
+ onClose={() => setIsFullScreen(false)}
315
+ open={isFullScreen}
244
316
  transitionDuration={400}
245
317
  >
246
318
  <MRT_TablePaper tableInstance={tableInstance} />
247
319
  </Dialog>
248
- {!tableInstance.getState().isFullScreen && (
249
- <MRT_TablePaper tableInstance={tableInstance} />
250
- )}
320
+ {!isFullScreen && <MRT_TablePaper tableInstance={tableInstance} />}
251
321
  </>
252
322
  );
253
323
  };
package/src/utils.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ColumnDef, Table } from '@tanstack/react-table';
2
- import { MRT_ColumnDef, MRT_FilterType } from '.';
3
- import { MRT_FILTER_TYPE } from './enums';
2
+ import { MRT_ColumnDef, MRT_FilterFn } from '.';
3
+ import { MRT_FILTER_OPTION } from './enums';
4
4
  import { defaultFilterFNs } from './filtersFNs';
5
5
 
6
6
  export const getAllLeafColumnDefs = (
@@ -24,31 +24,31 @@ export const getAllLeafColumnDefs = (
24
24
  export const createGroup = <D extends Record<string, any> = {}>(
25
25
  table: Table<D>,
26
26
  column: MRT_ColumnDef<D>,
27
- currentFilterTypes: { [key: string]: MRT_FilterType },
27
+ currentFilterFns: { [key: string]: MRT_FilterFn },
28
28
  ): ColumnDef<D> =>
29
29
  table.createGroup({
30
30
  ...column,
31
31
  columns: column?.columns?.map?.((col) =>
32
32
  col.columns
33
- ? createGroup<D>(table, col, currentFilterTypes)
34
- : createDataColumn(table, col, currentFilterTypes),
33
+ ? createGroup<D>(table, col, currentFilterFns)
34
+ : createDataColumn(table, col, currentFilterFns),
35
35
  ),
36
36
  } as any);
37
37
 
38
38
  export const createDataColumn = <D extends Record<string, any> = {}>(
39
39
  table: Table<D>,
40
40
  column: MRT_ColumnDef<D>,
41
- currentFilterTypes: { [key: string]: MRT_FilterType },
41
+ currentFilterFns: { [key: string]: MRT_FilterFn },
42
42
  ): ColumnDef<D> => // @ts-ignore
43
43
  table.createDataColumn(column.id, {
44
44
  filterFn:
45
- currentFilterTypes[column.id] instanceof Function
46
- ? currentFilterTypes[column.id]
47
- : defaultFilterFNs[currentFilterTypes[column.id] as MRT_FILTER_TYPE],
45
+ currentFilterFns[column.id] instanceof Function
46
+ ? currentFilterFns[column.id]
47
+ : defaultFilterFNs[currentFilterFns[column.id] as MRT_FILTER_OPTION],
48
48
  ...column,
49
49
  }) as any;
50
50
 
51
51
  export const createDisplayColumn = <D extends Record<string, any> = {}>(
52
52
  table: Table<D>,
53
53
  column: Omit<MRT_ColumnDef<D>, 'header'> & { header?: string },
54
- ): ColumnDef<D> => table.createDisplayColumn(column);
54
+ ): ColumnDef<D> => table.createDisplayColumn(column as ColumnDef<D>);