@hyphen/hyphen-components 2.13.0 → 2.14.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/dist/components/Pagination/Pagination.utilities.d.ts +3 -4
- package/dist/css/utilities.css +13 -0
- package/dist/hyphen-components.cjs.development.js +59 -58
- package/dist/hyphen-components.cjs.development.js.map +1 -1
- package/dist/hyphen-components.cjs.production.min.js +1 -1
- package/dist/hyphen-components.cjs.production.min.js.map +1 -1
- package/dist/hyphen-components.esm.js +59 -58
- package/dist/hyphen-components.esm.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/Box/Box.test.tsx +229 -314
- package/src/components/Pagination/Pagination.test.tsx +5 -2
- package/src/components/Pagination/Pagination.tsx +43 -25
- package/src/components/Pagination/Pagination.utilities.test.ts +15 -30
- package/src/components/Pagination/Pagination.utilities.ts +21 -59
- package/src/styles/display.scss +12 -0
- package/src/types/index.ts +2 -1
|
@@ -169,8 +169,11 @@ describe('Pagination', () => {
|
|
|
169
169
|
expect(ellipsisFound.length).toBe(2);
|
|
170
170
|
|
|
171
171
|
const buttonsFound = screen.queryAllByRole('button');
|
|
172
|
-
expect(buttonsFound
|
|
173
|
-
expect(
|
|
172
|
+
expect(buttonsFound.length).toBe(8);
|
|
173
|
+
expect(ellipsisFound[0].previousElementSibling?.textContent).toBe('1');
|
|
174
|
+
expect(ellipsisFound[0].nextElementSibling?.textContent).toBe('4');
|
|
175
|
+
expect(ellipsisFound[1].previousElementSibling?.textContent).toBe('7');
|
|
176
|
+
expect(ellipsisFound[1].nextElementSibling?.textContent).toBe('12');
|
|
174
177
|
});
|
|
175
178
|
});
|
|
176
179
|
|
|
@@ -4,7 +4,6 @@ import { Box } from '../Box/Box';
|
|
|
4
4
|
import { Button } from '../Button/Button';
|
|
5
5
|
import {
|
|
6
6
|
generatePages,
|
|
7
|
-
generatePageRange,
|
|
8
7
|
generatePageTotal,
|
|
9
8
|
generateActiveListRange,
|
|
10
9
|
} from './Pagination.utilities';
|
|
@@ -72,34 +71,43 @@ export const Pagination: FC<PaginationProps> = ({
|
|
|
72
71
|
numberOfPagesDisplayed = 5,
|
|
73
72
|
prevPageText = 'Previous',
|
|
74
73
|
}) => {
|
|
75
|
-
const pageTotal = useMemo(
|
|
76
|
-
()
|
|
77
|
-
|
|
78
|
-
);
|
|
74
|
+
const pageTotal = useMemo(() => {
|
|
75
|
+
if (itemsPerPage <= 0) return 1;
|
|
76
|
+
return generatePageTotal(totalItemsCount, itemsPerPage);
|
|
77
|
+
}, [totalItemsCount, itemsPerPage]);
|
|
79
78
|
|
|
80
|
-
const
|
|
81
|
-
() => generatePageRange(numberOfPagesDisplayed, pageTotal),
|
|
82
|
-
[numberOfPagesDisplayed, pageTotal]
|
|
83
|
-
);
|
|
79
|
+
const validActivePage = Math.max(1, Math.min(activePage, pageTotal));
|
|
84
80
|
|
|
85
81
|
const activeListRange = useMemo(
|
|
86
|
-
() =>
|
|
87
|
-
|
|
82
|
+
() =>
|
|
83
|
+
generateActiveListRange(validActivePage, totalItemsCount, itemsPerPage),
|
|
84
|
+
[validActivePage, totalItemsCount, itemsPerPage]
|
|
88
85
|
);
|
|
89
86
|
|
|
90
87
|
const pages = useMemo(
|
|
91
|
-
() =>
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
() => generatePages(pageTotal, validActivePage, numberOfPagesDisplayed),
|
|
89
|
+
[pageTotal, validActivePage, numberOfPagesDisplayed]
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const paginationClassNames = useMemo(
|
|
93
|
+
() => classNames(className),
|
|
94
|
+
[className]
|
|
94
95
|
);
|
|
95
96
|
|
|
97
|
+
const activeListRangeText = useMemo(() => {
|
|
98
|
+
if (totalItemsCount === 0) {
|
|
99
|
+
return 'No items to display';
|
|
100
|
+
}
|
|
101
|
+
return `Showing ${activeListRange.first}-${activeListRange.last} of ${totalItemsCount}`;
|
|
102
|
+
}, [activeListRange, totalItemsCount]);
|
|
103
|
+
|
|
96
104
|
return (
|
|
97
105
|
<Box
|
|
98
106
|
as="nav"
|
|
99
107
|
direction="row"
|
|
100
108
|
alignItems="center"
|
|
101
109
|
justifyContent="space-between"
|
|
102
|
-
className={
|
|
110
|
+
className={paginationClassNames}
|
|
103
111
|
>
|
|
104
112
|
<Box
|
|
105
113
|
direction="row"
|
|
@@ -110,16 +118,15 @@ export const Pagination: FC<PaginationProps> = ({
|
|
|
110
118
|
<Button
|
|
111
119
|
variant="secondary"
|
|
112
120
|
size={isCompact ? 'sm' : 'md'}
|
|
113
|
-
isDisabled={
|
|
114
|
-
onClick={() => onChange(
|
|
121
|
+
isDisabled={validActivePage === 1}
|
|
122
|
+
onClick={() => onChange(validActivePage - 1)}
|
|
115
123
|
>
|
|
116
124
|
{prevPageText}
|
|
117
125
|
</Button>
|
|
118
126
|
{arePagesVisible && (
|
|
119
127
|
<Box direction="row" gap="2xs">
|
|
120
|
-
{pages.map(({ pageNumber, isPage }) => {
|
|
121
|
-
|
|
122
|
-
return (
|
|
128
|
+
{pages.map(({ pageNumber, isPage }, index) => {
|
|
129
|
+
return isPage ? (
|
|
123
130
|
<Button
|
|
124
131
|
key={pageNumber}
|
|
125
132
|
onClick={() => onChange(pageNumber)}
|
|
@@ -130,8 +137,20 @@ export const Pagination: FC<PaginationProps> = ({
|
|
|
130
137
|
}}
|
|
131
138
|
className={className}
|
|
132
139
|
>
|
|
133
|
-
{
|
|
140
|
+
{pageNumber}
|
|
134
141
|
</Button>
|
|
142
|
+
) : (
|
|
143
|
+
<Box
|
|
144
|
+
key={`ellipsis-${index}`}
|
|
145
|
+
style={{
|
|
146
|
+
display: 'flexk',
|
|
147
|
+
minWidth: isCompact ? '33px' : '42px',
|
|
148
|
+
justifyContent: 'space-around',
|
|
149
|
+
alignItems: 'center',
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
...
|
|
153
|
+
</Box>
|
|
135
154
|
);
|
|
136
155
|
})}
|
|
137
156
|
</Box>
|
|
@@ -139,8 +158,8 @@ export const Pagination: FC<PaginationProps> = ({
|
|
|
139
158
|
<Button
|
|
140
159
|
variant="secondary"
|
|
141
160
|
size={isCompact ? 'sm' : 'md'}
|
|
142
|
-
isDisabled={
|
|
143
|
-
onClick={() => onChange(
|
|
161
|
+
isDisabled={validActivePage === pageTotal}
|
|
162
|
+
onClick={() => onChange(validActivePage + 1)}
|
|
144
163
|
>
|
|
145
164
|
{nextPageText}
|
|
146
165
|
</Button>
|
|
@@ -153,8 +172,7 @@ export const Pagination: FC<PaginationProps> = ({
|
|
|
153
172
|
}}
|
|
154
173
|
fontSize={isCompact ? 'sm' : 'md'}
|
|
155
174
|
>
|
|
156
|
-
{isTotalVisible &&
|
|
157
|
-
`Showing ${activeListRange.first}-${activeListRange.last} of ${totalItemsCount}`}
|
|
175
|
+
{isTotalVisible && activeListRangeText}
|
|
158
176
|
</Box>
|
|
159
177
|
</Box>
|
|
160
178
|
);
|
|
@@ -1,27 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generatePages,
|
|
3
|
-
generatePageRange,
|
|
4
3
|
generatePageTotal,
|
|
5
4
|
generateActiveListRange,
|
|
6
5
|
} from './Pagination.utilities';
|
|
7
6
|
|
|
8
|
-
describe('generatePageRange', () => {
|
|
9
|
-
it('returns the number of pages displayed if there are enough total pages', () => {
|
|
10
|
-
const pageRange = generatePageRange(3, 50);
|
|
11
|
-
expect(pageRange).toBe(3);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('returns the page total if it is smaller than the number of pages displayed', () => {
|
|
15
|
-
const pageRange = generatePageRange(3, 2);
|
|
16
|
-
expect(pageRange).toBe(2);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('returns the number of pages displayed if it is the same as total pages', () => {
|
|
20
|
-
const pageRange = generatePageRange(3, 3);
|
|
21
|
-
expect(pageRange).toBe(3);
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
7
|
describe('generatePageTotal', () => {
|
|
26
8
|
it('returns correct number of pages for a variety of inputs', () => {
|
|
27
9
|
const pageTotal1 = generatePageTotal(948, 20);
|
|
@@ -51,8 +33,8 @@ describe('generateActiveListRange', () => {
|
|
|
51
33
|
|
|
52
34
|
describe('generatePages', () => {
|
|
53
35
|
it('returns correct pages -- scenario 1', () => {
|
|
54
|
-
const pages = generatePages(
|
|
55
|
-
expect(pages.length).toBe(
|
|
36
|
+
const pages = generatePages(10, 3, 3);
|
|
37
|
+
expect(pages.length).toBe(6);
|
|
56
38
|
|
|
57
39
|
expect(pages[0].isPage).toBe(true);
|
|
58
40
|
expect(pages[0].pageNumber).toBe(1);
|
|
@@ -63,22 +45,25 @@ describe('generatePages', () => {
|
|
|
63
45
|
expect(pages[2].isPage).toBe(true);
|
|
64
46
|
expect(pages[2].pageNumber).toBe(3);
|
|
65
47
|
|
|
66
|
-
expect(pages[3].isPage).toBe(
|
|
67
|
-
expect(pages[3].pageNumber).toBe(
|
|
48
|
+
expect(pages[3].isPage).toBe(true);
|
|
49
|
+
expect(pages[3].pageNumber).toBe(4);
|
|
68
50
|
|
|
69
|
-
expect(pages[4].isPage).toBe(
|
|
70
|
-
expect(pages[4].pageNumber).toBe(
|
|
51
|
+
expect(pages[4].isPage).toBe(false);
|
|
52
|
+
expect(pages[4].pageNumber).toBe(-1);
|
|
53
|
+
|
|
54
|
+
expect(pages[5].isPage).toBe(true);
|
|
55
|
+
expect(pages[5].pageNumber).toBe(10);
|
|
71
56
|
});
|
|
72
57
|
|
|
73
58
|
it('returns correct pages -- scenario 2', () => {
|
|
74
|
-
const pages = generatePages(
|
|
59
|
+
const pages = generatePages(10, 6, 3);
|
|
75
60
|
expect(pages.length).toBe(7);
|
|
76
61
|
|
|
77
62
|
expect(pages[0].isPage).toBe(true);
|
|
78
63
|
expect(pages[0].pageNumber).toBe(1);
|
|
79
64
|
|
|
80
65
|
expect(pages[1].isPage).toBe(false);
|
|
81
|
-
expect(pages[1].pageNumber).toBe(
|
|
66
|
+
expect(pages[1].pageNumber).toBe(-1);
|
|
82
67
|
|
|
83
68
|
expect(pages[2].isPage).toBe(true);
|
|
84
69
|
expect(pages[2].pageNumber).toBe(5);
|
|
@@ -90,21 +75,21 @@ describe('generatePages', () => {
|
|
|
90
75
|
expect(pages[4].pageNumber).toBe(7);
|
|
91
76
|
|
|
92
77
|
expect(pages[5].isPage).toBe(false);
|
|
93
|
-
expect(pages[5].pageNumber).toBe(
|
|
78
|
+
expect(pages[5].pageNumber).toBe(-1);
|
|
94
79
|
|
|
95
80
|
expect(pages[6].isPage).toBe(true);
|
|
96
81
|
expect(pages[6].pageNumber).toBe(10);
|
|
97
82
|
});
|
|
98
83
|
|
|
99
84
|
it('returns correct pages -- scenario 3', () => {
|
|
100
|
-
const pages = generatePages(
|
|
85
|
+
const pages = generatePages(10, 9, 3);
|
|
101
86
|
expect(pages.length).toBe(5);
|
|
102
87
|
|
|
103
88
|
expect(pages[0].isPage).toBe(true);
|
|
104
89
|
expect(pages[0].pageNumber).toBe(1);
|
|
105
90
|
|
|
106
91
|
expect(pages[1].isPage).toBe(false);
|
|
107
|
-
expect(pages[1].pageNumber).toBe(
|
|
92
|
+
expect(pages[1].pageNumber).toBe(-1);
|
|
108
93
|
|
|
109
94
|
expect(pages[2].isPage).toBe(true);
|
|
110
95
|
expect(pages[2].pageNumber).toBe(8);
|
|
@@ -117,7 +102,7 @@ describe('generatePages', () => {
|
|
|
117
102
|
});
|
|
118
103
|
|
|
119
104
|
it('returns the correct pages -- one less page range than total', () => {
|
|
120
|
-
const pages = generatePages(
|
|
105
|
+
const pages = generatePages(3, 1, 2);
|
|
121
106
|
|
|
122
107
|
expect(pages[0].isPage).toBe(true);
|
|
123
108
|
expect(pages[0].pageNumber).toBe(1);
|
|
@@ -4,70 +4,45 @@ export interface Page {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
export const generatePages = (
|
|
7
|
-
pageRange: number,
|
|
8
7
|
pageTotal: number,
|
|
9
8
|
activePage: number,
|
|
10
9
|
numberOfPagesDisplayed: number
|
|
11
10
|
): Page[] => {
|
|
11
|
+
const pageRange = Math.min(pageTotal, Math.max(1, numberOfPagesDisplayed));
|
|
12
12
|
const pages: Page[] = [];
|
|
13
13
|
let startingPage = 1;
|
|
14
14
|
let endingPage = pageRange;
|
|
15
15
|
|
|
16
|
-
if (
|
|
17
|
-
startingPage = 1;
|
|
18
|
-
endingPage =
|
|
19
|
-
} else
|
|
20
|
-
startingPage =
|
|
21
|
-
endingPage = startingPage +
|
|
22
|
-
} else if (
|
|
23
|
-
activePage > numberOfPagesDisplayed &&
|
|
24
|
-
activePage + numberOfPagesDisplayed <= pageTotal
|
|
25
|
-
) {
|
|
26
|
-
startingPage = activePage - Math.floor(numberOfPagesDisplayed / 2);
|
|
27
|
-
endingPage = startingPage + (numberOfPagesDisplayed - 1);
|
|
16
|
+
if (activePage + Math.floor(pageRange / 2) >= pageTotal) {
|
|
17
|
+
startingPage = Math.max(1, pageTotal - pageRange + 1);
|
|
18
|
+
endingPage = pageTotal;
|
|
19
|
+
} else {
|
|
20
|
+
startingPage = Math.max(1, activePage - Math.floor(pageRange / 2));
|
|
21
|
+
endingPage = Math.min(pageTotal, startingPage + pageRange - 1);
|
|
28
22
|
}
|
|
29
23
|
|
|
30
24
|
for (let i = startingPage; i <= endingPage; i += 1) {
|
|
31
25
|
pages.push({ pageNumber: i, isPage: true });
|
|
32
26
|
}
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
: pageTotal - 1;
|
|
39
|
-
|
|
40
|
-
// only add ellipsis if there are more than 0 pages between the final page and the rest of the pages
|
|
41
|
-
if (pageTotal > numberOfPagesDisplayed + 1) {
|
|
42
|
-
pages.push({ pageNumber: secondToLastPage, isPage: false });
|
|
28
|
+
// Handling ellipsis for overflow pages
|
|
29
|
+
if (endingPage < pageTotal) {
|
|
30
|
+
if (endingPage < pageTotal - 1) {
|
|
31
|
+
pages.push({ pageNumber: -1, isPage: false }); // represents ellipsis
|
|
43
32
|
}
|
|
44
|
-
|
|
45
33
|
pages.push({ pageNumber: pageTotal, isPage: true });
|
|
46
34
|
}
|
|
47
35
|
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
pages.unshift(
|
|
55
|
-
{ pageNumber: 1, isPage: true },
|
|
56
|
-
{ pageNumber: threeDotsPage, isPage: false }
|
|
57
|
-
);
|
|
36
|
+
if (startingPage > 1) {
|
|
37
|
+
pages.unshift({ pageNumber: 1, isPage: true });
|
|
38
|
+
if (startingPage > 2) {
|
|
39
|
+
pages.splice(1, 0, { pageNumber: -1, isPage: false }); // represents ellipsis
|
|
40
|
+
}
|
|
58
41
|
}
|
|
59
42
|
|
|
60
|
-
return
|
|
43
|
+
return pages;
|
|
61
44
|
};
|
|
62
45
|
|
|
63
|
-
// Return the true page range in cases
|
|
64
|
-
// where number of pages wanted for display is larger than the actual page total.
|
|
65
|
-
export const generatePageRange = (
|
|
66
|
-
numberOfPagesDisplayed: number,
|
|
67
|
-
pageTotal: number
|
|
68
|
-
): number =>
|
|
69
|
-
numberOfPagesDisplayed > pageTotal ? pageTotal : numberOfPagesDisplayed;
|
|
70
|
-
|
|
71
46
|
export const generatePageTotal = (
|
|
72
47
|
totalItemsCount: number,
|
|
73
48
|
itemsPerPage: number
|
|
@@ -80,22 +55,9 @@ export const generateActiveListRange = (
|
|
|
80
55
|
activePage: number,
|
|
81
56
|
totalItemsCount: number,
|
|
82
57
|
itemsPerPage: number
|
|
83
|
-
): { first
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
const pageTotal = generatePageTotal(totalItemsCount, itemsPerPage);
|
|
87
|
-
|
|
88
|
-
if (activePage === 1) {
|
|
89
|
-
activePageRange.first = 1;
|
|
90
|
-
activePageRange.last =
|
|
91
|
-
totalItemsCount > itemsPerPage ? itemsPerPage : totalItemsCount;
|
|
92
|
-
} else if (activePage < pageTotal) {
|
|
93
|
-
activePageRange.first = activePage * itemsPerPage - (itemsPerPage - 1);
|
|
94
|
-
activePageRange.last = activePage * itemsPerPage;
|
|
95
|
-
} else {
|
|
96
|
-
activePageRange.first = activePage * itemsPerPage - (itemsPerPage - 1);
|
|
97
|
-
activePageRange.last = totalItemsCount;
|
|
98
|
-
}
|
|
58
|
+
): { first: number; last: number } => {
|
|
59
|
+
const first = (activePage - 1) * itemsPerPage + 1;
|
|
60
|
+
const last = Math.min(activePage * itemsPerPage, totalItemsCount);
|
|
99
61
|
|
|
100
|
-
return
|
|
62
|
+
return { first, last };
|
|
101
63
|
};
|
package/src/styles/display.scss
CHANGED
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
.display-table-cell {
|
|
28
28
|
display: table-cell;
|
|
29
29
|
}
|
|
30
|
+
.display-contents {
|
|
31
|
+
display: contents;
|
|
32
|
+
}
|
|
30
33
|
|
|
31
34
|
@media (min-width: $size-breakpoint-tablet) {
|
|
32
35
|
.display-inherit-tablet {
|
|
@@ -56,6 +59,9 @@
|
|
|
56
59
|
.display-table-cell-tablet {
|
|
57
60
|
display: table-cell;
|
|
58
61
|
}
|
|
62
|
+
.display-contents-tablet {
|
|
63
|
+
display: contents;
|
|
64
|
+
}
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
@media (min-width: $size-breakpoint-desktop) {
|
|
@@ -86,6 +92,9 @@
|
|
|
86
92
|
.display-table-cell-desktop {
|
|
87
93
|
display: table-cell;
|
|
88
94
|
}
|
|
95
|
+
.display-contents-desktop {
|
|
96
|
+
display: contents;
|
|
97
|
+
}
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
@media (min-width: $size-breakpoint-hd) {
|
|
@@ -116,4 +125,7 @@
|
|
|
116
125
|
.display-table-cell-hd {
|
|
117
126
|
display: table-cell;
|
|
118
127
|
}
|
|
128
|
+
.display-contents-hd {
|
|
129
|
+
display: contents;
|
|
130
|
+
}
|
|
119
131
|
}
|