material-react-table 0.36.0 → 0.37.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.
Files changed (33) hide show
  1. package/README.md +1 -0
  2. package/dist/cjs/MaterialReactTable.d.ts +33 -15
  3. package/dist/cjs/body/MRT_EditRowModal.d.ts +8 -0
  4. package/dist/cjs/buttons/MRT_EditActionButtons.d.ts +5 -5
  5. package/dist/cjs/index.js +181 -108
  6. package/dist/cjs/index.js.map +1 -1
  7. package/dist/cjs/inputs/MRT_EditCellTextField.d.ts +5 -5
  8. package/dist/esm/MaterialReactTable.d.ts +33 -15
  9. package/dist/esm/body/MRT_EditRowModal.d.ts +8 -0
  10. package/dist/esm/buttons/MRT_EditActionButtons.d.ts +5 -5
  11. package/dist/esm/inputs/MRT_EditCellTextField.d.ts +5 -5
  12. package/dist/esm/material-react-table.esm.js +182 -109
  13. package/dist/esm/material-react-table.esm.js.map +1 -1
  14. package/dist/index.d.ts +33 -15
  15. package/package.json +1 -1
  16. package/src/MaterialReactTable.tsx +48 -12
  17. package/src/body/MRT_EditRowModal.tsx +59 -0
  18. package/src/body/MRT_TableBodyCell.tsx +22 -18
  19. package/src/body/MRT_TableBodyRow.tsx +1 -1
  20. package/src/body/MRT_TableBodyRowGrabHandle.tsx +3 -2
  21. package/src/buttons/MRT_CopyButton.tsx +2 -2
  22. package/src/buttons/MRT_EditActionButtons.tsx +49 -25
  23. package/src/buttons/MRT_ToggleGlobalFilterButton.tsx +3 -16
  24. package/src/buttons/MRT_ToggleRowActionMenuButton.tsx +2 -1
  25. package/src/column.utils.ts +6 -5
  26. package/src/inputs/MRT_EditCellTextField.tsx +33 -19
  27. package/src/inputs/MRT_FilterTextField.tsx +9 -6
  28. package/src/inputs/MRT_GlobalFilterTextField.tsx +7 -2
  29. package/src/menus/MRT_ColumnActionMenu.tsx +2 -12
  30. package/src/table/MRT_TableContainer.tsx +10 -10
  31. package/src/table/MRT_TableRoot.tsx +26 -18
  32. package/src/toolbar/MRT_BottomToolbar.tsx +8 -2
  33. package/src/toolbar/MRT_TopToolbar.tsx +8 -2
