import React from 'react'; import { css } from 'emotion'; import { stylesFactory } from '../../themes'; import { Button, ButtonVariant } from '../Button'; import { Icon } from '../Icon/Icon'; const PAGE_LENGTH_TO_CONDENSE = 8; interface Props { /** The current page index being shown. */ currentPage: number; /** Number of total pages. */ numberOfPages: number; /** Callback function for fetching the selected page */ onNavigate: (toPage: number) => void; /** When set to true and the pagination result is only one page it will not render the pagination at all */ hideWhenSinglePage?: boolean; } export const Pagination: React.FC = ({ currentPage, numberOfPages, onNavigate, hideWhenSinglePage }) => { const styles = getStyles(); const pages = [...new Array(numberOfPages).keys()]; const condensePages = numberOfPages > PAGE_LENGTH_TO_CONDENSE; const getListItem = (page: number, variant: 'primary' | 'secondary') => (
  • ); const pageButtons = pages.reduce((pagesToRender, pageIndex) => { const page = pageIndex + 1; const variant: ButtonVariant = page === currentPage ? 'primary' : 'secondary'; // The indexes at which to start and stop condensing pages const lowerBoundIndex = PAGE_LENGTH_TO_CONDENSE; const upperBoundIndex = numberOfPages - PAGE_LENGTH_TO_CONDENSE + 1; // When the indexes overlap one another this number is negative const differenceOfBounds = upperBoundIndex - lowerBoundIndex; const isFirstOrLastPage = page === 1 || page === numberOfPages; // This handles when the lowerBoundIndex < currentPage < upperBoundIndex const currentPageIsBetweenBounds = differenceOfBounds > -1 && currentPage >= lowerBoundIndex && currentPage <= upperBoundIndex; if (condensePages) { if ( isFirstOrLastPage || (currentPage < lowerBoundIndex && page < lowerBoundIndex) || (differenceOfBounds >= 0 && currentPage > upperBoundIndex && page > upperBoundIndex) || (differenceOfBounds < 0 && currentPage >= lowerBoundIndex && page > upperBoundIndex) || (currentPageIsBetweenBounds && page >= currentPage - 2 && page <= currentPage + 2) ) { // Renders a button for the page pagesToRender.push(getListItem(page, variant)); } else if ( (page === lowerBoundIndex && currentPage < lowerBoundIndex) || (page === upperBoundIndex && currentPage > upperBoundIndex) || (currentPageIsBetweenBounds && (page === currentPage - 3 || page === currentPage + 3)) ) { // Renders and ellipsis to represent condensed pages pagesToRender.push(
  • ); } } else { pagesToRender.push(getListItem(page, variant)); } return pagesToRender; }, []); if (hideWhenSinglePage && numberOfPages <= 1) { return null; } return (
    1. {pageButtons}
    ); }; const getStyles = stylesFactory(() => { return { container: css` float: right; `, item: css` display: inline-block; padding-left: 10px; margin-bottom: 5px; `, ellipsis: css` transform: rotate(90deg); `, }; });