aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/molecules/nav/pagination.tsx
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-10-24 18:48:57 +0200
committerArmand Philippot <git@armandphilippot.com>2023-11-11 18:15:24 +0100
commit3f8ae3f558446aba3870e90c899db25ad9321499 (patch)
tree30824d02705337309d9223f8c5a6bd8fc41d482c /src/components/molecules/nav/pagination.tsx
parent98044be08600daf6bd7c7e1a4adada319dbcbbaf (diff)
refactor(components): rewrite Pagination component
Diffstat (limited to 'src/components/molecules/nav/pagination.tsx')
-rw-r--r--src/components/molecules/nav/pagination.tsx216
1 files changed, 0 insertions, 216 deletions
diff --git a/src/components/molecules/nav/pagination.tsx b/src/components/molecules/nav/pagination.tsx
deleted file mode 100644
index 73517c3..0000000
--- a/src/components/molecules/nav/pagination.tsx
+++ /dev/null
@@ -1,216 +0,0 @@
-/* eslint-disable max-statements */
-import { type FC, Fragment, type ReactNode } from 'react';
-import { useIntl } from 'react-intl';
-import { ButtonLink, List, ListItem } from '../../atoms';
-import styles from './pagination.module.scss';
-
-export type PaginationProps = {
- /**
- * An accessible name for the pagination.
- */
- 'aria-label'?: string;
- /**
- * The url part before page number. Default: /page/
- */
- baseUrl?: string;
- /**
- * Set additional classnames to the pagination wrapper.
- */
- className?: string;
- /**
- * The current page number.
- */
- current: number;
- /**
- * The number of items per page.
- */
- perPage: number;
- /**
- * The number of siblings on one side of the current page. Default: 1.
- */
- siblings?: number;
- /**
- * The total number of items.
- */
- total: number;
-};
-
-/**
- * Pagination component
- *
- * Render a page-based navigation.
- */
-export const Pagination: FC<PaginationProps> = ({
- baseUrl = '/page/',
- className = '',
- current,
- perPage,
- siblings = 2,
- total,
- ...props
-}) => {
- const intl = useIntl();
- const totalPages = Math.round(total / perPage);
- const hasPreviousPage = current > 1;
- const previousPageName = intl.formatMessage(
- {
- defaultMessage: '{icon} Previous page',
- description: 'Pagination: previous page link',
- id: 'aMFqPH',
- },
- { icon: '←' }
- );
- const previousPageUrl = `${baseUrl}${current - 1}`;
- const hasNextPage = current < totalPages;
- const nextPageName = intl.formatMessage(
- {
- defaultMessage: 'Next page {icon}',
- description: 'Pagination: Next page link',
- id: 'R4yaW6',
- },
- { icon: '→' }
- );
- const nextPageUrl = `${baseUrl}${current + 1}`;
-
- /**
- * Create an array with a range of values from start value to end value.
- *
- * @param {number} start - The first value.
- * @param {number} end - The last value.
- * @returns {number[]} An array from start value to end value.
- */
- const range = (start: number, end: number): number[] =>
- Array.from({ length: end - start + 1 }, (_, index) => index + start);
-
- /**
- * Get the pagination range.
- *
- * @param currentPage - The current page number.
- * @param maxPages - The total pages number.
- * @returns {(number|string)[]} An array of page numbers with or without dots.
- */
- const getPaginationRange = (
- currentPage: number,
- maxPages: number
- ): (number | string)[] => {
- const dots = '\u2026';
-
- /**
- * Show left dots if current page less left siblings is greater than the
- * first two pages.
- */
- const hasLeftDots = currentPage - siblings > 2;
-
- /**
- * Show right dots if current page plus right siblings is lower than the
- * total of pages less the last page.
- */
- const hasRightDots = currentPage + siblings < maxPages - 1;
-
- if (hasLeftDots && hasRightDots) {
- const middleItems = range(currentPage - siblings, currentPage + siblings);
- return [1, dots, ...middleItems, dots, maxPages];
- }
-
- if (hasLeftDots) {
- const rightItems = range(currentPage - siblings, maxPages);
- return [1, dots, ...rightItems];
- }
-
- if (hasRightDots) {
- const leftItems = range(1, currentPage + siblings);
- return [...leftItems, dots, maxPages];
- }
-
- return range(1, maxPages);
- };
-
- /**
- * Get a link or a span wrapped in a list item.
- *
- * @param {string} id - The item id.
- * @param {ReactNode} body - The link body.
- * @param {string} [link] - An URL.
- * @returns {JSX.Element} The list item.
- */
- const getItem = (id: string, body: ReactNode, link?: string): JSX.Element => {
- const linkModifier = id.startsWith('page') ? 'link--number' : '';
- const kind = id === 'previous' || id === 'next' ? 'tertiary' : 'secondary';
- const linkClass = `${styles.link} ${styles[linkModifier]}`;
- const disabledLinkClass = `${styles.link} ${styles['link--disabled']}`;
-
- return (
- <ListItem className={styles.item}>
- {link ? (
- <ButtonLink className={linkClass} kind={kind} to={link}>
- {body}
- </ButtonLink>
- ) : (
- <span className={disabledLinkClass}>{body}</span>
- )}
- </ListItem>
- );
- };
-
- /**
- * Get the list of pages.
- *
- * @param {number} currentPage - The current page number.
- * @param {number} maxPages - The total of pages.
- * @returns {JSX.Element[]} The list items.
- */
- const getPages = (currentPage: number, maxPages: number): JSX.Element[] => {
- const pagesRange = getPaginationRange(currentPage, maxPages);
-
- return pagesRange.map((page, index) => {
- const id = typeof page === 'string' ? `dots-${index}` : `page-${page}`;
- const currentPagePrefix = intl.formatMessage({
- defaultMessage: 'You are here:',
- description: 'Pagination: current page indication',
- id: 'yE/Jdz',
- });
- const body =
- typeof page === 'string'
- ? page // dots
- : intl.formatMessage(
- {
- defaultMessage: '<a11y>Page </a11y>{number}',
- description: 'Pagination: page number',
- id: 'TSXPzr',
- },
- {
- number: page,
- a11y: (chunks: ReactNode) => (
- // eslint-disable-next-line react/jsx-no-literals
- <span className="screen-reader-text">
- {page === currentPage && currentPagePrefix}
- {chunks}
- </span>
- ),
- }
- );
- const url =
- page === currentPage || typeof page === 'string'
- ? undefined
- : `${baseUrl}${page}`;
-
- return <Fragment key={id}>{getItem(id, body, url)}</Fragment>;
- });
- };
- const navClass = `${styles.wrapper} ${className}`;
- const listClass = `${styles.list} ${styles['list--pages']}`;
-
- return (
- <nav {...props} className={navClass}>
- <List className={listClass} hideMarker isInline spacing="2xs">
- {getPages(current, totalPages)}
- </List>
- <List className={styles.list} hideMarker isInline spacing="xs">
- {hasPreviousPage
- ? getItem('previous', previousPageName, previousPageUrl)
- : null}
- {hasNextPage ? getItem('next', nextPageName, nextPageUrl) : null}
- </List>
- </nav>
- );
-};