norma-library 0.4.8 → 0.4.9
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/dist/esm/components/DataGrid/base/dropdown.d.ts +4 -0
- package/dist/esm/components/DataGrid/base/dropdown.js +126 -0
- package/dist/esm/components/DataGrid/base/dropdown.js.map +1 -0
- package/dist/esm/components/DataGrid/base/number-filter.d.ts +4 -0
- package/dist/esm/components/DataGrid/base/number-filter.js +30 -0
- package/dist/esm/components/DataGrid/base/number-filter.js.map +1 -0
- package/dist/esm/components/DataGrid/base/sorting.d.ts +5 -0
- package/dist/esm/components/DataGrid/base/sorting.js +15 -0
- package/dist/esm/components/DataGrid/base/sorting.js.map +1 -0
- package/dist/esm/components/DataGrid/icons.d.ts +4 -0
- package/dist/esm/components/DataGrid/icons.js +15 -0
- package/dist/esm/components/DataGrid/icons.js.map +1 -0
- package/dist/esm/components/DataGrid/index.d.ts +5 -0
- package/dist/esm/components/DataGrid/index.js +146 -0
- package/dist/esm/components/DataGrid/index.js.map +1 -0
- package/dist/esm/components/DataGrid/shared.d.ts +20 -0
- package/dist/esm/components/DataGrid/shared.js +141 -0
- package/dist/esm/components/DataGrid/shared.js.map +1 -0
- package/dist/esm/components/DataGrid/styled.d.ts +10 -0
- package/dist/esm/components/DataGrid/styled.js +73 -0
- package/dist/esm/components/DataGrid/styled.js.map +1 -0
- package/dist/esm/components/index.d.ts +2 -1
- package/dist/esm/components/index.js +2 -1
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/interfaces/DataGrid.d.ts +40 -0
- package/dist/esm/interfaces/DataGrid.js +2 -0
- package/dist/esm/interfaces/DataGrid.js.map +1 -0
- package/dist/esm/interfaces/index.d.ts +2 -1
- package/dist/esm/interfaces/index.js +2 -1
- package/dist/esm/interfaces/index.js.map +1 -1
- package/dist/esm/types/index.d.ts +2 -1
- package/dist/esm/types/index.js.map +1 -1
- package/norma-library.tar +0 -0
- package/package.json +2 -2
- package/src/components/DataGrid/allData.json +2918 -0
- package/src/components/DataGrid/base/dropdown.tsx +235 -0
- package/src/components/DataGrid/base/number-filter.tsx +43 -0
- package/src/components/DataGrid/base/sorting.tsx +35 -0
- package/src/components/DataGrid/icons.tsx +61 -0
- package/src/components/DataGrid/index.tsx +319 -0
- package/src/components/DataGrid/shared.ts +179 -0
- package/src/components/DataGrid/styled.ts +102 -0
- package/src/components/DataGrid/styles/dropdown.module.css +86 -0
- package/src/components/DataGrid/styles/number-filter.module.css +16 -0
- package/src/components/DataGrid/styles/styles.module.css +107 -0
- package/src/components/index.ts +2 -1
- package/src/interfaces/DataGrid.ts +51 -0
- package/src/interfaces/index.ts +2 -1
- package/src/sample-data.json +178 -0
- package/src/stories/DataGrid.stories.tsx +28 -0
- package/src/types/index.ts +3 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import React, { useState, useEffect, Fragment } from "react";
|
|
2
|
+
import NumberFilter from "./number-filter";
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
Typography,
|
|
6
|
+
FormControl,
|
|
7
|
+
InputLabel,
|
|
8
|
+
OutlinedInput,
|
|
9
|
+
InputAdornment,
|
|
10
|
+
IconButton,
|
|
11
|
+
} from "@mui/material";
|
|
12
|
+
import Divider from "@mui/material/Divider";
|
|
13
|
+
import MenuList from "@mui/material/MenuList";
|
|
14
|
+
import MenuItem from "@mui/material/MenuItem";
|
|
15
|
+
import ListItemIcon from "@mui/material/ListItemIcon";
|
|
16
|
+
import ListItemText from "@mui/material/ListItemText";
|
|
17
|
+
|
|
18
|
+
import List from "@mui/material/List";
|
|
19
|
+
import ListItem from "@mui/material/ListItem";
|
|
20
|
+
import ListItemButton from "@mui/material/ListItemButton";
|
|
21
|
+
import Checkbox from "@mui/material/Checkbox";
|
|
22
|
+
|
|
23
|
+
import { Search } from "@mui/icons-material";
|
|
24
|
+
import { DropdownFilterProps } from "@/interfaces";
|
|
25
|
+
import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
|
|
26
|
+
|
|
27
|
+
import { DropDownStyled } from "../styled";
|
|
28
|
+
|
|
29
|
+
import { ArrowSmallDownIcon, ArrowSmallUpIcon, FunnelIcon } from "../icons";
|
|
30
|
+
|
|
31
|
+
const DropdownFilter = ({
|
|
32
|
+
onOrder,
|
|
33
|
+
onFilter,
|
|
34
|
+
onSelected,
|
|
35
|
+
onFilterSelected,
|
|
36
|
+
itemsSelected,
|
|
37
|
+
onSelectAll,
|
|
38
|
+
onChecketAll,
|
|
39
|
+
data,
|
|
40
|
+
}: DropdownFilterProps) => {
|
|
41
|
+
const [openFilter, setOpenFilter] = useState<boolean>(false);
|
|
42
|
+
const [selectAll, setSelectAll] = useState(onSelectAll);
|
|
43
|
+
const [selecteds, setItemsSelected] =
|
|
44
|
+
useState<(string | number)[]>(itemsSelected);
|
|
45
|
+
|
|
46
|
+
const handleFilter = () => {
|
|
47
|
+
setOpenFilter((prevState) => !prevState);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const handleFilterSelected = () => {
|
|
51
|
+
if (itemsSelected.length > 0) {
|
|
52
|
+
onFilterSelected();
|
|
53
|
+
} else {
|
|
54
|
+
onSelected([]);
|
|
55
|
+
onFilter("");
|
|
56
|
+
onFilterSelected();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const handleCheckboxChange = (option: string) => {
|
|
61
|
+
const updatedSelection = selecteds.includes(option)
|
|
62
|
+
? selecteds.filter((selected) => selected !== option)
|
|
63
|
+
: [...selecteds, option];
|
|
64
|
+
|
|
65
|
+
setItemsSelected(updatedSelection);
|
|
66
|
+
onSelected(updatedSelection);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const handleSelectAll = () => {
|
|
70
|
+
setSelectAll(selectAll ? false : true);
|
|
71
|
+
onChecketAll(selectAll ? false : true);
|
|
72
|
+
|
|
73
|
+
if (!selectAll) {
|
|
74
|
+
const allItems = data.map((item: any) => item.toString());
|
|
75
|
+
setItemsSelected(allItems);
|
|
76
|
+
onSelected(allItems);
|
|
77
|
+
} else {
|
|
78
|
+
setItemsSelected([]);
|
|
79
|
+
onSelected([]);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
setItemsSelected(selectAll ? data.map(String) : []);
|
|
85
|
+
onSelected(selectAll ? data.map(String) : []);
|
|
86
|
+
}, [selectAll]);
|
|
87
|
+
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
setItemsSelected(itemsSelected);
|
|
90
|
+
}, [selecteds]);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<DropDownStyled>
|
|
94
|
+
<Fragment>
|
|
95
|
+
<MenuList>
|
|
96
|
+
<MenuItem
|
|
97
|
+
onClick={() => {
|
|
98
|
+
onOrder("down");
|
|
99
|
+
setOpenFilter(false);
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
<ListItemIcon>
|
|
103
|
+
<ArrowSmallUpIcon width="16" height="16" />
|
|
104
|
+
</ListItemIcon>
|
|
105
|
+
<ListItemText>Classificar de A a Z</ListItemText>
|
|
106
|
+
</MenuItem>
|
|
107
|
+
<MenuItem
|
|
108
|
+
onClick={() => {
|
|
109
|
+
onOrder("up");
|
|
110
|
+
setOpenFilter(false);
|
|
111
|
+
}}
|
|
112
|
+
>
|
|
113
|
+
<ListItemIcon>
|
|
114
|
+
<ArrowSmallDownIcon width="16" height="16" />
|
|
115
|
+
</ListItemIcon>
|
|
116
|
+
<ListItemText>Classificar de Z a A</ListItemText>
|
|
117
|
+
</MenuItem>
|
|
118
|
+
<MenuItem onClick={handleFilter}>
|
|
119
|
+
<ListItemIcon>
|
|
120
|
+
<FunnelIcon width="16" height="16" />
|
|
121
|
+
</ListItemIcon>
|
|
122
|
+
<ListItemText>Filtro por números</ListItemText>
|
|
123
|
+
<Typography variant="body2" color="text.secondary">
|
|
124
|
+
<KeyboardArrowRightIcon
|
|
125
|
+
fontSize="medium"
|
|
126
|
+
style={{ position: "relative", top: "5px" }}
|
|
127
|
+
/>
|
|
128
|
+
</Typography>
|
|
129
|
+
{openFilter && (
|
|
130
|
+
<React.Fragment>
|
|
131
|
+
<NumberFilter onClick={() => console.log("Me clicou")} />
|
|
132
|
+
</React.Fragment>
|
|
133
|
+
)}
|
|
134
|
+
</MenuItem>
|
|
135
|
+
<Divider />
|
|
136
|
+
<FormControl sx={{ m: 1 }} variant="outlined">
|
|
137
|
+
<InputLabel htmlFor="outlined-adornment-search" size="small">
|
|
138
|
+
Buscar
|
|
139
|
+
</InputLabel>
|
|
140
|
+
<OutlinedInput
|
|
141
|
+
id="outlined-adornment-search"
|
|
142
|
+
endAdornment={
|
|
143
|
+
<InputAdornment position="end">
|
|
144
|
+
<IconButton edge="end">
|
|
145
|
+
<Search />
|
|
146
|
+
</IconButton>
|
|
147
|
+
</InputAdornment>
|
|
148
|
+
}
|
|
149
|
+
onChange={(event) => {
|
|
150
|
+
onFilter(event.target.value);
|
|
151
|
+
}}
|
|
152
|
+
label="Buscar"
|
|
153
|
+
fullWidth
|
|
154
|
+
size="small"
|
|
155
|
+
/>
|
|
156
|
+
</FormControl>
|
|
157
|
+
<Divider />
|
|
158
|
+
<List
|
|
159
|
+
sx={{
|
|
160
|
+
bgcolor: "#f2f2f2",
|
|
161
|
+
padding: " 5px",
|
|
162
|
+
overflow: " auto",
|
|
163
|
+
width: " 100%",
|
|
164
|
+
height: " 120px",
|
|
165
|
+
}}
|
|
166
|
+
>
|
|
167
|
+
<ListItem disablePadding onClick={handleSelectAll}>
|
|
168
|
+
<ListItemButton role={undefined} sx={{ py: 0, minHeight: 32 }}>
|
|
169
|
+
<ListItemIcon>
|
|
170
|
+
<Checkbox
|
|
171
|
+
edge="start"
|
|
172
|
+
tabIndex={-1}
|
|
173
|
+
checked={selectAll}
|
|
174
|
+
disableRipple
|
|
175
|
+
inputProps={{ "aria-labelledby": "all" }}
|
|
176
|
+
/>
|
|
177
|
+
</ListItemIcon>
|
|
178
|
+
<ListItemText
|
|
179
|
+
id={"all"}
|
|
180
|
+
primary={selectAll ? "Deselect All" : "Select All"}
|
|
181
|
+
primaryTypographyProps={{
|
|
182
|
+
fontSize: 14,
|
|
183
|
+
fontWeight: "medium",
|
|
184
|
+
}}
|
|
185
|
+
/>
|
|
186
|
+
</ListItemButton>
|
|
187
|
+
</ListItem>
|
|
188
|
+
{data.map((item: any, key: number) => {
|
|
189
|
+
const labelId = `checkbox-list-label-${item.toString()}`;
|
|
190
|
+
return (
|
|
191
|
+
<ListItem
|
|
192
|
+
key={key}
|
|
193
|
+
disablePadding
|
|
194
|
+
onClick={() => handleCheckboxChange(item.toString())}
|
|
195
|
+
>
|
|
196
|
+
<ListItemButton
|
|
197
|
+
role={undefined}
|
|
198
|
+
sx={{ py: 0, minHeight: 32 }}
|
|
199
|
+
>
|
|
200
|
+
<ListItemIcon>
|
|
201
|
+
<Checkbox
|
|
202
|
+
edge="start"
|
|
203
|
+
tabIndex={-1}
|
|
204
|
+
disableRipple
|
|
205
|
+
inputProps={{ "aria-labelledby": labelId }}
|
|
206
|
+
checked={selecteds.includes(item.toString())}
|
|
207
|
+
/>
|
|
208
|
+
</ListItemIcon>
|
|
209
|
+
<ListItemText
|
|
210
|
+
id={labelId}
|
|
211
|
+
primary={`${item}`}
|
|
212
|
+
primaryTypographyProps={{
|
|
213
|
+
fontSize: 14,
|
|
214
|
+
fontWeight: "medium",
|
|
215
|
+
}}
|
|
216
|
+
/>
|
|
217
|
+
</ListItemButton>
|
|
218
|
+
</ListItem>
|
|
219
|
+
);
|
|
220
|
+
})}
|
|
221
|
+
</List>
|
|
222
|
+
</MenuList>
|
|
223
|
+
<Button
|
|
224
|
+
variant="outlined"
|
|
225
|
+
sx={{ align: "right" }}
|
|
226
|
+
onClick={handleFilterSelected}
|
|
227
|
+
>
|
|
228
|
+
Confirm
|
|
229
|
+
</Button>
|
|
230
|
+
</Fragment>
|
|
231
|
+
</DropDownStyled>
|
|
232
|
+
);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export default DropdownFilter;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import List from "@mui/material/List";
|
|
4
|
+
import ListItem from "@mui/material/ListItem";
|
|
5
|
+
import ListItemText from "@mui/material/ListItemText";
|
|
6
|
+
import { NumberFilterProps } from "@/interfaces";
|
|
7
|
+
|
|
8
|
+
const items = [
|
|
9
|
+
"Equal",
|
|
10
|
+
"Does not equal",
|
|
11
|
+
"Greater than",
|
|
12
|
+
"Greater than or equal to",
|
|
13
|
+
"Less than",
|
|
14
|
+
"Less than or equal to",
|
|
15
|
+
"Between",
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const NumberFilter: React.FC<NumberFilterProps> = () => {
|
|
19
|
+
return (
|
|
20
|
+
<List
|
|
21
|
+
sx={{
|
|
22
|
+
bgcolor: "#FFF",
|
|
23
|
+
position: "absolute",
|
|
24
|
+
minHeight: "190px",
|
|
25
|
+
top: "0",
|
|
26
|
+
left: "auto",
|
|
27
|
+
right: "auto",
|
|
28
|
+
minWidth: "240px",
|
|
29
|
+
zIndex: "9",
|
|
30
|
+
padding: "5px 10px",
|
|
31
|
+
boxShadow: "0 0 10px #ccc",
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
{items.map((value, key) => (
|
|
35
|
+
<ListItem key={key} disableGutters>
|
|
36
|
+
<ListItemText primary={`${value}...`} />
|
|
37
|
+
</ListItem>
|
|
38
|
+
))}
|
|
39
|
+
</List>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default NumberFilter;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { SortingProps } from "@/interfaces";
|
|
4
|
+
// import { Icons } from "@/components/Icons";
|
|
5
|
+
|
|
6
|
+
export function ArrowSmallUpIcon(props: any) {
|
|
7
|
+
return (
|
|
8
|
+
<svg
|
|
9
|
+
fill="currentColor"
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
12
|
+
aria-hidden="true"
|
|
13
|
+
{...props}
|
|
14
|
+
>
|
|
15
|
+
<path
|
|
16
|
+
clipRule="evenodd"
|
|
17
|
+
fillRule="evenodd"
|
|
18
|
+
d="M12 20.25a.75.75 0 01-.75-.75V6.31l-5.47 5.47a.75.75 0 01-1.06-1.06l6.75-6.75a.75.75 0 011.06 0l6.75 6.75a.75.75 0 11-1.06 1.06l-5.47-5.47V19.5a.75.75 0 01-.75.75z"
|
|
19
|
+
/>
|
|
20
|
+
</svg>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const Sorting: React.FC<SortingProps> = ({ sort, active }) => {
|
|
25
|
+
const sortIcon = <ArrowSmallUpIcon />;
|
|
26
|
+
const opacityValue = active ? 1 : 0.5;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<button type="button" style={{ opacity: opacityValue }} className="arrows">
|
|
30
|
+
{sort && sortIcon}
|
|
31
|
+
</button>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default Sorting;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
export function FunnelIcon(props: any) {
|
|
4
|
+
return (
|
|
5
|
+
<svg
|
|
6
|
+
fill="none"
|
|
7
|
+
stroke="currentColor"
|
|
8
|
+
strokeWidth={1.5}
|
|
9
|
+
viewBox="0 0 24 24"
|
|
10
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
+
aria-hidden="true"
|
|
12
|
+
{...props}
|
|
13
|
+
>
|
|
14
|
+
<path
|
|
15
|
+
strokeLinecap="round"
|
|
16
|
+
strokeLinejoin="round"
|
|
17
|
+
d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 01-.659 1.591l-5.432 5.432a2.25 2.25 0 00-.659 1.591v2.927a2.25 2.25 0 01-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 00-.659-1.591L3.659 7.409A2.25 2.25 0 013 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0112 3z"
|
|
18
|
+
/>
|
|
19
|
+
</svg>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function ArrowSmallUpIcon(props: any) {
|
|
24
|
+
return (
|
|
25
|
+
<svg
|
|
26
|
+
fill="none"
|
|
27
|
+
stroke="currentColor"
|
|
28
|
+
strokeWidth={1.5}
|
|
29
|
+
viewBox="0 0 24 24"
|
|
30
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
+
aria-hidden="true"
|
|
32
|
+
{...props}
|
|
33
|
+
>
|
|
34
|
+
<path
|
|
35
|
+
strokeLinecap="round"
|
|
36
|
+
strokeLinejoin="round"
|
|
37
|
+
d="M12 19.5v-15m0 0l-6.75 6.75M12 4.5l6.75 6.75"
|
|
38
|
+
/>
|
|
39
|
+
</svg>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function ArrowSmallDownIcon(props: any) {
|
|
44
|
+
return (
|
|
45
|
+
<svg
|
|
46
|
+
fill="none"
|
|
47
|
+
stroke="currentColor"
|
|
48
|
+
strokeWidth={1.5}
|
|
49
|
+
viewBox="0 0 24 24"
|
|
50
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
51
|
+
aria-hidden="true"
|
|
52
|
+
{...props}
|
|
53
|
+
>
|
|
54
|
+
<path
|
|
55
|
+
strokeLinecap="round"
|
|
56
|
+
strokeLinejoin="round"
|
|
57
|
+
d="M12 4.5v15m0 0l6.75-6.75M12 19.5l-6.75-6.75"
|
|
58
|
+
/>
|
|
59
|
+
</svg>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useState, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
import { Box, Stack, ThemeProvider, useMediaQuery, Paper } from "@mui/material";
|
|
4
|
+
|
|
5
|
+
import Table from "@mui/material/Table";
|
|
6
|
+
import TableBody from "@mui/material/TableBody";
|
|
7
|
+
import TableCell from "@mui/material/TableCell";
|
|
8
|
+
import TableContainer from "@mui/material/TableContainer";
|
|
9
|
+
import TableHead from "@mui/material/TableHead";
|
|
10
|
+
import TableRow from "@mui/material/TableRow";
|
|
11
|
+
|
|
12
|
+
import ArrowDropUpIcon from "@mui/icons-material/ArrowDropUp";
|
|
13
|
+
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
|
|
14
|
+
|
|
15
|
+
import { DataGridBaseProps, DataSourceItem } from "../../interfaces";
|
|
16
|
+
|
|
17
|
+
import { themes } from "../../helpers";
|
|
18
|
+
|
|
19
|
+
import DropdownFilter from "./base/dropdown";
|
|
20
|
+
import { Pagination as MuiPagination } from "@mui/material";
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
filterDataSource,
|
|
24
|
+
generateRandomDataSource,
|
|
25
|
+
groupByDataSource,
|
|
26
|
+
sortDataSourceByColumn,
|
|
27
|
+
} from "./shared";
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
ButtonStyled,
|
|
31
|
+
DataGridHeaderStyled,
|
|
32
|
+
HeaderCogStyled,
|
|
33
|
+
TableCellStyled,
|
|
34
|
+
TableRowStyled,
|
|
35
|
+
TotalRecordsStyled,
|
|
36
|
+
} from "./styled";
|
|
37
|
+
|
|
38
|
+
export function ArrowSmallUpIcon(props: any) {
|
|
39
|
+
return (
|
|
40
|
+
<svg
|
|
41
|
+
fill="currentColor"
|
|
42
|
+
viewBox="0 0 24 24"
|
|
43
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
44
|
+
aria-hidden="true"
|
|
45
|
+
{...props}
|
|
46
|
+
>
|
|
47
|
+
<path
|
|
48
|
+
clipRule="evenodd"
|
|
49
|
+
fillRule="evenodd"
|
|
50
|
+
d="M12 20.25a.75.75 0 01-.75-.75V6.31l-5.47 5.47a.75.75 0 01-1.06-1.06l6.75-6.75a.75.75 0 011.06 0l6.75 6.75a.75.75 0 11-1.06 1.06l-5.47-5.47V19.5a.75.75 0 01-.75.75z"
|
|
51
|
+
/>
|
|
52
|
+
</svg>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function Cog6ToothIcon(props: any) {
|
|
57
|
+
return (
|
|
58
|
+
<svg
|
|
59
|
+
fill="none"
|
|
60
|
+
stroke="currentColor"
|
|
61
|
+
strokeWidth={1.5}
|
|
62
|
+
viewBox="0 0 24 24"
|
|
63
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
64
|
+
aria-hidden="true"
|
|
65
|
+
{...props}
|
|
66
|
+
>
|
|
67
|
+
<path
|
|
68
|
+
strokeLinecap="round"
|
|
69
|
+
strokeLinejoin="round"
|
|
70
|
+
d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z"
|
|
71
|
+
/>
|
|
72
|
+
<path
|
|
73
|
+
strokeLinecap="round"
|
|
74
|
+
strokeLinejoin="round"
|
|
75
|
+
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
76
|
+
/>
|
|
77
|
+
</svg>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const dataSource = generateRandomDataSource(30);
|
|
82
|
+
|
|
83
|
+
export const DataGrid: React.FC<DataGridBaseProps> = ({ data = [] }) => {
|
|
84
|
+
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
|
|
85
|
+
const theme = useMemo(
|
|
86
|
+
() => (prefersDarkMode ? themes.light : themes.light),
|
|
87
|
+
[prefersDarkMode]
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const pageSize = 10;
|
|
91
|
+
const columns = data[0].columns;
|
|
92
|
+
|
|
93
|
+
const [selectedItems, setSelectedItems] = useState<(string | number)[]>([]);
|
|
94
|
+
|
|
95
|
+
const [sorting, setSorting] = useState("down");
|
|
96
|
+
const [selectAll, setSelectAll] = useState<boolean>(false);
|
|
97
|
+
|
|
98
|
+
const [currentActiveSorting, setCurrentActiveSorting] =
|
|
99
|
+
useState<string>("id");
|
|
100
|
+
|
|
101
|
+
const [currentDropDownActive, setCurrentDropDownActive] = useState<
|
|
102
|
+
string | null
|
|
103
|
+
>(null);
|
|
104
|
+
|
|
105
|
+
const [originalDataSource, setOriginalDataSource] =
|
|
106
|
+
useState<DataSourceItem[]>(dataSource);
|
|
107
|
+
const [newDataSource, setDataSource] = useState<DataSourceItem[]>(dataSource);
|
|
108
|
+
const [totalRecords, setTotalRecords] = useState(dataSource.length);
|
|
109
|
+
const [totalPages, setTotalPages] = useState(
|
|
110
|
+
Math.ceil(dataSource.length / pageSize)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
114
|
+
const startIndex = (currentPage - 1) * pageSize;
|
|
115
|
+
const endIndex = Math.min(startIndex + pageSize, totalRecords);
|
|
116
|
+
|
|
117
|
+
const sortRefs = useRef<(React.RefObject<HTMLTableCellElement> | null)[]>(
|
|
118
|
+
new Array(columns.length).fill(null)
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const handleItemSelected = (items: (string | number)[]) => {
|
|
122
|
+
setSelectedItems(items);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const handleDropDown = (item: any) => {
|
|
126
|
+
setCurrentDropDownActive(item === currentDropDownActive ? null : item);
|
|
127
|
+
if (item !== currentDropDownActive) {
|
|
128
|
+
setCurrentActiveSorting(item);
|
|
129
|
+
setSorting("down");
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const handleSorting = (sort: string) => {
|
|
134
|
+
setSorting(sort === "up" ? "up" : "down");
|
|
135
|
+
currentDropDownActive && setCurrentActiveSorting(currentDropDownActive);
|
|
136
|
+
handleDropDown(currentDropDownActive);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const handleFilter = (filter: string) => {
|
|
140
|
+
const dataSourceFiltered = filterDataSource(
|
|
141
|
+
originalDataSource,
|
|
142
|
+
currentActiveSorting,
|
|
143
|
+
filter
|
|
144
|
+
);
|
|
145
|
+
setOriginalDataSource(dataSourceFiltered);
|
|
146
|
+
setCurrentPage(1);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const handleFilterSelected = () => {
|
|
150
|
+
if (selectedItems.length > 0) {
|
|
151
|
+
const filteredData = originalDataSource.filter((item: DataSourceItem) => {
|
|
152
|
+
const columnValue = currentActiveSorting
|
|
153
|
+
? item[currentActiveSorting]
|
|
154
|
+
: undefined;
|
|
155
|
+
|
|
156
|
+
if (typeof columnValue === "string") {
|
|
157
|
+
return selectedItems.includes(columnValue);
|
|
158
|
+
} else if (typeof columnValue === "number") {
|
|
159
|
+
return selectedItems.includes(columnValue.toString());
|
|
160
|
+
}
|
|
161
|
+
return false;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const sortedData = sortDataSourceByColumn(
|
|
165
|
+
filteredData,
|
|
166
|
+
currentActiveSorting,
|
|
167
|
+
sorting
|
|
168
|
+
);
|
|
169
|
+
setTotalRecords(sortedData.length);
|
|
170
|
+
setTotalPages(Math.ceil(sortedData.length / pageSize));
|
|
171
|
+
setCurrentPage(1);
|
|
172
|
+
setDataSource(sortedData.slice(startIndex, endIndex));
|
|
173
|
+
} else {
|
|
174
|
+
const sortedData = sortDataSourceByColumn(
|
|
175
|
+
dataSource,
|
|
176
|
+
currentActiveSorting,
|
|
177
|
+
sorting
|
|
178
|
+
);
|
|
179
|
+
setTotalRecords(sortedData.length);
|
|
180
|
+
setTotalPages(Math.ceil(sortedData.length / pageSize));
|
|
181
|
+
setCurrentPage(1);
|
|
182
|
+
setDataSource(sortedData.slice(startIndex, endIndex));
|
|
183
|
+
}
|
|
184
|
+
handleDropDown(currentDropDownActive);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const handleChangePage = (page: number) => {
|
|
188
|
+
setCurrentPage(page);
|
|
189
|
+
const startIndex = (page - 1) * pageSize;
|
|
190
|
+
const endIndex = Math.min(startIndex + pageSize, totalRecords);
|
|
191
|
+
setDataSource(originalDataSource.slice(startIndex, endIndex));
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
useEffect(() => {
|
|
195
|
+
if (selectedItems.length <= 0) {
|
|
196
|
+
const sortedData = sortDataSourceByColumn(
|
|
197
|
+
dataSource,
|
|
198
|
+
currentActiveSorting,
|
|
199
|
+
sorting
|
|
200
|
+
);
|
|
201
|
+
setDataSource(sortedData.slice(startIndex, endIndex));
|
|
202
|
+
setTotalRecords(sortedData.length);
|
|
203
|
+
setTotalPages(Math.ceil(sortedData.length / pageSize));
|
|
204
|
+
setCurrentPage(1);
|
|
205
|
+
}
|
|
206
|
+
}, [selectedItems]);
|
|
207
|
+
|
|
208
|
+
return (
|
|
209
|
+
<ThemeProvider theme={theme}>
|
|
210
|
+
<Box sx={{ width: "100%", minHeight: 480 }}>
|
|
211
|
+
<DataGridHeaderStyled>
|
|
212
|
+
<TotalRecordsStyled>
|
|
213
|
+
{totalRecords} results found for this search
|
|
214
|
+
</TotalRecordsStyled>
|
|
215
|
+
<HeaderCogStyled type="button">
|
|
216
|
+
<Cog6ToothIcon width={24} height={24} />
|
|
217
|
+
</HeaderCogStyled>
|
|
218
|
+
</DataGridHeaderStyled>
|
|
219
|
+
<TableContainer component={Paper} sx={{ overflowX: "inherit" }}>
|
|
220
|
+
<Table
|
|
221
|
+
sx={{ minWidth: 650, width: "100%" }}
|
|
222
|
+
aria-label="a dense table"
|
|
223
|
+
>
|
|
224
|
+
<TableHead>
|
|
225
|
+
<TableRow>
|
|
226
|
+
{columns &&
|
|
227
|
+
columns.map((item: any, key: any) => (
|
|
228
|
+
<TableCellStyled
|
|
229
|
+
key={key}
|
|
230
|
+
ref={(ref) =>
|
|
231
|
+
(sortRefs.current[key] =
|
|
232
|
+
ref as React.RefObject<HTMLTableCellElement> | null)
|
|
233
|
+
}
|
|
234
|
+
>
|
|
235
|
+
<Stack
|
|
236
|
+
direction="row"
|
|
237
|
+
spacing={2}
|
|
238
|
+
sx={{ position: "relative" }}
|
|
239
|
+
>
|
|
240
|
+
<ButtonStyled
|
|
241
|
+
variant="text"
|
|
242
|
+
size="small"
|
|
243
|
+
color={
|
|
244
|
+
currentActiveSorting === item.field
|
|
245
|
+
? "primary"
|
|
246
|
+
: "inherit"
|
|
247
|
+
}
|
|
248
|
+
endIcon={
|
|
249
|
+
currentActiveSorting === item.field &&
|
|
250
|
+
sorting === "up" ? (
|
|
251
|
+
<ArrowDropUpIcon />
|
|
252
|
+
) : (
|
|
253
|
+
<ArrowDropDownIcon />
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
onClick={() => {
|
|
257
|
+
handleDropDown(item.field);
|
|
258
|
+
}}
|
|
259
|
+
>
|
|
260
|
+
{item.headerText}
|
|
261
|
+
</ButtonStyled>
|
|
262
|
+
{currentDropDownActive &&
|
|
263
|
+
currentDropDownActive === item.field && (
|
|
264
|
+
<DropdownFilter
|
|
265
|
+
format={item.format}
|
|
266
|
+
onOrder={handleSorting}
|
|
267
|
+
onFilter={handleFilter}
|
|
268
|
+
onSelected={handleItemSelected}
|
|
269
|
+
itemsSelected={selectedItems}
|
|
270
|
+
onFilterSelected={handleFilterSelected}
|
|
271
|
+
onChecketAll={setSelectAll}
|
|
272
|
+
onSelectAll={selectAll}
|
|
273
|
+
data={groupByDataSource(dataSource, item.field)}
|
|
274
|
+
/>
|
|
275
|
+
)}
|
|
276
|
+
</Stack>
|
|
277
|
+
</TableCellStyled>
|
|
278
|
+
))}
|
|
279
|
+
</TableRow>
|
|
280
|
+
</TableHead>
|
|
281
|
+
<TableBody>
|
|
282
|
+
{newDataSource &&
|
|
283
|
+
newDataSource.map((item: DataSourceItem, key: number) => (
|
|
284
|
+
<TableRowStyled
|
|
285
|
+
key={key}
|
|
286
|
+
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
|
287
|
+
>
|
|
288
|
+
{Object.keys(item).map((columnKey) => (
|
|
289
|
+
<TableCell component="th" scope="row" key={columnKey}>
|
|
290
|
+
{item[columnKey]}
|
|
291
|
+
</TableCell>
|
|
292
|
+
))}
|
|
293
|
+
</TableRowStyled>
|
|
294
|
+
))}
|
|
295
|
+
</TableBody>
|
|
296
|
+
</Table>
|
|
297
|
+
<Stack
|
|
298
|
+
spacing={2}
|
|
299
|
+
sx={{
|
|
300
|
+
display: "flex",
|
|
301
|
+
justifyContent: "center",
|
|
302
|
+
alignItems: "center",
|
|
303
|
+
borderTop: "1px solid #ccc",
|
|
304
|
+
padding: 2,
|
|
305
|
+
}}
|
|
306
|
+
>
|
|
307
|
+
<MuiPagination
|
|
308
|
+
variant="outlined"
|
|
309
|
+
shape="rounded"
|
|
310
|
+
count={totalPages}
|
|
311
|
+
page={currentPage}
|
|
312
|
+
onChange={(_event, page) => handleChangePage(page)}
|
|
313
|
+
/>
|
|
314
|
+
</Stack>
|
|
315
|
+
</TableContainer>
|
|
316
|
+
</Box>
|
|
317
|
+
</ThemeProvider>
|
|
318
|
+
);
|
|
319
|
+
};
|