227 lines
5.8 KiB
TypeScript
227 lines
5.8 KiB
TypeScript
/**
|
|
* External dependencies
|
|
*/
|
|
import { __, sprintf } from '@wordpress/i18n';
|
|
import classNames from 'classnames';
|
|
import { Label } from '@woocommerce/blocks-components';
|
|
|
|
/**
|
|
* Internal dependencies
|
|
*/
|
|
import { getIndexes } from './utils';
|
|
import './style.scss';
|
|
|
|
interface PaginationProps {
|
|
/**
|
|
* Number of the page currently being displayed.
|
|
*/
|
|
currentPage: number;
|
|
/**
|
|
* Total number of pages.
|
|
*/
|
|
totalPages: number;
|
|
/**
|
|
* Displays first and last pages if they are not in the current range of pages displayed.
|
|
*/
|
|
displayFirstAndLastPages?: boolean;
|
|
/**
|
|
* Displays arrows to navigate to the previous and next pages.
|
|
*/
|
|
displayNextAndPreviousArrows?: boolean;
|
|
/**
|
|
* Callback function called when the user triggers a page change.
|
|
*/
|
|
onPageChange: ( currentPage: number ) => void;
|
|
/**
|
|
* Number of pages to display at the same time, including the active page
|
|
* and the pages displayed before and after it. It doesn't include the first
|
|
* and last pages.
|
|
*/
|
|
pagesToDisplay?: number;
|
|
}
|
|
|
|
const Pagination = ( {
|
|
currentPage,
|
|
displayFirstAndLastPages = true,
|
|
displayNextAndPreviousArrows = true,
|
|
pagesToDisplay = 3,
|
|
onPageChange,
|
|
totalPages,
|
|
}: PaginationProps ): JSX.Element => {
|
|
let { minIndex, maxIndex } = getIndexes(
|
|
pagesToDisplay,
|
|
currentPage,
|
|
totalPages
|
|
);
|
|
|
|
const showFirstPage = displayFirstAndLastPages && Boolean( minIndex !== 1 );
|
|
const showLastPage =
|
|
displayFirstAndLastPages && Boolean( maxIndex !== totalPages );
|
|
const showFirstPageEllipsis =
|
|
displayFirstAndLastPages && Boolean( minIndex && minIndex > 3 );
|
|
const showLastPageEllipsis =
|
|
displayFirstAndLastPages &&
|
|
Boolean( maxIndex && maxIndex < totalPages - 2 );
|
|
|
|
// Handle the cases where there would be an ellipsis replacing one single page
|
|
if ( showFirstPage && minIndex === 3 ) {
|
|
minIndex = minIndex - 1;
|
|
}
|
|
if ( showLastPage && maxIndex === totalPages - 2 ) {
|
|
maxIndex = maxIndex + 1;
|
|
}
|
|
|
|
const pages = [];
|
|
if ( minIndex && maxIndex ) {
|
|
for ( let i = minIndex; i <= maxIndex; i++ ) {
|
|
pages.push( i );
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="wc-block-pagination wc-block-components-pagination">
|
|
<Label
|
|
screenReaderLabel={ __(
|
|
'Navigate to another page',
|
|
'woo-gutenberg-products-block'
|
|
) }
|
|
/>
|
|
{ displayNextAndPreviousArrows && (
|
|
<button
|
|
className="wc-block-pagination-page wc-block-components-pagination__page wc-block-components-pagination-page--arrow"
|
|
onClick={ () => onPageChange( currentPage - 1 ) }
|
|
title={ __(
|
|
'Previous page',
|
|
'woo-gutenberg-products-block'
|
|
) }
|
|
disabled={ currentPage <= 1 }
|
|
>
|
|
<Label
|
|
label="←"
|
|
screenReaderLabel={ __(
|
|
'Previous page',
|
|
'woo-gutenberg-products-block'
|
|
) }
|
|
/>
|
|
</button>
|
|
) }
|
|
{ showFirstPage && (
|
|
<button
|
|
className={ classNames(
|
|
'wc-block-pagination-page',
|
|
'wc-block-components-pagination__page',
|
|
{
|
|
'wc-block-pagination-page--active':
|
|
currentPage === 1,
|
|
'wc-block-components-pagination__page--active':
|
|
currentPage === 1,
|
|
}
|
|
) }
|
|
onClick={ () => onPageChange( 1 ) }
|
|
disabled={ currentPage === 1 }
|
|
>
|
|
<Label
|
|
label={ '1' }
|
|
screenReaderLabel={ sprintf(
|
|
/* translators: %d is the page number (1, 2, 3...). */
|
|
__( 'Page %d', 'woo-gutenberg-products-block' ),
|
|
1
|
|
) }
|
|
/>
|
|
</button>
|
|
) }
|
|
{ showFirstPageEllipsis && (
|
|
<span
|
|
className="wc-block-pagination-ellipsis wc-block-components-pagination__ellipsis"
|
|
aria-hidden="true"
|
|
>
|
|
{ __( '…', 'woo-gutenberg-products-block' ) }
|
|
</span>
|
|
) }
|
|
{ pages.map( ( page ) => {
|
|
return (
|
|
<button
|
|
key={ page }
|
|
className={ classNames(
|
|
'wc-block-pagination-page',
|
|
'wc-block-components-pagination__page',
|
|
{
|
|
'wc-block-pagination-page--active':
|
|
currentPage === page,
|
|
'wc-block-components-pagination__page--active':
|
|
currentPage === page,
|
|
}
|
|
) }
|
|
onClick={
|
|
currentPage === page
|
|
? undefined
|
|
: () => onPageChange( page )
|
|
}
|
|
disabled={ currentPage === page }
|
|
>
|
|
<Label
|
|
label={ page.toString() }
|
|
screenReaderLabel={ sprintf(
|
|
/* translators: %d is the page number (1, 2, 3...). */
|
|
__( 'Page %d', 'woo-gutenberg-products-block' ),
|
|
page
|
|
) }
|
|
/>
|
|
</button>
|
|
);
|
|
} ) }
|
|
{ showLastPageEllipsis && (
|
|
<span
|
|
className="wc-block-pagination-ellipsis wc-block-components-pagination__ellipsis"
|
|
aria-hidden="true"
|
|
>
|
|
{ __( '…', 'woo-gutenberg-products-block' ) }
|
|
</span>
|
|
) }
|
|
{ showLastPage && (
|
|
<button
|
|
className={ classNames(
|
|
'wc-block-pagination-page',
|
|
'wc-block-components-pagination__page',
|
|
{
|
|
'wc-block-pagination-page--active':
|
|
currentPage === totalPages,
|
|
'wc-block-components-pagination__page--active':
|
|
currentPage === totalPages,
|
|
}
|
|
) }
|
|
onClick={ () => onPageChange( totalPages ) }
|
|
disabled={ currentPage === totalPages }
|
|
>
|
|
<Label
|
|
label={ totalPages.toString() }
|
|
screenReaderLabel={ sprintf(
|
|
/* translators: %d is the page number (1, 2, 3...). */
|
|
__( 'Page %d', 'woo-gutenberg-products-block' ),
|
|
totalPages
|
|
) }
|
|
/>
|
|
</button>
|
|
) }
|
|
{ displayNextAndPreviousArrows && (
|
|
<button
|
|
className="wc-block-pagination-page wc-block-components-pagination__page wc-block-components-pagination-page--arrow"
|
|
onClick={ () => onPageChange( currentPage + 1 ) }
|
|
title={ __( 'Next page', 'woo-gutenberg-products-block' ) }
|
|
disabled={ currentPage >= totalPages }
|
|
>
|
|
<Label
|
|
label="→"
|
|
screenReaderLabel={ __(
|
|
'Next page',
|
|
'woo-gutenberg-products-block'
|
|
) }
|
|
/>
|
|
</button>
|
|
) }
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Pagination;
|