diff --git a/CHANGELOG.md b/CHANGELOG.md index 618694e..486a1b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fix + +- paging when displayed inside a form. + +### Added + +- possibility to customize back/next first/last page navigation components. + ### Removed - remove cypress declarations diff --git a/cypress/cypress/component/Paging/Paging.cy.tsx b/cypress/cypress/component/Paging/Paging.cy.tsx index 9404959..0ede16e 100644 --- a/cypress/cypress/component/Paging/Paging.cy.tsx +++ b/cypress/cypress/component/Paging/Paging.cy.tsx @@ -100,4 +100,59 @@ describe("Paging.cy.tsx", () => { .replace("{total}", (pages * itemsPerPage).toString()), ); }); + + it("custom navigationComponents work correctly", () => { + const itemsPerPage = 10; + const pages = 5; + const currentPage = 3; + const translations = { showedItemsText: "Item {from} to {to} from {total}", itemsPerPageDropdown: "Items per page" }; + const customNavigationComponents = { + backPageComponent: "←", + nextPageComponent: "→", + firstPageComponent: "⇤", + lastPageComponent: "⇥", + }; + + mount( + , + ); + + // Check that custom navigation components are rendered + cy.get("[data-cy-root] > .container-fluid > .row > .col-6:nth-of-type(2) > .btn-group > button.btn").then( + (items: JQuery) => { + // Verify custom symbols are present + cy.wrap(items.filter((_, item) => item.textContent === "⇤")) + .should("exist") + .and("be.visible"); + cy.wrap(items.filter((_, item) => item.textContent === "←")) + .should("exist") + .and("be.visible"); + cy.wrap(items.filter((_, item) => item.textContent === "→")) + .should("exist") + .and("be.visible"); + cy.wrap(items.filter((_, item) => item.textContent === "⇥")) + .should("exist") + .and("be.visible"); + + // Test functionality with custom components + cy.wrap(items.filter((_, item) => item.textContent === "⇤")).click(); + cy.get("@setCurrentPage").should("be.calledWith", 1); + cy.wrap(items.filter((_, item) => item.textContent === "←")).click(); + cy.get("@setCurrentPage").should("be.calledWith", currentPage - 1); + cy.wrap(items.filter((_, item) => item.textContent === "→")).click(); + cy.get("@setCurrentPage").should("be.calledWith", currentPage + 1); + cy.wrap(items.filter((_, item) => item.textContent === "⇥")).click(); + cy.get("@setCurrentPage").should("be.calledWith", pages); + }, + ); + }); }); diff --git a/src/lib/Paging/Paging.tsx b/src/lib/Paging/Paging.tsx index 469f0dc..6714a12 100644 --- a/src/lib/Paging/Paging.tsx +++ b/src/lib/Paging/Paging.tsx @@ -1,5 +1,5 @@ import { Button, ButtonGroup, Col, DropdownItem, DropdownMenu, DropdownToggle, Row, UncontrolledButtonDropdown } from "reactstrap"; -import { useMemo } from "react"; +import { ReactNode, useMemo } from "react"; interface PagingProps { currentItemsPerPage: number; @@ -8,6 +8,7 @@ interface PagingProps { currentRecordCount: number; pagingPossible?: boolean; translations: PagingTranslations; + navigationComponents?: PagingNavigationComponents; possiblePageItemCounts?: number[]; maxPagesShown?: number; showControls?: boolean; @@ -21,6 +22,20 @@ interface PagingTranslations { itemsPerPageDropdown: string; } +interface PagingNavigationComponents { + backPageComponent: ReactNode; + nextPageComponent: ReactNode; + firstPageComponent: ReactNode; + lastPageComponent: ReactNode; +} + +const defaultNavigationComponents: PagingNavigationComponents = { + backPageComponent: "<", + nextPageComponent: ">", + firstPageComponent: "<<", + lastPageComponent: ">>", +}; + // eslint-disable-next-line complexity const Paging = ({ currentItemsPerPage, @@ -29,6 +44,7 @@ const Paging = ({ currentRecordCount, pagingPossible = true, translations, + navigationComponents = defaultNavigationComponents, possiblePageItemCounts, maxPagesShown = 7, showControls = true, @@ -36,6 +52,7 @@ const Paging = ({ setItemsPerPage, setCurrentPage, }: PagingProps) => { + const { backPageComponent, nextPageComponent, firstPageComponent, lastPageComponent } = navigationComponents; const maxPage = Math.ceil(totalRecords / currentItemsPerPage); const firstPageShown = Math.max(0, Math.min(currentPage - Math.ceil(maxPagesShown / 2), maxPage - maxPagesShown)); @@ -79,12 +96,12 @@ const Paging = ({ {showControls && ( )} {showControls && ( )} {Array.from({ length: maxPage + 1 }, (_, i) => i) @@ -97,12 +114,12 @@ const Paging = ({ ))} {showControls && ( )} {showControls && ( )} @@ -113,4 +130,4 @@ const Paging = ({ ); }; -export { Paging, PagingProps, PagingTranslations }; +export { Paging, PagingProps, PagingTranslations, PagingNavigationComponents }; diff --git a/styles/Form/_form.scss b/styles/Form/_form.scss index 87fa4bb..ae14c8c 100644 --- a/styles/Form/_form.scss +++ b/styles/Form/_form.scss @@ -1,4 +1,4 @@ -form div[role="group"] { +form div[role="group"]:not(.paging div[role="group"]) { display: flex; gap: 0.25rem;