diff --git a/package-lock.json b/package-lock.json index 52e1cb33..7bdf13c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21603,24 +21603,6 @@ } } }, - "node_modules/tailwindcss/node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/tapable": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz", diff --git a/src/lib/components/Pagination/Pagination.js b/src/lib/components/Pagination/Pagination.js index 1ce3d00b..4d87409d 100644 --- a/src/lib/components/Pagination/Pagination.js +++ b/src/lib/components/Pagination/Pagination.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2022 CERN. + * SPDX-FileCopyrightText: 2018-2026 CERN. * SPDX-License-Identifier: MIT */ @@ -10,6 +10,21 @@ import { Pagination as Paginator } from "semantic-ui-react"; import { AppContext } from "../ReactSearchKit"; import { ShouldRender } from "../ShouldRender"; +const a11yPaginationItem = (Item, itemProps) => ( + { + // ARIA button pattern: activate on "Space" in addition to "Enter". + // Mirrors the existing "Enter" handling in semantic-ui-react's PaginationItem. + if (event.key === " " && !itemProps.disabled) { + event.preventDefault(); // prevent page scroll + itemProps.onClick(event, itemProps); + } + }} + /> +); + const defaultOptions = { boundaryRangeCount: 1, siblingRangeCount: 1, @@ -141,6 +156,7 @@ const Element = ({ lastItem={showLast ? undefined : null} prevItem={showPrev ? undefined : null} nextItem={showNext ? undefined : null} + pageItem={a11yPaginationItem} size={size} {...props} /> diff --git a/src/lib/components/Pagination/Pagination.test.js b/src/lib/components/Pagination/Pagination.test.js new file mode 100644 index 00000000..20d0672b --- /dev/null +++ b/src/lib/components/Pagination/Pagination.test.js @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2026 CERN. + * SPDX-License-Identifier: MIT + */ +import { mount } from "enzyme"; +import React from "react"; +import { AppContext } from "../ReactSearchKit/AppContext"; +import Pagination from "./Pagination"; + +describe("test Pagination component", () => { + const mountPagination = (mockUpdateQueryPage) => + mount( + id }}> + + + ); + + const findPageItem = (wrapper, page) => + wrapper + .find("a.item") + .filterWhere( + (node) => node.prop("value") === page && node.prop("type") === "pageItem" + ); + + it("should change page when 'Space' is pressed on a page item", () => { + const mockUpdateQueryPage = jest.fn(); + const mockPreventDefault = jest.fn(); + const wrapper = mountPagination(mockUpdateQueryPage); + + findPageItem(wrapper, 2).simulate("keydown", { + key: " ", + preventDefault: mockPreventDefault, + }); + + expect(mockUpdateQueryPage).toHaveBeenCalledWith(2); + // page scroll on "Space" should be prevented + expect(mockPreventDefault).toHaveBeenCalled(); + }); + + it("should still change page when 'Enter' is pressed on a page item", () => { + const mockUpdateQueryPage = jest.fn(); + const wrapper = mountPagination(mockUpdateQueryPage); + + findPageItem(wrapper, 3).simulate("keydown", { + key: "Enter", + keyCode: 13, + which: 13, + }); + + expect(mockUpdateQueryPage).toHaveBeenCalledWith(3); + }); + + it("should expose page items with a 'button' role", () => { + const wrapper = mountPagination(jest.fn()); + + expect(findPageItem(wrapper, 2).prop("role")).toEqual("button"); + }); +});