@cutting/material-react-table 5.0.0 → 5.1.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 (190) hide show
  1. package/README.md +1 -4
  2. package/dist/index.d.ts +186 -524
  3. package/dist/index.js +323 -342
  4. package/dist/index.js.map +1 -1
  5. package/locales/ar/index.mjs +1 -2
  6. package/locales/az/index.mjs +1 -2
  7. package/locales/bg/index.mjs +1 -2
  8. package/locales/cs/index.mjs +1 -2
  9. package/locales/da/index.mjs +1 -2
  10. package/locales/de/index.mjs +1 -2
  11. package/locales/el/index.mjs +1 -2
  12. package/locales/en/index.mjs +1 -2
  13. package/locales/es/index.mjs +1 -2
  14. package/locales/et/index.mjs +1 -2
  15. package/locales/fa/index.mjs +1 -2
  16. package/locales/fi/index.mjs +1 -2
  17. package/locales/fr/index.mjs +1 -2
  18. package/locales/he/index.mjs +1 -2
  19. package/locales/hr/index.mjs +1 -2
  20. package/locales/hu/index.mjs +1 -2
  21. package/locales/hy/index.mjs +1 -2
  22. package/locales/id/index.mjs +1 -2
  23. package/locales/it/index.mjs +1 -2
  24. package/locales/ja/index.mjs +1 -2
  25. package/locales/ko/index.mjs +1 -2
  26. package/locales/nl/index.mjs +1 -2
  27. package/locales/no/index.mjs +1 -2
  28. package/locales/np/index.mjs +1 -2
  29. package/locales/pl/index.mjs +1 -2
  30. package/locales/pt/index.mjs +1 -2
  31. package/locales/pt-BR/index.mjs +1 -2
  32. package/locales/ro/index.mjs +1 -2
  33. package/locales/ru/index.mjs +1 -2
  34. package/locales/sk/index.mjs +1 -2
  35. package/locales/sr-Cyrl-RS/index.mjs +1 -2
  36. package/locales/sr-Latn-RS/index.mjs +1 -2
  37. package/locales/sv/index.mjs +1 -2
  38. package/locales/tr/index.mjs +1 -2
  39. package/locales/uk/index.mjs +1 -2
  40. package/locales/vi/index.mjs +1 -2
  41. package/locales/zh-Hans/index.mjs +1 -2
  42. package/locales/zh-Hant/index.mjs +1 -2
  43. package/package.json +19 -27
  44. package/src/MaterialReactTable.smoke.test.tsx +3 -9
  45. package/src/components/MaterialReactTable.tsx +13 -21
  46. package/src/components/body/MRT_TableBody.tsx +67 -82
  47. package/src/components/body/MRT_TableBodyCell.tsx +38 -80
  48. package/src/components/body/MRT_TableBodyCellValue.tsx +5 -14
  49. package/src/components/body/MRT_TableBodyRow.tsx +55 -102
  50. package/src/components/body/MRT_TableBodyRowGrabHandle.test.tsx +2 -6
  51. package/src/components/body/MRT_TableBodyRowGrabHandle.tsx +4 -9
  52. package/src/components/body/MRT_TableBodyRowPinButton.tsx +8 -14
  53. package/src/components/body/MRT_TableDetailPanel.test.tsx +3 -9
  54. package/src/components/body/MRT_TableDetailPanel.tsx +8 -14
  55. package/src/components/buttons/MRT_ColumnPinningButtons.test.tsx +6 -16
  56. package/src/components/buttons/MRT_ColumnPinningButtons.tsx +6 -12
  57. package/src/components/buttons/MRT_CopyButton.tsx +7 -15
  58. package/src/components/buttons/MRT_EditActionButtons.test.tsx +2 -6
  59. package/src/components/buttons/MRT_EditActionButtons.tsx +15 -37
  60. package/src/components/buttons/MRT_ExpandAllButton.tsx +8 -16
  61. package/src/components/buttons/MRT_ExpandButton.tsx +9 -21
  62. package/src/components/buttons/MRT_GrabHandleButton.tsx +6 -10
  63. package/src/components/buttons/MRT_RowPinButton.tsx +8 -23
  64. package/src/components/buttons/MRT_ShowHideColumnsButton.tsx +5 -18
  65. package/src/components/buttons/MRT_ToggleDensePaddingButton.test.tsx +4 -12
  66. package/src/components/buttons/MRT_ToggleDensePaddingButton.tsx +4 -11
  67. package/src/components/buttons/MRT_ToggleFiltersButton.test.tsx +4 -13
  68. package/src/components/buttons/MRT_ToggleFiltersButton.tsx +3 -5
  69. package/src/components/buttons/MRT_ToggleFullScreenButton.test.tsx +3 -11
  70. package/src/components/buttons/MRT_ToggleFullScreenButton.tsx +4 -9
  71. package/src/components/buttons/MRT_ToggleGlobalFilterButton.tsx +3 -5
  72. package/src/components/buttons/MRT_ToggleRowActionMenuButton.tsx +7 -15
  73. package/src/components/footer/MRT_TableFooter.tsx +9 -16
  74. package/src/components/footer/MRT_TableFooterCell.tsx +9 -32
  75. package/src/components/footer/MRT_TableFooterRow.tsx +18 -32
  76. package/src/components/head/MRT_TableHead.tsx +8 -18
  77. package/src/components/head/MRT_TableHeadCell.tsx +46 -100
  78. package/src/components/head/MRT_TableHeadCellColumnActionsButton.tsx +10 -30
  79. package/src/components/head/MRT_TableHeadCellFilterContainer.tsx +4 -15
  80. package/src/components/head/MRT_TableHeadCellFilterLabel.tsx +20 -54
  81. package/src/components/head/MRT_TableHeadCellGrabHandle.test.tsx +5 -19
  82. package/src/components/head/MRT_TableHeadCellGrabHandle.tsx +9 -38
  83. package/src/components/head/MRT_TableHeadCellResizeHandle.test.tsx +3 -13
  84. package/src/components/head/MRT_TableHeadCellResizeHandle.tsx +10 -24
  85. package/src/components/head/MRT_TableHeadCellSortLabel.tsx +10 -26
  86. package/src/components/head/MRT_TableHeadRow.tsx +24 -36
  87. package/src/components/inputs/MRT_EditCellTextField.test.tsx +2 -9
  88. package/src/components/inputs/MRT_EditCellTextField.tsx +9 -28
  89. package/src/components/inputs/MRT_FilterCheckbox.tsx +9 -23
  90. package/src/components/inputs/MRT_FilterRangeFields.tsx +6 -15
  91. package/src/components/inputs/MRT_FilterRangeSlider.tsx +24 -32
  92. package/src/components/inputs/MRT_FilterTextField.test.tsx +72 -14
  93. package/src/components/inputs/MRT_FilterTextField.tsx +77 -138
  94. package/src/components/inputs/MRT_GlobalFilterTextField.tsx +10 -32
  95. package/src/components/inputs/MRT_SelectCheckbox.test.tsx +4 -11
  96. package/src/components/inputs/MRT_SelectCheckbox.tsx +17 -36
  97. package/src/components/menus/MRT_ActionMenuItem.tsx +6 -15
  98. package/src/components/menus/MRT_CellActionMenu.tsx +6 -9
  99. package/src/components/menus/MRT_ColumnActionMenu.tsx +22 -57
  100. package/src/components/menus/MRT_FilterOptionMenu.tsx +38 -65
  101. package/src/components/menus/MRT_RowActionMenu.tsx +33 -22
  102. package/src/components/menus/MRT_ShowHideColumnsMenu.tsx +29 -65
  103. package/src/components/menus/MRT_ShowHideColumnsMenuItems.test.tsx +43 -0
  104. package/src/components/menus/MRT_ShowHideColumnsMenuItems.tsx +14 -50
  105. package/src/components/modals/MRT_EditRowModal.test.tsx +5 -21
  106. package/src/components/modals/MRT_EditRowModal.tsx +8 -26
  107. package/src/components/table/MRT_Table.tsx +12 -20
  108. package/src/components/table/MRT_TableContainer.test.tsx +147 -0
  109. package/src/components/table/MRT_TableContainer.tsx +33 -37
  110. package/src/components/table/MRT_TableLoadingOverlay.tsx +3 -5
  111. package/src/components/table/MRT_TablePaper.tsx +7 -14
  112. package/src/components/toolbar/MRT_BottomToolbar.tsx +11 -23
  113. package/src/components/toolbar/MRT_LinearProgressBar.tsx +4 -11
  114. package/src/components/toolbar/MRT_TablePagination.tsx +33 -40
  115. package/src/components/toolbar/MRT_ToolbarAlertBanner.tsx +21 -50
  116. package/src/components/toolbar/MRT_ToolbarDropZone.test.tsx +26 -10
  117. package/src/components/toolbar/MRT_ToolbarDropZone.tsx +23 -21
  118. package/src/components/toolbar/MRT_ToolbarInternalButtons.tsx +11 -21
  119. package/src/components/toolbar/MRT_TopToolbar.tsx +12 -28
  120. package/src/fns/aggregationFns.test.tsx +1 -3
  121. package/src/fns/filterFns.test.tsx +8 -37
  122. package/src/fns/filterFns.ts +71 -96
  123. package/src/fns/sortingFns.test.tsx +5 -21
  124. package/src/fns/sortingFns.ts +10 -14
  125. package/src/fns/tableFeatures.test.tsx +6 -29
  126. package/src/fns/tableFeatures.ts +5 -4
  127. package/src/hooks/display-columns/getMRT_RowActionsColumnDef.tsx +2 -11
  128. package/src/hooks/display-columns/getMRT_RowDragColumnDef.tsx +2 -10
  129. package/src/hooks/display-columns/getMRT_RowExpandColumnDef.tsx +8 -17
  130. package/src/hooks/display-columns/getMRT_RowNumbersColumnDef.tsx +3 -8
  131. package/src/hooks/display-columns/getMRT_RowPinningColumnDef.tsx +2 -8
  132. package/src/hooks/display-columns/getMRT_RowSelectColumnDef.tsx +3 -13
  133. package/src/hooks/display-columns/getMRT_RowSpacerColumnDef.tsx +1 -5
  134. package/src/hooks/useMRT_ColumnVirtualizer.ts +28 -49
  135. package/src/hooks/useMRT_Effects.test.tsx +114 -0
  136. package/src/hooks/useMRT_Effects.ts +26 -27
  137. package/src/hooks/useMRT_RowVirtualizer.ts +18 -33
  138. package/src/hooks/useMRT_Rows.ts +3 -42
  139. package/src/hooks/useMRT_TableInstance.ts +63 -129
  140. package/src/hooks/useMRT_TableOptions.ts +15 -29
  141. package/src/hooks/useMaterialReactTable.ts +2 -7
  142. package/src/icons.ts +38 -1
  143. package/src/index.ts +0 -4
  144. package/src/locales/ar.ts +1 -2
  145. package/src/locales/az.ts +1 -2
  146. package/src/locales/bg.ts +1 -2
  147. package/src/locales/cs.ts +2 -4
  148. package/src/locales/da.ts +1 -2
  149. package/src/locales/de.ts +1 -2
  150. package/src/locales/el.ts +1 -2
  151. package/src/locales/en.ts +1 -2
  152. package/src/locales/es.ts +1 -2
  153. package/src/locales/et.ts +2 -4
  154. package/src/locales/fa.ts +1 -2
  155. package/src/locales/fi.ts +2 -4
  156. package/src/locales/fr.ts +1 -2
  157. package/src/locales/he.ts +1 -2
  158. package/src/locales/hr.ts +1 -2
  159. package/src/locales/hu.ts +1 -2
  160. package/src/locales/hy.ts +1 -2
  161. package/src/locales/id.ts +2 -4
  162. package/src/locales/it.ts +1 -2
  163. package/src/locales/ja.ts +1 -2
  164. package/src/locales/ko.ts +1 -2
  165. package/src/locales/nl.ts +1 -2
  166. package/src/locales/no.ts +2 -4
  167. package/src/locales/np.ts +2 -4
  168. package/src/locales/pl.ts +1 -2
  169. package/src/locales/pt-BR.ts +1 -2
  170. package/src/locales/pt.ts +1 -2
  171. package/src/locales/ro.ts +1 -2
  172. package/src/locales/ru.ts +1 -2
  173. package/src/locales/sk.ts +2 -4
  174. package/src/locales/sr-Cyrl-RS.ts +1 -2
  175. package/src/locales/sr-Latn-RS.ts +1 -2
  176. package/src/locales/sv.ts +1 -2
  177. package/src/locales/tr.ts +1 -2
  178. package/src/locales/uk.ts +1 -2
  179. package/src/locales/vi.ts +1 -2
  180. package/src/types.ts +156 -349
  181. package/src/utils/cell.utils.ts +30 -68
  182. package/src/utils/column.utils.ts +61 -49
  183. package/src/utils/displayColumn.utils.ts +16 -38
  184. package/src/utils/highlight.utils.ts +7 -11
  185. package/src/utils/row.utils.ts +40 -65
  186. package/src/utils/slotProps.utils.ts +1 -4
  187. package/src/utils/style.utils.ts +18 -46
  188. package/src/utils/tanstack.helpers.ts +10 -17
  189. package/src/utils/utils.ts +6 -10
  190. package/src/utils/virtualization.utils.ts +5 -9
