@bsol-oss/react-datatable5 1.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/.cache/storybook/default/dev-server/a5a8bf6e622aef57065c6498611f40c911543d7d-3920d97c51b8ad2521918fb1205babd22b0ed3d7 +1 -0
- package/.cache/storybook/default/dev-server/a5a8bf6e622aef57065c6498611f40c911543d7d-43fdebe5fc35e4e9fabee9a83c7faea931b05ea0 +1 -0
- package/.cache/storybook/default/dev-server/a5a8bf6e622aef57065c6498611f40c911543d7d-f086b87885981c04ce7a583ff90a49313de83de7 +1 -0
- package/.eslintrc.cjs +19 -0
- package/.prettierignore +4 -0
- package/.storybook/main.ts +20 -0
- package/.storybook/preview.ts +14 -0
- package/README.md +42 -0
- package/package.json +59 -0
- package/prettier.json +6 -0
- package/rollup.config.js +10 -0
- package/src/assets/react.svg +1 -0
- package/src/components/ChakraDataTable.tsx +279 -0
- package/src/components/DataTable.tsx +97 -0
- package/src/components/DataTableContext.tsx +13 -0
- package/src/components/EditFilterButton.tsx +37 -0
- package/src/components/EditSortingButton.tsx +37 -0
- package/src/components/EditViewButton.tsx +46 -0
- package/src/components/PageSizeControl.tsx +29 -0
- package/src/components/ResetFilteringButton.tsx +18 -0
- package/src/components/ResetSortingButton.tsx +18 -0
- package/src/components/Table.tsx +20 -0
- package/src/components/TableBody.tsx +23 -0
- package/src/components/TableCardContainer.tsx +22 -0
- package/src/components/TableCards.tsx +36 -0
- package/src/components/TableFilter.tsx +34 -0
- package/src/components/TableFooter.tsx +27 -0
- package/src/components/TableHeader.tsx +106 -0
- package/src/components/TablePagination.tsx +57 -0
- package/src/components/TableSorter.tsx +62 -0
- package/src/components/TextCell.tsx +18 -0
- package/src/components/useDataFromUrl.tsx +52 -0
- package/src/components/useDataTable.tsx +7 -0
- package/src/index.tsx +27 -0
- package/src/stories/Button.stories.ts +52 -0
- package/src/stories/Button.tsx +52 -0
- package/src/stories/CardViewShowcase.tsx +103 -0
- package/src/stories/Configure.mdx +369 -0
- package/src/stories/DataTable-test.stories.tsx +83 -0
- package/src/stories/DataTable.stories.tsx +57 -0
- package/src/stories/DefaultDataTable.tsx +141 -0
- package/src/stories/Header.stories.ts +33 -0
- package/src/stories/Header.tsx +71 -0
- package/src/stories/Page.stories.ts +32 -0
- package/src/stories/Page.tsx +91 -0
- package/src/stories/TableViewShowcase.tsx +105 -0
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +5 -0
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +15 -0
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +3 -0
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +12 -0
- package/src/stories/assets/youtube.svg +4 -0
- package/src/stories/button.css +30 -0
- package/src/stories/header.css +32 -0
- package/src/stories/page.css +69 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +25 -0
- package/tsconfig.node.json +11 -0
- package/vite.config.ts +7 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { TableContext } from "./DataTableContext";
|
|
3
|
+
import {
|
|
4
|
+
Checkbox,
|
|
5
|
+
Flex,
|
|
6
|
+
FormControl,
|
|
7
|
+
IconButton,
|
|
8
|
+
Popover,
|
|
9
|
+
PopoverArrow,
|
|
10
|
+
PopoverBody,
|
|
11
|
+
PopoverContent,
|
|
12
|
+
PopoverTrigger,
|
|
13
|
+
} from "@chakra-ui/react";
|
|
14
|
+
import { IoMdEye } from "react-icons/io";
|
|
15
|
+
|
|
16
|
+
const EditViewButton = () => {
|
|
17
|
+
const { table } = useContext(TableContext);
|
|
18
|
+
return (
|
|
19
|
+
<Popover placement="bottom-end">
|
|
20
|
+
<PopoverTrigger>
|
|
21
|
+
<IconButton aria-label="view" icon={<IoMdEye />} />
|
|
22
|
+
</PopoverTrigger>
|
|
23
|
+
<PopoverContent width={"auto"}>
|
|
24
|
+
<PopoverArrow />
|
|
25
|
+
<PopoverBody>
|
|
26
|
+
<Flex flexFlow={"column"} gap={"1rem"}>
|
|
27
|
+
{table.getAllLeafColumns().map((column) => {
|
|
28
|
+
return (
|
|
29
|
+
<FormControl key={crypto.randomUUID()} width={"auto"}>
|
|
30
|
+
<Checkbox
|
|
31
|
+
isChecked={column.getIsVisible()}
|
|
32
|
+
onChange={column.getToggleVisibilityHandler()}
|
|
33
|
+
>
|
|
34
|
+
{column.id}
|
|
35
|
+
</Checkbox>
|
|
36
|
+
</FormControl>
|
|
37
|
+
);
|
|
38
|
+
})}
|
|
39
|
+
</Flex>
|
|
40
|
+
</PopoverBody>
|
|
41
|
+
</PopoverContent>
|
|
42
|
+
</Popover>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default EditViewButton;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { TableContext } from "./DataTableContext";
|
|
3
|
+
|
|
4
|
+
export interface PageSizeControlProps {
|
|
5
|
+
pageSizes?: number[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const PageSizeControl = ({
|
|
9
|
+
pageSizes = [10, 20, 30, 40, 50],
|
|
10
|
+
}: PageSizeControlProps) => {
|
|
11
|
+
const { table } = useContext(TableContext);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<select
|
|
15
|
+
value={table.getState().pagination.pageSize}
|
|
16
|
+
onChange={(e) => {
|
|
17
|
+
table.setPageSize(Number(e.target.value));
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
{pageSizes.map((pageSize) => (
|
|
21
|
+
<option key={pageSize} value={pageSize}>
|
|
22
|
+
{pageSize}
|
|
23
|
+
</option>
|
|
24
|
+
))}
|
|
25
|
+
</select>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default PageSizeControl;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { TableContext } from "./DataTableContext";
|
|
3
|
+
import { Button } from "@chakra-ui/react";
|
|
4
|
+
|
|
5
|
+
const ResetFilteringButton = () => {
|
|
6
|
+
const { table } = useContext(TableContext);
|
|
7
|
+
return (
|
|
8
|
+
<Button
|
|
9
|
+
onClick={() => {
|
|
10
|
+
table.resetColumnFilters();
|
|
11
|
+
}}
|
|
12
|
+
>
|
|
13
|
+
Reset Filtering
|
|
14
|
+
</Button>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default ResetFilteringButton;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { TableContext } from "./DataTableContext";
|
|
3
|
+
import { Button } from "@chakra-ui/react";
|
|
4
|
+
|
|
5
|
+
const ResetSortingButton = () => {
|
|
6
|
+
const { table } = useContext(TableContext);
|
|
7
|
+
return (
|
|
8
|
+
<Button
|
|
9
|
+
onClick={() => {
|
|
10
|
+
table.resetSorting();
|
|
11
|
+
}}
|
|
12
|
+
>
|
|
13
|
+
Reset Sorting
|
|
14
|
+
</Button>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default ResetSortingButton;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { Table as ChakraTable, Container } from "@chakra-ui/react";
|
|
3
|
+
import { useDataTable } from "./useDataTable";
|
|
4
|
+
|
|
5
|
+
interface TableProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const Table = ({ children }: TableProps) => {
|
|
10
|
+
const { table } = useDataTable();
|
|
11
|
+
return (
|
|
12
|
+
<Container maxW="100%" overflowY={"scroll"}>
|
|
13
|
+
<ChakraTable width={table.getCenterTotalSize()} variant="simple">
|
|
14
|
+
{children}
|
|
15
|
+
</ChakraTable>
|
|
16
|
+
</Container>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default Table;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Tbody, Td, Tr } from "@chakra-ui/table";
|
|
2
|
+
import { flexRender } from "@tanstack/react-table";
|
|
3
|
+
import { useContext } from "react";
|
|
4
|
+
import { TableContext } from "./DataTableContext";
|
|
5
|
+
|
|
6
|
+
const TableBody = () => {
|
|
7
|
+
const { table } = useContext(TableContext);
|
|
8
|
+
return (
|
|
9
|
+
<Tbody>
|
|
10
|
+
{table.getRowModel().rows.map((row) => (
|
|
11
|
+
<Tr key={crypto.randomUUID()}>
|
|
12
|
+
{row.getVisibleCells().map((cell) => (
|
|
13
|
+
<Td key={crypto.randomUUID()} width={`${cell.column.getSize()}px`}>
|
|
14
|
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
15
|
+
</Td>
|
|
16
|
+
))}
|
|
17
|
+
</Tr>
|
|
18
|
+
))}
|
|
19
|
+
</Tbody>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default TableBody;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Grid } from "@chakra-ui/react";
|
|
2
|
+
|
|
3
|
+
interface TableCardContainerProps {
|
|
4
|
+
children: JSX.Element;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const TableCardContainer = ({
|
|
8
|
+
children,
|
|
9
|
+
...props
|
|
10
|
+
}: TableCardContainerProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<Grid
|
|
13
|
+
gridTemplateColumns={["1fr", "1fr 1fr", "1fr 1fr 1fr"]}
|
|
14
|
+
gap={"0.5rem"}
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
{children}
|
|
18
|
+
</Grid>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default TableCardContainer;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Card, CardBody, Text, Box } from "@chakra-ui/react";
|
|
2
|
+
import { flexRender } from "@tanstack/react-table";
|
|
3
|
+
import { useContext } from "react";
|
|
4
|
+
import { TableContext } from "./DataTableContext";
|
|
5
|
+
|
|
6
|
+
const TableCards = () => {
|
|
7
|
+
const { table } = useContext(TableContext);
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<>
|
|
11
|
+
{table.getRowModel().rows.map((row) => {
|
|
12
|
+
return (
|
|
13
|
+
<Card key={crypto.randomUUID()}>
|
|
14
|
+
<CardBody display={"flex"} flexFlow={"column"} gap={"0.5rem"}>
|
|
15
|
+
{row.getVisibleCells().map((cell) => {
|
|
16
|
+
return (
|
|
17
|
+
<Box>
|
|
18
|
+
<Text>{`${cell.column.id}: `}</Text>
|
|
19
|
+
<Box>
|
|
20
|
+
{flexRender(
|
|
21
|
+
cell.column.columnDef.cell,
|
|
22
|
+
cell.getContext(),
|
|
23
|
+
)}
|
|
24
|
+
</Box>
|
|
25
|
+
</Box>
|
|
26
|
+
);
|
|
27
|
+
})}
|
|
28
|
+
</CardBody>
|
|
29
|
+
</Card>
|
|
30
|
+
);
|
|
31
|
+
})}
|
|
32
|
+
</>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default TableCards;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Input, Text, Box } from "@chakra-ui/react";
|
|
2
|
+
import { useDataTable } from "./useDataTable";
|
|
3
|
+
|
|
4
|
+
const TableFilter = () => {
|
|
5
|
+
const { table } = useDataTable();
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
{table.getLeafHeaders().map((header) => {
|
|
10
|
+
return (
|
|
11
|
+
<>
|
|
12
|
+
{header.column.getCanFilter() && (
|
|
13
|
+
<Box>
|
|
14
|
+
<Text>{header.column.id}</Text>
|
|
15
|
+
<Input
|
|
16
|
+
value={
|
|
17
|
+
header.column.getFilterValue()
|
|
18
|
+
? String(header.column.getFilterValue())
|
|
19
|
+
: ""
|
|
20
|
+
}
|
|
21
|
+
onChange={(e) => {
|
|
22
|
+
header.column.setFilterValue(e.target.value);
|
|
23
|
+
}}
|
|
24
|
+
/>
|
|
25
|
+
</Box>
|
|
26
|
+
)}
|
|
27
|
+
</>
|
|
28
|
+
);
|
|
29
|
+
})}
|
|
30
|
+
</>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default TableFilter;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Tfoot, Th, Tr } from "@chakra-ui/react";
|
|
2
|
+
import { useDataTable } from "./useDataTable";
|
|
3
|
+
import { flexRender } from "@tanstack/react-table";
|
|
4
|
+
|
|
5
|
+
export const TableFooter = () => {
|
|
6
|
+
const table = useDataTable().table;
|
|
7
|
+
return (
|
|
8
|
+
<Tfoot>
|
|
9
|
+
{table.getFooterGroups().map((footerGroup) => (
|
|
10
|
+
<Tr key={crypto.randomUUID()}>
|
|
11
|
+
{footerGroup.headers.map((header) => (
|
|
12
|
+
<Th key={crypto.randomUUID()} colSpan={header.colSpan}>
|
|
13
|
+
{header.isPlaceholder
|
|
14
|
+
? null
|
|
15
|
+
: flexRender(
|
|
16
|
+
header.column.columnDef.footer,
|
|
17
|
+
header.getContext(),
|
|
18
|
+
)}
|
|
19
|
+
</Th>
|
|
20
|
+
))}
|
|
21
|
+
</Tr>
|
|
22
|
+
))}
|
|
23
|
+
</Tfoot>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default TableFooter;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Box, Button, Flex, Th, Thead, Tr } from "@chakra-ui/react";
|
|
2
|
+
import { flexRender } from "@tanstack/react-table";
|
|
3
|
+
import { MdFilterListAlt } from "react-icons/md";
|
|
4
|
+
|
|
5
|
+
// import { Box } from "framer-motion";
|
|
6
|
+
import {
|
|
7
|
+
ChevronDownIcon,
|
|
8
|
+
ChevronUpIcon,
|
|
9
|
+
CloseIcon,
|
|
10
|
+
UpDownIcon,
|
|
11
|
+
} from "@chakra-ui/icons";
|
|
12
|
+
import { useDataTable } from "./useDataTable";
|
|
13
|
+
|
|
14
|
+
interface TableHeaderProps {
|
|
15
|
+
canResize?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const TableHeader = ({ canResize }: TableHeaderProps) => {
|
|
19
|
+
const { table } = useDataTable();
|
|
20
|
+
return (
|
|
21
|
+
<Thead>
|
|
22
|
+
{table.getHeaderGroups().map((headerGroup) => (
|
|
23
|
+
<Tr key={crypto.randomUUID()} style={{ columnSpan: "all" }}>
|
|
24
|
+
{headerGroup.headers.map((header) => {
|
|
25
|
+
const resizeProps = {
|
|
26
|
+
onClick: () => header.column.resetSize(),
|
|
27
|
+
onMouseDown: header.getResizeHandler(),
|
|
28
|
+
onTouchStart: header.getResizeHandler(),
|
|
29
|
+
cursor: "col-resize",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Th
|
|
34
|
+
padding={"0rem"}
|
|
35
|
+
key={crypto.randomUUID()}
|
|
36
|
+
colSpan={header.colSpan}
|
|
37
|
+
width={`${header.getSize()}px`}
|
|
38
|
+
>
|
|
39
|
+
<Flex alignItems={"center"} gap={"0.5rem"} padding={"0.5rem"}>
|
|
40
|
+
<Box>
|
|
41
|
+
{header.isPlaceholder
|
|
42
|
+
? null
|
|
43
|
+
: flexRender(
|
|
44
|
+
header.column.columnDef.header,
|
|
45
|
+
header.getContext(),
|
|
46
|
+
)}
|
|
47
|
+
</Box>
|
|
48
|
+
{header.column.getCanSort() && (
|
|
49
|
+
<>
|
|
50
|
+
<Button
|
|
51
|
+
onClick={(e) => {
|
|
52
|
+
header.column.toggleSorting();
|
|
53
|
+
}}
|
|
54
|
+
>
|
|
55
|
+
{header.column.getNextSortingOrder() === false && (
|
|
56
|
+
// <Text>To No sort</Text>
|
|
57
|
+
<ChevronUpIcon />
|
|
58
|
+
)}
|
|
59
|
+
{header.column.getNextSortingOrder() === "asc" && (
|
|
60
|
+
// <Text>To asc</Text>
|
|
61
|
+
<UpDownIcon />
|
|
62
|
+
)}
|
|
63
|
+
{header.column.getNextSortingOrder() === "desc" && (
|
|
64
|
+
// <Text>To desc</Text>
|
|
65
|
+
<ChevronDownIcon />
|
|
66
|
+
)}
|
|
67
|
+
</Button>
|
|
68
|
+
|
|
69
|
+
{header.column.getIsSorted() && (
|
|
70
|
+
<Button
|
|
71
|
+
onClick={(e) => {
|
|
72
|
+
header.column.clearSorting();
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
<CloseIcon />
|
|
76
|
+
</Button>
|
|
77
|
+
)}
|
|
78
|
+
</>
|
|
79
|
+
)}
|
|
80
|
+
|
|
81
|
+
{header.column.getIsFiltered() && <MdFilterListAlt />}
|
|
82
|
+
{canResize && (
|
|
83
|
+
<Box
|
|
84
|
+
borderRight={
|
|
85
|
+
header.column.getIsResizing()
|
|
86
|
+
? "0.25rem solid black"
|
|
87
|
+
: "0.25rem solid grey"
|
|
88
|
+
}
|
|
89
|
+
height={"5rem"}
|
|
90
|
+
width={"5px"}
|
|
91
|
+
userSelect={"none"}
|
|
92
|
+
style={{ touchAction: "none" }}
|
|
93
|
+
{...resizeProps}
|
|
94
|
+
></Box>
|
|
95
|
+
)}
|
|
96
|
+
</Flex>
|
|
97
|
+
</Th>
|
|
98
|
+
);
|
|
99
|
+
})}
|
|
100
|
+
</Tr>
|
|
101
|
+
))}
|
|
102
|
+
</Thead>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export default TableHeader;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Button, ButtonGroup, IconButton } from "@chakra-ui/react";
|
|
2
|
+
import {
|
|
3
|
+
MdArrowBack,
|
|
4
|
+
MdArrowForward,
|
|
5
|
+
MdFirstPage,
|
|
6
|
+
MdLastPage,
|
|
7
|
+
} from "react-icons/md";
|
|
8
|
+
import { useDataTable } from "./useDataTable";
|
|
9
|
+
|
|
10
|
+
interface PaginationProps {}
|
|
11
|
+
const TablePagination = (props: PaginationProps) => {
|
|
12
|
+
const {
|
|
13
|
+
firstPage,
|
|
14
|
+
getCanPreviousPage,
|
|
15
|
+
previousPage,
|
|
16
|
+
getState,
|
|
17
|
+
nextPage,
|
|
18
|
+
getCanNextPage,
|
|
19
|
+
lastPage,
|
|
20
|
+
} = useDataTable().table;
|
|
21
|
+
return (
|
|
22
|
+
<ButtonGroup isAttached>
|
|
23
|
+
<IconButton
|
|
24
|
+
icon={<MdFirstPage />}
|
|
25
|
+
onClick={() => firstPage()}
|
|
26
|
+
disabled={!getCanPreviousPage()}
|
|
27
|
+
aria-label={"first-page"}
|
|
28
|
+
></IconButton>
|
|
29
|
+
<IconButton
|
|
30
|
+
icon={<MdArrowBack />}
|
|
31
|
+
onClick={() => previousPage()}
|
|
32
|
+
disabled={!getCanPreviousPage()}
|
|
33
|
+
aria-label={"previous-page"}
|
|
34
|
+
></IconButton>
|
|
35
|
+
<Button onClick={() => {}} disabled={!getCanPreviousPage()}>
|
|
36
|
+
{getState().pagination.pageIndex + 1}
|
|
37
|
+
</Button>
|
|
38
|
+
|
|
39
|
+
<IconButton
|
|
40
|
+
onClick={() => nextPage()}
|
|
41
|
+
disabled={!getCanNextPage()}
|
|
42
|
+
aria-label={"next-page"}
|
|
43
|
+
>
|
|
44
|
+
<MdArrowForward />
|
|
45
|
+
</IconButton>
|
|
46
|
+
<IconButton
|
|
47
|
+
onClick={() => lastPage()}
|
|
48
|
+
disabled={!getCanNextPage()}
|
|
49
|
+
aria-label={"last-page"}
|
|
50
|
+
>
|
|
51
|
+
<MdLastPage />
|
|
52
|
+
</IconButton>
|
|
53
|
+
</ButtonGroup>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default TablePagination;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChevronDownIcon,
|
|
3
|
+
ChevronUpIcon,
|
|
4
|
+
CloseIcon,
|
|
5
|
+
UpDownIcon,
|
|
6
|
+
} from "@chakra-ui/icons";
|
|
7
|
+
import { Button, Flex, Text } from "@chakra-ui/react";
|
|
8
|
+
import { useDataTable } from "./useDataTable";
|
|
9
|
+
|
|
10
|
+
const TableSorter = () => {
|
|
11
|
+
const { table } = useDataTable();
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
{table.getHeaderGroups().map((headerGroup) => (
|
|
16
|
+
<>
|
|
17
|
+
{headerGroup.headers.map((header) => {
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
{header.column.getCanSort() && (
|
|
21
|
+
<Flex alignItems={"center"} gap={"0.5rem"} padding={"0.5rem"}>
|
|
22
|
+
<Text>{header.column.id}</Text>
|
|
23
|
+
<Button
|
|
24
|
+
onClick={(e) => {
|
|
25
|
+
header.column.toggleSorting();
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
{header.column.getNextSortingOrder() === false && (
|
|
29
|
+
// <Text>To No sort</Text>
|
|
30
|
+
<ChevronUpIcon />
|
|
31
|
+
)}
|
|
32
|
+
{header.column.getNextSortingOrder() === "asc" && (
|
|
33
|
+
// <Text>To asc</Text>
|
|
34
|
+
<UpDownIcon />
|
|
35
|
+
)}
|
|
36
|
+
{header.column.getNextSortingOrder() === "desc" && (
|
|
37
|
+
// <Text>To desc</Text>
|
|
38
|
+
<ChevronDownIcon />
|
|
39
|
+
)}
|
|
40
|
+
</Button>
|
|
41
|
+
|
|
42
|
+
{header.column.getIsSorted() && (
|
|
43
|
+
<Button
|
|
44
|
+
onClick={(e) => {
|
|
45
|
+
header.column.clearSorting();
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<CloseIcon />
|
|
49
|
+
</Button>
|
|
50
|
+
)}
|
|
51
|
+
</Flex>
|
|
52
|
+
)}
|
|
53
|
+
</>
|
|
54
|
+
);
|
|
55
|
+
})}
|
|
56
|
+
</>
|
|
57
|
+
))}
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default TableSorter;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Tooltip, Text } from "@chakra-ui/react";
|
|
2
|
+
|
|
3
|
+
const TextCell = ({ label, children }: any) => {
|
|
4
|
+
return (
|
|
5
|
+
<Tooltip label={label}>
|
|
6
|
+
<Text
|
|
7
|
+
as="span"
|
|
8
|
+
overflow="hidden"
|
|
9
|
+
textOverflow={"ellipsis"}
|
|
10
|
+
noOfLines={[1, 2, 3]}
|
|
11
|
+
>
|
|
12
|
+
{children}
|
|
13
|
+
</Text>
|
|
14
|
+
</Tooltip>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default TextCell;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
|
|
4
|
+
interface useDataFromUrlReturn<T> {
|
|
5
|
+
data: T;
|
|
6
|
+
loading: boolean;
|
|
7
|
+
hasError: boolean;
|
|
8
|
+
refreshData: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface useDataFromUrlProps<T> {
|
|
12
|
+
url: string;
|
|
13
|
+
params?: object;
|
|
14
|
+
defaultData: T;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const useDataFromUrl = <T,>({
|
|
18
|
+
url,
|
|
19
|
+
params = {},
|
|
20
|
+
defaultData,
|
|
21
|
+
}: useDataFromUrlProps<T>): useDataFromUrlReturn<T> => {
|
|
22
|
+
const [loading, setLoading] = useState<boolean>(true);
|
|
23
|
+
const [hasError, setHasError] = useState<boolean>(false);
|
|
24
|
+
const [data, setData] = useState<T>(defaultData);
|
|
25
|
+
const refreshData = async () => {
|
|
26
|
+
await getData();
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const getData = async () => {
|
|
30
|
+
try {
|
|
31
|
+
setLoading(true);
|
|
32
|
+
const { data } = await axios.get<T>(url, { params: params });
|
|
33
|
+
console.log("get DataFromUrl success", data);
|
|
34
|
+
setLoading(false);
|
|
35
|
+
setData(data);
|
|
36
|
+
} catch (e) {
|
|
37
|
+
console.log(e);
|
|
38
|
+
setLoading(false);
|
|
39
|
+
setHasError(true);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
getData().catch((e) => {
|
|
45
|
+
console.error(e);
|
|
46
|
+
});
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
return { data, loading, hasError, refreshData };
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default useDataFromUrl;
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import DataTable from "./components/DataTable";
|
|
2
|
+
import EditViewButton from "./components/EditViewButton";
|
|
3
|
+
import PageSizeControl from "./components/PageSizeControl";
|
|
4
|
+
import ResetFilteringButton from "./components/ResetFilteringButton";
|
|
5
|
+
import ResetSortingButton from "./components/ResetSortingButton";
|
|
6
|
+
import Table from "./components/Table";
|
|
7
|
+
import TableBody from "./components/TableBody";
|
|
8
|
+
import TableFilter from "./components/TableFilter";
|
|
9
|
+
import TableFooter from "./components/TableFooter";
|
|
10
|
+
import TableHeader from "./components/TableHeader";
|
|
11
|
+
import TablePagination from "./components/TablePagination";
|
|
12
|
+
import TextCell from "./components/TextCell";
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
DataTable,
|
|
16
|
+
EditViewButton,
|
|
17
|
+
PageSizeControl,
|
|
18
|
+
ResetFilteringButton,
|
|
19
|
+
ResetSortingButton,
|
|
20
|
+
Table,
|
|
21
|
+
TableBody,
|
|
22
|
+
TableFilter,
|
|
23
|
+
TableFooter,
|
|
24
|
+
TableHeader,
|
|
25
|
+
TablePagination,
|
|
26
|
+
TextCell,
|
|
27
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { fn } from "@storybook/test";
|
|
3
|
+
import { Button } from "./Button";
|
|
4
|
+
|
|
5
|
+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
|
|
6
|
+
const meta = {
|
|
7
|
+
title: "Example/Button",
|
|
8
|
+
component: Button,
|
|
9
|
+
parameters: {
|
|
10
|
+
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
|
|
11
|
+
layout: "centered",
|
|
12
|
+
},
|
|
13
|
+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
|
|
14
|
+
tags: ["autodocs"],
|
|
15
|
+
// More on argTypes: https://storybook.js.org/docs/api/argtypes
|
|
16
|
+
argTypes: {
|
|
17
|
+
backgroundColor: { control: "color" },
|
|
18
|
+
},
|
|
19
|
+
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
|
|
20
|
+
args: { onClick: fn() },
|
|
21
|
+
} satisfies Meta<typeof Button>;
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
type Story = StoryObj<typeof meta>;
|
|
25
|
+
|
|
26
|
+
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
|
|
27
|
+
export const Primary: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
primary: true,
|
|
30
|
+
label: "Button",
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const Secondary: Story = {
|
|
35
|
+
args: {
|
|
36
|
+
label: "Button",
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const Large: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
size: "large",
|
|
43
|
+
label: "Button",
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const Small: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
size: "small",
|
|
50
|
+
label: "Button",
|
|
51
|
+
},
|
|
52
|
+
};
|