From c559371e289b4b24cfa85df92ddaa5feb0d8815f Mon Sep 17 00:00:00 2001 From: Zou Quan <2990918167@qq.com> Date: Mon, 1 Jun 2026 11:53:59 +0000 Subject: [PATCH 01/12] fix: improve pagination a11y semantics without locale fallback helper --- src/Pager.tsx | 14 +- src/Pagination.tsx | 61 +- tests/__snapshots__/demo.test.tsx.snap | 1494 ++++++++++++++++++---- tests/__snapshots__/simple.test.tsx.snap | 14 +- tests/index.test.tsx | 18 + 5 files changed, 1359 insertions(+), 242 deletions(-) diff --git a/src/Pager.tsx b/src/Pager.tsx index 0d1dcc4f..f56d6c78 100644 --- a/src/Pager.tsx +++ b/src/Pager.tsx @@ -6,6 +6,7 @@ import type { PaginationProps } from './interface'; export interface PagerProps extends Pick { rootPrefixCls: string; page: number; + pageLabel?: string; active?: boolean; className?: string; style?: React.CSSProperties; @@ -22,6 +23,7 @@ const Pager: React.FC = (props) => { const { rootPrefixCls, page, + pageLabel, active, className, style, @@ -50,7 +52,14 @@ const Pager: React.FC = (props) => { onKeyPress(e, onClick, page); }; - const pager = itemRender(page, 'page', {page}); + const pager = itemRender( + page, + 'page', + , + ); + const pagerLabel = `${pageLabel || 'Page'} ${page}`.trim(); return pager ? (
  • = (props) => { onClick={handleClick} onKeyDown={handleKeyPress} tabIndex={0} + role="button" + aria-label={pagerLabel} + aria-current={active ? 'page' : undefined} > {pager}
  • diff --git a/src/Pagination.tsx b/src/Pagination.tsx index 452203d4..38b459f3 100644 --- a/src/Pagination.tsx +++ b/src/Pagination.tsx @@ -116,12 +116,15 @@ const Pagination: React.FC = (props) => { function getItemIcon( icon: React.ReactNode | React.ComponentType, - label: string, + _label: string, + title?: string, ) { let iconNode = icon || ( + + ); + } + + const pager = itemRender(page, 'page', {page}); return pager ? (
  • diff --git a/src/Pagination.tsx b/src/Pagination.tsx index 53f0076c..f7074ef6 100644 --- a/src/Pagination.tsx +++ b/src/Pagination.tsx @@ -16,6 +16,8 @@ import Pager from './Pager'; const defaultItemRender: PaginationProps['itemRender'] = (_, __, element) => element; +type PaginationItemType = 'prev' | 'next' | 'jump-prev' | 'jump-next'; + function noop() {} function isInteger(v: number) { @@ -114,25 +116,62 @@ const Pagination: React.FC = (props) => { calculatePage(undefined, pageSize, total), current + (showLessItems ? 3 : 5), ); + const isDefaultRender = itemRender === defaultItemRender; - function getItemIcon( + function getIconNode( icon: React.ReactNode | React.ComponentType, - _label: string, + ) { + let iconNode = icon; + if (typeof icon === 'function') { + iconNode = React.createElement(icon, props); + } + return iconNode as React.ReactNode; + } + + function getItemIcon(title?: string) { + return ; + } + + function getControlButtonContent( + icon: React.ReactNode | React.ComponentType, + ) { + const iconNode = getIconNode(icon); + + if ( + React.isValidElement<{ children?: React.ReactNode }>(iconNode) && + typeof iconNode.type === 'string' && + (iconNode.type === 'button' || iconNode.type === 'a') + ) { + return iconNode.props.children; + } + + return iconNode; + } + + function renderDefaultControlButton( + type: PaginationItemType, + icon: React.ReactNode | React.ComponentType, + label?: string, title?: string, + onClick?: React.MouseEventHandler, + buttonDisabled?: boolean, ) { - let iconNode = icon || ( + const iconContent = getControlButtonContent(icon); + + return ( ); - if (typeof icon === 'function') { - iconNode = React.createElement(icon, props); - } - return iconNode as React.ReactNode; } function getValidValue(e: any): number { @@ -279,15 +318,21 @@ const Pagination: React.FC = (props) => { function renderPrev(prevPage: number) { const prevPageTitle = locale.prev_page || 'prev page'; - const prevButton = itemRender( - prevPage, - 'prev', - getItemIcon( - prevIcon, - prevPageTitle, - showTitle ? prevPageTitle : undefined, - ), - ); + const prevButton = isDefaultRender + ? renderDefaultControlButton( + 'prev', + prevIcon, + prevPageTitle, + showTitle ? prevPageTitle : undefined, + prevHandle, + !hasPrev, + ) + : itemRender( + prevPage, + 'prev', + getIconNode(prevIcon) || + getItemIcon(showTitle ? prevPageTitle : undefined), + ); return React.isValidElement(prevButton) ? React.cloneElement(prevButton, { disabled: !hasPrev }) : prevButton; @@ -295,15 +340,21 @@ const Pagination: React.FC = (props) => { function renderNext(nextPage: number) { const nextPageTitle = locale.next_page || 'next page'; - const nextButton = itemRender( - nextPage, - 'next', - getItemIcon( - nextIcon, - nextPageTitle, - showTitle ? nextPageTitle : undefined, - ), - ); + const nextButton = isDefaultRender + ? renderDefaultControlButton( + 'next', + nextIcon, + nextPageTitle, + showTitle ? nextPageTitle : undefined, + nextHandle, + !hasNext, + ) + : itemRender( + nextPage, + 'next', + getIconNode(nextIcon) || + getItemIcon(showTitle ? nextPageTitle : undefined), + ); return React.isValidElement(nextButton) ? React.cloneElement(nextButton, { disabled: !hasNext }) : nextButton; @@ -345,6 +396,7 @@ const Pagination: React.FC = (props) => { const pagerProps: PagerProps = { rootPrefixCls: prefixCls, + defaultItemRender: isDefaultRender, onClick: handleChange, onKeyPress: runIfEnterOrSpace, showTitle, @@ -448,54 +500,84 @@ const Pagination: React.FC = (props) => { const jumpPrevContent = itemRender( jumpPrevPage, 'jump-prev', - getItemIcon( - jumpPrevIcon, - prevItemTitle, - showTitle ? prevItemTitle : undefined, - ), + getIconNode(jumpPrevIcon) || + getItemIcon(showTitle ? prevItemTitle : undefined), ); const jumpNextContent = itemRender( jumpNextPage, 'jump-next', - getItemIcon( - jumpNextIcon, - nextItemTitle, - showTitle ? nextItemTitle : undefined, - ), + getIconNode(jumpNextIcon) || + getItemIcon(showTitle ? nextItemTitle : undefined), ); if (showPrevNextJumpers) { - jumpPrev = jumpPrevContent ? ( -
  • - {jumpPrevContent} -
  • - ) : null; + if (isDefaultRender) { + jumpPrev = ( +
  • + {renderDefaultControlButton( + 'jump-prev', + jumpPrevIcon, + prevItemTitle, + showTitle ? prevItemTitle : undefined, + jumpPrevHandle, + )} +
  • + ); - jumpNext = jumpNextContent ? ( -
  • - {jumpNextContent} -
  • - ) : null; + jumpNext = ( +
  • + {renderDefaultControlButton( + 'jump-next', + jumpNextIcon, + nextItemTitle, + showTitle ? nextItemTitle : undefined, + jumpNextHandle, + )} +
  • + ); + } else { + jumpPrev = jumpPrevContent ? ( +
  • + {jumpPrevContent} +
  • + ) : null; + + jumpNext = jumpNextContent ? ( +
  • + {jumpNextContent} +
  • + ) : null; + } } let left = Math.max(1, current - pageBufferSize); @@ -564,16 +646,16 @@ const Pagination: React.FC = (props) => { const prevDisabled = !hasPrev || !allPages; prev = (
  • {prev}
  • @@ -594,16 +676,16 @@ const Pagination: React.FC = (props) => { next = (
  • {next}
  • diff --git a/tests/__snapshots__/demo.test.tsx.snap b/tests/__snapshots__/demo.test.tsx.snap index c29e01ee..f1698ed1 100644 --- a/tests/__snapshots__/demo.test.tsx.snap +++ b/tests/__snapshots__/demo.test.tsx.snap @@ -7,45 +7,36 @@ exports[`Example align 1`] = ` >
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • @@ -1450,7 +1113,6 @@ exports[`Example itemRender 1`] = `
  • @@ -1463,7 +1125,6 @@ exports[`Example itemRender 1`] = `
  • @@ -1476,7 +1137,6 @@ exports[`Example itemRender 1`] = `
  • @@ -1489,7 +1149,6 @@ exports[`Example itemRender 1`] = `
  • @@ -1502,21 +1161,17 @@ exports[`Example itemRender 1`] = `
  • -
  • @@ -1530,15 +1185,12 @@ exports[`Example itemRender 1`] = ` aria-disabled="false" aria-label="下一页" class="rc-pagination-next" - role="button" tabindex="0" + title="下一页" > -
  • Prev
  • @@ -1560,14 +1212,11 @@ exports[`Example itemRender 1`] = ` aria-current="page" aria-label="页 1" class="rc-pagination-item rc-pagination-item-1 rc-pagination-item-active" - role="button" tabindex="0" title="1" > @@ -1575,14 +1224,11 @@ exports[`Example itemRender 1`] = `
  • @@ -1590,14 +1236,11 @@ exports[`Example itemRender 1`] = `
  • @@ -1605,14 +1248,11 @@ exports[`Example itemRender 1`] = `
  • @@ -1620,14 +1260,11 @@ exports[`Example itemRender 1`] = `
  • @@ -1635,28 +1272,22 @@ exports[`Example itemRender 1`] = `
  • -
  • @@ -1665,8 +1296,8 @@ exports[`Example itemRender 1`] = ` aria-disabled="false" aria-label="下一页" class="rc-pagination-next" - role="button" tabindex="0" + title="下一页" > Next
  • @@ -1681,7 +1312,7 @@ exports[`Example itemRender 1`] = ` aria-disabled="true" aria-label="上一页" class="rc-pagination-prev rc-pagination-disabled" - role="button" + title="上一页" >
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - - - - - - + + + + + +
  • - +
  • - - - - - + + + + +
  • - - - - - + + + + +
  • - +
  • - +
  • - +
  • - - - - - - + + + + + +
  • - +
  • - - - - - + + + + +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • -
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • @@ -3981,99 +3258,72 @@ exports[`Example showTitle 1`] = ` >
  • - +
  • - +
  • - +
  • - +
  • @@ -4097,135 +3347,100 @@ exports[`Example showTotal 1`] = `
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • - +
  • + } + nextIcon={ + + } + jumpPrevIcon={ + // biome-ignore lint/a11y/useValidAnchor: test fallback output + + jumpPrevIcon + + } + jumpNextIcon={ + // biome-ignore lint/a11y/useValidAnchor: test fallback output + + jumpNextIcon + + } + />, + ); + + expect( + container.querySelectorAll('.rc-pagination-prev button'), + ).toHaveLength(1); + expect( + container.querySelectorAll('.rc-pagination-next button'), + ).toHaveLength(1); + expect( + container.querySelectorAll('.rc-pagination-jump-prev button'), + ).toHaveLength(1); + expect( + container.querySelectorAll('.rc-pagination-jump-next button'), + ).toHaveLength(1); + expect(container.querySelector('.rc-pagination-prev')).toHaveTextContent( + 'prevIcon', + ); + expect(container.querySelector('.rc-pagination-next')).toHaveTextContent( + 'nextIcon', + ); + expect( + container.querySelector('.rc-pagination-jump-prev'), + ).toHaveTextContent('jumpPrevIcon'); + expect( + container.querySelector('.rc-pagination-jump-next'), + ).toHaveTextContent('jumpNextIcon'); + }); + describe('showPrevNextJumpers props', () => { it('should hide jump-prev, jump-next if showPrevNextJumpers equals false', () => { const { container } = render( @@ -610,8 +682,10 @@ describe('should emit onChange when total is string', () => { }); it('onChange should be called when click page', () => { - const pagers = wrapper.container.querySelectorAll('.rc-pagination-item-3'); - fireEvent.click(pagers[0]); + const page3Button = wrapper.container.querySelector( + '.rc-pagination-item-3 button', + ); + fireEvent.click(page3Button); expect(onChange).toHaveBeenCalledWith(3, 10); }); }); @@ -632,35 +706,39 @@ describe('keyboard support', () => { onChange.mockReset(); }); - it('should work for prev page', () => { - const prevButton = $('li.rc-pagination-prev'); + it('should work for prev page', async () => { + const user = userEvent.setup(); + const prevButton = $('li.rc-pagination-prev button'); expect(prevButton).toBeTruthy(); fireEvent.click(prevButton); fireEvent.click(prevButton); - fireEvent.keyDown(prevButton, { key: 'Enter', keyCode: 13, which: 13 }); - fireEvent.keyDown(prevButton, { key: 'Enter', keyCode: 13, which: 13 }); + prevButton.focus(); + await user.keyboard('{Enter}{Enter}'); expect(onChange).toHaveBeenLastCalledWith(46, 10); }); - it('should work for prev page with space key', () => { - const prevButton = $('li.rc-pagination-prev'); + it('should work for prev page with space key', async () => { + const user = userEvent.setup(); + const prevButton = $('li.rc-pagination-prev button'); expect(prevButton).toBeTruthy(); - fireEvent.keyDown(prevButton, { key: ' ', keyCode: 32, which: 32 }); - fireEvent.keyDown(prevButton, { key: 'Spacebar', keyCode: 32, which: 32 }); + prevButton.focus(); + await user.keyboard(' '); + await user.keyboard(' '); expect(onChange).toHaveBeenLastCalledWith(48, 10); }); - it('should work for next page', () => { - const nextButton = $('li.rc-pagination-next'); + it('should work for next page', async () => { + const user = userEvent.setup(); + const nextButton = $('li.rc-pagination-next button'); expect(nextButton).toBeTruthy(); - fireEvent.keyDown(nextButton, { key: 'Enter', keyCode: 13, which: 13 }); - fireEvent.keyDown(nextButton, { key: 'Enter', keyCode: 13, which: 13 }); + nextButton.focus(); + await user.keyboard('{Enter}{Enter}'); fireEvent.click(nextButton); fireEvent.click(nextButton); @@ -668,69 +746,73 @@ describe('keyboard support', () => { expect(onChange).toHaveBeenLastCalledWith(54, 10); }); - it('should work for next page with space key', () => { - const nextButton = $('li.rc-pagination-next'); + it('should work for next page with space key', async () => { + const user = userEvent.setup(); + const nextButton = $('li.rc-pagination-next button'); expect(nextButton).toBeTruthy(); - fireEvent.keyDown(nextButton, { key: ' ', keyCode: 32, which: 32 }); - fireEvent.keyDown(nextButton, { key: 'Spacebar', keyCode: 32, which: 32 }); + nextButton.focus(); + await user.keyboard(' '); + await user.keyboard(' '); expect(onChange).toHaveBeenLastCalledWith(52, 10); }); - it('should work for next page with enter keyCode only', () => { - const nextButton = $('li.rc-pagination-next'); + it('should work for next page with enter keyCode only', async () => { + const user = userEvent.setup(); + const nextButton = $('li.rc-pagination-next button'); expect(nextButton).toBeTruthy(); - fireEvent.keyDown(nextButton, { keyCode: 13, which: 13 }); + nextButton.focus(); + await user.keyboard('{Enter}'); expect(onChange).toHaveBeenLastCalledWith(51, 10); }); - it('should work for jump prev page', () => { - const jumpPrevButton = $('li.rc-pagination-jump-prev'); + it('should work for jump prev page', async () => { + const user = userEvent.setup(); + const jumpPrevButton = $('li.rc-pagination-jump-prev button'); expect(jumpPrevButton).toBeTruthy(); - fireEvent.keyDown(jumpPrevButton, { key: 'Enter', keyCode: 13, which: 13 }); fireEvent.click(jumpPrevButton); + jumpPrevButton.focus(); + await user.keyboard('{Enter}'); expect(onChange).toHaveBeenLastCalledWith(40, 10); }); - it('should work for jump prev page with space key', () => { - const jumpPrevButton = $('li.rc-pagination-jump-prev'); + it('should work for jump prev page with space key', async () => { + const user = userEvent.setup(); + const jumpPrevButton = $('li.rc-pagination-jump-prev button'); expect(jumpPrevButton).toBeTruthy(); - fireEvent.keyDown(jumpPrevButton, { key: ' ', keyCode: 32, which: 32 }); - fireEvent.keyDown(jumpPrevButton, { - key: 'Spacebar', - keyCode: 32, - which: 32, - }); + jumpPrevButton.focus(); + await user.keyboard(' '); + await user.keyboard(' '); expect(onChange).toHaveBeenLastCalledWith(40, 10); }); - it('should work for jump next page', () => { - const jumpNextButton = $('li.rc-pagination-jump-next'); + it('should work for jump next page', async () => { + const user = userEvent.setup(); + const jumpNextButton = $('li.rc-pagination-jump-next button'); expect(jumpNextButton).toBeTruthy(); fireEvent.click(jumpNextButton); - fireEvent.keyDown(jumpNextButton, { key: 'Enter', keyCode: 13, which: 13 }); + jumpNextButton.focus(); + await user.keyboard('{Enter}'); expect(onChange).toHaveBeenLastCalledWith(60, 10); }); - it('should work for jump next page with space key', () => { - const jumpNextButton = $('li.rc-pagination-jump-next'); + it('should work for jump next page with space key', async () => { + const user = userEvent.setup(); + const jumpNextButton = $('li.rc-pagination-jump-next button'); expect(jumpNextButton).toBeTruthy(); - fireEvent.keyDown(jumpNextButton, { key: ' ', keyCode: 32, which: 32 }); - fireEvent.keyDown(jumpNextButton, { - key: 'Spacebar', - keyCode: 32, - which: 32, - }); + jumpNextButton.focus(); + await user.keyboard(' '); + await user.keyboard(' '); expect(onChange).toHaveBeenLastCalledWith(60, 10); }); diff --git a/tests/itemRender.test.tsx b/tests/itemRender.test.tsx index 50c426f2..374099bd 100644 --- a/tests/itemRender.test.tsx +++ b/tests/itemRender.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import type { RenderResult } from '@testing-library/react'; -import { render } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; import Pagination from '../src'; describe('itemRender', () => { @@ -108,4 +108,31 @@ describe('itemRender', () => { expect(prev.innerHTML).toBe('0'); expect(next.innerHTML).toBe('2'); }); + + it('should keep wrapper interaction for custom itemRender fallback', () => { + const onChange = jest.fn(); + const { container } = render( + originalElement} + />, + ); + + const pageButton = container.querySelector('.rc-pagination-item-13'); + const jumpNextButton = container.querySelector('.rc-pagination-jump-next'); + + expect(pageButton).not.toHaveAttribute('role'); + expect(jumpNextButton).not.toHaveAttribute('role'); + + fireEvent.click(pageButton); + fireEvent.keyDown(jumpNextButton, { + key: 'Spacebar', + keyCode: 32, + which: 32, + }); + + expect(onChange).toHaveBeenLastCalledWith(18, 10); + }); }); diff --git a/tests/jumper.test.tsx b/tests/jumper.test.tsx index f87dbcb7..474acc2f 100644 --- a/tests/jumper.test.tsx +++ b/tests/jumper.test.tsx @@ -185,7 +185,9 @@ describe('simple quick jumper', () => { // https://github.com/ant-design/ant-design/issues/10080 it('should not quick jump to previous page when input invalid char', () => { - const nextButton = wrapper.container.querySelector('.rc-pagination-next'); + const nextButton = wrapper.container.querySelector( + '.rc-pagination-next button', + ); fireEvent.click(nextButton); const input = wrapper.container.querySelector('input'); fireEvent.change(input, { target: { value: '&' } }); From 3d458466c21fac690c56c8f02992c50ad6d1f61e Mon Sep 17 00:00:00 2001 From: ZQDesigned <2990918167@qq.com> Date: Thu, 9 Jul 2026 00:55:01 +0800 Subject: [PATCH 11/12] fix: follow up pagination a11y review --- src/Pager.tsx | 2 +- src/Pagination.tsx | 30 +++++++++++++++++------------- tests/index.test.tsx | 34 +++++++++++++--------------------- 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/Pager.tsx b/src/Pager.tsx index 02446b0d..ede68cb0 100644 --- a/src/Pager.tsx +++ b/src/Pager.tsx @@ -54,7 +54,7 @@ const Pager: React.FC = (props) => { onKeyPress(e, onClick, page); }; - const pagerLabel = `${pageLabel} ${page}`.trim(); + const pagerLabel = pageLabel ? `${pageLabel} ${page}` : String(page); const itemTitle = showTitle ? String(page) : undefined; if (defaultItemRender) { diff --git a/src/Pagination.tsx b/src/Pagination.tsx index 5903a208..aac25455 100644 --- a/src/Pagination.tsx +++ b/src/Pagination.tsx @@ -643,16 +643,18 @@ const Pagination: React.FC = (props) => { const prevDisabled = !hasPrev || !allPages; prev = (
  • {prev}
  • @@ -661,28 +663,30 @@ const Pagination: React.FC = (props) => { let next = renderNext(nextPage); if (next) { - let nextDisabled: boolean, nextTabIndex: number | null; + let nextDisabled: boolean, nextTabIndex: number | undefined; if (simple) { nextDisabled = !hasNext; - nextTabIndex = hasPrev ? 0 : null; + nextTabIndex = hasPrev ? 0 : undefined; } else { nextDisabled = !hasNext || !allPages; - nextTabIndex = nextDisabled ? null : 0; + nextTabIndex = nextDisabled ? undefined : 0; } next = (
  • {next}
  • diff --git a/tests/index.test.tsx b/tests/index.test.tsx index 243cc4f4..93d33120 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -225,9 +225,9 @@ describe('Uncontrolled Pagination', () => { it('should response keyboard event', async () => { const user = userEvent.setup(); - const page3Button = wrapper.container.querySelector( + const page3Button = wrapper.container.querySelector( '.rc-pagination-item-3 button', - ); + )!; page3Button.focus(); await user.keyboard('{Enter}'); expect( @@ -693,7 +693,8 @@ describe('should emit onChange when total is string', () => { describe('keyboard support', () => { let wrapper: RenderResult; const onChange = jest.fn(); - const $ = (selector: string) => wrapper.container.querySelector(selector); + const $button = (selector: string) => + wrapper.container.querySelector(selector)!; beforeEach(() => { wrapper = render( @@ -708,8 +709,7 @@ describe('keyboard support', () => { it('should work for prev page', async () => { const user = userEvent.setup(); - const prevButton = $('li.rc-pagination-prev button'); - expect(prevButton).toBeTruthy(); + const prevButton = $button('li.rc-pagination-prev button'); fireEvent.click(prevButton); fireEvent.click(prevButton); @@ -722,8 +722,7 @@ describe('keyboard support', () => { it('should work for prev page with space key', async () => { const user = userEvent.setup(); - const prevButton = $('li.rc-pagination-prev button'); - expect(prevButton).toBeTruthy(); + const prevButton = $button('li.rc-pagination-prev button'); prevButton.focus(); await user.keyboard(' '); @@ -734,8 +733,7 @@ describe('keyboard support', () => { it('should work for next page', async () => { const user = userEvent.setup(); - const nextButton = $('li.rc-pagination-next button'); - expect(nextButton).toBeTruthy(); + const nextButton = $button('li.rc-pagination-next button'); nextButton.focus(); await user.keyboard('{Enter}{Enter}'); @@ -748,8 +746,7 @@ describe('keyboard support', () => { it('should work for next page with space key', async () => { const user = userEvent.setup(); - const nextButton = $('li.rc-pagination-next button'); - expect(nextButton).toBeTruthy(); + const nextButton = $button('li.rc-pagination-next button'); nextButton.focus(); await user.keyboard(' '); @@ -760,8 +757,7 @@ describe('keyboard support', () => { it('should work for next page with enter keyCode only', async () => { const user = userEvent.setup(); - const nextButton = $('li.rc-pagination-next button'); - expect(nextButton).toBeTruthy(); + const nextButton = $button('li.rc-pagination-next button'); nextButton.focus(); await user.keyboard('{Enter}'); @@ -771,8 +767,7 @@ describe('keyboard support', () => { it('should work for jump prev page', async () => { const user = userEvent.setup(); - const jumpPrevButton = $('li.rc-pagination-jump-prev button'); - expect(jumpPrevButton).toBeTruthy(); + const jumpPrevButton = $button('li.rc-pagination-jump-prev button'); fireEvent.click(jumpPrevButton); jumpPrevButton.focus(); @@ -783,8 +778,7 @@ describe('keyboard support', () => { it('should work for jump prev page with space key', async () => { const user = userEvent.setup(); - const jumpPrevButton = $('li.rc-pagination-jump-prev button'); - expect(jumpPrevButton).toBeTruthy(); + const jumpPrevButton = $button('li.rc-pagination-jump-prev button'); jumpPrevButton.focus(); await user.keyboard(' '); @@ -795,8 +789,7 @@ describe('keyboard support', () => { it('should work for jump next page', async () => { const user = userEvent.setup(); - const jumpNextButton = $('li.rc-pagination-jump-next button'); - expect(jumpNextButton).toBeTruthy(); + const jumpNextButton = $button('li.rc-pagination-jump-next button'); fireEvent.click(jumpNextButton); jumpNextButton.focus(); @@ -807,8 +800,7 @@ describe('keyboard support', () => { it('should work for jump next page with space key', async () => { const user = userEvent.setup(); - const jumpNextButton = $('li.rc-pagination-jump-next button'); - expect(jumpNextButton).toBeTruthy(); + const jumpNextButton = $button('li.rc-pagination-jump-next button'); jumpNextButton.focus(); await user.keyboard(' '); From 6aeae4ca13c3c448a34809a6477367f4b92830a4 Mon Sep 17 00:00:00 2001 From: ZQDesigned <2990918167@qq.com> Date: Thu, 9 Jul 2026 00:58:05 +0800 Subject: [PATCH 12/12] fix: disable default pagination buttons --- src/Pager.tsx | 8 ++++++-- src/Pagination.tsx | 7 ++++--- tests/__snapshots__/demo.test.tsx.snap | 9 +++++++++ tests/index.test.tsx | 9 +++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/Pager.tsx b/src/Pager.tsx index ede68cb0..cb48e8c7 100644 --- a/src/Pager.tsx +++ b/src/Pager.tsx @@ -3,7 +3,10 @@ import { clsx } from 'clsx'; import React from 'react'; import type { PaginationProps } from './interface'; -export interface PagerProps extends Pick { +export interface PagerProps extends Pick< + PaginationProps, + 'disabled' | 'itemRender' +> { rootPrefixCls: string; page: number; pageLabel?: string; @@ -25,6 +28,7 @@ const Pager: React.FC = (props) => { rootPrefixCls, page, pageLabel, + disabled, defaultItemRender, active, className, @@ -66,7 +70,7 @@ const Pager: React.FC = (props) => { title={itemTitle} aria-label={pagerLabel} aria-current={active ? 'page' : undefined} - disabled={cls.includes(`${prefixCls}-disabled`)} + disabled={disabled || cls.includes(`${prefixCls}-disabled`)} > {page} diff --git a/src/Pagination.tsx b/src/Pagination.tsx index aac25455..386567ca 100644 --- a/src/Pagination.tsx +++ b/src/Pagination.tsx @@ -159,7 +159,7 @@ const Pagination: React.FC = (props) => {