@digigov/ui 0.32.2 → 0.34.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/CHANGELOG.md +23 -1
- package/admin/Drawer/__stories__/Default.js +3 -0
- package/admin/Dropdown/index.d.ts +1 -1
- package/admin/Dropdown/index.js +45 -27
- package/core/CaretContainer/index.d.ts +3 -0
- package/core/CaretContainer/index.js +30 -0
- package/core/Table/Table.stories.d.ts +2 -0
- package/core/Table/Table.stories.js +28 -0
- package/core/Table/Table.stories.playwright.json +16 -0
- package/core/Table/__stories__/Stacked.d.ts +2 -0
- package/core/Table/__stories__/Stacked.js +42 -0
- package/core/Table/__stories__/WithSortFilters.d.ts +2 -0
- package/core/Table/__stories__/WithSortFilters.js +121 -0
- package/core/Table/index.d.ts +14 -1
- package/core/Table/index.js +107 -10
- package/core/index.d.ts +1 -0
- package/core/index.js +13 -0
- package/es/admin/Drawer/__stories__/Default.js +3 -0
- package/es/admin/Dropdown/index.js +45 -27
- package/es/core/CaretContainer/index.js +3 -0
- package/es/core/Table/Table.stories.js +2 -0
- package/es/core/Table/Table.stories.playwright.json +16 -0
- package/es/core/Table/__stories__/Stacked.js +29 -0
- package/es/core/Table/__stories__/WithSortFilters.js +106 -0
- package/es/core/Table/index.js +86 -1
- package/es/core/index.js +1 -0
- package/es/hooks/useSort.js +54 -0
- package/es/registry.js +2 -0
- package/esm/admin/Drawer/__stories__/Default.js +3 -0
- package/esm/admin/Dropdown/index.js +45 -27
- package/esm/core/CaretContainer/index.js +3 -0
- package/esm/core/Table/Table.stories.js +2 -0
- package/esm/core/Table/Table.stories.playwright.json +16 -0
- package/esm/core/Table/__stories__/Stacked.js +29 -0
- package/esm/core/Table/__stories__/WithSortFilters.js +106 -0
- package/esm/core/Table/index.js +86 -1
- package/esm/core/index.js +1 -0
- package/esm/hooks/useSort.js +54 -0
- package/esm/index.js +1 -1
- package/esm/registry.js +2 -0
- package/hooks/useSort.d.ts +9 -0
- package/hooks/useSort.js +67 -0
- package/package.json +3 -3
- package/registry.d.ts +1 -0
- package/registry.js +3 -0
- package/src/admin/Drawer/__stories__/Default.tsx +3 -1
- package/src/admin/Dropdown/index.tsx +80 -55
- package/src/core/CaretContainer/index.tsx +3 -0
- package/src/core/Table/Table.stories.js +2 -0
- package/src/core/Table/Table.stories.playwright.json +16 -0
- package/src/core/Table/__stories__/Stacked.tsx +59 -0
- package/src/core/Table/__stories__/WithSortFilters.tsx +152 -0
- package/src/core/Table/index.tsx +112 -2
- package/src/core/index.ts +1 -0
- package/src/hooks/useSort.tsx +53 -0
- package/src/registry.js +2 -0
|
@@ -69,9 +69,10 @@ export const Default = () => {
|
|
|
69
69
|
|
|
70
70
|
const layout = 'vertical';
|
|
71
71
|
const border = false;
|
|
72
|
+
const fixed = false;
|
|
72
73
|
|
|
73
74
|
return (
|
|
74
|
-
<Drawer direction="left" open={open}>
|
|
75
|
+
<Drawer upRelative="m" direction="left" open={open}>
|
|
75
76
|
<DrawerHeading onClick={() => toggleDrawer()}>
|
|
76
77
|
<Title size="md">Menu</Title>
|
|
77
78
|
</DrawerHeading>
|
|
@@ -79,6 +80,7 @@ export const Default = () => {
|
|
|
79
80
|
layout={layout}
|
|
80
81
|
links={links}
|
|
81
82
|
border={border}
|
|
83
|
+
fixed={fixed}
|
|
82
84
|
aria-label="Nav list"
|
|
83
85
|
>
|
|
84
86
|
{links.map((item, key) => (
|
|
@@ -21,67 +21,92 @@ export interface DropdownProps extends DropdownBaseProps {
|
|
|
21
21
|
/**
|
|
22
22
|
* Dropdown component is used for showing more options with a button.
|
|
23
23
|
*/
|
|
24
|
-
export const Dropdown = ({
|
|
25
|
-
closeBehaviour = 'clickOutside',
|
|
26
|
-
float = false,
|
|
27
|
-
...props
|
|
28
|
-
}: DropdownProps): React.ReactElement => {
|
|
29
|
-
const innerRef = useRef() as React.MutableRefObject<HTMLDetailsElement>;
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const parentElement = innerRef.current?.parentElement as HTMLElement;
|
|
43
|
-
if (innerRef.current.open) {
|
|
44
|
-
tbody.style.position = 'static';
|
|
45
|
-
const rect = innerRef.current?.getBoundingClientRect();
|
|
46
|
-
const parentRect = parentElement.getBoundingClientRect();
|
|
47
|
-
innerRef.current.style.position = 'static';
|
|
48
|
-
// arbitrary spacing of 12 pixels because CSS
|
|
49
|
-
const top = rect.top + window.pageYOffset;
|
|
50
|
-
const left = rect.left + window.pageXOffset;
|
|
51
|
-
parentElement.style.height = `${parentRect.height}px`;
|
|
52
|
-
parentElement.style.width = `${parentRect.width}px`;
|
|
53
|
-
innerRef.current.style.top = `${top}px`;
|
|
54
|
-
innerRef.current.style.left = `${left}px`;
|
|
55
|
-
innerRef.current.style.position = `absolute`;
|
|
56
|
-
innerRef.current.style.display = `block`;
|
|
57
|
-
innerRef.current.style.background = 'white';
|
|
58
|
-
} else {
|
|
59
|
-
tbody.style.position = 'relative';
|
|
60
|
-
parentElement.style.height = '';
|
|
61
|
-
parentElement.style.width = '';
|
|
62
|
-
innerRef.current.style.top = `0`;
|
|
63
|
-
innerRef.current.style.left = `0`;
|
|
64
|
-
innerRef.current.style.position = `relative`;
|
|
65
|
-
innerRef.current.style.display = `table-cell`;
|
|
66
|
-
innerRef.current.style.background = 'transparent';
|
|
25
|
+
export const Dropdown = React.forwardRef<HTMLDetailsElement, DropdownProps>(
|
|
26
|
+
function Dropdown(
|
|
27
|
+
{ closeBehaviour = 'clickOutside', float = false, ...props },
|
|
28
|
+
ref
|
|
29
|
+
) {
|
|
30
|
+
const innerRef = useRef<HTMLDetailsElement | null>(null);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const element = innerRef.current;
|
|
34
|
+
if (!element) {
|
|
35
|
+
return;
|
|
67
36
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
37
|
+
const keyDownHandler = (event) => {
|
|
38
|
+
if (event.key === 'Escape') {
|
|
39
|
+
element.open = false;
|
|
40
|
+
event.preventDefault();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const handleClickOutside = (event) => {
|
|
44
|
+
if (element && !element.contains(event.target)) {
|
|
45
|
+
element.open = false;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
73
49
|
if (closeBehaviour === 'clickOutside') {
|
|
74
|
-
document.
|
|
50
|
+
document.addEventListener('click', handleClickOutside, true);
|
|
75
51
|
}
|
|
52
|
+
document.addEventListener('keydown', keyDownHandler);
|
|
53
|
+
const toggleFloat = () => {
|
|
54
|
+
const tbody = element.closest('tbody') as HTMLElement;
|
|
55
|
+
const parentElement = element?.parentElement as HTMLElement;
|
|
56
|
+
if (element.open) {
|
|
57
|
+
tbody.style.position = 'static';
|
|
58
|
+
const rect = element?.getBoundingClientRect();
|
|
59
|
+
const parentRect = parentElement.getBoundingClientRect();
|
|
60
|
+
element.style.position = 'static';
|
|
61
|
+
// arbitrary spacing of 12 pixels because CSS
|
|
62
|
+
const top = rect.top + window.pageYOffset;
|
|
63
|
+
const left = rect.left + window.pageXOffset;
|
|
64
|
+
parentElement.style.height = `${parentRect.height}px`;
|
|
65
|
+
parentElement.style.width = `${parentRect.width}px`;
|
|
66
|
+
element.style.top = `${top}px`;
|
|
67
|
+
element.style.left = `${left}px`;
|
|
68
|
+
element.style.position = `absolute`;
|
|
69
|
+
element.style.display = `block`;
|
|
70
|
+
element.style.background = 'white';
|
|
71
|
+
} else {
|
|
72
|
+
tbody.style.position = 'relative';
|
|
73
|
+
parentElement.style.height = '';
|
|
74
|
+
parentElement.style.width = '';
|
|
75
|
+
element.style.top = `0`;
|
|
76
|
+
element.style.left = `0`;
|
|
77
|
+
element.style.position = `relative`;
|
|
78
|
+
element.style.display = `table-cell`;
|
|
79
|
+
// element.style.background = 'transparent';
|
|
80
|
+
}
|
|
81
|
+
};
|
|
76
82
|
if (float) {
|
|
77
|
-
|
|
83
|
+
element.addEventListener('toggle', toggleFloat);
|
|
78
84
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
return () => {
|
|
86
|
+
if (closeBehaviour === 'clickOutside') {
|
|
87
|
+
document.removeEventListener('click', handleClickOutside, true);
|
|
88
|
+
}
|
|
89
|
+
if (float) {
|
|
90
|
+
element.removeEventListener('toggle', toggleFloat);
|
|
91
|
+
}
|
|
92
|
+
document.removeEventListener('keydown', keyDownHandler);
|
|
93
|
+
};
|
|
94
|
+
}, []);
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
return (
|
|
98
|
+
<DropdownBase
|
|
99
|
+
ref={(el) => {
|
|
100
|
+
innerRef.current = el;
|
|
101
|
+
if (typeof ref === 'function') {
|
|
102
|
+
ref(el);
|
|
103
|
+
}
|
|
104
|
+
}}
|
|
105
|
+
{...props}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
);
|
|
85
110
|
|
|
86
111
|
export { DropdownBase };
|
|
87
112
|
export default Dropdown;
|
|
@@ -16,11 +16,13 @@ export * from './__stories__/VerticalHeaders';
|
|
|
16
16
|
export * from './__stories__/ZebraProp';
|
|
17
17
|
export * from './__stories__/NumericDataType';
|
|
18
18
|
export * from './__stories__/VerticalBorders';
|
|
19
|
+
export * from './__stories__/Stacked';
|
|
19
20
|
export * from './__stories__/DarkVariant';
|
|
20
21
|
export * from './__stories__/DarkVariantWithVerticalHeaders';
|
|
21
22
|
export * from './__stories__/WithLoader';
|
|
22
23
|
export * from './__stories__/DefinedWidth';
|
|
23
24
|
export * from './__stories__/Densed';
|
|
24
25
|
export * from './__stories__/MultipleProps';
|
|
26
|
+
export * from './__stories__/WithSortFilters';
|
|
25
27
|
export * from './__stories__/WithFloatingScroll';
|
|
26
28
|
export * from './__stories__/Full';
|
|
@@ -16,6 +16,22 @@
|
|
|
16
16
|
"title": "Toggle Loading"
|
|
17
17
|
}
|
|
18
18
|
]
|
|
19
|
+
},
|
|
20
|
+
"digigov-ui-core-table--with-sort-filters": {
|
|
21
|
+
"actionSets": [
|
|
22
|
+
{
|
|
23
|
+
"actions": [
|
|
24
|
+
{
|
|
25
|
+
"name": "click",
|
|
26
|
+
"args": {
|
|
27
|
+
"selector": "html>body>div:nth-child(5)>div>div>table>thead>tr>th:nth-child(2)>details>summary"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"id": "Gdm_Fpollj7d",
|
|
32
|
+
"title": "Table with filter action"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
19
35
|
}
|
|
20
36
|
}
|
|
21
37
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
TableContainer,
|
|
5
|
+
Table,
|
|
6
|
+
TableCaption,
|
|
7
|
+
TableHead,
|
|
8
|
+
TableRow,
|
|
9
|
+
TableBody,
|
|
10
|
+
TableHeadCell,
|
|
11
|
+
TableDataCell,
|
|
12
|
+
} from '@digigov/ui/core/Table';
|
|
13
|
+
|
|
14
|
+
export const Stacked = () => {
|
|
15
|
+
return (
|
|
16
|
+
<TableContainer>
|
|
17
|
+
<Table stacked="always">
|
|
18
|
+
<TableCaption>Περίοδος και ποσά</TableCaption>
|
|
19
|
+
<TableHead>
|
|
20
|
+
<TableRow>
|
|
21
|
+
<TableHeadCell>Περίοδος</TableHeadCell>
|
|
22
|
+
<TableHeadCell>Κανονικό ποσό</TableHeadCell>
|
|
23
|
+
<TableHeadCell>Μειωμένο ποσό</TableHeadCell>
|
|
24
|
+
</TableRow>
|
|
25
|
+
</TableHead>
|
|
26
|
+
<TableBody>
|
|
27
|
+
<TableRow>
|
|
28
|
+
<TableDataCell data-label="Περίοδος">
|
|
29
|
+
Πρώτες 6 εβδομάδες
|
|
30
|
+
</TableDataCell>
|
|
31
|
+
<TableDataCell data-label="Κανονικό ποσό">
|
|
32
|
+
€109.80 / εβδομάδα
|
|
33
|
+
</TableDataCell>
|
|
34
|
+
<TableDataCell data-label="Μειωμένο ποσό">
|
|
35
|
+
€69.80 / εβδομάδα
|
|
36
|
+
</TableDataCell>
|
|
37
|
+
</TableRow>
|
|
38
|
+
<TableRow>
|
|
39
|
+
<TableDataCell data-label="Περίοδος">
|
|
40
|
+
Επόμενες 33 εβδομάδες
|
|
41
|
+
</TableDataCell>
|
|
42
|
+
<TableDataCell data-label="Κανονικό ποσό">
|
|
43
|
+
€99.80 / εβδομάδα
|
|
44
|
+
</TableDataCell>
|
|
45
|
+
<TableDataCell data-label="Μειωμένο ποσό">
|
|
46
|
+
€64.80 / εβδομάδα
|
|
47
|
+
</TableDataCell>
|
|
48
|
+
</TableRow>
|
|
49
|
+
<TableRow>
|
|
50
|
+
<TableDataCell data-label="Περίοδος">Συνολικό ποσό </TableDataCell>
|
|
51
|
+
<TableDataCell data-label="Κανονικό ποσό">€4.282,20 </TableDataCell>
|
|
52
|
+
<TableDataCell data-label="Μειωμένο ποσό"> €3.282,20</TableDataCell>
|
|
53
|
+
</TableRow>
|
|
54
|
+
</TableBody>
|
|
55
|
+
</Table>
|
|
56
|
+
</TableContainer>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
export default Stacked;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
TableContainer,
|
|
5
|
+
Table,
|
|
6
|
+
TableCaption,
|
|
7
|
+
TableHead,
|
|
8
|
+
TableRow,
|
|
9
|
+
TableBody,
|
|
10
|
+
TableHeadCell,
|
|
11
|
+
TableDataCell,
|
|
12
|
+
TableNoDataRow,
|
|
13
|
+
TableSortLabel,
|
|
14
|
+
} from '@digigov/ui/core/Table';
|
|
15
|
+
import { useSort } from '@digigov/ui/hooks/useSort';
|
|
16
|
+
|
|
17
|
+
const headerConfig = [
|
|
18
|
+
{
|
|
19
|
+
name: 'product',
|
|
20
|
+
label: 'Προϊόν',
|
|
21
|
+
sortLabels: {
|
|
22
|
+
asc: 'Αλφαβητική σειρά (Α -> Ω)',
|
|
23
|
+
desc: 'Αλφαβητική σειρά (Ω -> Α)',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'price',
|
|
28
|
+
label: 'Τιμή',
|
|
29
|
+
sortLabels: {
|
|
30
|
+
asc: 'Αύξουσα σειρά',
|
|
31
|
+
desc: 'Φθίνουσα σειρά',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'stock',
|
|
36
|
+
label: 'Στοκ',
|
|
37
|
+
sortLabels: {
|
|
38
|
+
asc: 'Αύξουσα σειρά',
|
|
39
|
+
desc: 'Φθίνουσα σειρά',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'date',
|
|
44
|
+
label: 'Ημερομηνία',
|
|
45
|
+
sortLabels: {
|
|
46
|
+
asc: 'Αύξουσα σειρά',
|
|
47
|
+
desc: 'Φθίνουσα σειρά',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const data = [
|
|
53
|
+
{
|
|
54
|
+
id: 1,
|
|
55
|
+
product: 'Τυρί',
|
|
56
|
+
price: '4.9€',
|
|
57
|
+
stock: 20,
|
|
58
|
+
date: '2013-04-01',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 2,
|
|
62
|
+
product: 'Γάλα',
|
|
63
|
+
price: '1.9€',
|
|
64
|
+
stock: 32,
|
|
65
|
+
date: '2013-01-01',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 3,
|
|
69
|
+
product: 'Γιαούρτι',
|
|
70
|
+
price: '2.4€',
|
|
71
|
+
stock: 12,
|
|
72
|
+
date: '2002-04-12',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 4,
|
|
76
|
+
product: 'Κρέμα',
|
|
77
|
+
price: '3.9€',
|
|
78
|
+
stock: 8,
|
|
79
|
+
date: '2011-12-12',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: 5,
|
|
83
|
+
product: 'Βούτυρο',
|
|
84
|
+
price: '0.9€',
|
|
85
|
+
stock: 99,
|
|
86
|
+
date: '2019-06-01',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 6,
|
|
90
|
+
product: 'Καφές',
|
|
91
|
+
price: '2.9€',
|
|
92
|
+
stock: 86,
|
|
93
|
+
date: '2023-02-11',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: 7,
|
|
97
|
+
product: 'Ψωμί',
|
|
98
|
+
price: '99€',
|
|
99
|
+
stock: 12,
|
|
100
|
+
date: '2000-12-12',
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
export const WithSortFilters = () => {
|
|
105
|
+
const { sortedData, setSortedField, field, direction } = useSort(data);
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<div className="example">
|
|
109
|
+
<TableContainer>
|
|
110
|
+
<Table>
|
|
111
|
+
<TableCaption>Table of products</TableCaption>
|
|
112
|
+
<TableHead>
|
|
113
|
+
<TableRow>
|
|
114
|
+
{headerConfig.map((header, index) => {
|
|
115
|
+
return (
|
|
116
|
+
<TableHeadCell key={index}>
|
|
117
|
+
<TableSortLabel
|
|
118
|
+
labels={header.sortLabels}
|
|
119
|
+
onSort={(dir) => setSortedField(header.name, dir)}
|
|
120
|
+
direction={header.name === field ? direction : 0}
|
|
121
|
+
>
|
|
122
|
+
{header.label}
|
|
123
|
+
</TableSortLabel>
|
|
124
|
+
</TableHeadCell>
|
|
125
|
+
);
|
|
126
|
+
})}
|
|
127
|
+
</TableRow>
|
|
128
|
+
</TableHead>
|
|
129
|
+
<TableBody>
|
|
130
|
+
{sortedData.length > 0 ? (
|
|
131
|
+
sortedData.map((d, index) => {
|
|
132
|
+
return (
|
|
133
|
+
<TableRow key={index}>
|
|
134
|
+
<TableDataCell>{d.product}</TableDataCell>
|
|
135
|
+
<TableDataCell>{d.price}</TableDataCell>
|
|
136
|
+
<TableDataCell>{d.stock}</TableDataCell>
|
|
137
|
+
<TableDataCell>
|
|
138
|
+
{new Date(d.date).toLocaleDateString('en-GB')}
|
|
139
|
+
</TableDataCell>
|
|
140
|
+
</TableRow>
|
|
141
|
+
);
|
|
142
|
+
})
|
|
143
|
+
) : (
|
|
144
|
+
<TableNoDataRow>No data</TableNoDataRow>
|
|
145
|
+
)}
|
|
146
|
+
</TableBody>
|
|
147
|
+
</Table>
|
|
148
|
+
</TableContainer>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
export default WithSortFilters;
|
package/src/core/Table/index.tsx
CHANGED
|
@@ -1,3 +1,115 @@
|
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import Table from '@digigov/react-core/Table';
|
|
3
|
+
import {
|
|
4
|
+
Dropdown,
|
|
5
|
+
DropdownButton,
|
|
6
|
+
DropdownContent,
|
|
7
|
+
DropdownProps,
|
|
8
|
+
} from '@digigov/ui/admin/Dropdown';
|
|
9
|
+
import { NavVertical } from '@digigov/ui/core/NavList/NavVertical';
|
|
10
|
+
import { NavVerticalItem } from '@digigov/ui/core/NavList/NavVerticalItem';
|
|
11
|
+
import { CaretIcon } from '@digigov/ui/core/SvgIcon';
|
|
12
|
+
import CaretContainer from '@digigov/ui/core/CaretContainer';
|
|
13
|
+
|
|
14
|
+
export type SortDirection = 1 | -1 | 0;
|
|
15
|
+
|
|
16
|
+
export interface TableSortLabelProps extends DropdownProps {
|
|
17
|
+
labels: {
|
|
18
|
+
asc: string;
|
|
19
|
+
desc: string;
|
|
20
|
+
};
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
direction?: SortDirection;
|
|
23
|
+
onSort: (direction: SortDirection) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const TableSortLabel = React.forwardRef<
|
|
27
|
+
HTMLDetailsElement,
|
|
28
|
+
TableSortLabelProps
|
|
29
|
+
>(function TableSortLabel(
|
|
30
|
+
{ labels, disabled, children, direction = 0, onSort, ...props },
|
|
31
|
+
ref
|
|
32
|
+
) {
|
|
33
|
+
// TODO: this is a workaround for the dropdown component
|
|
34
|
+
// https://itnext.io/reusing-the-ref-from-forwardref-with-react-hooks-4ce9df693dd
|
|
35
|
+
const dropdownRef = useRef<HTMLDetailsElement | null>(null);
|
|
36
|
+
const active = [-1, 1].includes(direction);
|
|
37
|
+
return (
|
|
38
|
+
<Dropdown
|
|
39
|
+
ref={(el) => {
|
|
40
|
+
dropdownRef.current = el;
|
|
41
|
+
typeof ref === 'function' && ref(el);
|
|
42
|
+
}}
|
|
43
|
+
disabled={disabled}
|
|
44
|
+
{...props}
|
|
45
|
+
>
|
|
46
|
+
<DropdownButton variant="link" tabIndex={0} underline={active}>
|
|
47
|
+
{children}
|
|
48
|
+
<CaretContainer marginLeft={1}>
|
|
49
|
+
<CaretIcon
|
|
50
|
+
direction={'up'}
|
|
51
|
+
size="m"
|
|
52
|
+
variant={direction === 1 ? 'dark' : 'gray'}
|
|
53
|
+
/>
|
|
54
|
+
<CaretIcon
|
|
55
|
+
direction={'down'}
|
|
56
|
+
size="m"
|
|
57
|
+
variant={direction === -1 ? 'dark' : 'gray'}
|
|
58
|
+
/>
|
|
59
|
+
</CaretContainer>
|
|
60
|
+
</DropdownButton>
|
|
61
|
+
<DropdownContent>
|
|
62
|
+
<NavVertical>
|
|
63
|
+
<NavVerticalItem
|
|
64
|
+
active={direction === 1}
|
|
65
|
+
tabIndex={0}
|
|
66
|
+
onClick={() => {
|
|
67
|
+
onSort(1);
|
|
68
|
+
dropdownRef.current && (dropdownRef.current.open = false);
|
|
69
|
+
}}
|
|
70
|
+
onKeyDown={(e) => {
|
|
71
|
+
if (e.key === 'Enter') {
|
|
72
|
+
onSort(1);
|
|
73
|
+
dropdownRef.current && (dropdownRef.current.open = false);
|
|
74
|
+
}
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
<CaretIcon
|
|
78
|
+
direction={'up'}
|
|
79
|
+
marginRight={1}
|
|
80
|
+
marginTop={1}
|
|
81
|
+
size="m"
|
|
82
|
+
/>
|
|
83
|
+
{labels.asc}
|
|
84
|
+
</NavVerticalItem>
|
|
85
|
+
<NavVerticalItem
|
|
86
|
+
active={direction === -1}
|
|
87
|
+
tabIndex={0}
|
|
88
|
+
onClick={() => {
|
|
89
|
+
onSort(-1);
|
|
90
|
+
dropdownRef.current && (dropdownRef.current.open = false);
|
|
91
|
+
}}
|
|
92
|
+
onKeyDown={(e) => {
|
|
93
|
+
if (e.key === 'Enter') {
|
|
94
|
+
onSort(-1);
|
|
95
|
+
dropdownRef.current && (dropdownRef.current.open = false);
|
|
96
|
+
}
|
|
97
|
+
}}
|
|
98
|
+
>
|
|
99
|
+
<CaretIcon
|
|
100
|
+
direction={'down'}
|
|
101
|
+
marginRight={1}
|
|
102
|
+
marginTop={1}
|
|
103
|
+
size="m"
|
|
104
|
+
/>
|
|
105
|
+
{labels.desc}
|
|
106
|
+
</NavVerticalItem>
|
|
107
|
+
</NavVertical>
|
|
108
|
+
</DropdownContent>
|
|
109
|
+
</Dropdown>
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
|
|
1
113
|
export * from '@digigov/react-core/TableContainer';
|
|
2
114
|
export * from '@digigov/react-core/Table';
|
|
3
115
|
export * from '@digigov/react-core/TableBody';
|
|
@@ -8,6 +120,4 @@ export * from '@digigov/react-core/TableHeadCell';
|
|
|
8
120
|
export * from '@digigov/react-core/TableRow';
|
|
9
121
|
export * from '@digigov/react-core/TableNoDataRow';
|
|
10
122
|
export * from '@digigov/ui/core/Table/TableFloatingScroll';
|
|
11
|
-
|
|
12
|
-
import Table from '@digigov/react-core/Table';
|
|
13
123
|
export default Table;
|
package/src/core/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from '@digigov/ui/core/Accordion';
|
|
|
6
6
|
export * from '@digigov/ui/core/Blockquote';
|
|
7
7
|
export * from '@digigov/ui/core/Breadcrumbs';
|
|
8
8
|
export * from '@digigov/ui/core/Card';
|
|
9
|
+
export * from '@digigov/ui/core/CaretContainer';
|
|
9
10
|
export * from '@digigov/ui/core/Checkbox';
|
|
10
11
|
export * from '@digigov/ui/core/DateInputContainer';
|
|
11
12
|
export * from '@digigov/ui/core/Details';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { SortDirection } from '@digigov/ui/core/Table';
|
|
4
|
+
|
|
5
|
+
export interface UseSortResult {
|
|
6
|
+
sortedData: any[];
|
|
7
|
+
setSortedField: (item: string, value: SortDirection) => void;
|
|
8
|
+
field: string;
|
|
9
|
+
direction: SortDirection;
|
|
10
|
+
}
|
|
11
|
+
export type SortData = Record<string, any>[];
|
|
12
|
+
export const useSort = (data: SortData): UseSortResult => {
|
|
13
|
+
const [sortDataBy, setSortDataBy] = useState('');
|
|
14
|
+
const [direction, setDirection] = useState<-1 | 1 | 0>(0);
|
|
15
|
+
const sortedItems = useMemo(() => {
|
|
16
|
+
const sortableItems = [...data];
|
|
17
|
+
if (sortableItems.length === 0) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
if (sortDataBy) {
|
|
21
|
+
sortableItems.sort((a, b) => {
|
|
22
|
+
if (a[sortDataBy] === null) return 1;
|
|
23
|
+
if (b[sortDataBy] === null) return -1;
|
|
24
|
+
if (a[sortDataBy] === null && b[sortDataBy] === null) return 0;
|
|
25
|
+
return (
|
|
26
|
+
a[sortDataBy]
|
|
27
|
+
.toString()
|
|
28
|
+
.localeCompare(b[sortDataBy].toString(), undefined, {
|
|
29
|
+
numeric: true,
|
|
30
|
+
}) * (direction > 0 ? 1 : -1)
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return sortableItems;
|
|
35
|
+
}, [data, direction, sortDataBy]);
|
|
36
|
+
|
|
37
|
+
const setSortedField = (item, value) => {
|
|
38
|
+
if (item === sortDataBy && value === direction) {
|
|
39
|
+
setDirection(0);
|
|
40
|
+
setSortDataBy('');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
setDirection(value);
|
|
44
|
+
setSortDataBy(item);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
sortedData: sortedItems,
|
|
49
|
+
setSortedField,
|
|
50
|
+
field: sortDataBy,
|
|
51
|
+
direction,
|
|
52
|
+
};
|
|
53
|
+
};
|
package/src/registry.js
CHANGED
|
@@ -72,6 +72,7 @@ import * as _digigov_ui_core_Button_Icon from '@digigov/ui/core/Button/Icon';
|
|
|
72
72
|
import * as _digigov_ui_core_Button from '@digigov/ui/core/Button';
|
|
73
73
|
import * as _digigov_ui_core_Button_ThemeToggleButton from '@digigov/ui/core/Button/ThemeToggleButton';
|
|
74
74
|
import * as _digigov_ui_core_Card from '@digigov/ui/core/Card';
|
|
75
|
+
import * as _digigov_ui_core_CaretContainer from '@digigov/ui/core/CaretContainer';
|
|
75
76
|
import * as _digigov_ui_core_Checkbox from '@digigov/ui/core/Checkbox';
|
|
76
77
|
import * as _digigov_ui_core_DateInputContainer from '@digigov/ui/core/DateInputContainer';
|
|
77
78
|
import * as _digigov_ui_core_Details from '@digigov/ui/core/Details';
|
|
@@ -287,6 +288,7 @@ export default {
|
|
|
287
288
|
'@digigov/ui/core/Button': lazyImport(_digigov_ui_core_Button),
|
|
288
289
|
'@digigov/ui/core/Button/ThemeToggleButton': lazyImport(_digigov_ui_core_Button_ThemeToggleButton),
|
|
289
290
|
'@digigov/ui/core/Card': lazyImport(_digigov_ui_core_Card),
|
|
291
|
+
'@digigov/ui/core/CaretContainer': lazyImport(_digigov_ui_core_CaretContainer),
|
|
290
292
|
'@digigov/ui/core/Checkbox': lazyImport(_digigov_ui_core_Checkbox),
|
|
291
293
|
'@digigov/ui/core/DateInputContainer': lazyImport(_digigov_ui_core_DateInputContainer),
|
|
292
294
|
'@digigov/ui/core/Details': lazyImport(_digigov_ui_core_Details),
|