@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.
- package/README.md +68 -0
- package/data/MIGRATION.md +136 -0
- package/data/api.json +5379 -0
- package/data/examples/advanced.tsx +309 -0
- package/data/examples/aggregation-and-grouping.tsx +153 -0
- package/data/examples/aggregation-multi.tsx +105 -0
- package/data/examples/alternate-column-filtering.tsx +49 -0
- package/data/examples/alternate-detail-panel.tsx +81 -0
- package/data/examples/alternate-pagination.tsx +23 -0
- package/data/examples/basic.tsx +109 -0
- package/data/examples/chart-detail-panel.tsx +89 -0
- package/data/examples/column-actions-space.tsx +44 -0
- package/data/examples/column-alignment.tsx +70 -0
- package/data/examples/custom-column-actions.tsx +109 -0
- package/data/examples/custom-column-filtering-ui.tsx +89 -0
- package/data/examples/custom-headless.tsx +125 -0
- package/data/examples/custom-top-toolbar.tsx +88 -0
- package/data/examples/customize-display-columns.tsx +85 -0
- package/data/examples/customize-filter-components.tsx +101 -0
- package/data/examples/customize-filter-modes.tsx +73 -0
- package/data/examples/customize-filter-variants.tsx +116 -0
- package/data/examples/customize-global-filter-component.tsx +52 -0
- package/data/examples/customize-remove-column-grouping.tsx +94 -0
- package/data/examples/customize-row-selection.tsx +54 -0
- package/data/examples/customize-table-styles.tsx +100 -0
- package/data/examples/disable-column-actions.tsx +37 -0
- package/data/examples/disable-column-hiding.tsx +90 -0
- package/data/examples/disable-density-toggle.tsx +49 -0
- package/data/examples/dynamic-columns.tsx +189 -0
- package/data/examples/editing-crud-cell.tsx +377 -0
- package/data/examples/editing-crud-modal.tsx +370 -0
- package/data/examples/editing-crud-row.tsx +333 -0
- package/data/examples/editing-crud-table.tsx +369 -0
- package/data/examples/editing-crud-tree.tsx +416 -0
- package/data/examples/enable-cell-actions.tsx +76 -0
- package/data/examples/enable-click-to-copy.tsx +39 -0
- package/data/examples/enable-column-grouping.tsx +120 -0
- package/data/examples/enable-column-ordering.tsx +48 -0
- package/data/examples/enable-column-pinning.tsx +69 -0
- package/data/examples/enable-column-resizing.tsx +56 -0
- package/data/examples/enable-column-virtualization.tsx +27 -0
- package/data/examples/enable-detail-panel-conditionally.tsx +78 -0
- package/data/examples/enable-detail-panel-virtualized.tsx +80 -0
- package/data/examples/enable-expanding-tree.tsx +110 -0
- package/data/examples/enable-filter-facet-values.tsx +65 -0
- package/data/examples/enable-row-dragging.tsx +137 -0
- package/data/examples/enable-row-numbers-original.tsx +48 -0
- package/data/examples/enable-row-numbers-static.tsx +48 -0
- package/data/examples/enable-row-ordering.tsx +57 -0
- package/data/examples/enable-row-pinning-select.tsx +76 -0
- package/data/examples/enable-row-pinning-static.tsx +50 -0
- package/data/examples/enable-row-pinning-sticky.tsx +69 -0
- package/data/examples/enable-row-selection.tsx +96 -0
- package/data/examples/enable-row-virtualization.tsx +101 -0
- package/data/examples/enable-sticky-header.tsx +59 -0
- package/data/examples/expanding-tree-expanded.tsx +121 -0
- package/data/examples/expanding-tree-flat-parse.tsx +125 -0
- package/data/examples/expanding-tree-root-expanded.tsx +151 -0
- package/data/examples/export-to-csv.tsx +114 -0
- package/data/examples/export-to-pdf.tsx +104 -0
- package/data/examples/external-toolbar.tsx +108 -0
- package/data/examples/font-awesome-icons.tsx +106 -0
- package/data/examples/infinite-scrolling.tsx +208 -0
- package/data/examples/lazy-detail-panel.tsx +262 -0
- package/data/examples/lazy-sub-rows.tsx +190 -0
- package/data/examples/linear-progress.tsx +66 -0
- package/data/examples/loading.tsx +50 -0
- package/data/examples/localization-i18n-ar.tsx +65 -0
- package/data/examples/localization-i18n-az.tsx +60 -0
- package/data/examples/localization-i18n-bg.tsx +60 -0
- package/data/examples/localization-i18n-cs.tsx +60 -0
- package/data/examples/localization-i18n-da.tsx +60 -0
- package/data/examples/localization-i18n-de.tsx +60 -0
- package/data/examples/localization-i18n-el.tsx +60 -0
- package/data/examples/localization-i18n-en.tsx +60 -0
- package/data/examples/localization-i18n-es.tsx +60 -0
- package/data/examples/localization-i18n-et.tsx +60 -0
- package/data/examples/localization-i18n-fa.tsx +66 -0
- package/data/examples/localization-i18n-fi.tsx +60 -0
- package/data/examples/localization-i18n-fr.tsx +60 -0
- package/data/examples/localization-i18n-he.tsx +66 -0
- package/data/examples/localization-i18n-hr.tsx +60 -0
- package/data/examples/localization-i18n-hu.tsx +60 -0
- package/data/examples/localization-i18n-hy.tsx +65 -0
- package/data/examples/localization-i18n-id.tsx +60 -0
- package/data/examples/localization-i18n-it.tsx +60 -0
- package/data/examples/localization-i18n-ja.tsx +60 -0
- package/data/examples/localization-i18n-ko.tsx +60 -0
- package/data/examples/localization-i18n-nl.tsx +60 -0
- package/data/examples/localization-i18n-no.tsx +60 -0
- package/data/examples/localization-i18n-np.tsx +60 -0
- package/data/examples/localization-i18n-pl.tsx +60 -0
- package/data/examples/localization-i18n-pt-BR.tsx +60 -0
- package/data/examples/localization-i18n-pt.tsx +60 -0
- package/data/examples/localization-i18n-ro.tsx +60 -0
- package/data/examples/localization-i18n-ru.tsx +60 -0
- package/data/examples/localization-i18n-sk.tsx +60 -0
- package/data/examples/localization-i18n-sr-Cyrl-RS.tsx +60 -0
- package/data/examples/localization-i18n-sr-Latn-RS.tsx +60 -0
- package/data/examples/localization-i18n-sv.tsx +60 -0
- package/data/examples/localization-i18n-tr.tsx +60 -0
- package/data/examples/localization-i18n-uk.tsx +60 -0
- package/data/examples/localization-i18n-vi.tsx +60 -0
- package/data/examples/localization-i18n-zh-hans.tsx +60 -0
- package/data/examples/localization-i18n-zh-hant.tsx +60 -0
- package/data/examples/manual-selection.tsx +105 -0
- package/data/examples/minimal.tsx +78 -0
- package/data/examples/mui-theme.tsx +136 -0
- package/data/examples/multi-sorting.tsx +58 -0
- package/data/examples/persistent-state.tsx +184 -0
- package/data/examples/react-query.tsx +182 -0
- package/data/examples/remote.tsx +150 -0
- package/data/examples/row-actions-buttons.tsx +89 -0
- package/data/examples/row-actions-menu-items.tsx +64 -0
- package/data/examples/single-row-selection.tsx +98 -0
- package/data/examples/virtualized.tsx +138 -0
- package/data/guides/accessibility.md +119 -0
- package/data/guides/aggregation.md +210 -0
- package/data/guides/async-loading.md +132 -0
- package/data/guides/best-practices.md +363 -0
- package/data/guides/cell-actions.md +139 -0
- package/data/guides/click-to-copy.md +67 -0
- package/data/guides/column-actions.md +69 -0
- package/data/guides/column-filtering.md +366 -0
- package/data/guides/column-grouping.md +192 -0
- package/data/guides/column-hiding.md +133 -0
- package/data/guides/column-ordering-dnd.md +99 -0
- package/data/guides/column-pinning.md +72 -0
- package/data/guides/column-resizing.md +157 -0
- package/data/guides/column-size.md +162 -0
- package/data/guides/customize-components.md +395 -0
- package/data/guides/customize-icons.md +35 -0
- package/data/guides/data-columns.md +292 -0
- package/data/guides/density-toggle.md +46 -0
- package/data/guides/detail-panel.md +195 -0
- package/data/guides/display-columns.md +135 -0
- package/data/guides/editing.md +367 -0
- package/data/guides/expanding-sub-rows.md +194 -0
- package/data/guides/full-screen-toggle.md +63 -0
- package/data/guides/global-filtering.md +237 -0
- package/data/guides/localization.md +57 -0
- package/data/guides/memoization.md +157 -0
- package/data/guides/pagination.md +171 -0
- package/data/guides/row-actions.md +116 -0
- package/data/guides/row-numbers.md +24 -0
- package/data/guides/row-ordering-dnd.md +51 -0
- package/data/guides/row-pinning.md +96 -0
- package/data/guides/row-selection.md +237 -0
- package/data/guides/sorting.md +190 -0
- package/data/guides/state-management.md +165 -0
- package/data/guides/sticky-header.md +41 -0
- package/data/guides/table-event-listeners.md +103 -0
- package/data/guides/toolbar-customization.md +251 -0
- package/data/guides/virtualization.md +183 -0
- package/data/index.json +1930 -0
- package/data/reference/mrt-components.md +183 -0
- package/data/reference/mrt-hooks.md +125 -0
- package/data/skills/composable-components/SKILL.md +189 -0
- package/data/skills/customization/SKILL.md +190 -0
- package/data/skills/drag-and-drop-ordering/SKILL.md +227 -0
- package/data/skills/editing/SKILL.md +243 -0
- package/data/skills/filtering/SKILL.md +213 -0
- package/data/skills/getting-started/SKILL.md +213 -0
- package/data/skills/localization/SKILL.md +182 -0
- package/data/skills/migrate-v3-to-v4/SKILL.md +161 -0
- package/data/skills/state-and-server-data/SKILL.md +200 -0
- package/data/skills/virtualization/SKILL.md +203 -0
- package/dist/data.js +137 -0
- package/dist/index.js +232 -0
- package/package.json +50 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { MaterialReactTable, type MRT_ColumnDef } from 'material-react-table';
|
|
3
|
+
import { createTheme, ThemeProvider, useTheme } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
type Person = {
|
|
6
|
+
firstName: string;
|
|
7
|
+
lastName: string;
|
|
8
|
+
address: string;
|
|
9
|
+
city: string;
|
|
10
|
+
state: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
//column definitions...
|
|
14
|
+
const columns: MRT_ColumnDef<Person>[] = [
|
|
15
|
+
{
|
|
16
|
+
accessorKey: 'firstName',
|
|
17
|
+
header: 'First Name',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
accessorKey: 'lastName',
|
|
21
|
+
header: 'Last Name',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
accessorKey: 'address',
|
|
25
|
+
header: 'Address',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
accessorKey: 'city',
|
|
29
|
+
header: 'City',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
accessorKey: 'state',
|
|
33
|
+
header: 'State',
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
//end
|
|
37
|
+
|
|
38
|
+
//data definitions...
|
|
39
|
+
const data = [
|
|
40
|
+
{
|
|
41
|
+
firstName: 'Dylan',
|
|
42
|
+
lastName: 'Murray',
|
|
43
|
+
address: '261 Erdman Ford',
|
|
44
|
+
city: 'East Daphne',
|
|
45
|
+
state: 'Kentucky',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
firstName: 'Raquel',
|
|
49
|
+
lastName: 'Kohler',
|
|
50
|
+
address: '769 Dominic Grove',
|
|
51
|
+
city: 'Columbus',
|
|
52
|
+
state: 'Ohio',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
firstName: 'Ervin',
|
|
56
|
+
lastName: 'Reinger',
|
|
57
|
+
address: '566 Brakus Inlet',
|
|
58
|
+
city: 'South Linda',
|
|
59
|
+
state: 'West Virginia',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
firstName: 'Brittany',
|
|
63
|
+
lastName: 'McCullough',
|
|
64
|
+
address: '722 Emie Stream',
|
|
65
|
+
city: 'Lincoln',
|
|
66
|
+
state: 'Nebraska',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
firstName: 'Branson',
|
|
70
|
+
lastName: 'Frami',
|
|
71
|
+
address: '32188 Larkin Turnpike',
|
|
72
|
+
city: 'Charleston',
|
|
73
|
+
state: 'South Carolina',
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
//end
|
|
77
|
+
|
|
78
|
+
const Example = () => {
|
|
79
|
+
const globalTheme = useTheme(); //(optional) if you already have a theme defined in your app root, you can import here
|
|
80
|
+
|
|
81
|
+
const tableTheme = useMemo(
|
|
82
|
+
() =>
|
|
83
|
+
createTheme({
|
|
84
|
+
palette: {
|
|
85
|
+
mode: globalTheme.palette.mode, //let's use the same dark/light mode as the global theme
|
|
86
|
+
primary: globalTheme.palette.secondary, //swap in the secondary color as the primary for the table
|
|
87
|
+
info: {
|
|
88
|
+
main: 'rgb(255,122,0)', //add in a custom color for the toolbar alert background stuff
|
|
89
|
+
},
|
|
90
|
+
background: {
|
|
91
|
+
default:
|
|
92
|
+
globalTheme.palette.mode === 'light'
|
|
93
|
+
? 'rgb(254,255,244)' //random light yellow color for the background in light mode
|
|
94
|
+
: '#000', //pure black table in dark mode for fun
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
typography: {
|
|
98
|
+
button: {
|
|
99
|
+
textTransform: 'none', //customize typography styles for all buttons in table by default
|
|
100
|
+
fontSize: '1.2rem',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
components: {
|
|
104
|
+
MuiTooltip: {
|
|
105
|
+
styleOverrides: {
|
|
106
|
+
tooltip: {
|
|
107
|
+
fontSize: '1.1rem', //override to make tooltip font size larger
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
MuiSwitch: {
|
|
112
|
+
styleOverrides: {
|
|
113
|
+
thumb: {
|
|
114
|
+
color: 'pink', //change the color of the switch thumb in the columns show/hide menu to pink
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
[globalTheme],
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<ThemeProvider theme={tableTheme}>
|
|
125
|
+
<MaterialReactTable
|
|
126
|
+
columns={columns}
|
|
127
|
+
data={data}
|
|
128
|
+
enableRowSelection
|
|
129
|
+
enableColumnOrdering
|
|
130
|
+
enableColumnPinning
|
|
131
|
+
/>
|
|
132
|
+
</ThemeProvider>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export default Example;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MaterialReactTable,
|
|
3
|
+
useMaterialReactTable,
|
|
4
|
+
type MRT_ColumnDef,
|
|
5
|
+
} from 'material-react-table';
|
|
6
|
+
import { data, type Person } from './makeData';
|
|
7
|
+
import { Button } from '@mui/material';
|
|
8
|
+
|
|
9
|
+
const columns: MRT_ColumnDef<Person>[] = [
|
|
10
|
+
{
|
|
11
|
+
accessorKey: 'firstName',
|
|
12
|
+
header: 'First Name',
|
|
13
|
+
sortDescFirst: false, //sort first name in ascending order by default on first sort click (default for non-numeric columns)
|
|
14
|
+
},
|
|
15
|
+
//column definitions...
|
|
16
|
+
{
|
|
17
|
+
accessorKey: 'lastName',
|
|
18
|
+
header: 'Last Name',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
accessorKey: 'city',
|
|
22
|
+
header: 'City',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
accessorKey: 'state',
|
|
26
|
+
header: 'State',
|
|
27
|
+
},
|
|
28
|
+
//end
|
|
29
|
+
{
|
|
30
|
+
accessorKey: 'salary',
|
|
31
|
+
header: 'Salary',
|
|
32
|
+
sortDescFirst: true, //sort salary in descending order by default on first sort click (default for numeric columns)
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const Example = () => {
|
|
37
|
+
const table = useMaterialReactTable({
|
|
38
|
+
columns,
|
|
39
|
+
data,
|
|
40
|
+
isMultiSortEvent: () => true, //now no need to hold `shift` key to multi-sort
|
|
41
|
+
maxMultiSortColCount: 3, //prevent more than 3 columns from being sorted at once
|
|
42
|
+
initialState: {
|
|
43
|
+
sorting: [
|
|
44
|
+
{ id: 'state', desc: false }, //sort by state in ascending order by default
|
|
45
|
+
{ id: 'city', desc: true }, //then sort by city in descending order by default
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
renderTopToolbarCustomActions: ({ table }) => (
|
|
49
|
+
<Button onClick={() => table.resetSorting(true)}>
|
|
50
|
+
Clear All Sorting
|
|
51
|
+
</Button>
|
|
52
|
+
),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return <MaterialReactTable table={table} />;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default Example;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Button } from '@mui/material';
|
|
3
|
+
import {
|
|
4
|
+
MaterialReactTable,
|
|
5
|
+
type MRT_ColumnDef,
|
|
6
|
+
type MRT_ColumnFiltersState,
|
|
7
|
+
type MRT_DensityState,
|
|
8
|
+
type MRT_SortingState,
|
|
9
|
+
type MRT_VisibilityState,
|
|
10
|
+
} from 'material-react-table';
|
|
11
|
+
import { data, type Person } from './makeData';
|
|
12
|
+
|
|
13
|
+
//column definitions...
|
|
14
|
+
const columns: MRT_ColumnDef<Person>[] = [
|
|
15
|
+
{
|
|
16
|
+
accessorKey: 'firstName',
|
|
17
|
+
header: 'First Name',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
accessorKey: 'lastName',
|
|
21
|
+
header: 'Last Name',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
accessorKey: 'city',
|
|
25
|
+
header: 'City',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
accessorKey: 'state',
|
|
29
|
+
header: 'State',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
accessorKey: 'salary',
|
|
33
|
+
header: 'Salary',
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
//end
|
|
37
|
+
|
|
38
|
+
const Example = () => {
|
|
39
|
+
const isFirstRender = useRef(true);
|
|
40
|
+
|
|
41
|
+
const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>(
|
|
42
|
+
[],
|
|
43
|
+
);
|
|
44
|
+
const [columnVisibility, setColumnVisibility] = useState<MRT_VisibilityState>(
|
|
45
|
+
{},
|
|
46
|
+
);
|
|
47
|
+
const [density, setDensity] = useState<MRT_DensityState>('comfortable');
|
|
48
|
+
const [globalFilter, setGlobalFilter] = useState<string | undefined>(
|
|
49
|
+
undefined,
|
|
50
|
+
);
|
|
51
|
+
const [showGlobalFilter, setShowGlobalFilter] = useState(false);
|
|
52
|
+
const [showColumnFilters, setShowColumnFilters] = useState(false);
|
|
53
|
+
const [sorting, setSorting] = useState<MRT_SortingState>([]);
|
|
54
|
+
|
|
55
|
+
//load state from local storage
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
const columnFilters = sessionStorage.getItem('mrt_columnFilters_table_1');
|
|
58
|
+
const columnVisibility = sessionStorage.getItem(
|
|
59
|
+
'mrt_columnVisibility_table_1',
|
|
60
|
+
);
|
|
61
|
+
const density = sessionStorage.getItem('mrt_density_table_1');
|
|
62
|
+
const globalFilter = sessionStorage.getItem('mrt_globalFilter_table_1');
|
|
63
|
+
const showGlobalFilter = sessionStorage.getItem(
|
|
64
|
+
'mrt_showGlobalFilter_table_1',
|
|
65
|
+
);
|
|
66
|
+
const showColumnFilters = sessionStorage.getItem(
|
|
67
|
+
'mrt_showColumnFilters_table_1',
|
|
68
|
+
);
|
|
69
|
+
const sorting = sessionStorage.getItem('mrt_sorting_table_1');
|
|
70
|
+
|
|
71
|
+
if (columnFilters) {
|
|
72
|
+
setColumnFilters(JSON.parse(columnFilters));
|
|
73
|
+
}
|
|
74
|
+
if (columnVisibility) {
|
|
75
|
+
setColumnVisibility(JSON.parse(columnVisibility));
|
|
76
|
+
}
|
|
77
|
+
if (density) {
|
|
78
|
+
setDensity(JSON.parse(density));
|
|
79
|
+
}
|
|
80
|
+
if (globalFilter) {
|
|
81
|
+
setGlobalFilter(JSON.parse(globalFilter) || undefined);
|
|
82
|
+
}
|
|
83
|
+
if (showGlobalFilter) {
|
|
84
|
+
setShowGlobalFilter(JSON.parse(showGlobalFilter));
|
|
85
|
+
}
|
|
86
|
+
if (showColumnFilters) {
|
|
87
|
+
setShowColumnFilters(JSON.parse(showColumnFilters));
|
|
88
|
+
}
|
|
89
|
+
if (sorting) {
|
|
90
|
+
setSorting(JSON.parse(sorting));
|
|
91
|
+
}
|
|
92
|
+
isFirstRender.current = false;
|
|
93
|
+
}, []);
|
|
94
|
+
|
|
95
|
+
//save states to local storage
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (isFirstRender.current) return;
|
|
98
|
+
sessionStorage.setItem(
|
|
99
|
+
'mrt_columnFilters_table_1',
|
|
100
|
+
JSON.stringify(columnFilters),
|
|
101
|
+
);
|
|
102
|
+
}, [columnFilters]);
|
|
103
|
+
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (isFirstRender.current) return;
|
|
106
|
+
sessionStorage.setItem(
|
|
107
|
+
'mrt_columnVisibility_table_1',
|
|
108
|
+
JSON.stringify(columnVisibility),
|
|
109
|
+
);
|
|
110
|
+
}, [columnVisibility]);
|
|
111
|
+
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (isFirstRender.current) return;
|
|
114
|
+
sessionStorage.setItem('mrt_density_table_1', JSON.stringify(density));
|
|
115
|
+
}, [density]);
|
|
116
|
+
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (isFirstRender.current) return;
|
|
119
|
+
sessionStorage.setItem(
|
|
120
|
+
'mrt_globalFilter_table_1',
|
|
121
|
+
JSON.stringify(globalFilter ?? ''),
|
|
122
|
+
);
|
|
123
|
+
}, [globalFilter]);
|
|
124
|
+
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (isFirstRender.current) return;
|
|
127
|
+
sessionStorage.setItem(
|
|
128
|
+
'mrt_showGlobalFilter_table_1',
|
|
129
|
+
JSON.stringify(showGlobalFilter),
|
|
130
|
+
);
|
|
131
|
+
}, [showGlobalFilter]);
|
|
132
|
+
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (isFirstRender.current) return;
|
|
135
|
+
sessionStorage.setItem(
|
|
136
|
+
'mrt_showColumnFilters_table_1',
|
|
137
|
+
JSON.stringify(showColumnFilters),
|
|
138
|
+
);
|
|
139
|
+
}, [showColumnFilters]);
|
|
140
|
+
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
if (isFirstRender.current) return;
|
|
143
|
+
sessionStorage.setItem('mrt_sorting_table_1', JSON.stringify(sorting));
|
|
144
|
+
}, [sorting]);
|
|
145
|
+
|
|
146
|
+
const resetState = () => {
|
|
147
|
+
sessionStorage.removeItem('mrt_columnFilters_table_1');
|
|
148
|
+
sessionStorage.removeItem('mrt_columnVisibility_table_1');
|
|
149
|
+
sessionStorage.removeItem('mrt_density_table_1');
|
|
150
|
+
sessionStorage.removeItem('mrt_globalFilter_table_1');
|
|
151
|
+
sessionStorage.removeItem('mrt_showGlobalFilter_table_1');
|
|
152
|
+
sessionStorage.removeItem('mrt_showColumnFilters_table_1');
|
|
153
|
+
sessionStorage.removeItem('mrt_sorting_table_1');
|
|
154
|
+
window.location.reload();
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<MaterialReactTable
|
|
159
|
+
columns={columns}
|
|
160
|
+
data={data}
|
|
161
|
+
onColumnFiltersChange={setColumnFilters}
|
|
162
|
+
onColumnVisibilityChange={setColumnVisibility}
|
|
163
|
+
onDensityChange={setDensity}
|
|
164
|
+
onGlobalFilterChange={setGlobalFilter}
|
|
165
|
+
onShowColumnFiltersChange={setShowColumnFilters}
|
|
166
|
+
onShowGlobalFilterChange={setShowGlobalFilter}
|
|
167
|
+
onSortingChange={setSorting}
|
|
168
|
+
state={{
|
|
169
|
+
columnFilters,
|
|
170
|
+
columnVisibility,
|
|
171
|
+
density,
|
|
172
|
+
globalFilter,
|
|
173
|
+
showColumnFilters,
|
|
174
|
+
showGlobalFilter,
|
|
175
|
+
sorting,
|
|
176
|
+
}}
|
|
177
|
+
renderTopToolbarCustomActions={() => (
|
|
178
|
+
<Button onClick={resetState}>Reset State</Button>
|
|
179
|
+
)}
|
|
180
|
+
/>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export default Example;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { lazy, Suspense, useMemo, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
MaterialReactTable,
|
|
4
|
+
useMaterialReactTable,
|
|
5
|
+
type MRT_ColumnDef,
|
|
6
|
+
type MRT_ColumnFiltersState,
|
|
7
|
+
type MRT_PaginationState,
|
|
8
|
+
type MRT_SortingState,
|
|
9
|
+
} from 'material-react-table';
|
|
10
|
+
import { IconButton, Tooltip } from '@mui/material';
|
|
11
|
+
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
12
|
+
import {
|
|
13
|
+
QueryClient,
|
|
14
|
+
QueryClientProvider,
|
|
15
|
+
keepPreviousData,
|
|
16
|
+
useQuery,
|
|
17
|
+
} from '@tanstack/react-query'; //note: this is TanStack React Query V5
|
|
18
|
+
|
|
19
|
+
//Your API response shape will probably be different. Knowing a total row count is important though.
|
|
20
|
+
type UserApiResponse = {
|
|
21
|
+
data: Array<User>;
|
|
22
|
+
meta: {
|
|
23
|
+
totalRowCount: number;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type User = {
|
|
28
|
+
firstName: string;
|
|
29
|
+
lastName: string;
|
|
30
|
+
address: string;
|
|
31
|
+
state: string;
|
|
32
|
+
phoneNumber: string;
|
|
33
|
+
lastLogin: Date;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const Example = () => {
|
|
37
|
+
//manage our own state for stuff we want to pass to the API
|
|
38
|
+
const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>(
|
|
39
|
+
[],
|
|
40
|
+
);
|
|
41
|
+
const [globalFilter, setGlobalFilter] = useState('');
|
|
42
|
+
const [sorting, setSorting] = useState<MRT_SortingState>([]);
|
|
43
|
+
const [pagination, setPagination] = useState<MRT_PaginationState>({
|
|
44
|
+
pageIndex: 0,
|
|
45
|
+
pageSize: 10,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
//consider storing this code in a custom hook (i.e useFetchUsers)
|
|
49
|
+
const {
|
|
50
|
+
data: { data = [], meta } = {}, //your data and api response will probably be different
|
|
51
|
+
isError,
|
|
52
|
+
isRefetching,
|
|
53
|
+
isLoading,
|
|
54
|
+
refetch,
|
|
55
|
+
} = useQuery<UserApiResponse>({
|
|
56
|
+
queryKey: [
|
|
57
|
+
'users-list',
|
|
58
|
+
{
|
|
59
|
+
columnFilters, //refetch when columnFilters changes
|
|
60
|
+
globalFilter, //refetch when globalFilter changes
|
|
61
|
+
pagination, //refetch when pagination changes
|
|
62
|
+
sorting, //refetch when sorting changes
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
queryFn: async () => {
|
|
66
|
+
const fetchURL = new URL('/api/data', location.origin);
|
|
67
|
+
|
|
68
|
+
//read our state and pass it to the API as query params
|
|
69
|
+
fetchURL.searchParams.set(
|
|
70
|
+
'start',
|
|
71
|
+
`${pagination.pageIndex * pagination.pageSize}`,
|
|
72
|
+
);
|
|
73
|
+
fetchURL.searchParams.set('size', `${pagination.pageSize}`);
|
|
74
|
+
fetchURL.searchParams.set('filters', JSON.stringify(columnFilters ?? []));
|
|
75
|
+
fetchURL.searchParams.set('globalFilter', globalFilter ?? '');
|
|
76
|
+
fetchURL.searchParams.set('sorting', JSON.stringify(sorting ?? []));
|
|
77
|
+
|
|
78
|
+
//use whatever fetch library you want, fetch, axios, etc
|
|
79
|
+
const response = await fetch(fetchURL.href);
|
|
80
|
+
const json = (await response.json()) as UserApiResponse;
|
|
81
|
+
return json;
|
|
82
|
+
},
|
|
83
|
+
placeholderData: keepPreviousData, //don't go to 0 rows when refetching or paginating to next page
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const columns = useMemo<MRT_ColumnDef<User>[]>(
|
|
87
|
+
//column definitions...
|
|
88
|
+
() => [
|
|
89
|
+
{
|
|
90
|
+
accessorKey: 'firstName',
|
|
91
|
+
header: 'First Name',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
accessorKey: 'lastName',
|
|
95
|
+
header: 'Last Name',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
accessorKey: 'address',
|
|
99
|
+
header: 'Address',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
accessorKey: 'state',
|
|
103
|
+
header: 'State',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
accessorKey: 'phoneNumber',
|
|
107
|
+
header: 'Phone Number',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
accessorFn: (row) => new Date(row.lastLogin),
|
|
111
|
+
id: 'lastLogin',
|
|
112
|
+
header: 'Last Login',
|
|
113
|
+
Cell: ({ cell }) => new Date(cell.getValue<Date>()).toLocaleString(),
|
|
114
|
+
filterFn: 'greaterThan',
|
|
115
|
+
filterVariant: 'date',
|
|
116
|
+
enableGlobalFilter: false,
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
[],
|
|
120
|
+
//end
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const table = useMaterialReactTable({
|
|
124
|
+
columns,
|
|
125
|
+
data,
|
|
126
|
+
initialState: { showColumnFilters: true },
|
|
127
|
+
manualFiltering: true, //turn off built-in client-side filtering
|
|
128
|
+
manualPagination: true, //turn off built-in client-side pagination
|
|
129
|
+
manualSorting: true, //turn off built-in client-side sorting
|
|
130
|
+
muiToolbarAlertBannerProps: isError
|
|
131
|
+
? {
|
|
132
|
+
color: 'error',
|
|
133
|
+
children: 'Error loading data',
|
|
134
|
+
}
|
|
135
|
+
: undefined,
|
|
136
|
+
onColumnFiltersChange: setColumnFilters,
|
|
137
|
+
onGlobalFilterChange: setGlobalFilter,
|
|
138
|
+
onPaginationChange: setPagination,
|
|
139
|
+
onSortingChange: setSorting,
|
|
140
|
+
renderTopToolbarCustomActions: () => (
|
|
141
|
+
<Tooltip arrow title="Refresh Data">
|
|
142
|
+
<IconButton onClick={() => refetch()}>
|
|
143
|
+
<RefreshIcon />
|
|
144
|
+
</IconButton>
|
|
145
|
+
</Tooltip>
|
|
146
|
+
),
|
|
147
|
+
rowCount: meta?.totalRowCount ?? 0,
|
|
148
|
+
state: {
|
|
149
|
+
columnFilters,
|
|
150
|
+
globalFilter,
|
|
151
|
+
isLoading,
|
|
152
|
+
pagination,
|
|
153
|
+
showAlertBanner: isError,
|
|
154
|
+
showProgressBars: isRefetching,
|
|
155
|
+
sorting,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return <MaterialReactTable table={table} />;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
//react query setup in App.tsx
|
|
163
|
+
const ReactQueryDevtoolsProduction = lazy(() =>
|
|
164
|
+
import('@tanstack/react-query-devtools/build/modern/production.js').then(
|
|
165
|
+
(d) => ({
|
|
166
|
+
default: d.ReactQueryDevtools,
|
|
167
|
+
}),
|
|
168
|
+
),
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const queryClient = new QueryClient();
|
|
172
|
+
|
|
173
|
+
export default function App() {
|
|
174
|
+
return (
|
|
175
|
+
<QueryClientProvider client={queryClient}>
|
|
176
|
+
<Example />
|
|
177
|
+
<Suspense fallback={null}>
|
|
178
|
+
<ReactQueryDevtoolsProduction />
|
|
179
|
+
</Suspense>
|
|
180
|
+
</QueryClientProvider>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
MaterialReactTable,
|
|
4
|
+
useMaterialReactTable,
|
|
5
|
+
type MRT_ColumnDef,
|
|
6
|
+
type MRT_ColumnFiltersState,
|
|
7
|
+
type MRT_PaginationState,
|
|
8
|
+
type MRT_SortingState,
|
|
9
|
+
} from 'material-react-table';
|
|
10
|
+
|
|
11
|
+
type UserApiResponse = {
|
|
12
|
+
data: Array<User>;
|
|
13
|
+
meta: {
|
|
14
|
+
totalRowCount: number;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type User = {
|
|
19
|
+
firstName: string;
|
|
20
|
+
lastName: string;
|
|
21
|
+
address: string;
|
|
22
|
+
state: string;
|
|
23
|
+
phoneNumber: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const Example = () => {
|
|
27
|
+
//data and fetching state
|
|
28
|
+
const [data, setData] = useState<User[]>([]);
|
|
29
|
+
const [isError, setIsError] = useState(false);
|
|
30
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
31
|
+
const [isRefetching, setIsRefetching] = useState(false);
|
|
32
|
+
const [rowCount, setRowCount] = useState(0);
|
|
33
|
+
|
|
34
|
+
//table state
|
|
35
|
+
const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>(
|
|
36
|
+
[],
|
|
37
|
+
);
|
|
38
|
+
const [globalFilter, setGlobalFilter] = useState('');
|
|
39
|
+
const [sorting, setSorting] = useState<MRT_SortingState>([]);
|
|
40
|
+
const [pagination, setPagination] = useState<MRT_PaginationState>({
|
|
41
|
+
pageIndex: 0,
|
|
42
|
+
pageSize: 10,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
//if you want to avoid useEffect, look at the React Query example instead
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const fetchData = async () => {
|
|
48
|
+
if (!data.length) {
|
|
49
|
+
setIsLoading(true);
|
|
50
|
+
} else {
|
|
51
|
+
setIsRefetching(true);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const url = new URL('/api/data', location.origin);
|
|
55
|
+
url.searchParams.set(
|
|
56
|
+
'start',
|
|
57
|
+
`${pagination.pageIndex * pagination.pageSize}`,
|
|
58
|
+
);
|
|
59
|
+
url.searchParams.set('size', `${pagination.pageSize}`);
|
|
60
|
+
url.searchParams.set('filters', JSON.stringify(columnFilters ?? []));
|
|
61
|
+
url.searchParams.set('globalFilter', globalFilter ?? '');
|
|
62
|
+
url.searchParams.set('sorting', JSON.stringify(sorting ?? []));
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const response = await fetch(url.href);
|
|
66
|
+
const json = (await response.json()) as UserApiResponse;
|
|
67
|
+
setData(json.data);
|
|
68
|
+
setRowCount(json.meta.totalRowCount);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
setIsError(true);
|
|
71
|
+
console.error(error);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
setIsError(false);
|
|
75
|
+
setIsLoading(false);
|
|
76
|
+
setIsRefetching(false);
|
|
77
|
+
};
|
|
78
|
+
fetchData();
|
|
79
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
80
|
+
}, [
|
|
81
|
+
columnFilters, //re-fetch when column filters change
|
|
82
|
+
globalFilter, //re-fetch when global filter changes
|
|
83
|
+
pagination.pageIndex, //re-fetch when page index changes
|
|
84
|
+
pagination.pageSize, //re-fetch when page size changes
|
|
85
|
+
sorting, //re-fetch when sorting changes
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
const columns = useMemo<MRT_ColumnDef<User>[]>(
|
|
89
|
+
() => [
|
|
90
|
+
{
|
|
91
|
+
accessorKey: 'firstName',
|
|
92
|
+
header: 'First Name',
|
|
93
|
+
},
|
|
94
|
+
//column definitions...
|
|
95
|
+
{
|
|
96
|
+
accessorKey: 'lastName',
|
|
97
|
+
header: 'Last Name',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
accessorKey: 'address',
|
|
101
|
+
header: 'Address',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
accessorKey: 'state',
|
|
105
|
+
header: 'State',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
accessorKey: 'phoneNumber',
|
|
109
|
+
header: 'Phone Number',
|
|
110
|
+
},
|
|
111
|
+
//end
|
|
112
|
+
],
|
|
113
|
+
[],
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const table = useMaterialReactTable({
|
|
117
|
+
columns,
|
|
118
|
+
data,
|
|
119
|
+
enableRowSelection: true,
|
|
120
|
+
getRowId: (row) => row.phoneNumber,
|
|
121
|
+
initialState: { showColumnFilters: true },
|
|
122
|
+
manualFiltering: true,
|
|
123
|
+
manualPagination: true,
|
|
124
|
+
manualSorting: true,
|
|
125
|
+
muiToolbarAlertBannerProps: isError
|
|
126
|
+
? {
|
|
127
|
+
color: 'error',
|
|
128
|
+
children: 'Error loading data',
|
|
129
|
+
}
|
|
130
|
+
: undefined,
|
|
131
|
+
onColumnFiltersChange: setColumnFilters,
|
|
132
|
+
onGlobalFilterChange: setGlobalFilter,
|
|
133
|
+
onPaginationChange: setPagination,
|
|
134
|
+
onSortingChange: setSorting,
|
|
135
|
+
rowCount,
|
|
136
|
+
state: {
|
|
137
|
+
columnFilters,
|
|
138
|
+
globalFilter,
|
|
139
|
+
isLoading,
|
|
140
|
+
pagination,
|
|
141
|
+
showAlertBanner: isError,
|
|
142
|
+
showProgressBars: isRefetching,
|
|
143
|
+
sorting,
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
return <MaterialReactTable table={table} />;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export default Example;
|