@mini_7/material-react-table-mcp 4.0.0 → 4.0.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 (117) hide show
  1. package/README.md +1 -1
  2. package/data/examples/advanced.js +215 -0
  3. package/data/examples/aggregation-and-grouping.js +116 -0
  4. package/data/examples/aggregation-multi.js +89 -0
  5. package/data/examples/alternate-column-filtering.js +38 -0
  6. package/data/examples/alternate-detail-panel.js +65 -0
  7. package/data/examples/alternate-pagination.js +17 -0
  8. package/data/examples/basic.js +86 -0
  9. package/data/examples/chart-detail-panel.js +69 -0
  10. package/data/examples/column-actions-space.js +34 -0
  11. package/data/examples/column-alignment.js +58 -0
  12. package/data/examples/custom-column-actions.js +74 -0
  13. package/data/examples/custom-column-filtering-ui.js +59 -0
  14. package/data/examples/custom-headless.js +85 -0
  15. package/data/examples/custom-top-toolbar.js +60 -0
  16. package/data/examples/customize-display-columns.js +72 -0
  17. package/data/examples/customize-filter-components.js +78 -0
  18. package/data/examples/customize-filter-modes.js +59 -0
  19. package/data/examples/customize-filter-variants.js +98 -0
  20. package/data/examples/customize-global-filter-component.js +37 -0
  21. package/data/examples/customize-remove-column-grouping.js +75 -0
  22. package/data/examples/customize-row-selection.js +43 -0
  23. package/data/examples/customize-table-styles.js +81 -0
  24. package/data/examples/disable-column-actions.js +26 -0
  25. package/data/examples/disable-column-hiding.js +74 -0
  26. package/data/examples/disable-density-toggle.js +37 -0
  27. package/data/examples/dynamic-columns.js +124 -0
  28. package/data/examples/editing-crud-cell.js +288 -0
  29. package/data/examples/editing-crud-modal.js +275 -0
  30. package/data/examples/editing-crud-row.js +255 -0
  31. package/data/examples/editing-crud-table.js +280 -0
  32. package/data/examples/editing-crud-tree.js +328 -0
  33. package/data/examples/enable-cell-actions.js +52 -0
  34. package/data/examples/enable-click-to-copy.js +33 -0
  35. package/data/examples/enable-column-grouping.js +69 -0
  36. package/data/examples/enable-column-ordering.js +37 -0
  37. package/data/examples/enable-column-pinning.js +58 -0
  38. package/data/examples/enable-column-resizing.js +45 -0
  39. package/data/examples/enable-column-virtualization.js +19 -0
  40. package/data/examples/enable-detail-panel-conditionally.js +61 -0
  41. package/data/examples/enable-detail-panel-virtualized.js +64 -0
  42. package/data/examples/enable-expanding-tree.js +87 -0
  43. package/data/examples/enable-filter-facet-values.js +52 -0
  44. package/data/examples/enable-row-dragging.js +102 -0
  45. package/data/examples/enable-row-numbers-original.js +37 -0
  46. package/data/examples/enable-row-numbers-static.js +37 -0
  47. package/data/examples/enable-row-ordering.js +40 -0
  48. package/data/examples/enable-row-pinning-select.js +64 -0
  49. package/data/examples/enable-row-pinning-static.js +39 -0
  50. package/data/examples/enable-row-pinning-sticky.js +57 -0
  51. package/data/examples/enable-row-selection.js +71 -0
  52. package/data/examples/enable-row-virtualization.js +85 -0
  53. package/data/examples/enable-sticky-header.js +47 -0
  54. package/data/examples/expanding-tree-expanded.js +98 -0
  55. package/data/examples/expanding-tree-flat-parse.js +102 -0
  56. package/data/examples/expanding-tree-root-expanded.js +120 -0
  57. package/data/examples/export-to-csv.js +84 -0
  58. package/data/examples/export-to-pdf.js +76 -0
  59. package/data/examples/external-toolbar.js +82 -0
  60. package/data/examples/font-awesome-icons.js +62 -0
  61. package/data/examples/infinite-scrolling.js +137 -0
  62. package/data/examples/lazy-detail-panel.js +164 -0
  63. package/data/examples/lazy-sub-rows.js +118 -0
  64. package/data/examples/linear-progress.js +48 -0
  65. package/data/examples/loading.js +34 -0
  66. package/data/examples/localization-i18n-ar.js +40 -0
  67. package/data/examples/localization-i18n-az.js +38 -0
  68. package/data/examples/localization-i18n-bg.js +38 -0
  69. package/data/examples/localization-i18n-cs.js +38 -0
  70. package/data/examples/localization-i18n-da.js +38 -0
  71. package/data/examples/localization-i18n-de.js +38 -0
  72. package/data/examples/localization-i18n-el.js +38 -0
  73. package/data/examples/localization-i18n-en.js +38 -0
  74. package/data/examples/localization-i18n-es.js +38 -0
  75. package/data/examples/localization-i18n-et.js +38 -0
  76. package/data/examples/localization-i18n-fa.js +40 -0
  77. package/data/examples/localization-i18n-fi.js +38 -0
  78. package/data/examples/localization-i18n-fr.js +38 -0
  79. package/data/examples/localization-i18n-he.js +40 -0
  80. package/data/examples/localization-i18n-hr.js +38 -0
  81. package/data/examples/localization-i18n-hu.js +38 -0
  82. package/data/examples/localization-i18n-hy.js +40 -0
  83. package/data/examples/localization-i18n-id.js +38 -0
  84. package/data/examples/localization-i18n-it.js +38 -0
  85. package/data/examples/localization-i18n-ja.js +38 -0
  86. package/data/examples/localization-i18n-ko.js +38 -0
  87. package/data/examples/localization-i18n-nl.js +38 -0
  88. package/data/examples/localization-i18n-no.js +38 -0
  89. package/data/examples/localization-i18n-np.js +38 -0
  90. package/data/examples/localization-i18n-pl.js +38 -0
  91. package/data/examples/localization-i18n-pt-BR.js +38 -0
  92. package/data/examples/localization-i18n-pt.js +38 -0
  93. package/data/examples/localization-i18n-ro.js +38 -0
  94. package/data/examples/localization-i18n-ru.js +38 -0
  95. package/data/examples/localization-i18n-sk.js +38 -0
  96. package/data/examples/localization-i18n-sr-Cyrl-RS.js +38 -0
  97. package/data/examples/localization-i18n-sr-Latn-RS.js +38 -0
  98. package/data/examples/localization-i18n-sv.js +38 -0
  99. package/data/examples/localization-i18n-tr.js +38 -0
  100. package/data/examples/localization-i18n-uk.js +38 -0
  101. package/data/examples/localization-i18n-vi.js +38 -0
  102. package/data/examples/localization-i18n-zh-hans.js +38 -0
  103. package/data/examples/localization-i18n-zh-hant.js +38 -0
  104. package/data/examples/manual-selection.js +81 -0
  105. package/data/examples/minimal.js +66 -0
  106. package/data/examples/mui-theme.js +109 -0
  107. package/data/examples/multi-sorting.js +48 -0
  108. package/data/examples/persistent-state.js +126 -0
  109. package/data/examples/react-query.js +122 -0
  110. package/data/examples/remote.js +113 -0
  111. package/data/examples/row-actions-buttons.js +54 -0
  112. package/data/examples/row-actions-menu-items.js +36 -0
  113. package/data/examples/single-row-selection.js +74 -0
  114. package/data/examples/virtualized.js +122 -0
  115. package/dist/data.js +31 -9
  116. package/dist/index.js +18 -6
  117. package/package.json +1 -1
