UNPKG

3.78 kBJavaScriptView Raw
1import _extends from "@babel/runtime/helpers/esm/extends";
2import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3import { useControlled } from '@material-ui/core/utils';
4export default function usePagination(props = {}) {
5 // keep default values in sync with @default tags in Pagination.propTypes
6 const {
7 boundaryCount = 1,
8 componentName = 'usePagination',
9 count = 1,
10 defaultPage = 1,
11 disabled = false,
12 hideNextButton = false,
13 hidePrevButton = false,
14 onChange: handleChange,
15 page: pageProp,
16 showFirstButton = false,
17 showLastButton = false,
18 siblingCount = 1
19 } = props,
20 other = _objectWithoutPropertiesLoose(props, ["boundaryCount", "componentName", "count", "defaultPage", "disabled", "hideNextButton", "hidePrevButton", "onChange", "page", "showFirstButton", "showLastButton", "siblingCount"]);
21
22 const [page, setPageState] = useControlled({
23 controlled: pageProp,
24 default: defaultPage,
25 name: componentName,
26 state: 'page'
27 });
28
29 const handleClick = (event, value) => {
30 if (!pageProp) {
31 setPageState(value);
32 }
33
34 if (handleChange) {
35 handleChange(event, value);
36 }
37 }; // https://dev.to/namirsab/comment/2050
38
39
40 const range = (start, end) => {
41 const length = end - start + 1;
42 return Array.from({
43 length
44 }, (_, i) => start + i);
45 };
46
47 const startPages = range(1, Math.min(boundaryCount, count));
48 const endPages = range(Math.max(count - boundaryCount + 1, boundaryCount + 1), count);
49 const siblingsStart = Math.max(Math.min( // Natural start
50 page - siblingCount, // Lower boundary when page is high
51 count - boundaryCount - siblingCount * 2 - 1), // Greater than startPages
52 boundaryCount + 2);
53 const siblingsEnd = Math.min(Math.max( // Natural end
54 page + siblingCount, // Upper boundary when page is low
55 boundaryCount + siblingCount * 2 + 2), // Less than endPages
56 endPages[0] - 2); // Basic list of items to render
57 // e.g. itemList = ['first', 'previous', 1, 'ellipsis', 4, 5, 6, 'ellipsis', 10, 'next', 'last']
58
59 const itemList = [...(showFirstButton ? ['first'] : []), ...(hidePrevButton ? [] : ['previous']), ...startPages, // Start ellipsis
60 // eslint-disable-next-line no-nested-ternary
61 ...(siblingsStart > boundaryCount + 2 ? ['start-ellipsis'] : boundaryCount + 1 < count - boundaryCount ? [boundaryCount + 1] : []), // Sibling pages
62 ...range(siblingsStart, siblingsEnd), // End ellipsis
63 // eslint-disable-next-line no-nested-ternary
64 ...(siblingsEnd < count - boundaryCount - 1 ? ['end-ellipsis'] : count - boundaryCount > boundaryCount ? [count - boundaryCount] : []), ...endPages, ...(hideNextButton ? [] : ['next']), ...(showLastButton ? ['last'] : [])]; // Map the button type to its page number
65
66 const buttonPage = type => {
67 switch (type) {
68 case 'first':
69 return 1;
70
71 case 'previous':
72 return page - 1;
73
74 case 'next':
75 return page + 1;
76
77 case 'last':
78 return count;
79
80 default:
81 return null;
82 }
83 }; // Convert the basic item list to PaginationItem props objects
84
85
86 const items = itemList.map(item => {
87 return typeof item === 'number' ? {
88 onClick: event => {
89 handleClick(event, item);
90 },
91 type: 'page',
92 page: item,
93 selected: item === page,
94 disabled,
95 'aria-current': item === page ? 'true' : undefined
96 } : {
97 onClick: event => {
98 handleClick(event, buttonPage(item));
99 },
100 type: item,
101 page: buttonPage(item),
102 selected: false,
103 disabled: disabled || item.indexOf('ellipsis') === -1 && (item === 'next' || item === 'last' ? page >= count : page <= 1)
104 };
105 });
106 return _extends({
107 items
108 }, other);
109}
\No newline at end of file