@cutting/material-react-table 4.0.3 → 4.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.0.3",
2
+ "version": "4.0.5",
3
3
  "license": "MIT",
4
4
  "name": "@cutting/material-react-table",
5
5
  "description": "Maintenance fork of material-react-table updated for Material UI v9. A fully featured Material UI implementation of TanStack React Table V8.",
@@ -55,47 +55,47 @@
55
55
  "@emotion/styled": "^11.14.1",
56
56
  "@eslint/eslintrc": "^3.3.5",
57
57
  "@eslint/js": "^10.0.1",
58
- "@faker-js/faker": "^10.4.0",
59
- "@mui/icons-material": "^9.0.1",
60
- "@mui/material": "^9.0.1",
61
- "@mui/x-date-pickers": "^9.3.0",
58
+ "@faker-js/faker": "^10.5.0",
59
+ "@mui/icons-material": "^9.1.1",
60
+ "@mui/material": "^9.1.1",
61
+ "@mui/x-date-pickers": "^9.6.0",
62
62
  "@rollup/plugin-typescript": "^12.3.0",
63
63
  "@size-limit/preset-small-lib": "^12.1.0",
64
- "@storybook/addon-a11y": "^10.4.0",
65
- "@storybook/addon-docs": "^10.4.0",
66
- "@storybook/addon-links": "^10.4.0",
67
- "@storybook/react-vite": "^10.4.0",
64
+ "@storybook/addon-a11y": "^10.4.6",
65
+ "@storybook/addon-docs": "^10.4.6",
66
+ "@storybook/addon-links": "^10.4.6",
67
+ "@storybook/react-vite": "^10.4.6",
68
68
  "@testing-library/jest-dom": "^6.9.1",
69
69
  "@testing-library/react": "^16.3.2",
70
70
  "@testing-library/user-event": "^14.6.1",
71
- "@types/node": "^25.9.1",
72
- "@types/react": "^19.2.15",
71
+ "@types/node": "^26.0.0",
72
+ "@types/react": "^19.2.17",
73
73
  "@types/react-dom": "^19.2.3",
74
- "@typescript-eslint/eslint-plugin": "^8.59.4",
75
- "@typescript-eslint/parser": "^8.59.4",
74
+ "@typescript-eslint/eslint-plugin": "^8.61.1",
75
+ "@typescript-eslint/parser": "^8.61.1",
76
76
  "@vitejs/plugin-react": "^6.0.2",
77
- "dayjs": "^1.11.20",
78
- "eslint": "^10.4.0",
77
+ "dayjs": "^1.11.21",
78
+ "eslint": "^10.5.0",
79
79
  "eslint-plugin-mui-path-imports": "^0.0.15",
80
- "eslint-plugin-perfectionist": "^5.9.0",
81
- "eslint-plugin-storybook": "^10.4.0",
80
+ "eslint-plugin-perfectionist": "^5.9.1",
81
+ "eslint-plugin-storybook": "^10.4.6",
82
82
  "globals": "^17.6.0",
83
83
  "jsdom": "^29.1.1",
84
- "react": "^19.2.6",
85
- "react-dom": "^19.2.6",
86
- "react-is": "^19.2.6",
87
- "rollup": "^4.60.4",
84
+ "react": "^19.2.7",
85
+ "react-dom": "^19.2.7",
86
+ "react-is": "^19.2.7",
87
+ "rollup": "^4.62.0",
88
88
  "rollup-plugin-copy": "^3.5.0",
89
89
  "rollup-plugin-delete": "^3.0.2",
90
90
  "rollup-plugin-dts": "^6.4.1",
91
91
  "rollup-plugin-peer-deps-external": "^2.2.4",
92
92
  "size-limit": "^12.1.0",
93
- "storybook": "^10.4.0",
93
+ "storybook": "^10.4.6",
94
94
  "storybook-dark-mode": "^5.0.0",
95
95
  "tslib": "^2.8.1",
96
96
  "typescript": "6.0.3",
97
- "vite": "^8.0.14",
98
- "vitest": "^4.1.7"
97
+ "vite": "^8.0.16",
98
+ "vitest": "^4.1.9"
99
99
  },