@@ -10,23 +10,22 @@ import {
10
10
  } from '@tanstack/react-table';
11
11
 
12
12
  import { type MRT_Row, type MRT_RowData } from '../types';
13
+ import { type MRT_TableFeatures } from './tableFeatures';
13
14
 
14
- const fuzzy = <TData extends MRT_RowData>(
15
- rowA: Row<any, TData>,
16
- rowB: Row<any, TData>,
15
+ const fuzzy = <TFeatures extends MRT_TableFeatures, TData extends MRT_RowData>(
16
+ rowA: Row<TFeatures, TData>,
17
+ rowB: Row<TFeatures, TData>,
17
18
  columnId: string,
18
- ) => {
19
+ ): number => {
19
20
  let dir = 0;
20
- if (rowA.columnFiltersMeta[columnId]) {
21
+ if ('columnFiltersMeta' in rowA && 'columnFiltersMeta' in rowB && rowA.columnFiltersMeta[columnId]) {
21
22
  dir = compareItems(
22
23
  rowA.columnFiltersMeta[columnId] as RankingInfo,
23
24
  rowB.columnFiltersMeta[columnId] as RankingInfo,
24
25
  );
25
26
  }
26
27
  // Provide a fallback for when the item ranks are equal
27
- return dir === 0
28
- ? sortFn_alphanumeric(rowA, rowB, columnId)
29
- : dir;
28
+ return dir === 0 ? sortFn_alphanumeric(rowA, rowB, columnId) : dir;
30
29
  };
31
30
 
32
31
  export const MRT_SortingFns = {
@@ -39,9 +38,6 @@ export const MRT_SortingFns = {
39
38
  textCaseSensitive: sortFn_textCaseSensitive,
40
39
  };
41
40
 
42
- export const rankGlobalFuzzy = <TData extends MRT_RowData>(
43
- rowA: MRT_Row<TData>,
44
- rowB: MRT_Row<TData>,
45
- ) =>
46
- Math.max(...Object.values(rowB.columnFiltersMeta).map((v: any) => v.rank)) -
47
- Math.max(...Object.values(rowA.columnFiltersMeta).map((v: any) => v.rank));
41
+ export const rankGlobalFuzzy = <TData extends MRT_RowData>(rowA: MRT_Row<TData>, rowB: MRT_Row<TData>): number =>
42
+ Math.max(...Object.values(rowB.columnFiltersMeta).map((meta) => (meta as RankingInfo).rank)) -
43
+ Math.max(...Object.values(rowA.columnFiltersMeta).map((meta) => (meta as RankingInfo).rank));
@@ -8,20 +8,12 @@ interface Person {
8
8
  name: string;
9
9
  }
10
10
 
11
- const data: Person[] = [
12
- { name: 'Jonathan' },
13
- { name: 'Aaron' },
14
- { name: 'Sara' },
15
- ];
11
+ const data: Person[] = [{ name: 'Jonathan' }, { name: 'Aaron' }, { name: 'Sara' }];
16
12
 
17
- const columns: MRT_ColumnDef<Person>[] = [
18
- { accessorKey: 'name', header: 'Name' },
19
- ];
13
+ const columns: MRT_ColumnDef<Person>[] = [{ accessorKey: 'name', header: 'Name' }];
20
14
 
21
15
  const renderedNames = (container: HTMLElement) =>
22
- Array.from(container.querySelectorAll('tbody tr')).map(
23
- (row) => row.textContent,
24
- );
16
+ Array.from(container.querySelectorAll('tbody tr')).map((row) => row.textContent);
25
17
 
26
18
  describe('server-side options suppress client-side row models', () => {
27
19
  test('manualPagination renders the whole server page, ignoring pageSize', () => {
@@ -40,12 +32,7 @@ describe('server-side options suppress client-side row models', () => {
40
32
 
41
33
  test('manualFiltering keeps every row when a global filter is set', () => {
42
34
  const { container } = render(
43
- <MaterialReactTable
44
- columns={columns}
45
- data={data}
46
- manualFiltering
47
- state={{ globalFilter: 'zzz' }}
48
- />,
35
+ <MaterialReactTable columns={columns} data={data} manualFiltering state={{ globalFilter: 'zzz' }} />,
49
36
  );
50
37
 
51
38
  expect(renderedNames(container)).toEqual(['Jonathan', 'Aaron', 'Sara']);
@@ -69,24 +56,14 @@ describe('server-side options suppress client-side row models', () => {
69
56
  describe('client-side row models stay active by default', () => {
70
57
  test('pagination slices to pageSize', () => {
71
58
  const { container } = render(
72
- <MaterialReactTable
73
- columns={columns}
74
- data={data}
75
- state={{ pagination: { pageIndex: 0, pageSize: 2 } }}
76
- />,
59
+ <MaterialReactTable columns={columns} data={data} state={{ pagination: { pageIndex: 0, pageSize: 2 } }} />,
77
60
  );
78
61
 
79
62
  expect(renderedNames(container)).toEqual(['Jonathan', 'Aaron']);
80
63
  });
81
64
 
82
65
  test('global filter drops non-matching rows', () => {
83
- const { container } = render(
84
- <MaterialReactTable
85
- columns={columns}
86
- data={data}
87
- state={{ globalFilter: 'zzz' }}
88
- />,
89
- );
66
+ const { container } = render(<MaterialReactTable columns={columns} data={data} state={{ globalFilter: 'zzz' }} />);
90
67
 
91
68
  expect(renderedNames(container)).toEqual(['No results found']);
92
69
  });
@@ -1,5 +1,4 @@
1
1
  import {
2
- type AggregationFnDef,
3
2
  cellSelectionFeature,
4
3
  cellSpanningFeature,
5
4
  columnFacetingFeature,
@@ -18,6 +17,7 @@ import {
18
17
  createGroupedRowModel,
19
18
  createPaginatedRowModel,
20
19
  createSortedRowModel,
20
+ type CustomAggregationFns,
21
21
  type FilterFn,
22
22
  globalFilteringFeature,
23
23
  rowAggregationFeature,
@@ -32,6 +32,7 @@ import {
32
32
  tableFeatures,
33
33
  } from '@tanstack/react-table';
34
34
 
35
+ import { type MRT_RowData } from '../types';
35
36
  import { MRT_AggregationFns } from './aggregationFns';
36
37
  import { MRT_FilterFns } from './filterFns';
37
38
  import { MRT_SortingFns } from './sortingFns';
@@ -96,8 +97,8 @@ export const MRT_DefaultTableFeatures = tableFeatures({
96
97
  });
97
98
 
98
99
  export interface MRT_TableFeatures extends StockFeatures {
99
- aggregationFns: Record<string, AggregationFnDef<any, any, any, any>>;
100
- filterFns: Record<string, FilterFn<any, any>>;
100
+ aggregationFns: CustomAggregationFns<MRT_TableFeatures, MRT_RowData>;
101
+ filterFns: Record<string, FilterFn<MRT_TableFeatures, MRT_RowData>>;
101
102
  mrtFeature: TableFeature;
102
- sortFns: Record<string, SortFn<any, any>>;
103
+ sortFns: Record<string, SortFn<MRT_TableFeatures, MRT_RowData>>;
103
104
  }
@@ -1,9 +1,5 @@
1
1
  import { MRT_ToggleRowActionMenuButton } from '../../components/buttons/MRT_ToggleRowActionMenuButton';
2
- import {
3
- type MRT_ColumnDef,
4
- type MRT_RowData,
5
- type MRT_StatefulTableOptions,
6
- } from '../../types';
2
+ import { type MRT_ColumnDef, type MRT_RowData, type MRT_StatefulTableOptions } from '../../types';
7
3
  import { defaultDisplayColumnProps } from '../../utils/displayColumn.utils';
8
4
 
9
5
  export const getMRT_RowActionsColumnDef = <TData extends MRT_RowData>(
@@ -11,12 +7,7 @@ export const getMRT_RowActionsColumnDef = <TData extends MRT_RowData>(
11
7
  ): MRT_ColumnDef<TData> => {
12
8
  return {
13
9
  Cell: ({ cell, row, staticRowIndex, table }) => (
14
- <MRT_ToggleRowActionMenuButton
15
- cell={cell}
16
- row={row}
17
- staticRowIndex={staticRowIndex}
18
- table={table}
19
- />
10
+ <MRT_ToggleRowActionMenuButton cell={cell} row={row} staticRowIndex={staticRowIndex} table={table} />
20
11
  ),
21
12
  ...defaultDisplayColumnProps({
22
13
  header: 'actions',
@@ -1,11 +1,7 @@
1
1
  import { type RefObject } from 'react';
2
2
 
3
3
  import { MRT_TableBodyRowGrabHandle } from '../../components/body/MRT_TableBodyRowGrabHandle';
4
- import {
5
- type MRT_ColumnDef,
6
- type MRT_RowData,
7
- type MRT_StatefulTableOptions,
8
- } from '../../types';
4
+ import { type MRT_ColumnDef, type MRT_RowData, type MRT_StatefulTableOptions } from '../../types';
9
5
  import { defaultDisplayColumnProps } from '../../utils/displayColumn.utils';
10
6
 
11
7
  export const getMRT_RowDragColumnDef = <TData extends MRT_RowData>(
@@ -13,11 +9,7 @@ export const getMRT_RowDragColumnDef = <TData extends MRT_RowData>(
13
9
  ): MRT_ColumnDef<TData> => {
14
10
  return {
15
11
  Cell: ({ row, rowRef, table }) => (
16
- <MRT_TableBodyRowGrabHandle
17
- row={row}
18
- rowRef={rowRef as RefObject<HTMLTableRowElement | null>}
19
- table={table}
20
- />
12
+ <MRT_TableBodyRowGrabHandle row={row} rowRef={rowRef as RefObject<HTMLTableRowElement | null>} table={table} />
21
13
  ),
22
14
  grow: false,
23
15
  ...defaultDisplayColumnProps({
@@ -1,14 +1,9 @@
1
- import { Stack } from '@mui/material';
2
- import { Tooltip } from '@mui/material';
1
+ import { Stack, Tooltip } from '@mui/material';
3
2
  import { type ReactNode } from 'react';
4
3
 
5
4
  import { MRT_ExpandAllButton } from '../../components/buttons/MRT_ExpandAllButton';
6
5
  import { MRT_ExpandButton } from '../../components/buttons/MRT_ExpandButton';
7
- import {
8
- type MRT_ColumnDef,
9
- type MRT_RowData,
10
- type MRT_StatefulTableOptions,
11
- } from '../../types';
6
+ import { type MRT_ColumnDef, type MRT_RowData, type MRT_StatefulTableOptions } from '../../types';
12
7
  import { defaultDisplayColumnProps } from '../../utils/displayColumn.utils';
13
8
  import { getCommonTooltipProps } from '../../utils/style.utils';
14
9
 
@@ -39,10 +34,11 @@ export const getMRT_RowExpandColumnDef = <TData extends MRT_RowData>(
39
34
  return (
40
35
  <Stack
41
36
  sx={{
42
- alignItems: "center",
43
- flexDirection: "row",
44
- gap: "0.25rem"
45
- }}>
37
+ alignItems: 'center',
38
+ flexDirection: 'row',
39
+ gap: '0.25rem',
40
+ }}
41
+ >
46
42
  <MRT_ExpandButton {...expandButtonProps} />
47
43
  <Tooltip
48
44
  {...getCommonTooltipProps('right')}
@@ -68,12 +64,7 @@ export const getMRT_RowExpandColumnDef = <TData extends MRT_RowData>(
68
64
  <>
69
65
  <MRT_ExpandAllButton table={table} />
70
66
  {groupedColumnMode === 'remove' &&
71
- grouping
72
- ?.map(
73
- (groupedColumnId) =>
74
- table.getColumn(groupedColumnId)?.columnDef.header,
75
- )
76
- ?.join(', ')}
67
+ grouping?.map((groupedColumnId) => table.getColumn(groupedColumnId)?.columnDef.header)?.join(', ')}
77
68
  </>
78
69
  );
79
70
  }
@@ -1,8 +1,4 @@
1
- import {
2
- type MRT_ColumnDef,
3
- type MRT_RowData,
4
- type MRT_StatefulTableOptions,
5
- } from '../../types';
1
+ import { type MRT_ColumnDef, type MRT_RowData, type MRT_StatefulTableOptions } from '../../types';
6
2
  import { defaultDisplayColumnProps } from '../../utils/displayColumn.utils';
7
3
 
8
4
  export const getMRT_RowNumbersColumnDef = <TData extends MRT_RowData>(
@@ -15,9 +11,8 @@ export const getMRT_RowNumbersColumnDef = <TData extends MRT_RowData>(
15
11
 
16
12
  return {
17
13
  Cell: ({ row, staticRowIndex }) =>
18
- ((rowNumberDisplayMode === 'static'
19
- ? (staticRowIndex || 0) + (pageSize || 0) * (pageIndex || 0)
20
- : row.index) ?? 0) + 1,
14
+ ((rowNumberDisplayMode === 'static' ? (staticRowIndex || 0) + (pageSize || 0) * (pageIndex || 0) : row.index) ??
15
+ 0) + 1,
21
16
  grow: false,
22
17
  Header: () => localization.rowNumber,
23
18
  ...defaultDisplayColumnProps({
@@ -1,18 +1,12 @@
1
1
  import { MRT_TableBodyRowPinButton } from '../../components/body/MRT_TableBodyRowPinButton';
2
- import {
3
- type MRT_ColumnDef,
4
- type MRT_RowData,
5
- type MRT_StatefulTableOptions,
6
- } from '../../types';
2
+ import { type MRT_ColumnDef, type MRT_RowData, type MRT_StatefulTableOptions } from '../../types';
7
3
  import { defaultDisplayColumnProps } from '../../utils/displayColumn.utils';
8
4
 
9
5
  export const getMRT_RowPinningColumnDef = <TData extends MRT_RowData>(
10
6
  tableOptions: MRT_StatefulTableOptions<TData>,
11
7
  ): MRT_ColumnDef<TData> => {
12
8
  return {
13
- Cell: ({ row, table }) => (
14
- <MRT_TableBodyRowPinButton row={row} table={table} />
15
- ),
9
+ Cell: ({ row, table }) => <MRT_TableBodyRowPinButton row={row} table={table} />,
16
10
  grow: false,
17
11
  ...defaultDisplayColumnProps({
18
12
  header: 'pin',
@@ -1,9 +1,5 @@
1
1
  import { MRT_SelectCheckbox } from '../../components/inputs/MRT_SelectCheckbox';
2
- import {
3
- type MRT_ColumnDef,
4
- type MRT_RowData,
5
- type MRT_StatefulTableOptions,
6
- } from '../../types';
2
+ import { type MRT_ColumnDef, type MRT_RowData, type MRT_StatefulTableOptions } from '../../types';
7
3
  import { defaultDisplayColumnProps } from '../../utils/displayColumn.utils';
8
4
 
9
5
  export const getMRT_RowSelectColumnDef = <TData extends MRT_RowData>(
@@ -13,17 +9,11 @@ export const getMRT_RowSelectColumnDef = <TData extends MRT_RowData>(
13
9
 
14
10
  return {
15
11
  Cell: ({ row, staticRowIndex, table }) => (
16
- <MRT_SelectCheckbox
17
- row={row}
18
- staticRowIndex={staticRowIndex}
19
- table={table}
20
- />
12
+ <MRT_SelectCheckbox row={row} staticRowIndex={staticRowIndex} table={table} />
21
13
  ),
22
14
  grow: false,
23
15
  Header:
24
- enableSelectAll && enableMultiRowSelection
25
- ? ({ table }) => <MRT_SelectCheckbox table={table} />
26
- : undefined,
16
+ enableSelectAll && enableMultiRowSelection ? ({ table }) => <MRT_SelectCheckbox table={table} /> : undefined,
27
17
  ...defaultDisplayColumnProps({
28
18
  header: 'select',
29
19
  id: 'mrt-row-select',
@@ -1,8 +1,4 @@
1
- import {
2
- type MRT_ColumnDef,
3
- type MRT_RowData,
4
- type MRT_StatefulTableOptions,
5
- } from '../../types';
1
+ import { type MRT_ColumnDef, type MRT_RowData, type MRT_StatefulTableOptions } from '../../types';
6
2
  import { defaultDisplayColumnProps } from '../../utils/displayColumn.utils';
7
3
  import { MRT_DefaultDisplayColumn } from '../useMRT_TableOptions';
8
4
 
@@ -1,11 +1,7 @@
1
1
  import { type Range, useVirtualizer } from '@tanstack/react-virtual';
2
2
  import { useCallback, useMemo } from 'react';
3
3
 
4
- import {
5
- type MRT_ColumnVirtualizer,
6
- type MRT_RowData,
7
- type MRT_TableInstance,
8
- } from '../types';
4
+ import { type MRT_ColumnVirtualizer, type MRT_RowData, type MRT_TableInstance } from '../types';
9
5
  import { parseFromValuesOrFunc } from '../utils/utils';
10
6
  import { extraIndexRangeExtractor } from '../utils/virtualization.utils';
11
7
 
@@ -15,7 +11,7 @@ export const useMRT_ColumnVirtualizer = <
15
11
  TItemElement extends Element = HTMLTableCellElement,
16
12
  >(
17
13
  table: MRT_TableInstance<TData>,
18
- ): MRT_ColumnVirtualizer | undefined => {
14
+ ): MRT_ColumnVirtualizer<TScrollElement, TItemElement> | undefined => {
19
15
  const {
20
16
  options: {
21
17
  columnVirtualizerInstanceRef,
@@ -25,16 +21,13 @@ export const useMRT_ColumnVirtualizer = <
25
21
  },
26
22
  refs: { tableContainerRef },
27
23
  } = table;
28
- const { columnPinning, columnVisibility, draggingColumn } = table.state;
24
+ const { draggingColumn } = table.state;
29
25
 
30
- if (!enableColumnVirtualization) return undefined;
31
-
32
- const columnVirtualizerProps = parseFromValuesOrFunc(
33
- columnVirtualizerOptions,
34
- {
35
- table,
36
- },
37
- );
26
+ const columnVirtualizerProps = enableColumnVirtualization
27
+ ? parseFromValuesOrFunc(columnVirtualizerOptions, {
28
+ table,
29
+ })
30
+ : undefined;
38
31
 
39
32
  const visibleColumns = table.getVisibleLeafColumns();
40
33
 
@@ -42,33 +35,27 @@ export const useMRT_ColumnVirtualizer = <
42
35
  () =>
43
36
  enableColumnPinning
44
37
  ? [
45
- visibleColumns
46
- .filter((c) => c.getIsPinned() === 'start')
47
- .map((c) => c.getPinnedIndex()),
38
+ visibleColumns.filter((c) => c.getIsPinned() === 'start').map((c) => c.getPinnedIndex()),
48
39
  visibleColumns
49
40
  .filter((c) => c.getIsPinned() === 'end')
50
- .map(
51
- (column) => visibleColumns.length - column.getPinnedIndex() - 1,
52
- )
41
+ .map((column) => visibleColumns.length - column.getPinnedIndex() - 1)
53
42
  .sort((a, b) => a - b),
54
43
  ]
55
44
  : [[], []],
56
- [columnPinning, columnVisibility, enableColumnPinning],
45
+ [enableColumnPinning, visibleColumns],
57
46
  );
58
47
 
59
48
  const numPinnedLeft = leftPinnedIndexes.length;
60
49
  const numPinnedRight = rightPinnedIndexes.length;
61
50
 
62
51
  const draggingColumnIndex = useMemo(
63
- () =>
64
- draggingColumn?.id
65
- ? visibleColumns.findIndex((c) => c.id === draggingColumn?.id)
66
- : undefined,
67
- [draggingColumn?.id],
52
+ () => (draggingColumn?.id ? visibleColumns.findIndex((c) => c.id === draggingColumn?.id) : undefined),
53
+ [draggingColumn?.id, visibleColumns],
68
54
  );
69
55
 
70
56
  const columnVirtualizer = useVirtualizer({
71
57
  count: visibleColumns.length,
58
+ enabled: !!enableColumnVirtualization,
72
59
  estimateSize: (index) => visibleColumns[index].getSize(),
73
60
  getScrollElement: () => tableContainerRef.current,
74
61
  horizontal: true,
@@ -79,48 +66,40 @@ export const useMRT_ColumnVirtualizer = <
79
66
  if (!numPinnedLeft && !numPinnedRight) {
80
67
  return newIndexes;
81
68
  }
82
- return [
83
- ...new Set([
84
- ...leftPinnedIndexes,
85
- ...newIndexes,
86
- ...rightPinnedIndexes,
87
- ]),
88
- ];
69
+ return [...new Set([...leftPinnedIndexes, ...newIndexes, ...rightPinnedIndexes])];
89
70
  },
90
- [leftPinnedIndexes, rightPinnedIndexes, draggingColumnIndex],
71
+ [leftPinnedIndexes, rightPinnedIndexes, draggingColumnIndex, numPinnedLeft, numPinnedRight],
91
72
  ),
92
73
  ...columnVirtualizerProps,
93
74
  }) as unknown as MRT_ColumnVirtualizer<TScrollElement, TItemElement>;
94
75
 
76
+ if (!enableColumnVirtualization) {
77
+ return undefined;
78
+ }
79
+
95
80
  const virtualColumns = columnVirtualizer.getVirtualItems();
96
- columnVirtualizer.virtualColumns = virtualColumns as any;
81
+ columnVirtualizer.virtualColumns = virtualColumns;
97
82
  const numColumns = virtualColumns.length;
98
83
 
99
84
  if (numColumns) {
100
85
  const totalSize = columnVirtualizer.getTotalSize();
101
86
 
102
87
  const leftNonPinnedStart = virtualColumns[numPinnedLeft]?.start || 0;
103
- const leftNonPinnedEnd =
104
- virtualColumns[leftPinnedIndexes.length - 1]?.end || 0;
88
+ const leftNonPinnedEnd = virtualColumns[leftPinnedIndexes.length - 1]?.end || 0;
105
89
 
106
- const rightNonPinnedStart =
107
- virtualColumns[numColumns - numPinnedRight]?.start || 0;
108
- const rightNonPinnedEnd =
109
- virtualColumns[numColumns - numPinnedRight - 1]?.end || 0;
90
+ const rightNonPinnedStart = virtualColumns[numColumns - numPinnedRight]?.start || 0;
91
+ const rightNonPinnedEnd = virtualColumns[numColumns - numPinnedRight - 1]?.end || 0;
110
92
 
111
- columnVirtualizer.virtualPaddingLeft =
112
- leftNonPinnedStart - leftNonPinnedEnd;
93
+ columnVirtualizer.virtualPaddingLeft = leftNonPinnedStart - leftNonPinnedEnd;
113
94
 
114
95
  columnVirtualizer.virtualPaddingRight =
115
- totalSize -
116
- rightNonPinnedEnd -
117
- (numPinnedRight ? totalSize - rightNonPinnedStart : 0);
96
+ totalSize - rightNonPinnedEnd - (numPinnedRight ? totalSize - rightNonPinnedStart : 0);
118
97
  }
119
98
 
120
99
  if (columnVirtualizerInstanceRef) {
121
- //@ts-expect-error
100
+ // @ts-expect-error: the ref is typed for the default element generics, this virtualizer uses TScrollElement and TItemElement
122
101
  columnVirtualizerInstanceRef.current = columnVirtualizer;
123
102
  }
124
103
 
125
- return columnVirtualizer as any;
104
+ return columnVirtualizer;
126
105
  };
@@ -0,0 +1,114 @@
1
+ import { act, render } from '@testing-library/react';
2
+ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
3
+
4
+ import { MaterialReactTable } from '../components/MaterialReactTable';
5
+ import { type MRT_ColumnDef } from '../types';
6
+
7
+ interface Person {
8
+ age: number;
9
+ name: string;
10
+ }
11
+
12
+ const data: Person[] = [
13
+ { age: 30, name: 'John' },
14
+ { age: 25, name: 'Sara' },
15
+ ];
16
+
17
+ const columns: MRT_ColumnDef<Person>[] = [
18
+ { accessorKey: 'name', header: 'Name' },
19
+ { accessorKey: 'age', header: 'Age' },
20
+ ];
21
+
22
+ describe('pinned rows', () => {
23
+ beforeEach(() => {
24
+ vi.useFakeTimers();
25
+ });
26
+
27
+ afterEach(() => {
28
+ vi.useRealTimers();
29
+ });
30
+
31
+ test('the table stops re-rendering after mount', () => {
32
+ const muiTablePaperProps = vi.fn(() => ({}));
33
+
34
+ render(
35
+ <MaterialReactTable
36
+ columns={columns}
37
+ data={data}
38
+ enableRowPinning
39
+ initialState={{ rowPinning: { bottom: [], top: ['0'] } }}
40
+ muiTablePaperProps={muiTablePaperProps}
41
+ />,
42
+ );
43
+
44
+ act(() => {
45
+ vi.advanceTimersByTime(1000);
46
+ });
47
+ const settledRenders = muiTablePaperProps.mock.calls.length;
48
+
49
+ act(() => {
50
+ vi.advanceTimersByTime(1000);
51
+ });
52
+
53
+ expect(muiTablePaperProps).toHaveBeenCalledTimes(settledRenders);
54
+ });
55
+ });
56
+
57
+ describe('controlled state effects', () => {
58
+ test('does not reset the column order again when the table re-renders', () => {
59
+ const onColumnOrderChange = vi.fn();
60
+ const table = (isLoading: boolean) => (
61
+ <MaterialReactTable
62
+ columns={columns}
63
+ data={data}
64
+ onColumnOrderChange={onColumnOrderChange}
65
+ state={{ columnOrder: ['name'], isLoading }}
66
+ />
67
+ );
68
+ const { rerender } = render(table(false));
69
+ const mountCalls = onColumnOrderChange.mock.calls.length;
70
+
71
+ rerender(table(true));
72
+ rerender(table(false));
73
+
74
+ expect(onColumnOrderChange).toHaveBeenCalledTimes(mountCalls);
75
+ });
76
+
77
+ test('does not clamp the page index again when the table re-renders', () => {
78
+ const onPaginationChange = vi.fn();
79
+ const table = (showProgressBars: boolean) => (
80
+ <MaterialReactTable
81
+ columns={columns}
82
+ data={data}
83
+ onPaginationChange={onPaginationChange}
84
+ state={{ pagination: { pageIndex: 5, pageSize: 10 }, showProgressBars }}
85
+ />
86
+ );
87
+ const { rerender } = render(table(false));
88
+ const mountCalls = onPaginationChange.mock.calls.length;
89
+
90
+ rerender(table(true));
91
+ rerender(table(false));
92
+
93
+ expect(onPaginationChange).toHaveBeenCalledTimes(mountCalls);
94
+ });
95
+
96
+ test('does not clear the sorting again when the table re-renders', () => {
97
+ const onSortingChange = vi.fn();
98
+ const table = (showProgressBars: boolean) => (
99
+ <MaterialReactTable
100
+ columns={columns}
101
+ data={data}
102
+ onSortingChange={onSortingChange}
103
+ state={{ globalFilter: 'John', showProgressBars, sorting: [] }}
104
+ />
105
+ );
106
+ const { rerender } = render(table(false));
107
+ const mountCalls = onSortingChange.mock.calls.length;
108
+
109
+ rerender(table(true));
110
+ rerender(table(false));
111
+
112
+ expect(onSortingChange).toHaveBeenCalledTimes(mountCalls);
113
+ });
114
+ });