@cutting/material-react-table 4.1.0 → 5.0.0-beta.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.
Files changed (198) hide show
  1. package/dist/index.d.ts +360 -333
  2. package/dist/index.js +919 -928
  3. package/dist/index.js.map +1 -1
  4. package/locales/ar/package.json +2 -2
  5. package/locales/az/package.json +2 -2
  6. package/locales/bg/package.json +2 -2
  7. package/locales/cs/package.json +2 -2
  8. package/locales/da/package.json +2 -2
  9. package/locales/de/package.json +2 -2
  10. package/locales/el/package.json +2 -2
  11. package/locales/en/package.json +2 -2
  12. package/locales/es/package.json +2 -2
  13. package/locales/et/package.json +2 -2
  14. package/locales/fa/package.json +2 -2
  15. package/locales/fi/package.json +2 -2
  16. package/locales/fr/package.json +2 -2
  17. package/locales/he/package.json +2 -2
  18. package/locales/hr/package.json +2 -2
  19. package/locales/hu/package.json +2 -2
  20. package/locales/hy/package.json +2 -2
  21. package/locales/id/package.json +2 -2
  22. package/locales/it/package.json +2 -2
  23. package/locales/ja/package.json +2 -2
  24. package/locales/ko/package.json +2 -2
  25. package/locales/nl/package.json +2 -2
  26. package/locales/no/package.json +2 -2
  27. package/locales/np/package.json +2 -2
  28. package/locales/pl/package.json +2 -2
  29. package/locales/pt/package.json +2 -2
  30. package/locales/pt-BR/package.json +2 -2
  31. package/locales/ro/package.json +2 -2
  32. package/locales/ru/package.json +2 -2
  33. package/locales/sk/package.json +2 -2
  34. package/locales/sr-Cyrl-RS/package.json +2 -2
  35. package/locales/sr-Latn-RS/package.json +2 -2
  36. package/locales/sv/package.json +2 -2
  37. package/locales/tr/package.json +2 -2
  38. package/locales/uk/package.json +2 -2
  39. package/locales/vi/package.json +2 -2
  40. package/locales/zh-Hans/package.json +2 -2
  41. package/locales/zh-Hant/package.json +2 -2
  42. package/package.json +46 -61
  43. package/src/components/body/MRT_TableBody.tsx +1 -2
  44. package/src/components/body/MRT_TableBodyCell.tsx +4 -5
  45. package/src/components/body/MRT_TableBodyCellValue.tsx +1 -2
  46. package/src/components/body/MRT_TableBodyRow.tsx +1 -2
  47. package/src/components/body/MRT_TableBodyRowGrabHandle.test.tsx +42 -0
  48. package/src/components/body/MRT_TableBodyRowPinButton.tsx +1 -2
  49. package/src/components/body/MRT_TableDetailPanel.test.tsx +40 -0
  50. package/src/components/body/MRT_TableDetailPanel.tsx +1 -2
  51. package/src/components/buttons/MRT_ColumnPinningButtons.test.tsx +69 -0
  52. package/src/components/buttons/MRT_ColumnPinningButtons.tsx +3 -3
  53. package/src/components/buttons/MRT_EditActionButtons.test.tsx +50 -0
  54. package/src/components/buttons/MRT_EditActionButtons.tsx +1 -3
  55. package/src/components/buttons/MRT_ExpandAllButton.tsx +1 -2
  56. package/src/components/buttons/MRT_ExpandButton.tsx +1 -2
  57. package/src/components/buttons/MRT_ToggleDensePaddingButton.test.tsx +38 -0
  58. package/src/components/buttons/MRT_ToggleDensePaddingButton.tsx +1 -2
  59. package/src/components/buttons/MRT_ToggleFiltersButton.test.tsx +38 -0
  60. package/src/components/buttons/MRT_ToggleFiltersButton.tsx +1 -2
  61. package/src/components/buttons/MRT_ToggleFullScreenButton.test.tsx +36 -0
  62. package/src/components/buttons/MRT_ToggleFullScreenButton.tsx +1 -2
  63. package/src/components/buttons/MRT_ToggleGlobalFilterButton.tsx +1 -2
  64. package/src/components/buttons/MRT_ToggleRowActionMenuButton.tsx +2 -3
  65. package/src/components/footer/MRT_TableFooter.tsx +1 -2
  66. package/src/components/footer/MRT_TableFooterCell.tsx +1 -2
  67. package/src/components/head/MRT_TableHead.tsx +1 -2
  68. package/src/components/head/MRT_TableHeadCell.tsx +9 -9
  69. package/src/components/head/MRT_TableHeadCellFilterContainer.tsx +1 -2
  70. package/src/components/head/MRT_TableHeadCellGrabHandle.test.tsx +61 -0
  71. package/src/components/head/MRT_TableHeadCellGrabHandle.tsx +4 -5
  72. package/src/components/head/MRT_TableHeadCellResizeHandle.test.tsx +45 -0
  73. package/src/components/head/MRT_TableHeadCellResizeHandle.tsx +4 -5
  74. package/src/components/head/MRT_TableHeadCellSortLabel.tsx +1 -2
  75. package/src/components/inputs/MRT_EditCellTextField.test.tsx +36 -0
  76. package/src/components/inputs/MRT_EditCellTextField.tsx +1 -3
  77. package/src/components/inputs/MRT_FilterCheckbox.tsx +1 -2
  78. package/src/components/inputs/MRT_FilterRangeSlider.tsx +2 -1
  79. package/src/components/inputs/MRT_FilterTextField.test.tsx +75 -0
  80. package/src/components/inputs/MRT_GlobalFilterTextField.tsx +1 -2
  81. package/src/components/inputs/MRT_SelectCheckbox.test.tsx +69 -0
  82. package/src/components/inputs/MRT_SelectCheckbox.tsx +1 -2
  83. package/src/components/menus/MRT_CellActionMenu.tsx +1 -2
  84. package/src/components/menus/MRT_ColumnActionMenu.tsx +12 -13
  85. package/src/components/menus/MRT_FilterOptionMenu.tsx +1 -2
  86. package/src/components/menus/MRT_RowActionMenu.tsx +1 -2
  87. package/src/components/menus/MRT_ShowHideColumnsMenu.tsx +1 -2
  88. package/src/components/menus/MRT_ShowHideColumnsMenuItems.tsx +4 -5
  89. package/src/components/modals/MRT_EditRowModal.test.tsx +54 -0
  90. package/src/components/modals/MRT_EditRowModal.tsx +1 -2
  91. package/src/components/table/MRT_Table.tsx +4 -5
  92. package/src/components/table/MRT_TableContainer.tsx +1 -2
  93. package/src/components/table/MRT_TablePaper.tsx +1 -2
  94. package/src/components/toolbar/MRT_BottomToolbar.tsx +2 -3
  95. package/src/components/toolbar/MRT_LinearProgressBar.tsx +1 -2
  96. package/src/components/toolbar/MRT_TablePagination.tsx +1 -2
  97. package/src/components/toolbar/MRT_ToolbarAlertBanner.tsx +3 -4
  98. package/src/components/toolbar/MRT_ToolbarDropZone.test.tsx +42 -0
  99. package/src/components/toolbar/MRT_ToolbarDropZone.tsx +1 -2
  100. package/src/components/toolbar/MRT_TopToolbar.tsx +1 -2
  101. package/src/fns/aggregationFns.test.tsx +57 -0
  102. package/src/fns/filterFns.test.tsx +156 -0
  103. package/src/fns/filterFns.ts +36 -22
  104. package/src/fns/sortingFns.ts +14 -5
  105. package/src/fns/tableFeatures.test.tsx +106 -0
  106. package/src/fns/tableFeatures.ts +103 -0
  107. package/src/hooks/display-columns/getMRT_RowExpandColumnDef.tsx +2 -2
  108. package/src/hooks/useMRT_ColumnVirtualizer.ts +6 -5
  109. package/src/hooks/useMRT_Effects.ts +3 -4
  110. package/src/hooks/useMRT_RowVirtualizer.ts +1 -2
  111. package/src/hooks/useMRT_Rows.ts +1 -2
  112. package/src/hooks/useMRT_TableInstance.ts +82 -63
  113. package/src/hooks/useMRT_TableOptions.ts +5 -37
  114. package/src/icons.ts +1 -1
  115. package/src/types.ts +162 -134
  116. package/src/utils/column.utils.ts +31 -24
  117. package/src/utils/row.utils.ts +7 -10
  118. package/src/utils/style.utils.ts +9 -10
  119. package/src/utils/tanstack.helpers.ts +2 -2
  120. package/dist/index.d.mts +0 -1925
  121. package/dist/index.mjs +0 -5409
  122. package/dist/index.mjs.map +0 -1
  123. package/locales/ar/index.d.ts +0 -3
  124. package/locales/ar/index.js +0 -98
  125. package/locales/az/index.d.ts +0 -3
  126. package/locales/az/index.js +0 -98
  127. package/locales/bg/index.d.ts +0 -3
  128. package/locales/bg/index.js +0 -98
  129. package/locales/cs/index.d.ts +0 -3
  130. package/locales/cs/index.js +0 -98
  131. package/locales/da/index.d.ts +0 -3
  132. package/locales/da/index.js +0 -98
  133. package/locales/de/index.d.ts +0 -3
  134. package/locales/de/index.js +0 -98
  135. package/locales/el/index.d.ts +0 -3
  136. package/locales/el/index.js +0 -98
  137. package/locales/en/index.d.ts +0 -3
  138. package/locales/en/index.js +0 -98
  139. package/locales/es/index.d.ts +0 -3
  140. package/locales/es/index.js +0 -98
  141. package/locales/et/index.d.ts +0 -3
  142. package/locales/et/index.js +0 -98
  143. package/locales/fa/index.d.ts +0 -3
  144. package/locales/fa/index.js +0 -98
  145. package/locales/fi/index.d.ts +0 -3
  146. package/locales/fi/index.js +0 -98
  147. package/locales/fr/index.d.ts +0 -3
  148. package/locales/fr/index.js +0 -98
  149. package/locales/he/index.d.ts +0 -3
  150. package/locales/he/index.js +0 -98
  151. package/locales/hr/index.d.ts +0 -3
  152. package/locales/hr/index.js +0 -98
  153. package/locales/hu/index.d.ts +0 -3
  154. package/locales/hu/index.js +0 -98
  155. package/locales/hy/index.d.ts +0 -3
  156. package/locales/hy/index.js +0 -98
  157. package/locales/id/index.d.ts +0 -3
  158. package/locales/id/index.js +0 -98
  159. package/locales/it/index.d.ts +0 -3
  160. package/locales/it/index.js +0 -98
  161. package/locales/ja/index.d.ts +0 -3
  162. package/locales/ja/index.js +0 -98
  163. package/locales/ko/index.d.ts +0 -3
  164. package/locales/ko/index.js +0 -98
  165. package/locales/nl/index.d.ts +0 -3
  166. package/locales/nl/index.js +0 -98
  167. package/locales/no/index.d.ts +0 -3
  168. package/locales/no/index.js +0 -98
  169. package/locales/np/index.d.ts +0 -3
  170. package/locales/np/index.js +0 -98
  171. package/locales/pl/index.d.ts +0 -3
  172. package/locales/pl/index.js +0 -98
  173. package/locales/pt/index.d.ts +0 -3
  174. package/locales/pt/index.js +0 -98
  175. package/locales/pt-BR/index.d.ts +0 -3
  176. package/locales/pt-BR/index.js +0 -98
  177. package/locales/ro/index.d.ts +0 -3
  178. package/locales/ro/index.js +0 -98
  179. package/locales/ru/index.d.ts +0 -3
  180. package/locales/ru/index.js +0 -98
  181. package/locales/sk/index.d.ts +0 -3
  182. package/locales/sk/index.js +0 -98
  183. package/locales/sr-Cyrl-RS/index.d.ts +0 -3
  184. package/locales/sr-Cyrl-RS/index.js +0 -98
  185. package/locales/sr-Latn-RS/index.d.ts +0 -3
  186. package/locales/sr-Latn-RS/index.js +0 -98
  187. package/locales/sv/index.d.ts +0 -3
  188. package/locales/sv/index.js +0 -98
  189. package/locales/tr/index.d.ts +0 -3
  190. package/locales/tr/index.js +0 -98
  191. package/locales/uk/index.d.ts +0 -3
  192. package/locales/uk/index.js +0 -98
  193. package/locales/vi/index.d.ts +0 -3
  194. package/locales/vi/index.js +0 -98
  195. package/locales/zh-Hans/index.d.ts +0 -3
  196. package/locales/zh-Hans/index.js +0 -98
  197. package/locales/zh-Hant/index.d.ts +0 -3
  198. package/locales/zh-Hant/index.js +0 -98
