@cutting/material-react-table 4.1.0 → 5.0.0-beta.1

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,61 @@
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[] = [{ city: 'Glasgow', name: 'Alice' }];
13
+
14
+ const columns = (): MRT_ColumnDef<Person>[] => [
15
+ { accessorKey: 'name', header: 'Name' },
16
+ { accessorKey: 'city', header: 'City' },
17
+ ];
18
+
19
+ const headerOrder = (container: HTMLElement) =>
20
+ Array.from(container.querySelectorAll('thead th')).map((th) =>
21
+ th.textContent?.replace(/[^A-Za-z]/g, ''),
22
+ );
23
+
24
+ const dragColumnOnto = (container: HTMLElement, from: string, to: string) => {
25
+ const handles = Array.from(
26
+ container.querySelectorAll<HTMLElement>('thead [aria-label="Move"]'),
27
+ );
28
+ const headerCells = Array.from(
29
+ container.querySelectorAll<HTMLElement>('thead th'),
30
+ );
31
+ const fromIndex = headerCells.findIndex((th) =>
32
+ th.textContent?.includes(from),
33
+ );
34
+ const toIndex = headerCells.findIndex((th) => th.textContent?.includes(to));
35
+
36
+ fireEvent.dragStart(handles[fromIndex], {
37
+ dataTransfer: { setDragImage: () => {} },
38
+ });
39
+ fireEvent.dragEnter(headerCells[toIndex]);
40
+ fireEvent.dragOver(headerCells[toIndex]);
41
+ fireEvent.drop(headerCells[toIndex]);
42
+ fireEvent.dragEnd(handles[fromIndex]);
43
+ };
44
+
45
+ describe('column dragging', () => {
46
+ test('reorders columns when one is dragged onto another', () => {
47
+ const { container } = render(
48
+ <MaterialReactTable
49
+ columns={columns()}
50
+ data={data}
51
+ enableColumnOrdering
52
+ />,
53
+ );
54
+
55
+ expect(headerOrder(container)).toEqual(['Name', 'City']);
56
+
57
+ dragColumnOnto(container, 'Name', 'City');
58
+
59
+ expect(headerOrder(container)).toEqual(['City', 'Name']);
60
+ });
61
+ });
@@ -24,7 +24,6 @@ export const MRT_TableHeadCellGrabHandle = <TData extends MRT_RowData>({
24
24
  ...rest
25
25
  }: MRT_TableHeadCellGrabHandleProps<TData>) => {
26
26
  const {
27
- getState,
28
27
  options: { enableColumnOrdering, muiColumnDragHandleProps },
29
28
  setColumnOrder,
30
29
  setColumnPinning,
@@ -32,7 +31,7 @@ export const MRT_TableHeadCellGrabHandle = <TData extends MRT_RowData>({
32
31
  setHoveredColumn,
33
32
  } = table;
34
33
  const { columnDef } = column;
35
- const { columnOrder, draggingColumn, hoveredColumn } = getState();
34
+ const { columnOrder, draggingColumn, hoveredColumn } = table.state;
36
35
 
37
36
  const iconButtonProps = {
38
37
  ...parseFromValuesOrFunc(muiColumnDragHandleProps, { column, table }),
@@ -72,9 +71,9 @@ export const MRT_TableHeadCellGrabHandle = <TData extends MRT_RowData>({
72
71
  columnOrder,
73
72
  );
74
73
  setColumnOrder(reorderedColumns);
75
- setColumnPinning(({ left = [], right = [] }) => ({
76
- left: reorderedColumns.filter((header) => left.includes(header)),
77
- right: reorderedColumns.filter((header) => right.includes(header)),
74
+ setColumnPinning(({ end = [], start = [] }) => ({
75
+ end: reorderedColumns.filter((header) => end.includes(header)),
76
+ start: reorderedColumns.filter((header) => start.includes(header)),
78
77
  }));
79
78
  }
80
79
  setDraggingColumn(null);
@@ -0,0 +1,45 @@
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[] = [{ city: 'Glasgow', name: 'Alice' }];
13
+
14
+ const columns = (): MRT_ColumnDef<Person>[] => [
15
+ { accessorKey: 'name', header: 'Name' },
16
+ { accessorKey: 'city', header: 'City' },
17
+ ];
18
+
19
+ const nameColumnSize = (container: HTMLElement) =>
20
+ (container.querySelector('table') as HTMLElement).style.getPropertyValue(
21
+ '--header-name-size',
22
+ );
23
+
24
+ describe('column resizing', () => {
25
+ test('dragging the resize handle widens the column', () => {
26
+ const { container } = render(
27
+ <MaterialReactTable
28
+ columns={columns()}
29
+ data={data}
30
+ enableColumnResizing
31
+ />,
32
+ );
33
+
34
+ const before = nameColumnSize(container);
35
+ const handle = container.querySelector(
36
+ 'thead .Mui-TableHeadCell-ResizeHandle-Wrapper',
37
+ ) as HTMLElement;
38
+
39
+ fireEvent.mouseDown(handle, { clientX: 0 });
40
+ fireEvent.mouseMove(document, { clientX: 120 });
41
+ fireEvent.mouseUp(document, { clientX: 120 });
42
+
43
+ expect(nameColumnSize(container)).not.toBe(before);
44
+ });
45
+ });
@@ -20,11 +20,10 @@ export const MRT_TableHeadCellResizeHandle = <TData extends MRT_RowData>({
20
20
  ...rest
21
21
  }: MRT_TableHeadCellResizeHandleProps<TData>) => {
22
22
  const {
23
- getState,
24
23
  options: { columnResizeDirection, columnResizeMode },
25
- setColumnSizingInfo,
24
+ setColumnResizing,
26
25
  } = table;
27
- const { density } = getState();
26
+ const { density } = table.state;
28
27
  const { column } = header;
29
28
 
30
29
  const handler = header.getResizeHandler();
@@ -42,7 +41,7 @@ export const MRT_TableHeadCellResizeHandle = <TData extends MRT_RowData>({
42
41
  <Box
43
42
  className="Mui-TableHeadCell-ResizeHandle-Wrapper"
44
43
  onDoubleClick={() => {
45
- setColumnSizingInfo((old) => ({
44
+ setColumnResizing((old) => ({
46
45
  ...old,
47
46
  isResizingColumn: false,
48
47
  }));
@@ -55,7 +54,7 @@ export const MRT_TableHeadCellResizeHandle = <TData extends MRT_RowData>({
55
54
  column.getIsResizing() && columnResizeMode === 'onEnd'
56
55
  ? `translateX(${
57
56
  (columnResizeDirection === 'rtl' ? -1 : 1) *
58
- (getState().columnSizingInfo.deltaOffset ?? 0)
57
+ (table.state.columnResizing.deltaOffset ?? 0)
59
58
  }px)`
60
59
  : undefined,
61
60
  }}
@@ -21,7 +21,6 @@ export const MRT_TableHeadCellSortLabel = <TData extends MRT_RowData>({
21
21
  ...rest
22
22
  }: MRT_TableHeadCellSortLabelProps<TData>) => {
23
23
  const {
24
- getState,
25
24
  options: {
26
25
  icons: { ArrowDownwardIcon, SyncAltIcon },
27
26
  localization,
@@ -29,7 +28,7 @@ export const MRT_TableHeadCellSortLabel = <TData extends MRT_RowData>({
29
28
  } = table;
30
29
  const { column } = header;
31
30
  const { columnDef } = column;
32
- const { isLoading, showSkeletons, sorting } = getState();
31
+ const { isLoading, showSkeletons, sorting } = table.state;
33
32
 
34
33
  const isSorted = !!column.getIsSorted();
35
34
 
@@ -0,0 +1,36 @@
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('cell editing', () => {
19
+ test('opens a text field in the cell that was clicked', async () => {
20
+ const user = userEvent.setup();
21
+ const { container } = render(
22
+ <MaterialReactTable
23
+ columns={columns()}
24
+ data={data}
25
+ editDisplayMode="cell"
26
+ enableEditing
27
+ />,
28
+ );
29
+
30
+ expect(container.querySelectorAll('tbody input')).toHaveLength(0);
31
+
32
+ await user.dblClick(container.querySelector('tbody td') as HTMLElement);
33
+
34
+ expect(container.querySelectorAll('tbody input')).toHaveLength(1);
35
+ });
36
+ });
@@ -28,7 +28,6 @@ export const MRT_EditCellTextField = <TData extends MRT_RowData>({
28
28
  ...rest
29
29
  }: MRT_EditCellTextFieldProps<TData>) => {
30
30
  const {
31
- getState,
32
31
  options: { createDisplayMode, editDisplayMode, muiEditTextFieldProps },
33
32
  refs: { editInputRefs },
34
33
  setCreatingRow,
@@ -37,7 +36,7 @@ export const MRT_EditCellTextField = <TData extends MRT_RowData>({
37
36
  } = table;
38
37
  const { column, row } = cell;
39
38
  const { columnDef } = column;
40
- const { creatingRow, editingRow } = getState();
39
+ const { creatingRow, editingRow } = table.state;
41
40
  const { editSelectOptions, editVariant } = columnDef;
42
41
 
43
42
  const isCreating = creatingRow?.id === row.id;
@@ -72,7 +71,6 @@ export const MRT_EditCellTextField = <TData extends MRT_RowData>({
72
71
  const isSelectEdit = editVariant === 'select' || textFieldProps?.select;
73
72
 
74
73
  const saveInputValueToRowCache = (newValue: string) => {
75
- //@ts-expect-error
76
74
  row._valuesCache[column.id] = newValue;
77
75
  if (isCreating) {
78
76
  setCreatingRow(row);
@@ -22,10 +22,9 @@ export const MRT_FilterCheckbox = <TData extends MRT_RowData>({
22
22
  ...rest
23
23
  }: MRT_FilterCheckboxProps<TData>) => {
24
24
  const {
25
- getState,
26
25
  options: { localization, muiFilterCheckboxProps },
27
26
  } = table;
28
- const { density } = getState();
27
+ const { density } = table.state;
29
28
  const { columnDef } = column;
30
29
 
31
30
  const checkboxProps = {
@@ -8,6 +8,7 @@ import {
8
8
  type MRT_RowData,
9
9
  type MRT_TableInstance,
10
10
  } from '../../types';
11
+ import { getColumnFilterInfo } from '../../utils/column.utils';
11
12
  import { parseFromValuesOrFunc } from '../../utils/utils';
12
13
 
13
14
  export interface MRT_FilterRangeSliderProps<TData extends MRT_RowData>
@@ -28,7 +29,7 @@ export const MRT_FilterRangeSlider = <TData extends MRT_RowData>({
28
29
  const { column } = header;
29
30
  const { columnDef } = column;
30
31
 
31
- const currentFilterOption = columnDef._filterFn;
32
+ const { currentFilterOption } = getColumnFilterInfo({ header, table });
32
33
 
33
34
  const showChangeModeButton =
34
35
  enableColumnFilterModes && columnDef.enableColumnFilterModes !== false;
@@ -0,0 +1,75 @@
1
+ import { render, waitFor } 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
+ city: string;
10
+ name: string;
11
+ }
12
+
13
+ const data: Person[] = [
14
+ { city: 'Glasgow', name: 'Alice' },
15
+ { city: 'Dundee', name: 'Bob' },
16
+ { city: 'Glasgow', name: 'Cara' },
17
+ ];
18
+
19
+ const columns = (): MRT_ColumnDef<Person>[] => [
20
+ { accessorKey: 'name', header: 'Name' },
21
+ { accessorKey: 'city', filterVariant: 'select', header: 'City' },
22
+ ];
23
+
24
+ describe('faceted select filter', () => {
25
+ test('offers the distinct values present in the data', async () => {
26
+ const user = userEvent.setup();
27
+ const { baseElement, container } = render(
28
+ <MaterialReactTable
29
+ columns={columns()}
30
+ data={data}
31
+ enableFacetedValues
32
+ initialState={{ showColumnFilters: true }}
33
+ />,
34
+ );
35
+
36
+ const selects = container.querySelectorAll<HTMLElement>(
37
+ 'thead [role="combobox"]',
38
+ );
39
+
40
+ await user.click(selects[selects.length - 1]);
41
+
42
+ const options = Array.from(
43
+ baseElement.querySelectorAll<HTMLElement>('li[role="option"]'),
44
+ ).map((li) => li.textContent);
45
+
46
+ expect(options).toContain('Glasgow (2)');
47
+ expect(options).toContain('Dundee (1)');
48
+ });
49
+
50
+ test('picking an option filters the rows', async () => {
51
+ const user = userEvent.setup();
52
+ const { container } = render(
53
+ <MaterialReactTable
54
+ columns={columns()}
55
+ data={data}
56
+ enableFacetedValues
57
+ initialState={{ showColumnFilters: true }}
58
+ />,
59
+ );
60
+
61
+ const selects = container.querySelectorAll<HTMLElement>(
62
+ 'thead [role="combobox"]',
63
+ );
64
+
65
+ await user.click(selects[selects.length - 1]);
66
+ await user.keyboard('{ArrowDown}{Enter}');
67
+
68
+ await waitFor(() => {
69
+ const names = Array.from(container.querySelectorAll('tbody tr')).map(
70
+ (tr) => tr.querySelector('td')?.textContent,
71
+ );
72
+ expect(names).toEqual(['Alice', 'Cara']);
73
+ });
74
+ });
75
+ });
@@ -28,7 +28,6 @@ export const MRT_GlobalFilterTextField = <TData extends MRT_RowData>({
28
28
  ...rest
29
29
  }: MRT_GlobalFilterTextFieldProps<TData>) => {
30
30
  const {
31
- getState,
32
31
  options: {
33
32
  enableGlobalFilterModes,
34
33
  icons: { CloseIcon, SearchIcon },
@@ -39,7 +38,7 @@ export const MRT_GlobalFilterTextField = <TData extends MRT_RowData>({
39
38
  refs: { searchInputRef },
40
39
  setGlobalFilter,
41
40
  } = table;
42
- const { globalFilter, showGlobalFilter } = getState();
41
+ const { globalFilter, showGlobalFilter } = table.state;
43
42
 
44
43
  const textFieldProps = {
45
44
  ...parseFromValuesOrFunc(muiSearchTextFieldProps, {
@@ -0,0 +1,69 @@
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' }, { name: 'Bob' }];
13
+
14
+ const columns = (): MRT_ColumnDef<Person>[] => [
15
+ { accessorKey: 'name', header: 'Name' },
16
+ ];
17
+
18
+ const selectAll = (container: HTMLElement) =>
19
+ container.querySelector('thead input[type="checkbox"]') as HTMLInputElement;
20
+
21
+ const rowBoxes = (container: HTMLElement) =>
22
+ Array.from(
23
+ container.querySelectorAll<HTMLInputElement>(
24
+ 'tbody input[type="checkbox"]',
25
+ ),
26
+ );
27
+
28
+ const renderTable = () =>
29
+ render(<MaterialReactTable columns={columns()} data={data} enableRowSelection />);
30
+
31
+ describe('row selection checkboxes', () => {
32
+ test('select all checks every row', async () => {
33
+ const user = userEvent.setup();
34
+ const { container } = renderTable();
35
+
36
+ await user.click(selectAll(container));
37
+
38
+ expect(rowBoxes(container).map((box) => box.checked)).toEqual([true, true]);
39
+ expect(selectAll(container).checked).toBe(true);
40
+ });
41
+
42
+ test('select all is indeterminate when only some rows are selected', async () => {
43
+ const user = userEvent.setup();
44
+ const { container } = renderTable();
45
+
46
+ await user.click(rowBoxes(container)[0]);
47
+
48
+ expect(selectAll(container).checked).toBe(false);
49
+ expect(selectAll(container).dataset.indeterminate).toBe('true');
50
+ });
51
+
52
+ test('select all is not indeterminate when every row is selected', async () => {
53
+ const user = userEvent.setup();
54
+ const { container } = renderTable();
55
+
56
+ await user.click(selectAll(container));
57
+
58
+ expect(selectAll(container).dataset.indeterminate).toBe('false');
59
+ });
60
+
61
+ test('clicking a row checkbox toggles only that row', async () => {
62
+ const user = userEvent.setup();
63
+ const { container } = renderTable();
64
+
65
+ await user.click(rowBoxes(container)[0]);
66
+
67
+ expect(rowBoxes(container).map((box) => box.checked)).toEqual([true, false]);
68
+ });
69
+ });
@@ -31,7 +31,6 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
31
31
  ...rest
32
32
  }: MRT_SelectCheckboxProps<TData>) => {
33
33
  const {
34
- getState,
35
34
  options: {
36
35
  enableMultiRowSelection,
37
36
  localization,
@@ -40,7 +39,7 @@ export const MRT_SelectCheckbox = <TData extends MRT_RowData>({
40
39
  selectAllMode,
41
40
  },
42
41
  } = table;
43
- const { density, isLoading } = getState();
42
+ const { density, isLoading } = table.state;
44
43
 
45
44
  const selectAll = !row;
46
45
 
@@ -15,7 +15,6 @@ export const MRT_CellActionMenu = <TData extends MRT_RowData>({
15
15
  ...rest
16
16
  }: MRT_CellActionMenuProps<TData>) => {
17
17
  const {
18
- getState,
19
18
  options: {
20
19
  editDisplayMode,
21
20
  enableClickToCopy,
@@ -27,7 +26,7 @@ export const MRT_CellActionMenu = <TData extends MRT_RowData>({
27
26
  },
28
27
  refs: { actionCellRef },
29
28
  } = table;
30
- const { actionCell, density } = getState();
29
+ const { actionCell, density } = table.state;
31
30
  const cell = actionCell!;
32
31
  const { row } = cell;
33
32
  const { column } = cell;
@@ -6,6 +6,7 @@ import {
6
6
  type MRT_RowData,
7
7
  type MRT_TableInstance,
8
8
  } from '../../types';
9
+ import { getColumnFilterInfo } from '../../utils/column.utils';
9
10
  import { MRT_ActionMenuItem } from './MRT_ActionMenuItem';
10
11
  import { MRT_FilterOptionMenu } from './MRT_FilterOptionMenu';
11
12
 
@@ -26,10 +27,8 @@ export const MRT_ColumnActionMenu = <TData extends MRT_RowData>({
26
27
  }: MRT_ColumnActionMenuProps<TData>) => {
27
28
  const {
28
29
  getAllLeafColumns,
29
- getState,
30
30
  options: {
31
31
  columnFilterDisplayMode,
32
- columnFilterModeOptions,
33
32
  enableColumnFilterModes,
34
33
  enableColumnFilters,
35
34
  enableColumnPinning,
@@ -56,13 +55,13 @@ export const MRT_ColumnActionMenu = <TData extends MRT_RowData>({
56
55
  refs: { filterInputRefs },
57
56
  setColumnFilterFns,
58
57
  setColumnOrder,
59
- setColumnSizingInfo,
58
+ setColumnResizing,
60
59
  setShowColumnFilters,
61
60
  } = table;
62
61
  const { column } = header;
63
62
  const { columnDef } = column;
64
63
  const { columnSizing, columnVisibility, density, showColumnFilters } =
65
- getState();
64
+ table.state;
66
65
  const columnFilterValue = column.getFilterValue();
67
66
 
68
67
  const [filterMenuAnchorEl, setFilterMenuAnchorEl] =
@@ -84,7 +83,7 @@ export const MRT_ColumnActionMenu = <TData extends MRT_RowData>({
84
83
  };
85
84
 
86
85
  const handleResetColumnSize = () => {
87
- setColumnSizingInfo((old) => ({ ...old, isResizingColumn: false }));
86
+ setColumnResizing((old) => ({ ...old, isResizingColumn: false }));
88
87
  column.resetSize();
89
88
  setAnchorEl(null);
90
89
  };
@@ -94,7 +93,7 @@ export const MRT_ColumnActionMenu = <TData extends MRT_RowData>({
94
93
  setAnchorEl(null);
95
94
  };
96
95
 
97
- const handlePinColumn = (pinDirection: 'left' | 'right' | false) => {
96
+ const handlePinColumn = (pinDirection: 'end' | 'start' | false) => {
98
97
  column.pin(pinDirection);
99
98
  setAnchorEl(null);
100
99
  };
@@ -108,7 +107,7 @@ export const MRT_ColumnActionMenu = <TData extends MRT_RowData>({
108
107
  const handleClearFilter = () => {
109
108
  column.setFilterValue(undefined);
110
109
  setAnchorEl(null);
111
- if (['empty', 'notEmpty'].includes(columnDef._filterFn)) {
110
+ if (['empty', 'notEmpty'].includes(currentFilterOption)) {
112
111
  setColumnFilterFns((prev) => ({
113
112
  ...prev,
114
113
  [header.id]: allowedColumnFilterOptions?.[0] ?? 'fuzzy',
@@ -136,8 +135,8 @@ export const MRT_ColumnActionMenu = <TData extends MRT_RowData>({
136
135
 
137
136
  const isSelectFilter = !!columnDef.filterSelectOptions;
138
137
 
139
- const allowedColumnFilterOptions =
140
- columnDef?.columnFilterModeOptions ?? columnFilterModeOptions;
138
+ const { allowedColumnFilterOptions, currentFilterOption } =
139
+ getColumnFilterInfo({ header, table });
141
140
 
142
141
  const showFilterModeSubMenu =
143
142
  enableColumnFilterModes &&
@@ -250,19 +249,19 @@ export const MRT_ColumnActionMenu = <TData extends MRT_RowData>({
250
249
  ...(enableColumnPinning && column.getCanPin()
251
250
  ? [
252
251
  <MRT_ActionMenuItem
253
- disabled={column.getIsPinned() === 'left' || !column.getCanPin()}
252
+ disabled={column.getIsPinned() === 'start' || !column.getCanPin()}
254
253
  icon={<PushPinIcon style={{ transform: 'rotate(90deg)' }} />}
255
254
  key={7}
256
255
  label={localization.pinToLeft}
257
- onClick={() => handlePinColumn('left')}
256
+ onClick={() => handlePinColumn('start')}
258
257
  table={table}
259
258
  />,
260
259
  <MRT_ActionMenuItem
261
- disabled={column.getIsPinned() === 'right' || !column.getCanPin()}
260
+ disabled={column.getIsPinned() === 'end' || !column.getCanPin()}
262
261
  icon={<PushPinIcon style={{ transform: 'rotate(-90deg)' }} />}
263
262
  key={8}
264
263
  label={localization.pinToRight}
265
- onClick={() => handlePinColumn('right')}
264
+ onClick={() => handlePinColumn('end')}
266
265
  table={table}
267
266
  />,
268
267
  <MRT_ActionMenuItem
@@ -125,7 +125,6 @@ export const MRT_FilterOptionMenu = <TData extends MRT_RowData>({
125
125
  ...rest
126
126
  }: MRT_FilterOptionMenuProps<TData>) => {
127
127
  const {
128
- getState,
129
128
  options: {
130
129
  columnFilterModeOptions,
131
130
  globalFilterModeOptions,
@@ -137,7 +136,7 @@ export const MRT_FilterOptionMenu = <TData extends MRT_RowData>({
137
136
  setColumnFilterFns,
138
137
  setGlobalFilterFn,
139
138
  } = table;
140
- const { density, globalFilterFn } = getState();
139
+ const { density, globalFilterFn } = table.state;
141
140
  const { column } = header ?? {};
142
141
  const { columnDef } = column ?? {};
143
142
  const currentFilterValue = column?.getFilterValue();
@@ -29,7 +29,6 @@ export const MRT_RowActionMenu = <TData extends MRT_RowData>({
29
29
  ...rest
30
30
  }: MRT_RowActionMenuProps<TData>) => {
31
31
  const {
32
- getState,
33
32
  options: {
34
33
  editDisplayMode,
35
34
  enableEditing,
@@ -39,7 +38,7 @@ export const MRT_RowActionMenu = <TData extends MRT_RowData>({
39
38
  renderRowActionMenuItems,
40
39
  },
41
40
  } = table;
42
- const { density } = getState();
41
+ const { density } = table.state;
43
42
 
44
43
  const menuItems = useMemo(() => {
45
44
  const items: ReactNode[] = [];
@@ -36,7 +36,6 @@ export const MRT_ShowHideColumnsMenu = <TData extends MRT_RowData>({
36
36
  getIsSomeColumnsVisible,
37
37
  getLeftLeafColumns,
38
38
  getRightLeafColumns,
39
- getState,
40
39
  initialState,
41
40
  options: {
42
41
  enableColumnOrdering,
@@ -46,7 +45,7 @@ export const MRT_ShowHideColumnsMenu = <TData extends MRT_RowData>({
46
45
  mrtTheme: { menuBackgroundColor },
47
46
  },
48
47
  } = table;
49
- const { columnOrder, columnPinning, density } = getState();
48
+ const { columnOrder, columnPinning, density } = table.state;
50
49
 
51
50
  const handleToggleAllColumns = (value?: boolean) => {
52
51
  const updates =
@@ -43,7 +43,6 @@ export const MRT_ShowHideColumnsMenuItems = <TData extends MRT_RowData>({
43
43
  ...rest
44
44
  }: MRT_ShowHideColumnsMenuItemsProps<TData>) => {
45
45
  const {
46
- getState,
47
46
  options: {
48
47
  enableColumnOrdering,
49
48
  enableColumnPinning,
@@ -54,7 +53,7 @@ export const MRT_ShowHideColumnsMenuItems = <TData extends MRT_RowData>({
54
53
  setColumnOrder,
55
54
  setColumnPinning,
56
55
  } = table;
57
- const { columnOrder } = getState();
56
+ const { columnOrder } = table.state;
58
57
  const { columnDef } = column;
59
58
  const { columnDefType } = columnDef;
60
59
 
@@ -93,9 +92,9 @@ export const MRT_ShowHideColumnsMenuItems = <TData extends MRT_RowData>({
93
92
  columnOrder,
94
93
  );
95
94
  setColumnOrder(reorderedColumns);
96
- setColumnPinning(({ left = [], right = [] }) => ({
97
- left: reorderedColumns.filter((header) => left.includes(header)),
98
- right: reorderedColumns.filter((header) => right.includes(header)),
95
+ setColumnPinning(({ end = [], start = [] }) => ({
96
+ end: reorderedColumns.filter((header) => end.includes(header)),
97
+ start: reorderedColumns.filter((header) => start.includes(header)),
99
98
  }));
100
99
  }
101
100
  };