Skip to content

Commit e6d10f8

Browse files
committed
feat(pagination): implement <Pagination> component
1 parent f553213 commit e6d10f8

File tree

5 files changed

+116
-3
lines changed

5 files changed

+116
-3
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ A React implementation of Boostrap v4 components.
77
## Roadmap
88

99
- [] Dialogs
10-
- [] Tabs
11-
- [] Pagination
10+
- [] UrlLinkedTabs
11+
- [] UrlLinkedPagination
1212
- [] Smartable
1313
- [] Form validations (dependent field validation)
1414
- [] Form Autocomplete

demo/demo.jsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom';
33

4-
import { StatefulTabs } from '../src/';
4+
import { StatefulTabs, Pagination } from '../src/';
55
import { FormExamples } from './FormExamples';
66
import { TableExamples } from './TableExamples';
77
import { TabsExamples } from './TabsExamples';
@@ -10,6 +10,7 @@ ReactDOM.render(
1010
<div className="mt-3">
1111
<StatefulTabs
1212
vertical={true}
13+
initialTab={3}
1314
tabs={[
1415
{
1516
title: 'Forms',
@@ -20,6 +21,7 @@ ReactDOM.render(
2021
content: <TableExamples />,
2122
},
2223
{ title: 'Tabs', content: <TabsExamples /> },
24+
{ title: 'Pagination', content: <PaginationExamples /> },
2325
]}
2426
/>
2527
</div>,
@@ -28,3 +30,7 @@ ReactDOM.render(
2830

2931
// eslint-disable-next-line no-undef
3032
module.hot.accept();
33+
34+
function PaginationExamples() {
35+
return <Pagination lastPage={10} actualPage={4} onSelect={console.log} />;
36+
}

src/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './forms';
22
export * from './table';
33
export * from './tabs';
4+
export * from './mixed';

src/mixed/Pagination.jsx

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
export function Pagination({
5+
actualPage,
6+
ariaLabel,
7+
firstLabel,
8+
lastLabel,
9+
lastPage,
10+
maxPageWindow,
11+
nextLabel,
12+
onSelect,
13+
previousLabel,
14+
}) {
15+
const pageWindow = Math.min(maxPageWindow, lastPage);
16+
const centerOfPageWindow = Math.max(Math.floor(pageWindow / 2), 2);
17+
const lastStartPage = Math.max(lastPage - pageWindow + 1, 1);
18+
const startPage = Math.max(Math.min(actualPage - centerOfPageWindow, lastStartPage), 1);
19+
const showPreviousNavigation = startPage > 1;
20+
21+
const pages = Array.from(
22+
{
23+
length: pageWindow,
24+
},
25+
(v, i) => startPage + i
26+
);
27+
28+
const select = (page) => (e) => {
29+
e.preventDefault();
30+
e.stopPropagation();
31+
onSelect(page);
32+
};
33+
34+
return (
35+
<nav aria-label={ariaLabel}>
36+
<ul className="pagination">
37+
{showPreviousNavigation && (
38+
<React.Fragment>
39+
<li className="page-item">
40+
<a className="page-link" href="" onClick={select(1)} aria-label={firstLabel}>
41+
<span aria-hidden="true">&laquo;</span>
42+
<span className="sr-only">{firstLabel}</span>
43+
</a>
44+
</li>
45+
46+
<li className="page-item">
47+
<a className="page-link" href="" onClick={select(actualPage - 1)} aria-label={previousLabel}>
48+
<span aria-hidden="true">&lsaquo;</span>
49+
<span className="sr-only">{previousLabel}</span>
50+
</a>
51+
</li>
52+
</React.Fragment>
53+
)}
54+
55+
{pages.map((page) => (
56+
<li key={`pages-${page}`} className={`page-item${actualPage === page ? ' active' : ''}`}>
57+
<a className="page-link" href="" onClick={select(page)}>
58+
{page}
59+
</a>
60+
</li>
61+
))}
62+
63+
{startPage < lastStartPage && (
64+
<React.Fragment>
65+
<li className="page-item">
66+
<a className="page-link" href="" onClick={select(actualPage + 1)} aria-label={nextLabel}>
67+
<span aria-hidden="true">&rsaquo;</span>
68+
<span className="sr-only">{nextLabel}</span>
69+
</a>
70+
</li>
71+
72+
<li className="page-item">
73+
<a className="page-link" href="" onClick={select(lastPage)} aria-label={lastLabel}>
74+
<span aria-hidden="true">&raquo;</span>
75+
<span className="sr-only">{lastLabel}</span>
76+
</a>
77+
</li>
78+
</React.Fragment>
79+
)}
80+
</ul>
81+
</nav>
82+
);
83+
}
84+
85+
Pagination.defaultProps = {
86+
actualPage: 1,
87+
ariaLabel: 'Page navigation',
88+
firstLabel: 'First',
89+
lastLabel: 'Last',
90+
maxPageWindow: 5,
91+
nextLabel: 'Next',
92+
previousLabel: 'Previous',
93+
};
94+
95+
Pagination.propTypes = {
96+
actualPage: PropTypes.number,
97+
ariaLabel: PropTypes.string,
98+
firstLabel: PropTypes.string,
99+
lastLabel: PropTypes.string,
100+
lastPage: PropTypes.number,
101+
maxPageWindow: PropTypes.number,
102+
nextLabel: PropTypes.string,
103+
onSelect: PropTypes.func.isRequired,
104+
previousLabel: PropTypes.string,
105+
};

src/mixed/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Pagination';

0 commit comments

Comments
 (0)