diff --git a/README.md b/README.md index fc91fe57..43e3062a 100644 --- a/README.md +++ b/README.md @@ -52,35 +52,36 @@ ReactDOM.render(, container); ## API -| Parameter | Description | Type | Default | -| ---------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -| disabled | disable pagination | Bool | - | -| align | align of pagination | start \| center \| end | undefined | -| defaultCurrent | uncontrolled current page | Number | 1 | -| current | current page | Number | undefined | -| total | items total count | Number | 0 | -| defaultPageSize | default items per page | Number | 10 | -| pageSize | items per page | Number | 10 | -| onChange | page change callback | Function(current, pageSize) | - | -| showSizeChanger | show pageSize changer | Bool | `false` when total less then `totalBoundaryShowSizeChanger`, `true` when otherwise | -| totalBoundaryShowSizeChanger | when total larger than it, `showSizeChanger` will be true | number | 50 | -| pageSizeOptions | specify the sizeChanger selections | Array | ['10', '20', '50', '100'] | -| onShowSizeChange | pageSize change callback | Function(current, size) | - | -| hideOnSinglePage | hide on single page | Bool | false | -| showPrevNextJumpers | show jump-prev, jump-next | Bool | true | -| showQuickJumper | show quick goto jumper | Bool / Object | false / {goButton: true} | -| showTotal | show total records and range | Function(total, [from, to]) | - | -| className | className of pagination | String | - | -| simple | when set, show simple pager | Bool / { readOnly?: boolean; } | - | -| locale | to set l10n config | Object | [zh_CN](https://github.com/react-component/pagination/blob/master/src/locale/zh_CN.js) | -| style | the style of pagination | Object | {} | -| showLessItems | show less page items | Bool | false | -| showTitle | show page items title | Bool | true | -| itemRender | custom page item renderer | Function(current, type: 'page' \| 'prev' \| 'next' \| 'jump-prev' \| 'jump-next', element): React.ReactNode \| `(current, type, element) => element` | | -| prevIcon | specify the default previous icon | ReactNode \| (props: PaginationProps) => ReactNode | | -| nextIcon | specify the default next icon | ReactNode \| (props: PaginationProps) => ReactNode | | -| jumpPrevIcon | specify the default previous icon | ReactNode \| (props: PaginationProps) => ReactNode | | -| jumpNextIcon | specify the default next icon | ReactNode \| (props: PaginationProps) => ReactNode | | +// prettier-ignore +| Parameter | Description | Type | Default | +| --- | --- | --- | --- | +| disabled | disable pagination | Bool | - | +| align | align of pagination | start \| center \| end | undefined | +| defaultCurrent | uncontrolled current page | Number | 1 | +| current | current page | Number | undefined | +| total | items total count | Number | 0 | +| defaultPageSize | default items per page | Number | 10 | +| pageSize | items per page | Number | 10 | +| onChange | page change callback | Function(current, pageSize) | - | +| showSizeChanger | show pageSize changer | boolean \| [SelectProps](https://github.com/react-component/select/blob/561f8b7d69fd5dd2cd7d917c88976cca4e539a9d/src/Select.tsx#L112) | `false` when total less than `totalBoundaryShowSizeChanger`, `true` when otherwise | +| totalBoundaryShowSizeChanger | when total larger than it, `showSizeChanger` will be true | number | 50 | +| pageSizeOptions | specify the sizeChanger selections | Array | ['10', '20', '50', '100'] | +| onShowSizeChange | pageSize change callback | Function(current, size) | - | +| hideOnSinglePage | hide on single page | Bool | false | +| showPrevNextJumpers | show jump-prev, jump-next | Bool | true | +| showQuickJumper | show quick goto jumper | Bool / Object | false / {goButton: true} | +| showTotal | show total records and range | Function(total, [from, to]) | - | +| className | className of pagination | String | - | +| simple | when set, show simple pager | Bool / { readOnly?: boolean; } | - | +| locale | to set l10n config | Object | [zh_CN](https://github.com/react-component/pagination/blob/master/src/locale/zh_CN.js) | +| style | the style of pagination | Object | {} | +| showLessItems | show less page items | Bool | false | +| showTitle | show page items title | Bool | true | +| itemRender | custom page item renderer | Function(current, type: 'page' \| 'prev' \| 'next' \| 'jump-prev' \| 'jump-next', element): React.ReactNode \| `(current, type, element) => element` | | +| prevIcon | specify the default previous icon | ReactNode \| (props: PaginationProps) => ReactNode | | +| nextIcon | specify the default next icon | ReactNode \| (props: PaginationProps) => ReactNode | | +| jumpPrevIcon | specify the default previous icon | ReactNode \| (props: PaginationProps) => ReactNode | | +| jumpNextIcon | specify the default next icon | ReactNode \| (props: PaginationProps) => ReactNode | | ## License diff --git a/docs/demo/showSizeChanger.md b/docs/demo/showSizeChanger.md new file mode 100644 index 00000000..bda79137 --- /dev/null +++ b/docs/demo/showSizeChanger.md @@ -0,0 +1,8 @@ +--- +title: showSizeChanger +nav: + title: Demo + path: /demo +--- + + diff --git a/docs/examples/showSizeChanger.tsx b/docs/examples/showSizeChanger.tsx new file mode 100644 index 00000000..b086391a --- /dev/null +++ b/docs/examples/showSizeChanger.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import Pagination from 'rc-pagination'; +import Select from 'rc-select'; +import '../../assets/index.less'; + +export default () => { + const onPageSizeOnChange = (value) => { + console.log(value); + }; + + return ( + <> + + + + + ); +}; diff --git a/package.json b/package.json index b7eef013..c8faa806 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@rc-component/father-plugin": "^1.0.0", "@testing-library/jest-dom": "^6.1.5", "@testing-library/react": "^15.0.4", + "@testing-library/user-event": "^14.5.2", "@types/jest": "^29.2.2", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", diff --git a/src/Options.tsx b/src/Options.tsx index 99733aaf..6973b568 100644 --- a/src/Options.tsx +++ b/src/Options.tsx @@ -1,8 +1,9 @@ import type { SelectProps } from 'rc-select'; import type { OptionProps } from 'rc-select/es/Option'; import KEYCODE from 'rc-util/lib/KeyCode'; +import classNames from 'classnames'; import React from 'react'; -import type { PaginationLocale } from './interface'; +import type { PaginationLocale, PaginationProps } from './interface'; interface InternalSelectProps extends SelectProps { /** @@ -25,6 +26,7 @@ interface OptionsProps { selectComponentClass: React.ComponentType> & { Option?: React.ComponentType>; }; + showSizeChanger: PaginationProps['showSizeChanger']; } const defaultPageSizeOptions = ['10', '20', '50', '100']; @@ -42,6 +44,7 @@ const Options: React.FC = (props) => { selectPrefixCls, disabled, buildOptionText, + showSizeChanger, } = props; const [goInputText, setGoInputText] = React.useState(''); @@ -57,8 +60,11 @@ const Options: React.FC = (props) => { ? buildOptionText : (value: string) => `${value} ${locale.items_per_page}`; - const changeSizeHandle = (value: number) => { + const changeSizeHandle = (value: number, option) => { changeSize?.(Number(value)); + if (typeof showSizeChanger === 'object') { + showSizeChanger.onChange?.(value, option); + } }; const handleChange = (e: React.ChangeEvent) => { @@ -109,7 +115,7 @@ const Options: React.FC = (props) => { // ============== render ============== - if (!changeSize && !quickGo) { + if (!showSizeChanger && !quickGo) { return null; } @@ -117,26 +123,41 @@ const Options: React.FC = (props) => { let goInput: React.ReactNode = null; let gotoButton: React.ReactNode = null; - if (changeSize && Select) { - const options = getPageSizeOptions().map((opt, i) => ( - - {mergeBuildOptionText(opt)} - - )); + if (showSizeChanger && Select) { + const { + options: showSizeChangerOptions, + className: showSizeChangerClassName, + } = + typeof showSizeChanger === 'object' + ? showSizeChanger + : ({} as SelectProps); + // use showSizeChanger.options if existed, otherwise use pageSizeOptions + const options = showSizeChangerOptions + ? undefined + : getPageSizeOptions().map((opt, i) => ( + + {mergeBuildOptionText(opt)} + + )); changeSelect = ( diff --git a/src/Pagination.tsx b/src/Pagination.tsx index 449b5c3c..fd37018b 100644 --- a/src/Pagination.tsx +++ b/src/Pagination.tsx @@ -63,7 +63,7 @@ const Pagination: React.FC = (props) => { disabled, simple, showTotal, - showSizeChanger: showSizeChangerProp, + showSizeChanger = total > totalBoundaryShowSizeChanger, pageSizeOptions, // render @@ -225,8 +225,6 @@ const Pagination: React.FC = (props) => { const hasPrev = current > 1; const hasNext = current < calculatePage(undefined, pageSize, total); - const showSizeChanger = - showSizeChangerProp ?? total > totalBoundaryShowSizeChanger; function prevHandle() { if (hasPrev) handleChange(current - 1); @@ -586,11 +584,12 @@ const Pagination: React.FC = (props) => { disabled={disabled} selectComponentClass={selectComponentClass} selectPrefixCls={selectPrefixCls} - changeSize={showSizeChanger ? changePageSize : null} + changeSize={changePageSize} pageSize={pageSize} pageSizeOptions={pageSizeOptions} quickGo={shouldDisplayQuickJumper ? handleChange : null} goButton={gotoButton} + showSizeChanger={showSizeChanger} /> ); diff --git a/src/interface.ts b/src/interface.ts index 7cc6032b..6a1d60d3 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -1,4 +1,5 @@ import type React from 'react'; +import type { SelectProps } from 'rc-select'; export interface PaginationLocale { // Options @@ -32,12 +33,12 @@ export interface PaginationData { hideOnSinglePage: boolean; align: 'start' | 'center' | 'end'; - showSizeChanger: boolean; + showSizeChanger: boolean | SelectProps; showLessItems: boolean; showPrevNextJumpers: boolean; showQuickJumper: boolean | object; showTitle: boolean; - simple: boolean | { readOnly?: boolean; }; + simple: boolean | { readOnly?: boolean }; disabled: boolean; locale: PaginationLocale; @@ -62,7 +63,6 @@ export interface PaginationProps element: React.ReactNode, ) => React.ReactNode; showTotal?: (total: number, range: [number, number]) => React.ReactNode; - // WAI-ARIA role?: React.AriaRole | undefined; } diff --git a/tests/__snapshots__/demo.test.tsx.snap b/tests/__snapshots__/demo.test.tsx.snap index 0e218d2a..cab49ac7 100644 --- a/tests/__snapshots__/demo.test.tsx.snap +++ b/tests/__snapshots__/demo.test.tsx.snap @@ -2874,6 +2874,337 @@ exports[`Example more 1`] = ` `; +exports[`Example showSizeChanger 1`] = ` +
+ + + +
+`; + exports[`Example showTitle 1`] = `
diff --git a/tests/options.test.tsx b/tests/options.test.tsx index 715bb959..747644bc 100644 --- a/tests/options.test.tsx +++ b/tests/options.test.tsx @@ -12,6 +12,7 @@ const WrapperOptions: React.FC = (props) => ( pageSize={10} changeSize={jest.fn()} quickGo={jest.fn()} + showSizeChanger {...props} /> ); @@ -22,19 +23,17 @@ describe('Options', () => { expect(container.firstChild).toMatchSnapshot(); }); - describe('props:buildOptionText', () => { - it('should render correctly', () => { - const mockBuildOptionText = jest - .fn() - .mockImplementation((value) => ( -
buildOptionText-{value}
- )); - const { container } = render( - , - ); - const options = container.querySelector('.custom-options'); - expect(options).toBeTruthy(); - expect(options).toHaveTextContent('buildOptionText-10'); - }); + it('props:buildOptionText should render correctly', () => { + const mockBuildOptionText = jest + .fn() + .mockImplementation((value) => ( +
buildOptionText-{value}
+ )); + const { container } = render( + , + ); + const options = container.querySelector('.custom-options'); + expect(options).toBeTruthy(); + expect(options).toHaveTextContent('buildOptionText-10'); }); }); diff --git a/tests/sizer.test.tsx b/tests/sizer.test.tsx index b6832ccc..9643c507 100644 --- a/tests/sizer.test.tsx +++ b/tests/sizer.test.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { render, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import Select from 'rc-select'; import Pagination from '../src'; @@ -82,4 +83,92 @@ describe('Pagination with sizer', () => { container.querySelector('.rc-select-selection-item'), ).toHaveTextContent('20 条/页'); }); + + describe('showSizeChanger is object', () => { + const options = [ + { value: '10', label: '10 条每页' }, + { value: '25', label: '25 条每页' }, + { value: '50', label: '50 条每页' }, + { value: '75', label: '75 条每页' }, + { value: '100', label: '100 条每页' }, + ]; + + it('showSizeChanger.className should be added to select node', async () => { + const { container } = render( + , + ); + const select = container.querySelector('.rc-select'); + expect(select.className).toContain('custom-class-name'); + expect(select.className).toContain('rc-pagination-options-size-changer'); + }); + + it('should onChange called when pageSize change', () => { + const onChange = jest.fn(); + const { container, getByRole } = render( + , + ); + const select = getByRole('combobox'); + expect(select).toBeTruthy(); + fireEvent.mouseDown(select); + expect( + container.querySelectorAll('.rc-select-item')[2], + ).toHaveTextContent('50 条每页'); + const pageSize1 = container.querySelectorAll('.rc-select-item')[1]; + fireEvent.click(pageSize1); + expect(onChange).toHaveBeenCalledWith('25', { + label: '25 条每页', + value: '25', + }); + }); + + it('should onChange called when pageSize change with search', async () => { + const onChange = jest.fn(); + const { container } = render( + , + ); + expect(container.querySelector('input').hasAttribute('readOnly')).toBe( + false, + ); + await userEvent.type(container.querySelector('input'), '25'); + expect( + container.querySelectorAll('.rc-select-item-option-content'), + ).toHaveLength(1); + expect( + container.querySelector('.rc-select-item-option-content').textContent, + ).toBe('25 条每页'); + const pageSize1 = container.querySelector( + '.rc-select-item-option-content', + ); + expect(pageSize1).toBeInTheDocument(); + fireEvent.click(pageSize1); + expect(onChange).toHaveBeenCalledWith('25', { + label: '25 条每页', + value: '25', + }); + }); + }); });