@@ -74,10 +74,9 @@ export const prepareColumns = <TData extends Record<string, any> = {}>(
74
74
  } else if (columnDef.columnDefType === 'data') {
75
75
  if (Object.keys(filterFns).includes(columnFilterFns[columnDef.id])) {
76
76
  columnDef.filterFn =
77
- // @ts-ignore
78
77
  filterFns[columnFilterFns[columnDef.id]] ?? filterFns.fuzzy;
79
- //@ts-ignore
80
- columnDef._filterFn = columnFilterFns[columnDef.id];
78
+ (columnDef as MRT_DefinedColumnDef)._filterFn =
79
+ columnFilterFns[columnDef.id];
81
80
  }
82
81
  if (Object.keys(sortingFns).includes(columnDef.sortingFn as string)) {
83
82
  // @ts-ignore
@@ -116,7 +115,8 @@ export const getLeadingDisplayColumnIds = <
116
115
  [
117
116
  (props.enableRowDragging || props.enableRowOrdering) && 'mrt-row-drag',
118
117
  ((props.positionActionsColumn === 'first' && props.enableRowActions) ||
119
- (props.enableEditing && props.editingMode === 'row')) &&
118
+ (props.enableEditing &&
119
+ ['row', 'modal'].includes(props.editingMode ?? ''))) &&
120
120
  'mrt-row-actions',
121
121
  props.positionExpandColumn === 'first' &&
122
122
  (props.enableExpanding ||
@@ -133,7 +133,8 @@ export const getTrailingDisplayColumnIds = <
133
133
  props: MaterialReactTableProps<TData>,
134
134
  ) => [
135
135
  ((props.positionActionsColumn === 'last' && props.enableRowActions) ||
136
- (props.enableEditing && props.editingMode === 'row')) &&
136
+ (props.enableEditing &&
137
+ ['row', 'modal'].includes(props.editingMode ?? ''))) &&
137
138
  'mrt-row-actions',
138
139
  props.positionExpandColumn === 'last' &&
139
140
  (props.enableExpanding ||
@@ -1,22 +1,22 @@
1
- import React, {
2
- ChangeEvent,
3
- FC,
4
- FocusEvent,
5
- MouseEvent,
6
- useState,
7
- } from 'react';
1
+ import React, { ChangeEvent, FocusEvent, MouseEvent, useState } from 'react';
8
2
  import { TextField, TextFieldProps } from '@mui/material';
9
- import type { MRT_Cell, MRT_Row, MRT_TableInstance } from '..';
3
+ import type { MRT_Cell, MRT_TableInstance } from '..';
10
4
 
11
- interface Props {
12
- cell: MRT_Cell;
13
- table: MRT_TableInstance;
5
+ interface Props<TData extends Record<string, any> = {}> {
6
+ cell: MRT_Cell<TData>;
7
+ table: MRT_TableInstance<TData>;
8
+ showLabel?: boolean;
14
9
  }
15
10
 
16
- export const MRT_EditCellTextField: FC<Props> = ({ cell, table }) => {
11
+ export const MRT_EditCellTextField = <TData extends Record<string, any> = {}>({
12
+ cell,
13
+ showLabel,
14
+ table,
15
+ }: Props<TData>) => {
17
16
  const {
18
17
  getState,
19
- options: { tableId, muiTableBodyCellEditTextFieldProps },
18
+ options: { muiTableBodyCellEditTextFieldProps },
19
+ refs: { editInputRefs },
20
20
  setEditingCell,
21
21
  setEditingRow,
22
22
  } = table;
@@ -28,13 +28,15 @@ export const MRT_EditCellTextField: FC<Props> = ({ cell, table }) => {
28
28
 
29
29
  const mTableBodyCellEditTextFieldProps =
30
30
  muiTableBodyCellEditTextFieldProps instanceof Function
31
- ? muiTableBodyCellEditTextFieldProps({ cell, table })
31
+ ? muiTableBodyCellEditTextFieldProps({ cell, column, row, table })
32
32
  : muiTableBodyCellEditTextFieldProps;
33
33
 
34
34
  const mcTableBodyCellEditTextFieldProps =
35
35
  columnDef.muiTableBodyCellEditTextFieldProps instanceof Function
36
36
  ? columnDef.muiTableBodyCellEditTextFieldProps({
37
37
  cell,
38
+ column,
39
+ row,
38
40
  table,
39
41
  })
40
42
  : columnDef.muiTableBodyCellEditTextFieldProps;
@@ -52,26 +54,38 @@ export const MRT_EditCellTextField: FC<Props> = ({ cell, table }) => {
52
54
  const handleBlur = (event: FocusEvent<HTMLInputElement>) => {
53
55
  textFieldProps.onBlur?.(event);
54
56
  if (editingRow) {
55
- if (!row._valuesCache) row._valuesCache = {};
56
- (row._valuesCache as Record<string, any>)[column.id] = value;
57
- setEditingRow({ ...editingRow } as MRT_Row);
57
+ setEditingRow({
58
+ ...editingRow,
59
+ _valuesCache: { ...editingRow._valuesCache, [column.id]: value },
60
+ } as any);
58
61
  }
59
62
  setEditingCell(null);
60
63
  };
61
64
 
62
65
  if (columnDef.Edit) {
63
- return <>{columnDef.Edit?.({ cell, column, table })}</>;
66
+ return <>{columnDef.Edit?.({ cell, column, row, table })}</>;
64
67
  }
65
68
 
66
69
  return (
67
70
  <TextField
68
- id={`mrt-${tableId}-edit-cell-text-field-${cell.id}`}
71
+ disabled={columnDef.enableEditing === false}
72
+ fullWidth
73
+ label={showLabel ? column.columnDef.header : undefined}
69
74
  margin="none"
75
+ name={cell.id}
70
76
  onClick={(e: MouseEvent<HTMLInputElement>) => e.stopPropagation()}
71
77
  placeholder={columnDef.header}
72
78
  value={value}
73
79
  variant="standard"
74
80
  {...textFieldProps}
81
+ inputRef={(inputRef) => {
82
+ if (inputRef) {
83
+ editInputRefs.current[column.id] = inputRef;
84
+ if (textFieldProps.inputRef) {
85
+ textFieldProps.inputRef = inputRef;
86
+ }
87
+ }
88
+ }}
75
89
  onBlur={handleBlur}
76
90
  onChange={handleChange}
77
91
  />
@@ -40,8 +40,8 @@ export const MRT_FilterTextField: FC<Props> = ({
40
40
  icons: { FilterListIcon, CloseIcon },
41
41
  localization,
42
42
  muiTableHeadCellFilterTextFieldProps,
43
- tableId,
44
43
  },
44
+ refs: { filterInputRefs },
45
45
  setColumnFilterFns,
46
46
  } = table;
47
47
  const { column } = header;
@@ -80,9 +80,6 @@ export const MRT_FilterTextField: FC<Props> = ({
80
80
  (!isSelectFilter && !isMultiSelectFilter);
81
81
 
82
82
  const currentFilterOption = columnFilterFns?.[header.id];
83
- const filterId = `mrt-${tableId}-${header.id}-filter-text-field${
84
- rangeFilterIndex ?? ''
85
- }`;
86
83
  const filterChipLabel = ['empty', 'notEmpty'].includes(currentFilterOption)
87
84
  ? //@ts-ignore
88
85
  localization[
@@ -184,7 +181,6 @@ export const MRT_FilterTextField: FC<Props> = ({
184
181
  <>
185
182
  <TextField
186
183
  fullWidth
187
- id={filterId}
188
184
  inputProps={{
189
185
  disabled: !!filterChipLabel,
190
186
  sx: {
@@ -195,7 +191,7 @@ export const MRT_FilterTextField: FC<Props> = ({
195
191
  }}
196
192
  helperText={
197
193
  showChangeModeButton ? (
198
- <label htmlFor={filterId}>
194
+ <label>
199
195
  {localization.filterMode.replace(
200
196
  '{filterType}',
201
197
  // @ts-ignore
@@ -294,6 +290,13 @@ export const MRT_FilterTextField: FC<Props> = ({
294
290
  : undefined,
295
291
  }}
296
292
  {...textFieldProps}
293
+ inputRef={(inputRef) => {
294
+ filterInputRefs.current[`${column.id}-${rangeFilterIndex ?? 0}`] =
295
+ inputRef;
296
+ if (textFieldProps.inputRef) {
297
+ textFieldProps.inputRef = inputRef;
298
+ }
299
+ }}
297
300
  sx={(theme) => ({
298
301
  p: 0,
299
302
  minWidth: !filterChipLabel ? '6rem' : 'auto',
@@ -27,8 +27,8 @@ export const MRT_GlobalFilterTextField = <
27
27
  icons: { SearchIcon, CloseIcon },
28
28
  localization,
29
29
  muiSearchTextFieldProps,
30
- tableId,
31
30
  },
31
+ refs: { searchInputRef },
32
32
  } = table;
33
33
  const { globalFilter, showGlobalFilter } = getState();
34
34
 
@@ -64,7 +64,6 @@ export const MRT_GlobalFilterTextField = <
64
64
  return (
65
65
  <Collapse in={showGlobalFilter} orientation="horizontal">
66
66
  <TextField
67
- id={`mrt-${tableId}-search-text-field`}
68
67
  placeholder={localization.search}
69
68
  onChange={handleChange}
70
69
  value={searchValue ?? ''}
@@ -104,6 +103,12 @@ export const MRT_GlobalFilterTextField = <
104
103
  ),
105
104
  }}
106
105
  {...textFieldProps}
106
+ inputRef={(inputRef) => {
107
+ searchInputRef.current = inputRef;
108
+ if (textFieldProps?.inputRef) {
109
+ textFieldProps.inputRef = inputRef;
110
+ }
111
+ }}
107
112
  />
108
113
  <MRT_FilterOptionMenu
109
114
  anchorEl={anchorEl}
@@ -54,9 +54,9 @@ export const MRT_ColumnActionMenu: FC<Props> = ({
54
54
  RestartAltIcon,
55
55
  VisibilityOffIcon,
56
56
  },
57
- tableId,
58
57
  localization,
59
58
  },
59
+ refs: { filterInputRefs },
60
60
  setShowFilters,
61
61
  } = table;
62
62
  const { column } = header;
@@ -111,17 +111,7 @@ export const MRT_ColumnActionMenu: FC<Props> = ({
111
111
 
112
112
  const handleFilterByColumn = () => {
113
113
  setShowFilters(true);
114
- setTimeout(
115
- () =>
116
- document
117
- .getElementById(
118
- // @ts-ignore
119
- header.muiTableHeadCellFilterTextFieldProps?.id ??
120
- `mrt-${tableId}-${header.id}-filter-text-field`,
121
- )
122
- ?.focus(),
123
- 200,
124
- );
114
+ queueMicrotask(() => filterInputRefs.current[`${column.id}-0`]?.focus());
125
115
  setAnchorEl(null);
126
116
  };
127
117
 
@@ -3,7 +3,6 @@ import React, {
3
3
  RefObject,
4
4
  useEffect,
5
5
  useLayoutEffect,
6
- useRef,
7
6
  useState,
8
7
  } from 'react';
9
8
  import { TableContainer } from '@mui/material';
@@ -24,8 +23,8 @@ export const MRT_TableContainer: FC<Props> = ({ table }) => {
24
23
  enableStickyHeader,
25
24
  enableRowVirtualization,
26
25
  muiTableContainerProps,
27
- tableId,
28
26
  },
27
+ refs: { tableContainerRef, bottomToolbarRef, topToolbarRef },
29
28
  } = table;
30
29
  const { isFullScreen } = getState();
31
30
 
@@ -36,20 +35,15 @@ export const MRT_TableContainer: FC<Props> = ({ table }) => {
36
35
  ? muiTableContainerProps({ table })
37
36
  : muiTableContainerProps;
38
37
 
39
- const tableContainerRef =
40
- tableContainerProps?.ref ?? useRef<HTMLDivElement>(null);
41
-
42
38
  useIsomorphicLayoutEffect(() => {
43
39
  const topToolbarHeight =
44
40
  typeof document !== 'undefined'
45
- ? document?.getElementById(`mrt-${tableId}-toolbar-top`)
46
- ?.offsetHeight ?? 0
41
+ ? topToolbarRef.current?.offsetHeight ?? 0
47
42
  : 0;
48
43
 
49
44
  const bottomToolbarHeight =
50
45
  typeof document !== 'undefined'
51
- ? document?.getElementById(`mrt-${tableId}-toolbar-bottom`)
52
- ?.offsetHeight ?? 0
46
+ ? bottomToolbarRef?.current?.offsetHeight ?? 0
53
47
  : 0;
54
48
 
55
49
  setTotalToolbarHeight(topToolbarHeight + bottomToolbarHeight);
@@ -57,8 +51,14 @@ export const MRT_TableContainer: FC<Props> = ({ table }) => {
57
51
 
58
52
  return (
59
53
  <TableContainer
60
- ref={tableContainerRef}
61
54
  {...tableContainerProps}
55
+ ref={(ref: HTMLDivElement) => {
56
+ tableContainerRef.current = ref;
57
+ if (tableContainerProps?.ref) {
58
+ //@ts-ignore
59
+ tableContainerProps.ref.current = ref;
60
+ }
61
+ }}
62
62
  sx={(theme) => ({
63
63
  maxWidth: '100%',
64
64
  maxHeight:
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useMemo, useState } from 'react';
1
+ import React, { useMemo, useRef, useState } from 'react';
2
2
  import {
3
3
  TableState,
4
4
  getCoreRowModel,
@@ -33,16 +33,17 @@ import type {
33
33
  MRT_TableState,
34
34
  MaterialReactTableProps,
35
35
  } from '..';
36
+ import { MRT_EditRowModal } from '../body/MRT_EditRowModal';
36
37
 
37
38
  export const MRT_TableRoot = <TData extends Record<string, any> = {}>(
38
39
  props: MaterialReactTableProps<TData>,
39
40
  ) => {
40
- const [tableId, setIdPrefix] = useState(props.tableId);
41
- useEffect(
42
- () =>
43
- setIdPrefix(props.tableId ?? Math.random().toString(36).substring(2, 9)),
44
- [props.tableId],
45
- );
41
+ const bottomToolbarRef = useRef<HTMLDivElement>(null);
42
+ const editInputRefs = useRef<Record<string, HTMLInputElement>>({});
43
+ const filterInputRefs = useRef<Record<string, HTMLInputElement>>({});
44
+ const searchInputRef = useRef<HTMLInputElement>(null);
45
+ const tableContainerRef = useRef<HTMLDivElement>(null);
46
+ const topToolbarRef = useRef<HTMLDivElement>(null);
46
47
 
47
48
  const initialState: Partial<MRT_TableState<TData>> = useMemo(() => {
48
49
  const initState = props.initialState ?? {};
@@ -125,11 +126,8 @@ export const MRT_TableRoot = <TData extends Record<string, any> = {}>(
125
126
  id: 'mrt-row-drag',
126
127
  },
127
128
  columnOrder.includes('mrt-row-actions') && {
128
- Cell: ({ cell }) => (
129
- <MRT_ToggleRowActionMenuButton
130
- row={cell.row as any}
131
- table={table}
132
- />
129
+ Cell: ({ row }) => (
130
+ <MRT_ToggleRowActionMenuButton row={row as any} table={table} />
133
131
  ),
134
132
  header: props.localization?.actions,
135
133
  size: 70,
@@ -138,8 +136,8 @@ export const MRT_TableRoot = <TData extends Record<string, any> = {}>(
138
136
  id: 'mrt-row-actions',
139
137
  },
140
138
  columnOrder.includes('mrt-row-expand') && {
141
- Cell: ({ cell }) => (
142
- <MRT_ExpandButton row={cell.row as any} table={table} />
139
+ Cell: ({ row }) => (
140
+ <MRT_ExpandButton row={row as any} table={table} />
143
141
  ),
144
142
  Header: () =>
145
143
  props.enableExpandAll ? (
@@ -152,8 +150,8 @@ export const MRT_TableRoot = <TData extends Record<string, any> = {}>(
152
150
  id: 'mrt-row-expand',
153
151
  },
154
152
  columnOrder.includes('mrt-row-select') && {
155
- Cell: ({ cell }) => (
156
- <MRT_SelectCheckbox row={cell.row as any} table={table} />
153
+ Cell: ({ row }) => (
154
+ <MRT_SelectCheckbox row={row as any} table={table} />
157
155
  ),
158
156
  Header: () =>
159
157
  props.enableSelectAll ? (
@@ -166,7 +164,7 @@ export const MRT_TableRoot = <TData extends Record<string, any> = {}>(
166
164
  id: 'mrt-row-select',
167
165
  },
168
166
  columnOrder.includes('mrt-row-numbers') && {
169
- Cell: ({ cell }) => cell.row.index + 1,
167
+ Cell: ({ row }) => row.index + 1,
170
168
  Header: () => props.localization?.rowNumber,
171
169
  header: props.localization?.rowNumbers,
172
170
  size: 60,
@@ -268,8 +266,15 @@ export const MRT_TableRoot = <TData extends Record<string, any> = {}>(
268
266
  showGlobalFilter,
269
267
  ...props.state,
270
268
  } as TableState,
271
- tableId,
272
269
  }),
270
+ refs: {
271
+ bottomToolbarRef,
272
+ editInputRefs,
273
+ filterInputRefs,
274
+ searchInputRef,
275
+ tableContainerRef,
276
+ topToolbarRef,
277
+ },
273
278
  setColumnFilterFns: props.onFilterFnsChange ?? setColumnFilterFns,
274
279
  setDensity: props.onDensityChange ?? setDensity,
275
280
  setDraggingColumn: props.onDraggingColumnChange ?? setDraggingColumn,
@@ -300,6 +305,9 @@ export const MRT_TableRoot = <TData extends Record<string, any> = {}>(
300
305
  <MRT_TablePaper table={table} />
301
306
  </Dialog>
302
307
  {!isFullScreen && <MRT_TablePaper table={table} />}
308
+ {editingRow && props.editingMode === 'modal' && (
309
+ <MRT_EditRowModal row={editingRow as any} table={table} open />
310
+ )}
303
311
  </>
304
312
  );
305
313
  };
@@ -21,8 +21,8 @@ export const MRT_BottomToolbar: FC<Props> = ({ table }) => {
21
21
  positionToolbarAlertBanner,
22
22
  positionToolbarDropZone,
23
23
  renderBottomToolbarCustomActions,
24
- tableId,
25
24
  },
25
+ refs: { bottomToolbarRef },
26
26
  } = table;
27
27
  const { isFullScreen } = getState();
28
28
 
@@ -37,9 +37,15 @@ export const MRT_BottomToolbar: FC<Props> = ({ table }) => {
37
37
 
38
38
  return (
39
39
  <Toolbar
40
- id={`mrt-${tableId}-toolbar-bottom`}
41
40
  variant="dense"
42
41
  {...toolbarProps}
42
+ ref={(ref: HTMLDivElement) => {
43
+ bottomToolbarRef.current = ref;
44
+ if (toolbarProps?.ref) {
45
+ // @ts-ignore
46
+ toolbarProps.ref.current = ref;
47
+ }
48
+ }}
43
49
  sx={(theme) =>
44
50
  ({
45
51
  ...commonToolbarStyles({ theme }),
@@ -37,8 +37,8 @@ export const MRT_TopToolbar: FC<Props> = ({ table }) => {
37
37
  positionToolbarAlertBanner,
38
38
  positionToolbarDropZone,
39
39
  renderTopToolbarCustomActions,
40
- tableId,
41
40
  },
41
+ refs: { topToolbarRef },
42
42
  } = table;
43
43
 
44
44
  const { isFullScreen, showGlobalFilter } = getState();
@@ -55,9 +55,15 @@ export const MRT_TopToolbar: FC<Props> = ({ table }) => {
55
55
 
56
56
  return (
57
57
  <Toolbar
58
- id={`mrt-${tableId}-toolbar-top`}
59
58
  variant="dense"
60
59
  {...toolbarProps}
60
+ ref={(ref: HTMLDivElement) => {
61
+ topToolbarRef.current = ref;
62
+ if (toolbarProps?.ref) {
63
+ // @ts-ignore
64
+ toolbarProps.ref.current = ref;
65
+ }
66
+ }}
61
67
  sx={(theme) =>
62
68
  ({
63
69
  position: isFullScreen ? 'sticky' : undefined,