@@ -0,0 +1,82 @@
1
+ import { MRT_GlobalFilterTextField, MRT_ShowHideColumnsButton, MRT_TablePagination, MRT_ToggleDensePaddingButton, MRT_ToggleFiltersButton, MRT_ToolbarAlertBanner, useMaterialReactTable, MRT_TableContainer, } from 'material-react-table';
2
+ import { IconButton, Box, Button, Typography, Tooltip } from '@mui/material';
3
+ import PrintIcon from '@mui/icons-material/Print';
4
+ import { data } from './makeData';
5
+ const columns = [
6
+ {
7
+ accessorKey: 'firstName',
8
+ header: 'First Name',
9
+ },
10
+ {
11
+ accessorKey: 'lastName',
12
+ header: 'Last Name',
13
+ },
14
+ {
15
+ accessorKey: 'age',
16
+ header: 'Age',
17
+ },
18
+ {
19
+ accessorKey: 'salary',
20
+ header: 'Salary',
21
+ },
22
+ ];
23
+ const Example = () => {
24
+ const table = useMaterialReactTable({
25
+ columns,
26
+ data,
27
+ enableRowSelection: true,
28
+ initialState: { showGlobalFilter: true },
29
+ });
30
+ return (<Box sx={{ border: 'gray 2px dashed', padding: '16px' }}>
31
+ {/* Our Custom External Top Toolbar */}
32
+ <Box sx={(theme) => ({
33
+ display: 'flex',
34
+ backgroundColor: 'inherit',
35
+ borderRadius: '4px',
36
+ flexDirection: 'row',
37
+ gap: '16px',
38
+ justifyContent: 'space-between',
39
+ padding: '24px 16px',
40
+ '@media max-width: 768px': {
41
+ flexDirection: 'column',
42
+ },
43
+ })}>
44
+ <Box>
45
+ <Button color="primary" onClick={() => {
46
+ alert('Add User');
47
+ }} variant="contained">
48
+ Create New Account
49
+ </Button>
50
+ </Box>
51
+ <MRT_GlobalFilterTextField table={table}/>
52
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
53
+ <MRT_ToggleFiltersButton table={table}/>
54
+ <MRT_ShowHideColumnsButton table={table}/>
55
+ <MRT_ToggleDensePaddingButton table={table}/>
56
+ <Tooltip title="Print">
57
+ <IconButton onClick={() => window.print()}>
58
+ <PrintIcon />
59
+ </IconButton>
60
+ </Tooltip>
61
+ </Box>
62
+ </Box>
63
+ {/* Some Page Content */}
64
+ <Typography sx={{
65
+ p: '16px 4px',
66
+ }}>
67
+ {"Hey I'm some page content. I'm just one of your normal components between your custom toolbar and the MRT Table below"}
68
+ </Typography>
69
+ {/* The MRT Table with no toolbars built-in */}
70
+ <MRT_TableContainer table={table}/>
71
+ {/* Our Custom Bottom Toolbar */}
72
+ <Box>
73
+ <Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
74
+ <MRT_TablePagination table={table}/>
75
+ </Box>
76
+ <Box sx={{ display: 'grid', width: '100%' }}>
77
+ <MRT_ToolbarAlertBanner stackAlertBanner table={table}/>
78
+ </Box>
79
+ </Box>
80
+ </Box>);
81
+ };
82
+ export default Example;
@@ -0,0 +1,62 @@
1
+ import { useMemo } from 'react';
2
+ import { MaterialReactTable, } from 'material-react-table';
3
+ import { data } from './makeData';
4
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
5
+ import { faArrowDownWideShort, faBars, faBarsStaggered, faColumns, faCompress, faEllipsisH, faEllipsisVertical, faExpand, faEyeSlash, faFilter, faFilterCircleXmark, faGripLines, faSearch, faSearchMinus, faSortDown, faThumbTack, } from '@fortawesome/free-solid-svg-icons';
6
+ import '@fortawesome/fontawesome-svg-core/styles.css';
7
+ import { config } from '@fortawesome/fontawesome-svg-core';
8
+ config.autoAddCss = false;
9
+ /**
10
+ * These are just some of the icons visible in this table's feature set.
11
+ * If you skip customizing some icons, those particular icons will fallback the the default Material UI icons.
12
+ */
13
+ const fontAwesomeIcons = {
14
+ ArrowDownwardIcon: (props) => (<FontAwesomeIcon icon={faSortDown} {...props}/>),
15
+ ClearAllIcon: () => <FontAwesomeIcon icon={faBarsStaggered}/>,
16
+ DensityLargeIcon: () => <FontAwesomeIcon icon={faGripLines}/>,
17
+ DensityMediumIcon: () => <FontAwesomeIcon icon={faBars}/>,
18
+ DensitySmallIcon: () => <FontAwesomeIcon icon={faBars}/>,
19
+ DragHandleIcon: () => <FontAwesomeIcon icon={faGripLines}/>,
20
+ FilterListIcon: (props) => (<FontAwesomeIcon icon={faFilter} {...props}/>),
21
+ FilterListOffIcon: () => <FontAwesomeIcon icon={faFilterCircleXmark}/>,
22
+ FullscreenExitIcon: () => <FontAwesomeIcon icon={faCompress}/>,
23
+ FullscreenIcon: () => <FontAwesomeIcon icon={faExpand}/>,
24
+ SearchIcon: (props) => <FontAwesomeIcon icon={faSearch} {...props}/>,
25
+ SearchOffIcon: () => <FontAwesomeIcon icon={faSearchMinus}/>,
26
+ ViewColumnIcon: () => <FontAwesomeIcon icon={faColumns}/>,
27
+ MoreVertIcon: () => <FontAwesomeIcon icon={faEllipsisVertical}/>,
28
+ MoreHorizIcon: () => <FontAwesomeIcon icon={faEllipsisH}/>,
29
+ SortIcon: (props) => (<FontAwesomeIcon icon={faArrowDownWideShort} {...props}/> //props so that style rotation transforms are applied
30
+ ),
31
+ PushPinIcon: (props) => (<FontAwesomeIcon icon={faThumbTack} {...props}/> //props so that style rotation transforms are applied
32
+ ),
33
+ VisibilityOffIcon: () => <FontAwesomeIcon icon={faEyeSlash}/>,
34
+ };
35
+ const Example = () => {
36
+ const columns = useMemo(
37
+ //column definitions...
38
+ () => [
39
+ {
40
+ accessorKey: 'firstName',
41
+ header: 'First Name',
42
+ },
43
+ {
44
+ accessorKey: 'lastName',
45
+ header: 'Last Name',
46
+ },
47
+ {
48
+ accessorKey: 'address',
49
+ header: 'Address',
50
+ },
51
+ {
52
+ accessorKey: 'city',
53
+ header: 'City',
54
+ },
55
+ {
56
+ accessorKey: 'state',
57
+ header: 'State',
58
+ },
59
+ ], []);
60
+ return (<MaterialReactTable columns={columns} data={data} enableColumnOrdering enableColumnPinning icons={fontAwesomeIcons}/>);
61
+ };
62
+ export default Example;
@@ -0,0 +1,137 @@
1
+ import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
2
+ import { MaterialReactTable, useMaterialReactTable, } from 'material-react-table';
3
+ import { Typography } from '@mui/material';
4
+ import { QueryClient, QueryClientProvider, useInfiniteQuery, } from '@tanstack/react-query'; //Note: this is TanStack React Query V5
5
+ const columns = [
6
+ {
7
+ accessorKey: 'firstName',
8
+ header: 'First Name',
9
+ },
10
+ {
11
+ accessorKey: 'lastName',
12
+ header: 'Last Name',
13
+ },
14
+ {
15
+ accessorKey: 'address',
16
+ header: 'Address',
17
+ },
18
+ {
19
+ accessorKey: 'state',
20
+ header: 'State',
21
+ },
22
+ {
23
+ accessorKey: 'phoneNumber',
24
+ header: 'Phone Number',
25
+ },
26
+ ];
27
+ const fetchSize = 25;
28
+ const Example = () => {
29
+ const tableContainerRef = useRef(null); //we can get access to the underlying TableContainer element and react to its scroll events
30
+ const rowVirtualizerInstanceRef = useRef(null); //we can get access to the underlying Virtualizer instance and call its scrollToIndex method
31
+ const [columnFilters, setColumnFilters] = useState([]);
32
+ const [globalFilter, setGlobalFilter] = useState();
33
+ const [sorting, setSorting] = useState([]);
34
+ const { data, fetchNextPage, isError, isFetching, isLoading } = useInfiniteQuery({
35
+ queryKey: [
36
+ 'users-list',
37
+ {
38
+ columnFilters, //refetch when columnFilters changes
39
+ globalFilter, //refetch when globalFilter changes
40
+ sorting, //refetch when sorting changes
41
+ },
42
+ ],
43
+ queryFn: async ({ pageParam }) => {
44
+ const url = new URL('/api/data', location.origin); // nextjs api route
45
+ url.searchParams.set('start', `${pageParam * fetchSize}`);
46
+ url.searchParams.set('size', `${fetchSize}`);
47
+ url.searchParams.set('filters', JSON.stringify(columnFilters ?? []));
48
+ url.searchParams.set('globalFilter', globalFilter ?? '');
49
+ url.searchParams.set('sorting', JSON.stringify(sorting ?? []));
50
+ const response = await fetch(url.href);
51
+ const json = (await response.json());
52
+ return json;
53
+ },
54
+ initialPageParam: 0,
55
+ getNextPageParam: (_lastGroup, groups) => groups.length,
56
+ refetchOnWindowFocus: false,
57
+ });
58
+ const flatData = useMemo(() => data?.pages.flatMap((page) => page.data) ?? [], [data]);
59
+ const totalDBRowCount = data?.pages?.[0]?.meta?.totalRowCount ?? 0;
60
+ const totalFetched = flatData.length;
61
+ //called on scroll and possibly on mount to fetch more data as the user scrolls and reaches bottom of table
62
+ const fetchMoreOnBottomReached = useCallback((containerRefElement) => {
63
+ if (containerRefElement) {
64
+ const { scrollHeight, scrollTop, clientHeight } = containerRefElement;
65
+ //once the user has scrolled within 400px of the bottom of the table, fetch more data if we can
66
+ if (scrollHeight - scrollTop - clientHeight < 400 &&
67
+ !isFetching &&
68
+ totalFetched < totalDBRowCount) {
69
+ fetchNextPage();
70
+ }
71
+ }
72
+ }, [fetchNextPage, isFetching, totalFetched, totalDBRowCount]);
73
+ //scroll to top of table when sorting or filters change
74
+ useEffect(() => {
75
+ //scroll to the top of the table when the sorting changes
76
+ try {
77
+ rowVirtualizerInstanceRef.current?.scrollToIndex?.(0);
78
+ }
79
+ catch (error) {
80
+ console.error(error);
81
+ }
82
+ }, [sorting, columnFilters, globalFilter]);
83
+ //a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data
84
+ useEffect(() => {
85
+ fetchMoreOnBottomReached(tableContainerRef.current);
86
+ }, [fetchMoreOnBottomReached]);
87
+ const table = useMaterialReactTable({
88
+ columns,
89
+ data: flatData,
90
+ enablePagination: false,
91
+ enableRowNumbers: true,
92
+ enableRowVirtualization: true,
93
+ manualFiltering: true,
94
+ manualSorting: true,
95
+ muiTableContainerProps: {
96
+ ref: tableContainerRef, //get access to the table container element
97
+ sx: { maxHeight: '600px' }, //give the table a max height
98
+ onScroll: (event) => fetchMoreOnBottomReached(event.target), //add an event listener to the table container element
99
+ },
100
+ muiToolbarAlertBannerProps: isError
101
+ ? {
102
+ color: 'error',
103
+ children: 'Error loading data',
104
+ }
105
+ : undefined,
106
+ onColumnFiltersChange: setColumnFilters,
107
+ onGlobalFilterChange: setGlobalFilter,
108
+ onSortingChange: setSorting,
109
+ renderBottomToolbarCustomActions: () => (<Typography>
110
+ Fetched {totalFetched} of {totalDBRowCount} total rows.
111
+ </Typography>),
112
+ state: {
113
+ columnFilters,
114
+ globalFilter,
115
+ isLoading,
116
+ showAlertBanner: isError,
117
+ showProgressBars: isFetching,
118
+ sorting,
119
+ },
120
+ rowVirtualizerInstanceRef, //get access to the virtualizer instance
121
+ rowVirtualizerOptions: { overscan: 4 },
122
+ });
123
+ return <MaterialReactTable table={table}/>;
124
+ };
125
+ //react query setup in App.tsx
126
+ const ReactQueryDevtoolsProduction = lazy(() => import('@tanstack/react-query-devtools/build/modern/production.js').then((d) => ({
127
+ default: d.ReactQueryDevtools,
128
+ })));
129
+ const queryClient = new QueryClient();
130
+ export default function App() {
131
+ return (<QueryClientProvider client={queryClient}>
132
+ <Example />
133
+ <Suspense fallback={null}>
134
+ <ReactQueryDevtoolsProduction />
135
+ </Suspense>
136
+ </QueryClientProvider>);
137
+ }
@@ -0,0 +1,164 @@
1
+ import { lazy, Suspense, useMemo, useState } from 'react';
2
+ import { MaterialReactTable, useMaterialReactTable, } from 'material-react-table';
3
+ import { Alert, CircularProgress, Stack } from '@mui/material';
4
+ import AddIcon from '@mui/icons-material/Add';
5
+ import MinusIcon from '@mui/icons-material/Remove';
6
+ import { QueryClient, QueryClientProvider, keepPreviousData, useQuery, } from '@tanstack/react-query'; //note: this is TanStack React Query V5
7
+ const DetailPanel = ({ row }) => {
8
+ const { data: userInfo, isLoading, isError, } = useFetchUserInfo({
9
+ phoneNumber: row.id, //the row id is set to the user's phone number
10
+ }, {
11
+ enabled: row.getIsExpanded(),
12
+ });
13
+ if (isLoading)
14
+ return <CircularProgress />;
15
+ if (isError)
16
+ return <Alert severity="error">Error Loading User Info</Alert>;
17
+ const { favoriteMusic, favoriteSong, quote } = userInfo ?? {};
18
+ return (<Stack sx={{
19
+ gap: '0.5rem',
20
+ minHeight: '00px',
21
+ }}>
22
+ <div>
23
+ <b>Favorite Music:</b> {favoriteMusic}
24
+ </div>
25
+ <div>
26
+ <b>Favorite Song:</b> {favoriteSong}
27
+ </div>
28
+ <div>
29
+ <b>Quote:</b> {quote}
30
+ </div>
31
+ </Stack>);
32
+ };
33
+ const Example = () => {
34
+ //manage our own state for stuff we want to pass to the API
35
+ const [columnFilters, setColumnFilters] = useState([]);
36
+ const [globalFilter, setGlobalFilter] = useState('');
37
+ const [sorting, setSorting] = useState([]);
38
+ const [pagination, setPagination] = useState({
39
+ pageIndex: 0,
40
+ pageSize: 5,
41
+ });
42
+ const { data: { data = [], meta } = {}, isError, isRefetching, isLoading, } = useFetchUsers({
43
+ columnFilters,
44
+ globalFilter,
45
+ pagination,
46
+ sorting,
47
+ });
48
+ const columns = useMemo(
49
+ //column definitions...
50
+ () => [
51
+ {
52
+ accessorKey: 'firstName',
53
+ header: 'First Name',
54
+ },
55
+ {
56
+ accessorKey: 'lastName',
57
+ header: 'Last Name',
58
+ },
59
+ {
60
+ accessorKey: 'address',
61
+ header: 'Address',
62
+ },
63
+ {
64
+ accessorKey: 'state',
65
+ header: 'State',
66
+ },
67
+ {
68
+ accessorKey: 'phoneNumber',
69
+ header: 'Phone Number',
70
+ },
71
+ ], []);
72
+ const table = useMaterialReactTable({
73
+ columns,
74
+ data,
75
+ getRowId: (row) => row.phoneNumber,
76
+ manualFiltering: true, //turn off built-in client-side filtering
77
+ manualPagination: true, //turn off built-in client-side pagination
78
+ manualSorting: true, //turn off built-in client-side sorting
79
+ muiExpandButtonProps: ({ row }) => ({
80
+ children: row.getIsExpanded() ? <MinusIcon /> : <AddIcon />,
81
+ }),
82
+ muiToolbarAlertBannerProps: isError
83
+ ? {
84
+ color: 'error',
85
+ children: 'Error loading data',
86
+ }
87
+ : undefined,
88
+ onColumnFiltersChange: setColumnFilters,
89
+ onGlobalFilterChange: setGlobalFilter,
90
+ onPaginationChange: setPagination,
91
+ onSortingChange: setSorting,
92
+ renderDetailPanel: ({ row }) => <DetailPanel row={row}/>,
93
+ rowCount: meta?.totalRowCount ?? 0,
94
+ state: {
95
+ columnFilters,
96
+ globalFilter,
97
+ isLoading,
98
+ pagination,
99
+ showAlertBanner: isError,
100
+ showProgressBars: isRefetching,
101
+ sorting,
102
+ },
103
+ });
104
+ return <MaterialReactTable table={table}/>;
105
+ };
106
+ //react query setup in App.tsx
107
+ const ReactQueryDevtoolsProduction = lazy(() => import('@tanstack/react-query-devtools/build/modern/production.js').then((d) => ({
108
+ default: d.ReactQueryDevtools,
109
+ })));
110
+ const queryClient = new QueryClient();
111
+ export default function App() {
112
+ return (<QueryClientProvider client={queryClient}>
113
+ <Example />
114
+ <Suspense fallback={null}>
115
+ <ReactQueryDevtoolsProduction />
116
+ </Suspense>
117
+ </QueryClientProvider>);
118
+ }
119
+ //fetch user hook
120
+ const useFetchUsers = ({ columnFilters, globalFilter, pagination, sorting, }) => {
121
+ return useQuery({
122
+ queryKey: [
123
+ 'users', //give a unique key for this query
124
+ columnFilters, //refetch when columnFilters changes
125
+ globalFilter, //refetch when globalFilter changes
126
+ pagination.pageIndex, //refetch when pagination.pageIndex changes
127
+ pagination.pageSize, //refetch when pagination.pageSize changes
128
+ sorting, //refetch when sorting changes
129
+ ],
130
+ queryFn: async () => {
131
+ const fetchURL = new URL('/api/data', location.origin);
132
+ //read our state and pass it to the API as query params
133
+ fetchURL.searchParams.set('start', `${pagination.pageIndex * pagination.pageSize}`);
134
+ fetchURL.searchParams.set('size', `${pagination.pageSize}`);
135
+ fetchURL.searchParams.set('filters', JSON.stringify(columnFilters ?? []));
136
+ fetchURL.searchParams.set('globalFilter', globalFilter ?? '');
137
+ fetchURL.searchParams.set('sorting', JSON.stringify(sorting ?? []));
138
+ //use whatever fetch library you want, fetch, axios, etc
139
+ const response = await fetch(fetchURL.href);
140
+ const json = (await response.json());
141
+ return json;
142
+ },
143
+ placeholderData: keepPreviousData, //don't go to 0 rows when refetching or paginating to next page
144
+ });
145
+ };
146
+ //fetch more user info hook
147
+ const useFetchUserInfo = (params, options) => {
148
+ return useQuery({
149
+ enabled: options.enabled, //only fetch when the detail panel is opened
150
+ staleTime: 60 * 1000, //don't refetch for 60 seconds
151
+ queryKey: ['user', params.phoneNumber], //give a unique key for this query for each user fetch
152
+ queryFn: async () => {
153
+ const fetchURL = new URL(`/api/moredata/${params.phoneNumber
154
+ .replaceAll('-', '')
155
+ .replaceAll('.', '')
156
+ .replaceAll('(', '')
157
+ .replaceAll(')', '')}`, location.origin);
158
+ //use whatever fetch library you want, fetch, axios, etc
159
+ const response = await fetch(fetchURL.href);
160
+ const json = (await response.json());
161
+ return json;
162
+ },
163
+ });
164
+ };
@@ -0,0 +1,118 @@
1
+ import { lazy, Suspense, useMemo, useState } from 'react';
2
+ import { MaterialReactTable, useMaterialReactTable, } from 'material-react-table';
3
+ import { QueryClient, QueryClientProvider, keepPreviousData, useQuery, } from '@tanstack/react-query'; //note: this is TanStack React Query V5
4
+ const columns = [
5
+ //column definitions...
6
+ {
7
+ accessorKey: 'firstName',
8
+ header: 'First Name',
9
+ },
10
+ {
11
+ accessorKey: 'lastName',
12
+ header: 'Last Name',
13
+ },
14
+ {
15
+ accessorKey: 'email',
16
+ header: 'Email',
17
+ },
18
+ {
19
+ accessorKey: 'state',
20
+ header: 'State',
21
+ },
22
+ //end
23
+ ];
24
+ const Example = () => {
25
+ const [sorting, setSorting] = useState([]);
26
+ const [pagination, setPagination] = useState({
27
+ pageIndex: 0,
28
+ pageSize: 10,
29
+ });
30
+ const [expanded, setExpanded] = useState({}); //Record<string, boolean> | true
31
+ //which rows have sub-rows expanded and need their direct sub-rows to be included in the API call
32
+ const expandedRowIds = useMemo(() => expanded === true
33
+ ? 'all'
34
+ : Object.entries(expanded)
35
+ .filter(([_managerId, isExpanded]) => isExpanded)
36
+ .map(([managerId]) => managerId), [expanded]);
37
+ const { data: { data = [], meta } = {}, isError, isRefetching, isLoading, } = useFetchUsers({
38
+ pagination,
39
+ sorting,
40
+ expandedRowIds,
41
+ });
42
+ //get data for root rows only (top of the tree data)
43
+ const rootData = useMemo(() => data.filter((r) => !r.managerId), [data]);
44
+ const table = useMaterialReactTable({
45
+ columns,
46
+ data: rootData,
47
+ enableExpanding: true, //enable expanding column
48
+ enableFilters: false,
49
+ //tell MRT which rows have additional sub-rows that can be fetched
50
+ getRowCanExpand: (row) => !!row.original.subordinateIds.length, //just some type of boolean
51
+ //identify rows by the user's id
52
+ getRowId: (row) => row.id,
53
+ //if data is delivered in a flat array, MRT can convert it to a tree structure
54
+ //though it's usually better if the API can construct the nested structure before this point
55
+ getSubRows: (row) => data.filter((r) => r.managerId === row.id), //parse flat array into tree structure
56
+ // paginateExpandedRows: false, //the back-end in this example is acting as if this option is false
57
+ manualPagination: true, //turn off built-in client-side pagination
58
+ manualSorting: true, //turn off built-in client-side sorting
59
+ muiToolbarAlertBannerProps: isError
60
+ ? {
61
+ color: 'error',
62
+ children: 'Error loading data',
63
+ }
64
+ : undefined,
65
+ onExpandedChange: setExpanded,
66
+ onPaginationChange: setPagination,
67
+ onSortingChange: setSorting,
68
+ rowCount: meta?.totalRowCount ?? 0,
69
+ state: {
70
+ expanded,
71
+ isLoading,
72
+ pagination,
73
+ showAlertBanner: isError,
74
+ showProgressBars: isRefetching,
75
+ sorting,
76
+ },
77
+ });
78
+ return <MaterialReactTable table={table}/>;
79
+ };
80
+ //react query setup in App.tsx
81
+ const ReactQueryDevtoolsProduction = lazy(() => import('@tanstack/react-query-devtools/build/modern/production.js').then((d) => ({
82
+ default: d.ReactQueryDevtools,
83
+ })));
84
+ const queryClient = new QueryClient();
85
+ export default function App() {
86
+ return (<QueryClientProvider client={queryClient}>
87
+ <Example />
88
+ <Suspense fallback={null}>
89
+ <ReactQueryDevtoolsProduction />
90
+ </Suspense>
91
+ </QueryClientProvider>);
92
+ }
93
+ //fetch user hook
94
+ const useFetchUsers = ({ pagination, sorting, expandedRowIds, }) => {
95
+ return useQuery({
96
+ queryKey: [
97
+ 'users', //give a unique key for this query
98
+ {
99
+ pagination, //refetch when pagination changes
100
+ sorting, //refetch when sorting changes
101
+ expandedRowIds,
102
+ },
103
+ ],
104
+ queryFn: async () => {
105
+ const fetchURL = new URL('/api/treedata', location.origin); // nextjs api route
106
+ //read our state and pass it to the API as query params
107
+ fetchURL.searchParams.set('start', `${pagination.pageIndex * pagination.pageSize}`);
108
+ fetchURL.searchParams.set('size', `${pagination.pageSize}`);
109
+ fetchURL.searchParams.set('sorting', JSON.stringify(sorting ?? []));
110
+ fetchURL.searchParams.set('expandedRowIds', expandedRowIds === 'all' ? 'all' : JSON.stringify(expandedRowIds ?? []));
111
+ //use whatever fetch library you want, fetch, axios, etc
112
+ const response = await fetch(fetchURL.href);
113
+ const json = (await response.json());
114
+ return json;
115
+ },
116
+ placeholderData: keepPreviousData, //don't go to 0 rows when refetching or paginating to next page
117
+ });
118
+ };
@@ -0,0 +1,48 @@
1
+ import { useEffect, useMemo, useState } from 'react';
2
+ import { MaterialReactTable } from 'material-react-table';
3
+ import { data } from './makeData';
4
+ import { Button } from '@mui/material';
5
+ const Example = () => {
6
+ const columns = useMemo(
7
+ //column definitions...
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
+ },
21
+ {
22
+ accessorKey: 'city',
23
+ header: 'City',
24
+ },
25
+ ], []);
26
+ const [progress, setProgress] = useState(0);
27
+ //simulate random progress for demo purposes
28
+ useEffect(() => {
29
+ const interval = setInterval(() => {
30
+ setProgress((oldProgress) => {
31
+ const newProgress = Math.random() * 20;
32
+ return Math.min(oldProgress + newProgress, 100);
33
+ });
34
+ }, 1000);
35
+ return () => clearInterval(interval);
36
+ }, []);
37
+ return (<MaterialReactTable columns={columns} data={data} muiLinearProgressProps={({ isTopToolbar }) => ({
38
+ color: 'secondary',
39
+ variant: 'determinate', //if you want to show exact progress value
40
+ value: progress, //value between 0 and 100
41
+ sx: {
42
+ display: isTopToolbar ? 'block' : 'none', //hide bottom progress bar
43
+ },
44
+ })} renderTopToolbarCustomActions={() => (<Button onClick={() => setProgress(0)} variant="contained">
45
+ Reset
46
+ </Button>)} state={{ showProgressBars: true }}/>);
47
+ };
48
+ export default Example;
@@ -0,0 +1,34 @@
1
+ import { useMemo } from 'react';
2
+ import { MaterialReactTable } from 'material-react-table';
3
+ const data = [];
4
+ const Example = () => {
5
+ const columns = useMemo(
6
+ //column definitions...
7
+ () => [
8
+ {
9
+ accessorKey: 'firstName',
10
+ header: 'First Name',
11
+ },
12
+ {
13
+ accessorKey: 'lastName',
14
+ header: 'Last Name',
15
+ },
16
+ {
17
+ accessorKey: 'email',
18
+ header: 'Email',
19
+ },
20
+ {
21
+ accessorKey: 'city',
22
+ header: 'City',
23
+ },
24
+ ], []);
25
+ return (<MaterialReactTable columns={columns} data={data} state={{ isLoading: true }} muiCircularProgressProps={{
26
+ color: 'secondary',
27
+ thickness: 5,
28
+ size: 55,
29
+ }} muiSkeletonProps={{
30
+ animation: 'pulse',
31
+ height: 28,
32
+ }}/>);
33
+ };
34
+ export default Example;