-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Expand file tree
/
Copy pathuseGetPageElements.tsx
More file actions
132 lines (110 loc) · 4.31 KB
/
useGetPageElements.tsx
File metadata and controls
132 lines (110 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import type { ComponentProps } from 'react';
import type BasePagination from '#ui/Common/BasePagination';
import Ellipsis from '#ui/Common/BasePagination/Ellipsis';
import type { PaginationListItemProps } from '#ui/Common/BasePagination/PaginationListItem';
import PaginationListItem from '#ui/Common/BasePagination/PaginationListItem';
import type { LinkLike } from '#ui/types';
const parsePages = (
pages: ComponentProps<typeof BasePagination>['pages'],
currentPage: number,
totalPages: number,
as: LinkLike,
getLabel: (pageNumber: number) => string
): Array<PaginationListItemProps> =>
pages.map(({ url }, index) => ({
url,
pageNumber: index + 1,
currentPage,
totalPages,
label: getLabel(index + 1),
as,
}));
const createPaginationListItems = (
parsedPages: Array<PaginationListItemProps>
) => parsedPages.map(page => <PaginationListItem key={page.url} {...page} />);
// The minimum amount of elements are first page, current page, and last page
const MINIMUM_AMOUNT_OF_ELEMENTS = 3;
// Not more than two ellipses will be shown at the same time
const MAXIMUM_AMOUNT_OF_ELLIPSES = 2;
// The logic of this custom hook has taken the internal logic of
// React MUI's Pagination component as reference. More info here:
// https://github.com/mui/material-ui/blob/master/packages/mui-material/src/usePagination/usePagination.js
export const useGetPageElements = (
currentPage: ComponentProps<typeof BasePagination>['currentPage'],
pages: ComponentProps<typeof BasePagination>['pages'],
currentPageSiblingsCount: number,
as: LinkLike,
getLabel: (pageNumber: number) => string
) => {
const totalPages = pages.length;
const parsedPages = parsePages(pages, currentPage, totalPages, as, getLabel);
const currentPageIndex = currentPage - 1;
// We multiply it by two (2) as siblings are located on both left and right sides
// of the current page
const totalSiblingsCount = 2 * currentPageSiblingsCount;
const visiblePages =
totalSiblingsCount +
MINIMUM_AMOUNT_OF_ELEMENTS +
MAXIMUM_AMOUNT_OF_ELLIPSES;
// When there are more pages than the visible pages to be shown
// we do not need to perform any calculations
if (totalPages <= visiblePages) {
return createPaginationListItems(parsedPages);
}
// The index of the far-left sibling of the current page
const leftSiblingsFirstIndex = Math.max(
currentPageIndex - currentPageSiblingsCount,
1
);
// The index of the far-right sibling of the current page
const rightSiblingsLastIndex = Math.min(
currentPageIndex + currentPageSiblingsCount + 1,
totalPages
);
const firstIndex = 0;
const lastIndex = totalPages - 1;
// If there are at least two (2) elements between the far-left sibling of
// the current page, and the first page, we should show left ellipsis
// between them
const hasLeftEllipsis = leftSiblingsFirstIndex > firstIndex + 2;
// If there are at least two (2) elements between the far-right sibling of
// the current page, and the last page, we should show right ellipsis
// between them
const hasRightEllipsis = rightSiblingsLastIndex < lastIndex - 1;
if (!hasLeftEllipsis && hasRightEllipsis) {
const leftPagesLastIndex = MINIMUM_AMOUNT_OF_ELEMENTS + totalSiblingsCount;
const leftPages = parsedPages.slice(firstIndex, leftPagesLastIndex);
return [
...createPaginationListItems(leftPages),
<Ellipsis key="ellipsis" />,
...createPaginationListItems(parsedPages.slice(lastIndex)),
];
}
if (hasLeftEllipsis && !hasRightEllipsis) {
const rightPagesFirstIndex =
MINIMUM_AMOUNT_OF_ELEMENTS + totalSiblingsCount;
const rightPages = parsedPages.slice(totalPages - rightPagesFirstIndex);
return [
...createPaginationListItems(
parsedPages.slice(firstIndex, firstIndex + 1)
),
<Ellipsis key="ellipsis" />,
...createPaginationListItems(rightPages),
];
}
if (hasLeftEllipsis && hasRightEllipsis) {
const middlePages = parsedPages.slice(
leftSiblingsFirstIndex,
rightSiblingsLastIndex
);
return [
...createPaginationListItems(
parsedPages.slice(firstIndex, firstIndex + 1)
),
<Ellipsis key="ellipsis-1" />,
...createPaginationListItems(middlePages),
<Ellipsis key="ellipsis-2" />,
...createPaginationListItems(parsedPages.slice(lastIndex)),
];
}
};