@mini_7/material-react-table-mcp 4.0.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 (170) hide show
  1. package/README.md +68 -0
  2. package/data/MIGRATION.md +136 -0
  3. package/data/api.json +5379 -0
  4. package/data/examples/advanced.tsx +309 -0
  5. package/data/examples/aggregation-and-grouping.tsx +153 -0
  6. package/data/examples/aggregation-multi.tsx +105 -0
  7. package/data/examples/alternate-column-filtering.tsx +49 -0
  8. package/data/examples/alternate-detail-panel.tsx +81 -0
  9. package/data/examples/alternate-pagination.tsx +23 -0
  10. package/data/examples/basic.tsx +109 -0
  11. package/data/examples/chart-detail-panel.tsx +89 -0
  12. package/data/examples/column-actions-space.tsx +44 -0
  13. package/data/examples/column-alignment.tsx +70 -0
  14. package/data/examples/custom-column-actions.tsx +109 -0
  15. package/data/examples/custom-column-filtering-ui.tsx +89 -0
  16. package/data/examples/custom-headless.tsx +125 -0
  17. package/data/examples/custom-top-toolbar.tsx +88 -0
  18. package/data/examples/customize-display-columns.tsx +85 -0
  19. package/data/examples/customize-filter-components.tsx +101 -0
  20. package/data/examples/customize-filter-modes.tsx +73 -0
  21. package/data/examples/customize-filter-variants.tsx +116 -0
  22. package/data/examples/customize-global-filter-component.tsx +52 -0
  23. package/data/examples/customize-remove-column-grouping.tsx +94 -0
  24. package/data/examples/customize-row-selection.tsx +54 -0
  25. package/data/examples/customize-table-styles.tsx +100 -0
  26. package/data/examples/disable-column-actions.tsx +37 -0
  27. package/data/examples/disable-column-hiding.tsx +90 -0
  28. package/data/examples/disable-density-toggle.tsx +49 -0
  29. package/data/examples/dynamic-columns.tsx +189 -0
  30. package/data/examples/editing-crud-cell.tsx +377 -0
  31. package/data/examples/editing-crud-modal.tsx +370 -0
  32. package/data/examples/editing-crud-row.tsx +333 -0
  33. package/data/examples/editing-crud-table.tsx +369 -0
  34. package/data/examples/editing-crud-tree.tsx +416 -0
  35. package/data/examples/enable-cell-actions.tsx +76 -0
  36. package/data/examples/enable-click-to-copy.tsx +39 -0
  37. package/data/examples/enable-column-grouping.tsx +120 -0
  38. package/data/examples/enable-column-ordering.tsx +48 -0
  39. package/data/examples/enable-column-pinning.tsx +69 -0
  40. package/data/examples/enable-column-resizing.tsx +56 -0
  41. package/data/examples/enable-column-virtualization.tsx +27 -0
  42. package/data/examples/enable-detail-panel-conditionally.tsx +78 -0
  43. package/data/examples/enable-detail-panel-virtualized.tsx +80 -0
  44. package/data/examples/enable-expanding-tree.tsx +110 -0
  45. package/data/examples/enable-filter-facet-values.tsx +65 -0
  46. package/data/examples/enable-row-dragging.tsx +137 -0
  47. package/data/examples/enable-row-numbers-original.tsx +48 -0
  48. package/data/examples/enable-row-numbers-static.tsx +48 -0
  49. package/data/examples/enable-row-ordering.tsx +57 -0
  50. package/data/examples/enable-row-pinning-select.tsx +76 -0
  51. package/data/examples/enable-row-pinning-static.tsx +50 -0
  52. package/data/examples/enable-row-pinning-sticky.tsx +69 -0
  53. package/data/examples/enable-row-selection.tsx +96 -0
  54. package/data/examples/enable-row-virtualization.tsx +101 -0
  55. package/data/examples/enable-sticky-header.tsx +59 -0
  56. package/data/examples/expanding-tree-expanded.tsx +121 -0
  57. package/data/examples/expanding-tree-flat-parse.tsx +125 -0
  58. package/data/examples/expanding-tree-root-expanded.tsx +151 -0
  59. package/data/examples/export-to-csv.tsx +114 -0
  60. package/data/examples/export-to-pdf.tsx +104 -0
  61. package/data/examples/external-toolbar.tsx +108 -0
  62. package/data/examples/font-awesome-icons.tsx +106 -0
  63. package/data/examples/infinite-scrolling.tsx +208 -0
  64. package/data/examples/lazy-detail-panel.tsx +262 -0
  65. package/data/examples/lazy-sub-rows.tsx +190 -0
  66. package/data/examples/linear-progress.tsx +66 -0
  67. package/data/examples/loading.tsx +50 -0
  68. package/data/examples/localization-i18n-ar.tsx +65 -0
  69. package/data/examples/localization-i18n-az.tsx +60 -0
  70. package/data/examples/localization-i18n-bg.tsx +60 -0
  71. package/data/examples/localization-i18n-cs.tsx +60 -0
  72. package/data/examples/localization-i18n-da.tsx +60 -0
  73. package/data/examples/localization-i18n-de.tsx +60 -0
  74. package/data/examples/localization-i18n-el.tsx +60 -0
  75. package/data/examples/localization-i18n-en.tsx +60 -0
  76. package/data/examples/localization-i18n-es.tsx +60 -0
  77. package/data/examples/localization-i18n-et.tsx +60 -0
  78. package/data/examples/localization-i18n-fa.tsx +66 -0
  79. package/data/examples/localization-i18n-fi.tsx +60 -0
  80. package/data/examples/localization-i18n-fr.tsx +60 -0
  81. package/data/examples/localization-i18n-he.tsx +66 -0
  82. package/data/examples/localization-i18n-hr.tsx +60 -0
  83. package/data/examples/localization-i18n-hu.tsx +60 -0
  84. package/data/examples/localization-i18n-hy.tsx +65 -0
  85. package/data/examples/localization-i18n-id.tsx +60 -0
  86. package/data/examples/localization-i18n-it.tsx +60 -0
  87. package/data/examples/localization-i18n-ja.tsx +60 -0
  88. package/data/examples/localization-i18n-ko.tsx +60 -0
  89. package/data/examples/localization-i18n-nl.tsx +60 -0
  90. package/data/examples/localization-i18n-no.tsx +60 -0
  91. package/data/examples/localization-i18n-np.tsx +60 -0
  92. package/data/examples/localization-i18n-pl.tsx +60 -0
  93. package/data/examples/localization-i18n-pt-BR.tsx +60 -0
  94. package/data/examples/localization-i18n-pt.tsx +60 -0
  95. package/data/examples/localization-i18n-ro.tsx +60 -0
  96. package/data/examples/localization-i18n-ru.tsx +60 -0
  97. package/data/examples/localization-i18n-sk.tsx +60 -0
  98. package/data/examples/localization-i18n-sr-Cyrl-RS.tsx +60 -0
  99. package/data/examples/localization-i18n-sr-Latn-RS.tsx +60 -0
  100. package/data/examples/localization-i18n-sv.tsx +60 -0
  101. package/data/examples/localization-i18n-tr.tsx +60 -0
  102. package/data/examples/localization-i18n-uk.tsx +60 -0
  103. package/data/examples/localization-i18n-vi.tsx +60 -0
  104. package/data/examples/localization-i18n-zh-hans.tsx +60 -0
  105. package/data/examples/localization-i18n-zh-hant.tsx +60 -0
  106. package/data/examples/manual-selection.tsx +105 -0
  107. package/data/examples/minimal.tsx +78 -0
  108. package/data/examples/mui-theme.tsx +136 -0
  109. package/data/examples/multi-sorting.tsx +58 -0
  110. package/data/examples/persistent-state.tsx +184 -0
  111. package/data/examples/react-query.tsx +182 -0
  112. package/data/examples/remote.tsx +150 -0
  113. package/data/examples/row-actions-buttons.tsx +89 -0
  114. package/data/examples/row-actions-menu-items.tsx +64 -0
  115. package/data/examples/single-row-selection.tsx +98 -0
  116. package/data/examples/virtualized.tsx +138 -0
  117. package/data/guides/accessibility.md +119 -0
  118. package/data/guides/aggregation.md +210 -0
  119. package/data/guides/async-loading.md +132 -0
  120. package/data/guides/best-practices.md +363 -0
  121. package/data/guides/cell-actions.md +139 -0
  122. package/data/guides/click-to-copy.md +67 -0
  123. package/data/guides/column-actions.md +69 -0
  124. package/data/guides/column-filtering.md +366 -0
  125. package/data/guides/column-grouping.md +192 -0
  126. package/data/guides/column-hiding.md +133 -0
  127. package/data/guides/column-ordering-dnd.md +99 -0
  128. package/data/guides/column-pinning.md +72 -0
  129. package/data/guides/column-resizing.md +157 -0
  130. package/data/guides/column-size.md +162 -0
  131. package/data/guides/customize-components.md +395 -0
  132. package/data/guides/customize-icons.md +35 -0
  133. package/data/guides/data-columns.md +292 -0
  134. package/data/guides/density-toggle.md +46 -0
  135. package/data/guides/detail-panel.md +195 -0
  136. package/data/guides/display-columns.md +135 -0
  137. package/data/guides/editing.md +367 -0
  138. package/data/guides/expanding-sub-rows.md +194 -0
  139. package/data/guides/full-screen-toggle.md +63 -0
  140. package/data/guides/global-filtering.md +237 -0
  141. package/data/guides/localization.md +57 -0
  142. package/data/guides/memoization.md +157 -0
  143. package/data/guides/pagination.md +171 -0
  144. package/data/guides/row-actions.md +116 -0
  145. package/data/guides/row-numbers.md +24 -0
  146. package/data/guides/row-ordering-dnd.md +51 -0
  147. package/data/guides/row-pinning.md +96 -0
  148. package/data/guides/row-selection.md +237 -0
  149. package/data/guides/sorting.md +190 -0
  150. package/data/guides/state-management.md +165 -0
  151. package/data/guides/sticky-header.md +41 -0
  152. package/data/guides/table-event-listeners.md +103 -0
  153. package/data/guides/toolbar-customization.md +251 -0
  154. package/data/guides/virtualization.md +183 -0
  155. package/data/index.json +1930 -0
  156. package/data/reference/mrt-components.md +183 -0
  157. package/data/reference/mrt-hooks.md +125 -0
  158. package/data/skills/composable-components/SKILL.md +189 -0
  159. package/data/skills/customization/SKILL.md +190 -0
  160. package/data/skills/drag-and-drop-ordering/SKILL.md +227 -0
  161. package/data/skills/editing/SKILL.md +243 -0
  162. package/data/skills/filtering/SKILL.md +213 -0
  163. package/data/skills/getting-started/SKILL.md +213 -0
  164. package/data/skills/localization/SKILL.md +182 -0
  165. package/data/skills/migrate-v3-to-v4/SKILL.md +161 -0
  166. package/data/skills/state-and-server-data/SKILL.md +200 -0
  167. package/data/skills/virtualization/SKILL.md +203 -0
  168. package/dist/data.js +137 -0
  169. package/dist/index.js +232 -0
  170. package/package.json +50 -0
