import React from 'react';
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';
import { usePagination } from './Pagination';
const leftCaret = '\u2039'; // ‹
const rightCaret = '\u203A'; // ›
export type PaginationControlsProps = {
/* Allows for custom aria-label. */
'aria-label'?: string;
/* If enabled and there are no items, the component is hidden. */
autoHide?: boolean;
/* When `true` an ellipse is displayed when there are more pages outside of the page range. */
breakLabel?: boolean;
/* */
className?: string;
/* If enabled, shows next and previous arrows on the "Next" and "Back" buttons. */
directionLinks?: boolean;
/* Add bootstrap styles to list element. */
listClassName?: string;
/* The number of pages to display on the ends when there are pages outside of the page range. **Default:** `2`. */
marginPages?: number;
/* The number of pages to display at a time. **Default**: `5`. */
pageRange?: number;
/* When `showPaginationText` is true, this function allows for customization of the pagination text that is displayed. */
populatePaginationText?: (lower: number, upper: number, total: number) => React.ReactNode;
/* When true, this will show pagination text next to the controls describing the current page and page range. This defaults to the following: 1-50 of 100. */
showPaginationText?: boolean;
};
const PaginationControls = ({
directionLinks = false,
autoHide = true,
pageRange = 5,
marginPages = 2,
breakLabel = true,
showPaginationText = false,
populatePaginationText,
...rest
}: PaginationControlsProps): React.JSX.Element | null => {
const { pageCount, currentPage, setPage, lower, upper, total } = usePagination();
const createItem = (pageNumber: number) => (
setPage(pageNumber)}
type="button"
aria-label={`Go to page ${pageNumber}`}
aria-current={currentPage === pageNumber}
>
{pageNumber}
);
const getForwardJump = () => {
const forwardJump = currentPage + pageRange;
return Math.min(forwardJump, pageCount);
};
const getBackwardJump = () => {
const backwardJump = currentPage - pageRange;
return Math.max(backwardJump, 1);
};
const handleBreakClick = (index: number) => {
setPage(currentPage < index ? getForwardJump() : getBackwardJump());
};
const createBreak = (index: number) => (
handleBreakClick(index)}
type="button"
aria-label={
currentPage < index
? `Jump forwards to page ${getForwardJump()}`
: `Jump backwards to page ${getBackwardJump()}`
}
>
…
);
// Todo - Look into creating a PR for allowing custom components in the below repo
// https://github.com/AdeleD/react-paginate/blob/master/react_components/PaginationBoxView.js#L216
const paginate = () => {
const items = [];
const selected = currentPage - 1;
if (pageCount <= pageRange) {
for (let index = 0; index < pageCount; index++) {
items.push(createItem(index + 1));
}
} else {
let leftSide = pageRange / 2;
let rightSide = pageRange - leftSide;
if (selected > pageCount - leftSide) {
rightSide = pageCount - selected;
leftSide = pageRange - rightSide;
} else if (selected < leftSide) {
leftSide = selected;
rightSide = pageRange - leftSide;
}
let breakView;
let pageNumber;
for (let index = 0; index < pageCount; index++) {
pageNumber = index + 1;
if (
pageNumber <= marginPages ||
pageNumber > pageCount - marginPages ||
(index >= selected - leftSide && index <= selected + rightSide)
) {
items.push(createItem(pageNumber));
} else if (items.at(-1) !== breakView && breakLabel) {
breakView = createBreak(pageNumber);
items.push(breakView);
}
}
}
return items;
};
return pageCount > 1 || !autoHide ? (
{directionLinks ? (
(currentPage === 1 ? null : setPage(currentPage - 1))}
type="button"
aria-disabled={currentPage === 1}
previous
>
{leftCaret} Prev
) : (
''
)}
{paginate()}
{directionLinks ? (
(currentPage === pageCount ? null : setPage(currentPage + 1))}
type="button"
aria-disabled={currentPage === pageCount}
next
>
Next {rightCaret}
) : (
''
)}
{showPaginationText && (
{populatePaginationText ? populatePaginationText(lower, upper, total) : `${lower}-${upper} of ${total}`}
)}
) : null;
};
export default PaginationControls;