@@ -0,0 +1,54 @@
1
+ import { render } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { describe, expect, test } from 'vitest';
4
+
5
+ import { type MRT_ColumnDef } from '../../types';
6
+ import { MaterialReactTable } from '../MaterialReactTable';
7
+
8
+ interface Person {
9
+ name: string;
10
+ }
11
+
12
+ const data: Person[] = [{ name: 'Alice' }];
13
+
14
+ const columns = (): MRT_ColumnDef<Person>[] => [
15
+ { accessorKey: 'name', header: 'Name' },
16
+ ];
17
+
18
+ describe('row editing', () => {
19
+ test('opens the edit modal when the edit button is clicked', async () => {
20
+ const user = userEvent.setup();
21
+ const { baseElement, container } = render(
22
+ <MaterialReactTable
23
+ columns={columns()}
24
+ data={data}
25
+ editDisplayMode="modal"
26
+ enableEditing
27
+ />,
28
+ );
29
+
30
+ await user.click(
31
+ container.querySelector('[aria-label="Edit"]') as HTMLElement,
32
+ );
33
+
34
+ expect(baseElement.querySelectorAll('input').length).toBeGreaterThan(0);
35
+ });
36
+
37
+ test('opens inline inputs when editDisplayMode is row', async () => {
38
+ const user = userEvent.setup();
39
+ const { container } = render(
40
+ <MaterialReactTable
41
+ columns={columns()}
42
+ data={data}
43
+ editDisplayMode="row"
44
+ enableEditing
45
+ />,
46
+ );
47
+
48
+ await user.click(
49
+ container.querySelector('[aria-label="Edit"]') as HTMLElement,
50
+ );
51
+
52
+ expect(container.querySelectorAll('tbody input').length).toBeGreaterThan(0);
53
+ });
54
+ });
@@ -25,7 +25,6 @@ export const MRT_EditRowModal = <TData extends MRT_RowData>({
25
25
  ...rest
26
26
  }: MRT_EditRowModalProps<TData>) => {
27
27
  const {
28
- getState,
29
28
  options: {
30
29
  localization,
31
30
  muiCreateRowModalProps,
@@ -38,7 +37,7 @@ export const MRT_EditRowModal = <TData extends MRT_RowData>({
38
37
  setCreatingRow,
39
38
  setEditingRow,
40
39
  } = table;
41
- const { creatingRow, editingRow } = getState();
40
+ const { creatingRow, editingRow } = table.state;
42
41
  const row = (creatingRow ?? editingRow) as MRT_Row<TData>;
43
42
 
44
43
  const dialogProps = {
@@ -19,7 +19,6 @@ export const MRT_Table = <TData extends MRT_RowData>({
19
19
  }: MRT_TableProps<TData>) => {
20
20
  const {
21
21
  getFlatHeaders,
22
- getState,
23
22
  options: {
24
23
  columns,
25
24
  enableStickyHeader,
@@ -31,8 +30,8 @@ export const MRT_Table = <TData extends MRT_RowData>({
31
30
  renderCaption,
32
31
  },
33
32
  } = table;
34
- const { columnSizing, columnSizingInfo, columnVisibility, isFullScreen } =
35
- getState();
33
+ const { columnResizing, columnSizing, columnVisibility, isFullScreen } =
34
+ table.state;
36
35
 
37
36
  const tableProps = {
38
37
  ...parseFromValuesOrFunc(muiTableProps, { table }),
@@ -51,7 +50,7 @@ export const MRT_Table = <TData extends MRT_RowData>({
51
50
  colSizes[`--col-${parseCSSVarId(header.column.id)}-size`] = colSize;
52
51
  }
53
52
  return colSizes;
54
- }, [columns, columnSizing, columnSizingInfo, columnVisibility]);
53
+ }, [columns, columnSizing, columnResizing, columnVisibility]);
55
54
 
56
55
  const columnVirtualizer = useMRT_ColumnVirtualizer(table);
57
56
 
@@ -74,7 +73,7 @@ export const MRT_Table = <TData extends MRT_RowData>({
74
73
  >
75
74
  {!!Caption && <caption>{Caption}</caption>}
76
75
  {enableTableHead && <MRT_TableHead {...commonTableGroupProps} />}
77
- {memoMode === 'table-body' || columnSizingInfo.isResizingColumn ? (
76
+ {memoMode === 'table-body' || columnResizing.isResizingColumn ? (
78
77
  <Memo_MRT_TableBody {...commonTableGroupProps} />
79
78
  ) : (
80
79
  <MRT_TableBody {...commonTableGroupProps} />
@@ -21,7 +21,6 @@ export const MRT_TableContainer = <TData extends MRT_RowData>({
21
21
  ...rest
22
22
  }: MRT_TableContainerProps<TData>) => {
23
23
  const {
24
- getState,
25
24
  options: {
26
25
  createDisplayMode,
27
26
  editDisplayMode,
@@ -38,7 +37,7 @@ export const MRT_TableContainer = <TData extends MRT_RowData>({
38
37
  isFullScreen,
39
38
  isLoading,
40
39
  showLoadingOverlay,
41
- } = getState();
40
+ } = table.state;
42
41
 
43
42
  const loading =
44
43
  showLoadingOverlay !== false && (isLoading || showLoadingOverlay);
@@ -17,7 +17,6 @@ export const MRT_TablePaper = <TData extends MRT_RowData>({
17
17
  ...rest
18
18
  }: MRT_TablePaperProps<TData>) => {
19
19
  const {
20
- getState,
21
20
  options: {
22
21
  enableBottomToolbar,
23
22
  enableTopToolbar,
@@ -28,7 +27,7 @@ export const MRT_TablePaper = <TData extends MRT_RowData>({
28
27
  },
29
28
  refs: { tablePaperRef },
30
29
  } = table;
31
- const { isFullScreen } = getState();
30
+ const { isFullScreen } = table.state;
32
31
 
33
32
  const paperProps = {
34
33
  ...parseFromValuesOrFunc(muiTablePaperProps, { table }),
@@ -1,4 +1,4 @@
1
- import { Box, useMediaQuery, type BoxProps } from '@mui/material';
1
+ import { Box, type BoxProps, useMediaQuery } from '@mui/material';
2
2
  import { alpha } from '@mui/material/styles';
3
3
 
4
4
  import { type MRT_RowData, type MRT_TableInstance } from '../../types';
@@ -19,7 +19,6 @@ export const MRT_BottomToolbar = <TData extends MRT_RowData>({
19
19
  ...rest
20
20
  }: MRT_BottomToolbarProps<TData>) => {
21
21
  const {
22
- getState,
23
22
  options: {
24
23
  enablePagination,
25
24
  muiBottomToolbarProps,
@@ -30,7 +29,7 @@ export const MRT_BottomToolbar = <TData extends MRT_RowData>({
30
29
  },
31
30
  refs: { bottomToolbarRef },
32
31
  } = table;
33
- const { isFullScreen } = getState();
32
+ const { isFullScreen } = table.state;
34
33
 
35
34
  const isMobile = useMediaQuery('(max-width:720px)');
36
35
 
@@ -16,10 +16,9 @@ export const MRT_LinearProgressBar = <TData extends MRT_RowData>({
16
16
  ...rest
17
17
  }: MRT_LinearProgressBarProps<TData>) => {
18
18
  const {
19
- getState,
20
19
  options: { muiLinearProgressProps },
21
20
  } = table;
22
- const { isSaving, showProgressBars } = getState();
21
+ const { isSaving, showProgressBars } = table.state;
23
22
 
24
23
  const linearProgressProps = {
25
24
  ...parseFromValuesOrFunc(muiLinearProgressProps, {
@@ -37,7 +37,6 @@ export const MRT_TablePagination = <TData extends MRT_RowData>({
37
37
  const isMobile = useMediaQuery('(max-width: 720px)');
38
38
 
39
39
  const {
40
- getState,
41
40
  options: {
42
41
  enableToolbarInternalActions,
43
42
  icons: { ChevronLeftIcon, ChevronRightIcon, FirstPageIcon, LastPageIcon },
@@ -49,7 +48,7 @@ export const MRT_TablePagination = <TData extends MRT_RowData>({
49
48
  } = table;
50
49
  const {
51
50
  pagination: { pageIndex = 0, pageSize = 10 },
52
- } = getState();
51
+ } = table.state;
53
52
 
54
53
  const paginationProps = {
55
54
  ...parseFromValuesOrFunc(muiPaginationProps, {
@@ -26,7 +26,6 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
26
26
  const {
27
27
  getCoreRowModel,
28
28
  getFilteredSelectedRowModel,
29
- getState,
30
29
  options: {
31
30
  enableRowSelection,
32
31
  enableSelectAll,
@@ -40,7 +39,7 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
40
39
  },
41
40
  refs: { tablePaperRef },
42
41
  } = table;
43
- const { density, grouping, rowSelection, showAlertBanner } = getState();
42
+ const { density, grouping, rowSelection, showAlertBanner } = table.state;
44
43
 
45
44
  const alertProps = {
46
45
  ...parseFromValuesOrFunc(muiToolbarAlertBannerProps, {
@@ -100,8 +99,8 @@ export const MRT_ToolbarAlertBanner = <TData extends MRT_RowData>({
100
99
  <Fragment key={`${index}-${columnId}`}>
101
100
  {index > 0 ? localization.thenBy : ''}
102
101
  <Chip
103
- label={table.getColumn(columnId).columnDef.header}
104
- onDelete={() => table.getColumn(columnId).toggleGrouping()}
102
+ label={table.getColumn(columnId)?.columnDef.header}
103
+ onDelete={() => table.getColumn(columnId)?.toggleGrouping()}
105
104
  {...chipProps}
106
105
  />
107
106
  </Fragment>
@@ -0,0 +1,42 @@
1
+ import { fireEvent, render } from '@testing-library/react';
2
+ import { describe, expect, test } from 'vitest';
3
+
4
+ import { type MRT_ColumnDef } from '../../types';
5
+ import { MaterialReactTable } from '../MaterialReactTable';
6
+
7
+ interface Person {
8
+ city: string;
9
+ name: string;
10
+ }
11
+
12
+ const data: Person[] = [
13
+ { city: 'Glasgow', name: 'Alice' },
14
+ { city: 'Glasgow', name: 'Bob' },
15
+ ];
16
+
17
+ const columns = (): MRT_ColumnDef<Person>[] => [
18
+ { accessorKey: 'name', header: 'Name' },
19
+ { accessorKey: 'city', header: 'City' },
20
+ ];
21
+
22
+ describe('grouping drop zone', () => {
23
+ test('dropping a column on it groups by that column', () => {
24
+ const { container } = render(
25
+ <MaterialReactTable columns={columns()} data={data} enableGrouping />,
26
+ );
27
+
28
+ const handle = container.querySelector(
29
+ 'thead button[aria-label="Move"]',
30
+ ) as HTMLElement;
31
+
32
+ fireEvent.dragStart(handle, {
33
+ dataTransfer: { setDragImage: () => {} },
34
+ });
35
+ fireEvent.dragEnter(
36
+ container.querySelector('[class*="ToolbarDropZone"]') as HTMLElement,
37
+ );
38
+ fireEvent.dragEnd(handle);
39
+
40
+ expect(container.textContent).toContain('Grouped by');
41
+ });
42
+ });
@@ -17,14 +17,13 @@ export const MRT_ToolbarDropZone = <TData extends MRT_RowData>({
17
17
  ...rest
18
18
  }: MRT_ToolbarDropZoneProps<TData>) => {
19
19
  const {
20
- getState,
21
20
  options: { enableGrouping, localization },
22
21
  setHoveredColumn,
23
22
  setShowToolbarDropZone,
24
23
  } = table;
25
24
 
26
25
  const { draggingColumn, grouping, hoveredColumn, showToolbarDropZone } =
27
- getState();
26
+ table.state;
28
27
 
29
28
  const handleDragEnter = (_event: DragEvent<HTMLDivElement>) => {
30
29
  setHoveredColumn({ id: 'drop-zone' });
@@ -18,7 +18,6 @@ export const MRT_TopToolbar = <TData extends MRT_RowData>({
18
18
  table,
19
19
  }: MRT_TopToolbarProps<TData>) => {
20
20
  const {
21
- getState,
22
21
  options: {
23
22
  enableGlobalFilter,
24
23
  enablePagination,
@@ -33,7 +32,7 @@ export const MRT_TopToolbar = <TData extends MRT_RowData>({
33
32
  refs: { topToolbarRef },
34
33
  } = table;
35
34
 
36
- const { isFullScreen, showGlobalFilter } = getState();
35
+ const { isFullScreen, showGlobalFilter } = table.state;
37
36
 
38
37
  const isMobile = useMediaQuery('(max-width:720px)');
39
38
  const isTablet = useMediaQuery('(max-width:1024px)');
@@ -0,0 +1,57 @@
1
+ import { render } from '@testing-library/react';
2
+ import { describe, expect, test } from 'vitest';
3
+
4
+ import { MaterialReactTable } from '../components/MaterialReactTable';
5
+ import { type MRT_ColumnDef } from '../types';
6
+
7
+ interface Sale {
8
+ amount: number;
9
+ region: string;
10
+ }
11
+
12
+ const data: Sale[] = [
13
+ { amount: 10, region: 'North' },
14
+ { amount: 30, region: 'North' },
15
+ { amount: 100, region: 'South' },
16
+ ];
17
+
18
+ const columns = (aggregationFn: string): MRT_ColumnDef<Sale>[] => [
19
+ { accessorKey: 'region', header: 'Region' },
20
+ {
21
+ accessorKey: 'amount',
22
+ AggregatedCell: ({ cell }) => <span>agg:{String(cell.getValue())}</span>,
23
+ aggregationFn,
24
+ header: 'Amount',
25
+ },
26
+ ];
27
+
28
+ const renderGrouped = (aggregationFn: string) =>
29
+ render(
30
+ <MaterialReactTable
31
+ columns={columns(aggregationFn)}
32
+ data={data}
33
+ enableExpanding
34
+ enableGrouping
35
+ initialState={{ expanded: true, grouping: ['region'] }}
36
+ />,
37
+ ).container;
38
+
39
+ describe('aggregation fns', () => {
40
+ test.each([
41
+ ['sum', ['agg:40', 'agg:100']],
42
+ ['max', ['agg:30', 'agg:100']],
43
+ ['min', ['agg:10', 'agg:100']],
44
+ ['mean', ['agg:20', 'agg:100']],
45
+ ['count', ['agg:2', 'agg:1']],
46
+ ])('%s aggregates each group', (aggregationFn, expected) => {
47
+ const container = renderGrouped(aggregationFn);
48
+
49
+ const aggregated = Array.from(
50
+ container.querySelectorAll('tbody td'),
51
+ )
52
+ .map((td) => td.textContent)
53
+ .filter((text) => text?.startsWith('agg:'));
54
+
55
+ expect(aggregated).toEqual(expected);
56
+ });
57
+ });
@@ -0,0 +1,156 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, expect, test } from 'vitest';
3
+
4
+ import { MaterialReactTable } from '../components/MaterialReactTable';
5
+ import { type MRT_ColumnDef } from '../types';
6
+
7
+ interface Person {
8
+ name: string;
9
+ }
10
+
11
+ const data: Person[] = [
12
+ { name: 'Jonathan' },
13
+ { name: 'John' },
14
+ { name: 'Sara' },
15
+ { name: 'Aaron' },
16
+ ];
17
+
18
+ const columns: MRT_ColumnDef<Person>[] = [
19
+ { accessorKey: 'name', header: 'Name' },
20
+ ];
21
+
22
+ const renderedNames = (container: HTMLElement) =>
23
+ Array.from(container.querySelectorAll('tbody tr')).map(
24
+ (row) => row.textContent,
25
+ );
26
+
27
+ describe('fuzzy global filter', () => {
28
+ test('keeps rows whose value matches the term and drops the rest', () => {
29
+ render(
30
+ <MaterialReactTable
31
+ columns={columns}
32
+ data={data}
33
+ initialState={{ globalFilter: 'john' }}
34
+ />,
35
+ );
36
+
37
+ expect(screen.getByText('John')).toBeInTheDocument();
38
+ expect(screen.getByText('Jonathan')).toBeInTheDocument();
39
+ expect(screen.queryByText('Sara')).not.toBeInTheDocument();
40
+ expect(screen.queryByText('Aaron')).not.toBeInTheDocument();
41
+ });
42
+
43
+ test('orders matches by rank rather than by source order', () => {
44
+ const { container } = render(
45
+ <MaterialReactTable
46
+ columns={columns}
47
+ data={data}
48
+ initialState={{ globalFilter: 'john' }}
49
+ />,
50
+ );
51
+
52
+ expect(renderedNames(container)).toEqual(['John', 'Jonathan']);
53
+ });
54
+
55
+ test('falls back to source order when ranked results are disabled', () => {
56
+ const { container } = render(
57
+ <MaterialReactTable
58
+ columns={columns}
59
+ data={data}
60
+ enableGlobalFilterRankedResults={false}
61
+ initialState={{ globalFilter: 'john' }}
62
+ />,
63
+ );
64
+
65
+ expect(renderedNames(container)).toEqual(['Jonathan', 'John']);
66
+ });
67
+
68
+ test('drops every row when no value matches the term', () => {
69
+ const { container } = render(
70
+ <MaterialReactTable
71
+ columns={columns}
72
+ data={data}
73
+ initialState={{ globalFilter: 'zzz' }}
74
+ />,
75
+ );
76
+
77
+ expect(renderedNames(container)).toEqual(['No results found']);
78
+ });
79
+ });
80
+
81
+ interface Employee {
82
+ age: number;
83
+ name: string;
84
+ }
85
+
86
+ const employees: Employee[] = [
87
+ { age: 30, name: 'Alice' },
88
+ { age: 20, name: 'Bob' },
89
+ { age: 40, name: 'alice' },
90
+ ];
91
+
92
+ const employeeColumns = (): MRT_ColumnDef<Employee>[] => [
93
+ { accessorKey: 'name', header: 'Name' },
94
+ { accessorKey: 'age', header: 'Age' },
95
+ ];
96
+
97
+ const renderFiltered = (
98
+ columnId: string,
99
+ filterFn: string,
100
+ value: unknown,
101
+ ) => {
102
+ const { container } = render(
103
+ <MaterialReactTable
104
+ columns={employeeColumns()}
105
+ data={employees}
106
+ initialState={{
107
+ columnFilterFns: { [columnId]: filterFn },
108
+ columnFilters: [{ id: columnId, value }],
109
+ }}
110
+ />,
111
+ );
112
+ return Array.from(container.querySelectorAll('tbody tr')).map(
113
+ (row) => row.querySelector('td')?.textContent,
114
+ );
115
+ };
116
+
117
+ describe('column filter fns', () => {
118
+ test.each([
119
+ ['contains', 'ali', ['Alice', 'alice']],
120
+ ['startsWith', 'al', ['Alice', 'alice']],
121
+ ['endsWith', 'ce', ['Alice', 'alice']],
122
+ ['equals', 'alice', ['Alice', 'alice']],
123
+ ['notEquals', 'alice', ['Bob']],
124
+ ['fuzzy', 'bob', ['Bob']],
125
+ ['includesString', 'ali', ['Alice', 'alice']],
126
+ ['includesStringSensitive', 'ali', ['alice']],
127
+ ['equalsString', 'alice', ['Alice', 'alice']],
128
+ ['equalsStringSensitive', 'alice', ['alice']],
129
+ ])('%s filters the name column', (filterFn, value, expected) => {
130
+ expect(renderFiltered('name', filterFn, value)).toEqual(expected);
131
+ });
132
+
133
+ test.each([
134
+ ['greaterThan', 25, ['Alice', 'alice']],
135
+ ['greaterThanOrEqualTo', 30, ['Alice', 'alice']],
136
+ ['lessThan', 30, ['Bob']],
137
+ ['lessThanOrEqualTo', 20, ['Bob']],
138
+ ])('%s filters the age column', (filterFn, value, expected) => {
139
+ expect(renderFiltered('age', filterFn, value)).toEqual(expected);
140
+ });
141
+
142
+ test.each([
143
+ ['between', [25, 45], ['Alice', 'alice']],
144
+ ['betweenInclusive', [20, 30], ['Alice', 'Bob']],
145
+ ['inNumberRange', [20, 30], ['Alice', 'Bob']],
146
+ ])('%s filters the age column by range', (filterFn, value, expected) => {
147
+ expect(renderFiltered('age', filterFn, value)).toEqual(expected);
148
+ });
149
+
150
+ test.each([
151
+ ['empty', ['No results found']],
152
+ ['notEmpty', ['Alice', 'Bob', 'alice']],
153
+ ])('%s applies to the name column', (filterFn, expected) => {
154
+ expect(renderFiltered('name', filterFn, 'x')).toEqual(expected);
155
+ });
156
+ });