@@ -0,0 +1,416 @@
1
+ import { lazy, Suspense, useMemo, useState } from 'react';
2
+ import {
3
+ MaterialReactTable,
4
+ createRow,
5
+ type MRT_ColumnDef,
6
+ type MRT_Row,
7
+ type MRT_TableOptions,
8
+ useMaterialReactTable,
9
+ } from 'material-react-table';
10
+ import {
11
+ Box,
12
+ Button,
13
+ IconButton,
14
+ Tooltip,
15
+ darken,
16
+ lighten,
17
+ } from '@mui/material';
18
+ import {
19
+ QueryClient,
20
+ QueryClientProvider,
21
+ useMutation,
22
+ useQuery,
23
+ useQueryClient,
24
+ } from '@tanstack/react-query';
25
+ import { type User, fakeData, usStates } from './makeData';
26
+ import PersonAddAltIcon from '@mui/icons-material/PersonAddAlt';
27
+ import EditIcon from '@mui/icons-material/Edit';
28
+ import DeleteIcon from '@mui/icons-material/Delete';
29
+
30
+ const Example = () => {
31
+ const [creatingRowIndex, setCreatingRowIndex] = useState<
32
+ number | undefined
33
+ >();
34
+ const [validationErrors, setValidationErrors] = useState<
35
+ Record<string, string | undefined>
36
+ >({});
37
+
38
+ const columns = useMemo<MRT_ColumnDef<User>[]>(
39
+ () => [
40
+ {
41
+ accessorKey: 'id',
42
+ header: 'Id',
43
+ enableEditing: false,
44
+ size: 80,
45
+ },
46
+ {
47
+ accessorKey: 'firstName',
48
+ header: 'First Name',
49
+ muiEditTextFieldProps: {
50
+ required: true,
51
+ error: !!validationErrors?.firstName,
52
+ helperText: validationErrors?.firstName,
53
+ //remove any previous validation errors when user focuses on the input
54
+ onFocus: () =>
55
+ setValidationErrors({
56
+ ...validationErrors,
57
+ firstName: undefined,
58
+ }),
59
+ //optionally add validation checking for onBlur or onChange
60
+ },
61
+ },
62
+ {
63
+ accessorKey: 'lastName',
64
+ header: 'Last Name',
65
+ muiEditTextFieldProps: {
66
+ required: true,
67
+ error: !!validationErrors?.lastName,
68
+ helperText: validationErrors?.lastName,
69
+ //remove any previous validation errors when user focuses on the input
70
+ onFocus: () =>
71
+ setValidationErrors({
72
+ ...validationErrors,
73
+ lastName: undefined,
74
+ }),
75
+ },
76
+ },
77
+ {
78
+ accessorKey: 'city',
79
+ header: 'City',
80
+ muiEditTextFieldProps: {
81
+ required: true,
82
+ error: !!validationErrors?.city,
83
+ helperText: validationErrors?.city,
84
+ //remove any previous validation errors when user focuses on the input
85
+ onFocus: () =>
86
+ setValidationErrors({
87
+ ...validationErrors,
88
+ city: undefined,
89
+ }),
90
+ },
91
+ },
92
+ {
93
+ accessorKey: 'state',
94
+ header: 'State',
95
+ editVariant: 'select',
96
+ editSelectOptions: usStates,
97
+ muiEditTextFieldProps: {
98
+ select: true,
99
+ error: !!validationErrors?.state,
100
+ helperText: validationErrors?.state,
101
+ },
102
+ },
103
+ ],
104
+ [validationErrors],
105
+ );
106
+
107
+ //call CREATE hook
108
+ const { mutateAsync: createUser, isPending: isCreatingUser } =
109
+ useCreateUser();
110
+ //call READ hook
111
+ const {
112
+ data: fetchedUsers = [],
113
+ isError: isLoadingUsersError,
114
+ isFetching: isFetchingUsers,
115
+ isLoading: isLoadingUsers,
116
+ } = useGetUsers();
117
+ //call UPDATE hook
118
+ const { mutateAsync: updateUser, isPending: isUpdatingUser } =
119
+ useUpdateUser();
120
+ //call DELETE hook
121
+ const { mutateAsync: deleteUser, isPending: isDeletingUser } =
122
+ useDeleteUser();
123
+
124
+ //CREATE action
125
+ const handleCreateUser: MRT_TableOptions<User>['onCreatingRowSave'] = async ({
126
+ values,
127
+ row,
128
+ table,
129
+ }) => {
130
+ const newValidationErrors = validateUser(values);
131
+ if (Object.values(newValidationErrors).some((error) => error)) {
132
+ setValidationErrors(newValidationErrors);
133
+ return;
134
+ }
135
+ setValidationErrors({});
136
+ await createUser({ ...values, managerId: row.original.managerId });
137
+ table.setCreatingRow(null); //exit creating mode
138
+ };
139
+
140
+ //UPDATE action
141
+ const handleSaveUser: MRT_TableOptions<User>['onEditingRowSave'] = async ({
142
+ values,
143
+ table,
144
+ }) => {
145
+ const newValidationErrors = validateUser(values);
146
+ if (Object.values(newValidationErrors).some((error) => error)) {
147
+ setValidationErrors(newValidationErrors);
148
+ return;
149
+ }
150
+ setValidationErrors({});
151
+ await updateUser(values);
152
+ table.setEditingRow(null); //exit editing mode
153
+ };
154
+
155
+ //DELETE action
156
+ const openDeleteConfirmModal = (row: MRT_Row<User>) => {
157
+ if (window.confirm('Are you sure you want to delete this user?')) {
158
+ deleteUser(row.original.id);
159
+ }
160
+ };
161
+
162
+ const table = useMaterialReactTable({
163
+ columns,
164
+ data: fetchedUsers,
165
+ createDisplayMode: 'row', // ('modal', and 'custom' are also available)
166
+ editDisplayMode: 'row', // ('modal', 'cell', 'table', and 'custom' are also available)
167
+ enableColumnPinning: true,
168
+ enableEditing: true,
169
+ enableExpanding: true,
170
+ positionCreatingRow: creatingRowIndex, //index where new row is inserted before
171
+ getRowId: (row) => row.id,
172
+ muiToolbarAlertBannerProps: isLoadingUsersError
173
+ ? {
174
+ color: 'error',
175
+ children: 'Error loading data',
176
+ }
177
+ : undefined,
178
+ muiTableContainerProps: {
179
+ sx: {
180
+ minHeight: '500px',
181
+ },
182
+ },
183
+ muiTableBodyRowProps: ({ row }) => ({
184
+ //conditional styling based on row depth
185
+ sx: (theme) => ({
186
+ td: {
187
+ backgroundColor: darken(
188
+ lighten(theme.palette.background.paper, 0.1),
189
+ row.depth * (theme.palette.mode === 'dark' ? 0.2 : 0.1),
190
+ ),
191
+ },
192
+ }),
193
+ }),
194
+ onCreatingRowCancel: () => setValidationErrors({}),
195
+ onCreatingRowSave: handleCreateUser,
196
+ onEditingRowCancel: () => setValidationErrors({}),
197
+ onEditingRowSave: handleSaveUser,
198
+ renderRowActions: ({ row, staticRowIndex, table }) => (
199
+ <Box sx={{ display: 'flex', gap: '1rem' }}>
200
+ <Tooltip title="Edit">
201
+ <IconButton onClick={() => table.setEditingRow(row)}>
202
+ <EditIcon />
203
+ </IconButton>
204
+ </Tooltip>
205
+ <Tooltip title="Delete">
206
+ <IconButton color="error" onClick={() => openDeleteConfirmModal(row)}>
207
+ <DeleteIcon />
208
+ </IconButton>
209
+ </Tooltip>
210
+ <Tooltip title="Add Subordinate">
211
+ <IconButton
212
+ onClick={() => {
213
+ setCreatingRowIndex((staticRowIndex || 0) + 1);
214
+ table.setCreatingRow(
215
+ createRow(
216
+ table,
217
+ {
218
+ id: null!,
219
+ firstName: '',
220
+ lastName: '',
221
+ city: '',
222
+ state: '',
223
+ managerId: row.id,
224
+ subRows: [],
225
+ },
226
+ -1,
227
+ row.depth + 1,
228
+ ),
229
+ );
230
+ }}
231
+ >
232
+ <PersonAddAltIcon />
233
+ </IconButton>
234
+ </Tooltip>
235
+ </Box>
236
+ ),
237
+ renderTopToolbarCustomActions: ({ table }) => (
238
+ <Button
239
+ startIcon={<PersonAddAltIcon />}
240
+ variant="contained"
241
+ onClick={() => {
242
+ setCreatingRowIndex(table.getRowModel().rows.length); //create new row at bottom of table
243
+ table.setCreatingRow(true);
244
+ }}
245
+ >
246
+ Create New User
247
+ </Button>
248
+ ),
249
+ initialState: {
250
+ columnPinning: { end: [], start: ['mrt-row-actions'] },
251
+ expanded: true,
252
+ pagination: { pageSize: 20, pageIndex: 0 },
253
+ },
254
+ state: {
255
+ isLoading: isLoadingUsers,
256
+ isSaving: isCreatingUser || isUpdatingUser || isDeletingUser,
257
+ showAlertBanner: isLoadingUsersError,
258
+ showProgressBars: isFetchingUsers,
259
+ },
260
+ });
261
+
262
+ return <MaterialReactTable table={table} />;
263
+ };
264
+
265
+ //CREATE hook (post new user to api)
266
+ function useCreateUser() {
267
+ const queryClient = useQueryClient();
268
+ return useMutation({
269
+ mutationFn: async (user: User) => {
270
+ console.info('create user', user);
271
+ //send api update request here
272
+ await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
273
+ return Promise.resolve();
274
+ },
275
+ //client side optimistic update
276
+ onMutate: (newUserInfo: User) => {
277
+ queryClient.setQueryData(['users'], (_prevUsers: User[]) => {
278
+ const prevUsers: User[] = JSON.parse(JSON.stringify(_prevUsers));
279
+ newUserInfo.subRows = [];
280
+ if (newUserInfo.managerId) {
281
+ const manager = findUserInTree(newUserInfo.managerId, prevUsers);
282
+ if (manager) {
283
+ manager.subRows = [
284
+ ...(manager.subRows || []),
285
+ {
286
+ ...newUserInfo,
287
+ id: `${manager.id}.${(manager.subRows?.length || 0) + 1}`,
288
+ },
289
+ ];
290
+ }
291
+ } else {
292
+ prevUsers.push({
293
+ ...newUserInfo,
294
+ id: `${prevUsers.length + 1}`,
295
+ });
296
+ }
297
+ return [...prevUsers];
298
+ });
299
+ },
300
+ // onSettled: () => queryClient.invalidateQueries({ queryKey: ['users'] }), //refetch users after mutation, disabled for demo
301
+ });
302
+ }
303
+
304
+ //READ hook (get users from api)
305
+ function useGetUsers() {
306
+ return useQuery<User[]>({
307
+ queryKey: ['users'],
308
+ queryFn: async () => {
309
+ //send api request here
310
+ await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
311
+ return Promise.resolve(fakeData);
312
+ },
313
+ refetchOnWindowFocus: false,
314
+ });
315
+ }
316
+
317
+ //UPDATE hook (put user in api)
318
+ function useUpdateUser() {
319
+ const queryClient = useQueryClient();
320
+ return useMutation({
321
+ mutationFn: async (user: User) => {
322
+ console.info('update user', user);
323
+ //send api update request here
324
+ await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
325
+ return Promise.resolve();
326
+ },
327
+ //client side optimistic update
328
+ onMutate: (newUserInfo: User) => {
329
+ queryClient.setQueryData(['users'], (prevUsers: any) => {
330
+ let user = findUserInTree(newUserInfo.id, prevUsers);
331
+ user = { ...user, ...newUserInfo };
332
+ return [...prevUsers];
333
+ });
334
+ },
335
+ // onSettled: () => queryClient.invalidateQueries({ queryKey: ['users'] }), //refetch users after mutation, disabled for demo
336
+ });
337
+ }
338
+
339
+ //DELETE hook (delete user in api)
340
+ function useDeleteUser() {
341
+ const queryClient = useQueryClient();
342
+ return useMutation({
343
+ mutationFn: async (userId: string) => {
344
+ console.info('delete user', userId);
345
+ //send api update request here
346
+ await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
347
+ return Promise.resolve();
348
+ },
349
+ //client side optimistic update
350
+ onMutate: (userId: string) => {
351
+ queryClient.setQueryData(['users'], (prevUsers: any) => {
352
+ const newUsers: User[] = JSON.parse(JSON.stringify(prevUsers));
353
+ //remove user
354
+ const user = findUserInTree(userId, newUsers);
355
+ if (user) {
356
+ const manager = findUserInTree(user.managerId, newUsers);
357
+ if (manager) {
358
+ manager.subRows = manager.subRows?.filter(
359
+ (subUser) => subUser.id !== user.id,
360
+ );
361
+ } else {
362
+ return newUsers.filter((user) => user.id !== userId);
363
+ }
364
+ }
365
+ return [...newUsers];
366
+ });
367
+ },
368
+ // onSettled: () => queryClient.invalidateQueries({ queryKey: ['users'] }), //refetch users after mutation, disabled for demo
369
+ });
370
+ }
371
+
372
+ //react query setup in App.tsx
373
+ const ReactQueryDevtoolsProduction = lazy(() =>
374
+ import('@tanstack/react-query-devtools/build/modern/production.js').then(
375
+ (d) => ({
376
+ default: d.ReactQueryDevtools,
377
+ }),
378
+ ),
379
+ );
380
+
381
+ const queryClient = new QueryClient();
382
+
383
+ export default function App() {
384
+ return (
385
+ <QueryClientProvider client={queryClient}>
386
+ <Example />
387
+ <Suspense fallback={null}>
388
+ <ReactQueryDevtoolsProduction />
389
+ </Suspense>
390
+ </QueryClientProvider>
391
+ );
392
+ }
393
+
394
+ const validateRequired = (value: string) => !!value.length;
395
+
396
+ function validateUser(user: User) {
397
+ return {
398
+ firstName: !validateRequired(user.firstName)
399
+ ? 'First Name is Required'
400
+ : '',
401
+ lastName: !validateRequired(user.lastName) ? 'Last Name is Required' : '',
402
+ };
403
+ }
404
+
405
+ function findUserInTree(managerId: string | null, users: User[]): User | null {
406
+ for (let i = 0; i < users.length; i++) {
407
+ if (users[i].id === managerId) {
408
+ return users[i];
409
+ }
410
+ if (users[i].subRows) {
411
+ const found = findUserInTree(managerId, users[i].subRows!);
412
+ if (found) return found;
413
+ }
414
+ }
415
+ return null;
416
+ }
@@ -0,0 +1,76 @@
1
+ import { useMemo } from 'react';
2
+ import {
3
+ MaterialReactTable,
4
+ MRT_ActionMenuItem,
5
+ useMaterialReactTable,
6
+ type MRT_ColumnDef,
7
+ } from 'material-react-table';
8
+ import { data, type Person } from './makeData';
9
+ import { Divider } from '@mui/material';
10
+ import EmailIcon from '@mui/icons-material/Email';
11
+ import PersonOffOutlinedIcon from '@mui/icons-material/PersonOffOutlined';
12
+
13
+ export const Example = () => {
14
+ const columns = useMemo<MRT_ColumnDef<Person>[]>(
15
+ //column definitions...
16
+ () => [
17
+ {
18
+ accessorKey: 'firstName',
19
+ header: 'First Name',
20
+ },
21
+ {
22
+ accessorKey: 'lastName',
23
+ header: 'Last Name',
24
+ },
25
+ {
26
+ accessorKey: 'address',
27
+ header: 'Address',
28
+ },
29
+ {
30
+ accessorKey: 'city',
31
+ header: 'City',
32
+ },
33
+ {
34
+ accessorKey: 'state',
35
+ header: 'State',
36
+ },
37
+ ],
38
+ [],
39
+ //end
40
+ );
41
+
42
+ const table = useMaterialReactTable({
43
+ columns,
44
+ data,
45
+ enableCellActions: true,
46
+ enableClickToCopy: 'context-menu',
47
+ enableEditing: true,
48
+ editDisplayMode: 'cell',
49
+ renderCellActionMenuItems: ({ closeMenu, table, internalMenuItems }) => [
50
+ ...internalMenuItems,
51
+ <Divider key="divider" />,
52
+ <MRT_ActionMenuItem
53
+ icon={<EmailIcon />}
54
+ key={1}
55
+ label="Item 1"
56
+ onClick={() => {
57
+ closeMenu();
58
+ }}
59
+ table={table}
60
+ />,
61
+ <MRT_ActionMenuItem
62
+ icon={<PersonOffOutlinedIcon />}
63
+ key={2}
64
+ label="Item 2"
65
+ onClick={() => {
66
+ closeMenu();
67
+ }}
68
+ table={table}
69
+ />,
70
+ ],
71
+ });
72
+
73
+ return <MaterialReactTable table={table} />;
74
+ };
75
+
76
+ export default Example;
@@ -0,0 +1,39 @@
1
+ import { useMemo } from 'react';
2
+ import { MaterialReactTable, type MRT_ColumnDef } from 'material-react-table';
3
+ import { ContentCopy } from '@mui/icons-material';
4
+ import { data, type Person } from './makeData';
5
+
6
+ const Example = () => {
7
+ const columns = useMemo<MRT_ColumnDef<Person>[]>(
8
+ () => [
9
+ {
10
+ accessorKey: 'firstName',
11
+ header: 'First Name',
12
+ },
13
+ {
14
+ accessorKey: 'lastName',
15
+ header: 'Last Name',
16
+ },
17
+ {
18
+ accessorKey: 'email',
19
+ header: 'Email',
20
+ enableClickToCopy: true,
21
+ muiCopyButtonProps: {
22
+ fullWidth: true,
23
+ startIcon: <ContentCopy />,
24
+ sx: { justifyContent: 'flex-start' },
25
+ },
26
+ },
27
+ {
28
+ accessorKey: 'city',
29
+ header: 'City',
30
+ enableClickToCopy: true,
31
+ },
32
+ ],
33
+ [],
34
+ );
35
+
36
+ return <MaterialReactTable columns={columns} data={data} />;
37
+ };
38
+
39
+ export default Example;
@@ -0,0 +1,120 @@
1
+ import { useMemo, useState } from 'react';
2
+ import {
3
+ MaterialReactTable,
4
+ useMaterialReactTable,
5
+ type MRT_ColumnDef,
6
+ } from 'material-react-table';
7
+ import { data, type Person } from './makeData';
8
+ import {
9
+ FormControl,
10
+ FormControlLabel,
11
+ FormLabel,
12
+ Radio,
13
+ RadioGroup,
14
+ Stack,
15
+ } from '@mui/material';
16
+
17
+ const Example = () => {
18
+ const columns = useMemo<MRT_ColumnDef<Person>[]>(
19
+ //column definitions...
20
+ () => [
21
+ {
22
+ header: 'First Name',
23
+ accessorKey: 'firstName',
24
+ },
25
+ {
26
+ header: 'Last Name',
27
+ accessorKey: 'lastName',
28
+ },
29
+ {
30
+ header: 'Age',
31
+ accessorKey: 'age',
32
+ },
33
+ {
34
+ header: 'Gender',
35
+ accessorKey: 'gender',
36
+ },
37
+ {
38
+ header: 'State',
39
+ accessorKey: 'state',
40
+ },
41
+ {
42
+ header: 'Salary',
43
+ accessorKey: 'salary',
44
+ },
45
+ ],
46
+ [],
47
+ //end
48
+ );
49
+
50
+ //demo state
51
+ const [groupedColumnMode, setGroupedColumnMode] = useState<
52
+ false | 'remove' | 'reorder'
53
+ >('reorder'); //default is 'reorder
54
+
55
+ const table = useMaterialReactTable({
56
+ columns,
57
+ data,
58
+ enableGrouping: true,
59
+ groupedColumnMode,
60
+ initialState: {
61
+ expanded: true, //expand all groups by default
62
+ grouping: ['state', 'gender'], //an array of columns to group by by default (can be multiple)
63
+ pagination: { pageIndex: 0, pageSize: 20 },
64
+ },
65
+ muiTableContainerProps: { sx: { maxHeight: '800px' } },
66
+ });
67
+
68
+ return (
69
+ <Stack
70
+ sx={{
71
+ gap: '1rem',
72
+ }}
73
+ >
74
+ <DemoRadioGroup
75
+ groupedColumnMode={groupedColumnMode}
76
+ setGroupedColumnMode={setGroupedColumnMode}
77
+ />
78
+ <MaterialReactTable table={table} />
79
+ </Stack>
80
+ );
81
+ };
82
+
83
+ export default Example;
84
+
85
+ //demo...
86
+ const DemoRadioGroup = ({
87
+ groupedColumnMode,
88
+ setGroupedColumnMode,
89
+ }: {
90
+ groupedColumnMode: false | 'remove' | 'reorder';
91
+ setGroupedColumnMode: (
92
+ groupedColumnMode: false | 'remove' | 'reorder',
93
+ ) => void;
94
+ }) => {
95
+ return (
96
+ <FormControl sx={{ margin: 'auto', textAlign: 'center' }}>
97
+ <FormLabel>Grouped Column Mode</FormLabel>
98
+ <RadioGroup
99
+ row
100
+ value={groupedColumnMode}
101
+ onChange={(event) =>
102
+ setGroupedColumnMode(
103
+ event.target.value === 'false'
104
+ ? false
105
+ : (event.target.value as any),
106
+ )
107
+ }
108
+ >
109
+ <FormControlLabel
110
+ control={<Radio />}
111
+ label='"reorder" (default)'
112
+ value="reorder"
113
+ />
114
+ <FormControlLabel control={<Radio />} label='"remove"' value="remove" />
115
+ <FormControlLabel value={false} control={<Radio />} label="false" />
116
+ </RadioGroup>
117
+ </FormControl>
118
+ );
119
+ };
120
+ //end
@@ -0,0 +1,48 @@
1
+ import { useMemo } from 'react';
2
+ import {
3
+ MaterialReactTable,
4
+ useMaterialReactTable,
5
+ type MRT_ColumnDef,
6
+ } from 'material-react-table';
7
+ import { data, type Person } from './makeData';
8
+
9
+ const Example = () => {
10
+ const columns = useMemo<MRT_ColumnDef<Person>[]>(
11
+ () => [
12
+ {
13
+ accessorKey: 'firstName',
14
+ header: 'First Name',
15
+ },
16
+ //column definitions...
17
+ {
18
+ accessorKey: 'lastName',
19
+ header: 'Last Name',
20
+ },
21
+ {
22
+ accessorKey: 'address',
23
+ header: 'Address',
24
+ },
25
+ {
26
+ accessorKey: 'city',
27
+ header: 'City',
28
+ },
29
+ //end
30
+ {
31
+ accessorKey: 'state',
32
+ enableColumnOrdering: false, //disable column ordering for this column,
33
+ header: 'State',
34
+ },
35
+ ],
36
+ [],
37
+ );
38
+
39
+ const table = useMaterialReactTable({
40
+ columns,
41
+ data,
42
+ enableColumnOrdering: true,
43
+ });
44
+
45
+ return <MaterialReactTable table={table} />;
46
+ };
47
+
48
+ export default Example;