diff --git a/src/Pagination/NextButton.tsx b/src/Pagination/NextButton.tsx index ef0d60739..242780fb6 100644 --- a/src/Pagination/NextButton.tsx +++ b/src/Pagination/NextButton.tsx @@ -1,11 +1,17 @@ -// @ts-nocheck -import React from "react"; +import React, { ReactNode } from "react"; import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; import { Icon } from "../Icon"; import PaginationButton from "./PaginationButton"; -const NextButton = ({ disabled, onClick, label, "aria-label": ariaLabel }) => { +type NextButtonProps = { + disabled: boolean; + onClick: React.MouseEventHandler; + label: ReactNode; + ariaLabel: string; +}; + +const NextButton = ({ disabled, onClick, label, ariaLabel }: NextButtonProps) => { const { t } = useTranslation(); return ( @@ -18,14 +24,12 @@ NextButton.propTypes = { disabled: PropTypes.bool, onClick: PropTypes.func, label: PropTypes.node, - "aria-label": PropTypes.string, + ariaLabel: PropTypes.string, }; NextButton.defaultProps = { disabled: false, onClick: null, - label: undefined, - "aria-label": undefined, }; export default NextButton; diff --git a/src/Pagination/PageNumber.tsx b/src/Pagination/PageNumber.tsx index eb4b60a46..6fe2d6f3f 100644 --- a/src/Pagination/PageNumber.tsx +++ b/src/Pagination/PageNumber.tsx @@ -1,7 +1,11 @@ import styled from "styled-components"; import PaginationButton from "./PaginationButton"; -const PageNumber = styled(PaginationButton)(({ theme, currentPage }: any) => ({ +type PageNumberProps = { + currentPage: boolean; +}; + +const PageNumber = styled(PaginationButton)(({ theme, currentPage }) => ({ background: currentPage ? theme.colors.darkBlue : "transparent", color: currentPage ? theme.colors.whiteGrey : theme.colors.black, })); diff --git a/src/Pagination/Pagination.spec.tsx b/src/Pagination/Pagination.spec.tsx index 62ab5ee5a..574af3069 100644 --- a/src/Pagination/Pagination.spec.tsx +++ b/src/Pagination/Pagination.spec.tsx @@ -1,29 +1,29 @@ import React from "react"; import { fireEvent } from "@testing-library/react"; import { renderWithNDSProvider } from "../NDSProvider/renderWithNDSProvider.spec-utils"; -import { getPageItemstoDisplay } from "./Pagination"; +import { getPageItemsToDisplay } from "./Pagination"; import { Pagination } from "."; describe("Pagination", () => { describe("truncation", () => { it("it returns an array of page numbers without truncation when there are less than 6 pages", () => { - expect(getPageItemstoDisplay(6, 2)).toEqual([1, 2, 3, 4, 5, 6]); - expect(getPageItemstoDisplay(1, 1)).toEqual([1]); - expect(getPageItemstoDisplay(5, 1)).toEqual([1, 2, 3, 4, 5]); + expect(getPageItemsToDisplay(6, 2)).toEqual([1, 2, 3, 4, 5, 6]); + expect(getPageItemsToDisplay(1, 1)).toEqual([1]); + expect(getPageItemsToDisplay(5, 1)).toEqual([1, 2, 3, 4, 5]); }); it("it returns an array of page numbers with truncation at the beginning when current page is 5 pages from the end", () => { - expect(getPageItemstoDisplay(12, 10)).toEqual([1, "...", 8, 9, 10, 11, 12]); - expect(getPageItemstoDisplay(20, 20)).toEqual([1, "...", 16, 17, 18, 19, 20]); - expect(getPageItemstoDisplay(12, 8)).toEqual([1, "...", 8, 9, 10, 11, 12]); + expect(getPageItemsToDisplay(12, 10)).toEqual([1, "...", 8, 9, 10, 11, 12]); + expect(getPageItemsToDisplay(20, 20)).toEqual([1, "...", 16, 17, 18, 19, 20]); + expect(getPageItemsToDisplay(12, 8)).toEqual([1, "...", 8, 9, 10, 11, 12]); }); it("it returns an array of page numbers with truncation at the end when current page is 5 pages from the beginning", () => { - expect(getPageItemstoDisplay(15, 1)).toEqual([1, 2, 3, 4, 5, "...", 15]); - expect(getPageItemstoDisplay(7, 5)).toEqual([1, 2, 3, 4, 5, "...", 7]); - expect(getPageItemstoDisplay(8, 2)).toEqual([1, 2, 3, 4, 5, "...", 8]); + expect(getPageItemsToDisplay(15, 1)).toEqual([1, 2, 3, 4, 5, "...", 15]); + expect(getPageItemsToDisplay(7, 5)).toEqual([1, 2, 3, 4, 5, "...", 7]); + expect(getPageItemsToDisplay(8, 2)).toEqual([1, 2, 3, 4, 5, "...", 8]); }); it("it returns an array of page numbers with truncation at the both sides is in the middle", () => { - expect(getPageItemstoDisplay(15, 6)).toEqual([1, "...", 5, 6, 7, 8, "...", 15]); - expect(getPageItemstoDisplay(15, 10)).toEqual([1, "...", 9, 10, 11, 12, "...", 15]); + expect(getPageItemsToDisplay(15, 6)).toEqual([1, "...", 5, 6, 7, 8, "...", 15]); + expect(getPageItemsToDisplay(15, 10)).toEqual([1, "...", 9, 10, 11, 12, "...", 15]); }); }); describe("callbacks", () => { diff --git a/src/Pagination/Pagination.tsx b/src/Pagination/Pagination.tsx index 44b6bcf7f..f67ba3290 100644 --- a/src/Pagination/Pagination.tsx +++ b/src/Pagination/Pagination.tsx @@ -1,43 +1,59 @@ -// @ts-nocheck -import React from "react"; +import React, { ReactNode, RefObject } from "react"; import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; import { Flex } from "../Flex"; import { Text } from "../Type"; +import { FlexProps } from "../Flex/Flex"; import PageNumber from "./PageNumber"; import PreviousButton from "./PreviousButton"; import NextButton from "./NextButton"; +import { flushSync } from "react-dom"; -const SEPERATOR = "..."; +const SEPARATOR = "..."; -export const getPageItemstoDisplay = (totalPages, currentPage) => { - const pages = Array.from({ length: totalPages }, (v, k) => k + 1); +export const getPageItemsToDisplay = (totalPages: number, currentPage: number) => { const MAX_PAGES_TO_SHOW = 6; + + const pages = Array.from({ length: totalPages }, (v, i) => i + 1); + if (totalPages <= MAX_PAGES_TO_SHOW) return pages; if (currentPage <= MAX_PAGES_TO_SHOW - 1) { - return [...pages.slice(0, 5), SEPERATOR, totalPages]; + return [...pages.slice(0, 5), SEPARATOR, totalPages]; } if (currentPage > totalPages - 5) { - return [1, SEPERATOR, ...pages.slice(totalPages - 5)]; + return [1, SEPARATOR, ...pages.slice(totalPages - 5)]; } - return [1, SEPERATOR, ...pages.slice(currentPage - 2, currentPage + 2), SEPERATOR, totalPages]; + return [1, SEPARATOR, ...pages.slice(currentPage - 2, currentPage + 2), SEPARATOR, totalPages]; +}; + +type PaginationProps = FlexProps & { + currentPage: number; + totalPages: number; + onNext?: () => void; + onPrevious?: () => void; + onSelectPage?: (page: string | number) => void; + nextLabel?: ReactNode; + nextAriaLabel?: string; + previousLabel?: ReactNode; + previousAriaLabel?: string; }; -const Pagination: React.FC = (props) => { - const { - currentPage, - totalPages, - onNext, - onPrevious, - onSelectPage, - nextAriaLabel, - nextLabel, - previousAriaLabel, +function Pagination({ + currentPage, + totalPages, + onNext, + onPrevious, + onSelectPage, + nextAriaLabel, + nextLabel, + previousAriaLabel, + previousLabel, previousLabel, - "aria-label": ariaLabel, - ...restProps - } = props; + "aria-label": ariaLabel, + ...restProps +}: PaginationProps) { const { t } = useTranslation(); + return ( = (props) => { ariaLabel={previousAriaLabel} label={previousLabel} /> - {getPageItemstoDisplay(totalPages, currentPage).map((page, index) => { + {getPageItemsToDisplay(totalPages, currentPage).map((page, index) => { const isCurrentPage = currentPage === page; - if (page === SEPERATOR) + if (page === SEPARATOR) return ( // eslint-disable-next-line react/no-array-index-key - {SEPERATOR} + {SEPARATOR} ); else @@ -62,7 +78,7 @@ const Pagination: React.FC = (props) => { aria-current={isCurrentPage} currentPage={isCurrentPage} disabled={isCurrentPage} - aria-label={isCurrentPage ? null : t("go to page", { count: page })} + aria-label={isCurrentPage ? null : t("go to page", { count: Number(page) })} key={page} onClick={() => onSelectPage(page)} > @@ -73,7 +89,7 @@ const Pagination: React.FC = (props) => { ); -}; +} Pagination.propTypes = { currentPage: PropTypes.number.isRequired, diff --git a/src/Pagination/PaginationButton.tsx b/src/Pagination/PaginationButton.tsx index 1c4aeb81a..fb81567ff 100644 --- a/src/Pagination/PaginationButton.tsx +++ b/src/Pagination/PaginationButton.tsx @@ -1,11 +1,12 @@ import styled from "styled-components"; +import { DefaultNDSThemeType } from "../theme.type"; -const getHoverBackground = (currentPage, disabled, theme) => { +const getHoverBackground = (currentPage: boolean, disabled: boolean, theme: DefaultNDSThemeType) => { if (currentPage) { return theme.colors.darkBlue; } if (disabled) { - return "inital"; + return "initial"; } return theme.colors.lightGrey; }; diff --git a/src/Pagination/PreviousButton.tsx b/src/Pagination/PreviousButton.tsx index a9b286bbf..b95bd2599 100644 --- a/src/Pagination/PreviousButton.tsx +++ b/src/Pagination/PreviousButton.tsx @@ -1,11 +1,17 @@ -// @ts-nocheck -import React from "react"; +import React, { ReactNode } from "react"; import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; import { Icon } from "../Icon"; import PaginationButton from "./PaginationButton"; -const PreviousButton = ({ disabled, onClick, label, "aria-label": ariaLabel }: any) => { +type PreviousButtonProps = { + disabled: boolean; + onClick: React.MouseEventHandler; + label: ReactNode; + ariaLabel: string; +}; + +const PreviousButton = ({ disabled, onClick, label, ariaLabel }: PreviousButtonProps) => { const { t } = useTranslation(); return ( @@ -18,14 +24,12 @@ PreviousButton.propTypes = { disabled: PropTypes.bool, onClick: PropTypes.func, label: PropTypes.node, - "aria-label": PropTypes.string, + ariaLabel: PropTypes.string, }; PreviousButton.defaultProps = { disabled: false, onClick: null, - label: undefined, - "aria-label": undefined, }; export default PreviousButton;