100
100
  "peerDependencies": {
101
101
  "@emotion/react": ">=11.13",
@@ -109,7 +109,7 @@
109
109
  "dependencies": {
110
110
  "@tanstack/match-sorter-utils": "8.19.4",
111
111
  "@tanstack/react-table": "8.21.3",
112
- "@tanstack/react-virtual": "3.13.25",
112
+ "@tanstack/react-virtual": "3.14.3",
113
113
  "highlight-words": "2.0.0"
114
114
  },
115
115
  "scripts": {
@@ -53,4 +53,23 @@ describe('MaterialReactTable smoke', () => {
53
53
  );
54
54
  expect(firstBodyRow?.textContent).toContain('Aaron');
55
55
  });
56
+
57
+ test('wraps matching text in a highlight span when global filter is active', () => {
58
+ render(
59
+ <MaterialReactTable
60
+ columns={columns}
61
+ data={data}
62
+ enableFilterMatchHighlighting
63
+ enableGlobalFilter
64
+ initialState={{ globalFilter: 'Sar', showGlobalFilter: true }}
65
+ />,
66
+ );
67
+
68
+ const highlightWrapper = screen.getByRole('note', { name: 'Sara' });
69
+ expect(highlightWrapper).toBeInTheDocument();
70
+
71
+ const matchSpans = highlightWrapper.querySelectorAll('span');
72
+ expect(matchSpans.length).toBeGreaterThan(1);
73
+ expect(highlightWrapper.textContent).toBe('Sara');
74
+ });
56
75
  });
@@ -1,5 +1,4 @@
1
1
  import { Box } from '@mui/material';
2
- import highlightWords from 'highlight-words';
3
2
  import { type ReactNode, type RefObject } from 'react';
4
3
 
5
4
  import {
@@ -7,6 +6,7 @@ import {
7
6
  type MRT_RowData,
8
7
  type MRT_TableInstance,
9
8
  } from '../../types';
9
+ import { highlightWords } from '../../utils/highlight.utils';
10
10
 
11
11
  const allowedTypes = ['string', 'number'];
12
12
 
@@ -78,7 +78,7 @@ export const MRT_TableBodyCellValue = <TData extends MRT_RowData>({
78
78
  allowedTypes.includes(typeof globalFilter) &&
79
79
  column.getCanGlobalFilter()))
80
80
  ) {
81
- const chunks = highlightWords?.({
81
+ const chunks = highlightWords({
82
82
  matchExactly:
83
83
  (filterValue ? columnDef._filterFn : globalFilterFn) !== 'fuzzy',
84
84
  query: (filterValue ?? globalFilter ?? '').toString(),
@@ -0,0 +1,52 @@
1
+ export interface HighlightChunk {
2
+ key: string;
3
+ match: boolean;
4
+ text: string;
5
+ }
6
+
7
+ interface HighlightWordsArgs {
8
+ matchExactly?: boolean;
9
+ query: string;
10
+ text: string;
11
+ }
12
+
13
+ const escapeRegExp = (term: string): string =>
14
+ term.replace(/[|\\{}()[\]^$+*?.-]/g, (char) => `\\${char}`);
15
+
16
+ const termsToRegExpString = (terms: string): string =>
17
+ terms.replace(/\s{2,}/g, ' ').split(' ').join('|');
18
+
19
+ const buildRegExp = (terms: string, matchExactly: boolean): RegExp => {
20
+ const fromString = /^([/~@;%#'])(.*?)\1([gimsuy]*)$/.exec(terms);
21
+ if (fromString) {
22
+ return new RegExp(fromString[2], fromString[3]);
23
+ }
24
+ const escaped = escapeRegExp(terms.trim());
25
+ const pattern = matchExactly ? escaped : termsToRegExpString(escaped);
26
+ return new RegExp(`(${pattern})`, 'ig');
27
+ };
28
+
29
+ let uidCounter = 0;
30
+ const uid = (): string => `mrt-hl-${(uidCounter += 1).toString(36)}`;
31
+
32
+ export const highlightWords = ({
33
+ matchExactly = false,
34
+ query,
35
+ text,
36
+ }: HighlightWordsArgs): HighlightChunk[] => {
37
+ const safeQuery = typeof query === 'string' ? query.trim() : query;
38
+ if (safeQuery === '') {
39
+ return [{ key: uid(), match: false, text }];
40
+ }
41
+ const searchRegexp = buildRegExp(query, matchExactly);
42
+ return text
43
+ .split(searchRegexp)
44
+ .filter((str) => str.length > 0)
45
+ .map((str) => ({
46
+ key: uid(),
47
+ match: matchExactly
48
+ ? str.toLowerCase() === safeQuery.toLowerCase()
49
+ : searchRegexp.test(str),
50
+ text: str,
51
+ }));
52
+ };