diff --git a/components/pagination/Pagination.tsx b/components/pagination/Pagination.tsx index 1092c63032..dd9853559b 100644 --- a/components/pagination/Pagination.tsx +++ b/components/pagination/Pagination.tsx @@ -8,17 +8,20 @@ import type { PaginationLocale, PaginationProps as RcPaginationProps } from 'rc- import RcPagination from 'rc-pagination'; import enUS from 'rc-pagination/lib/locale/en_US'; +import { devUseWarning } from '../_util/warning'; import { ConfigContext } from '../config-provider'; import useSize from '../config-provider/hooks/useSize'; import useBreakpoint from '../grid/hooks/useBreakpoint'; -import type { SelectProps } from '../select'; import { useLocale } from '../locale'; +import type { SelectProps } from '../select'; +import Select from '../select'; import { useToken } from '../theme/internal'; -import { MiddleSelect, MiniSelect } from './Select'; import useStyle from './style'; import BorderedStyle from './style/bordered'; +import useShowSizeChanger from './useShowSizeChanger'; -export interface PaginationProps extends RcPaginationProps { +export interface PaginationProps + extends Omit { showQuickJumper?: boolean | { goButton?: React.ReactNode }; size?: 'default' | 'small'; responsive?: boolean; @@ -26,6 +29,10 @@ export interface PaginationProps extends RcPaginationProps { totalBoundaryShowSizeChanger?: number; rootClassName?: string; showSizeChanger?: boolean | SelectProps; + /** @deprecated Not official support. Will be removed in next major version. */ + selectComponentClass?: any; + /** `string` type will be removed in next major version. */ + pageSizeOptions?: (string | number)[]; } export type PaginationPosition = 'top' | 'bottom' | 'both'; @@ -46,9 +53,10 @@ const Pagination: React.FC = (props) => { style, size: customizeSize, locale: customLocale, - selectComponentClass, responsive, showSizeChanger, + selectComponentClass, + pageSizeOptions, ...restProps } = props; const { xs } = useBreakpoint(responsive); @@ -60,8 +68,86 @@ const Pagination: React.FC = (props) => { // Style const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls); - const mergedShowSizeChanger = showSizeChanger ?? pagination.showSizeChanger; + // ============================== Size ============================== + const mergedSize = useSize(customizeSize); + const isSmall = mergedSize === 'small' || !!(xs && !mergedSize && responsive); + + // ============================= Locale ============================= + const [contextLocale] = useLocale('Pagination', enUS); + + const locale = { ...contextLocale, ...customLocale }; + + // ========================== Size Changer ========================== + // Merge the props showSizeChanger + const [propShowSizeChanger, propSizeChangerSelectProps] = useShowSizeChanger(showSizeChanger); + const [contextShowSizeChanger, contextSizeChangerSelectProps] = useShowSizeChanger( + pagination.showSizeChanger, + ); + + const mergedShowSizeChanger = propShowSizeChanger ?? contextShowSizeChanger; + const mergedShowSizeChangerSelectProps = + propSizeChangerSelectProps ?? contextSizeChangerSelectProps; + + const SizeChanger: typeof Select = selectComponentClass || Select; + + // Generate options + const mergedPageSizeOptions = React.useMemo(() => { + return pageSizeOptions ? pageSizeOptions.map((option) => Number(option)) : undefined; + }, [pageSizeOptions]); + + // Render size changer + const sizeChangerRender: RcPaginationProps['sizeChangerRender'] = (info) => { + const { + disabled, + size: pageSize, + onSizeChange, + 'aria-label': ariaLabel, + className: sizeChangerClassName, + options, + } = info; + + const { className: propSizeChangerClassName, onChange: propSizeChangerOnChange } = + mergedShowSizeChangerSelectProps || {}; + + // Origin Select is using Select.Option, + // So it make the option value must be string + // Just for compatible + const selectedValue = options.find( + (option) => String(option.value) === String(pageSize), + )?.value; + + return ( + triggerNode.parentNode} + aria-label={ariaLabel} + options={options} + {...mergedShowSizeChangerSelectProps} + value={selectedValue} + onChange={(nextSize, option) => { + onSizeChange?.(nextSize); + propSizeChangerOnChange?.(nextSize, option); + }} + size={isSmall ? 'small' : 'middle'} + className={classNames(sizeChangerClassName, propSizeChangerClassName)} + /> + ); + }; + + if (process.env.NODE_ENV !== 'production') { + const warning = devUseWarning('Pagination'); + + warning( + !selectComponentClass, + 'usage', + '`selectComponentClass` is not official api which will be removed.', + ); + } + + // ============================= Render ============================= const iconsProps = React.useMemo>(() => { const ellipsis = •••; const prevIcon = ( @@ -103,14 +189,6 @@ const Pagination: React.FC = (props) => { return { prevIcon, nextIcon, jumpPrevIcon, jumpNextIcon }; }, [direction, prefixCls]); - const [contextLocale] = useLocale('Pagination', enUS); - - const locale = { ...contextLocale, ...customLocale }; - - const mergedSize = useSize(customizeSize); - - const isSmall = mergedSize === 'small' || !!(xs && !mergedSize && responsive); - const selectPrefixCls = getPrefixCls('select', customizeSelectPrefixCls); const extendedClassName = classNames( @@ -139,9 +217,10 @@ const Pagination: React.FC = (props) => { prefixCls={prefixCls} selectPrefixCls={selectPrefixCls} className={extendedClassName} - selectComponentClass={selectComponentClass || (isSmall ? MiniSelect : MiddleSelect)} locale={locale} + pageSizeOptions={mergedPageSizeOptions} showSizeChanger={mergedShowSizeChanger} + sizeChangerRender={sizeChangerRender} /> , ); diff --git a/components/pagination/Select.tsx b/components/pagination/Select.tsx deleted file mode 100644 index d4bb9192a3..0000000000 --- a/components/pagination/Select.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as React from 'react'; - -import type { SelectProps } from '../select'; -import Select from '../select'; - -type CompoundedComponent = React.FC & { - Option: typeof Select.Option; -}; - -const MiniSelect: CompoundedComponent = (props) => ; - -MiniSelect.Option = Select.Option; -MiddleSelect.Option = Select.Option; - -export { MiniSelect, MiddleSelect }; diff --git a/components/pagination/__tests__/index.test.tsx b/components/pagination/__tests__/index.test.tsx index 55cbc0db04..1f107446ad 100644 --- a/components/pagination/__tests__/index.test.tsx +++ b/components/pagination/__tests__/index.test.tsx @@ -56,6 +56,8 @@ describe('Pagination', () => { }); it('should support custom selectComponentClass', () => { + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + const CustomSelect: React.FC<{ className?: string }> & { Option: OptionFC } = ({ className, ...props @@ -67,6 +69,11 @@ describe('Pagination', () => { , ); expect(container.querySelectorAll('.custom-select').length).toBeTruthy(); + expect(errorSpy).toHaveBeenCalledWith( + 'Warning: [antd: Pagination] `selectComponentClass` is not official api which will be removed.', + ); + + errorSpy.mockRestore(); }); describe('ConfigProvider', () => { @@ -104,4 +111,19 @@ describe('Pagination', () => { expect(container.querySelector('.ant-pagination-end')).toBeTruthy(); }); }); + + it('showSizeChanger support showSearch=false', () => { + const { container } = render( + , + ); + + // Expect `input` is `readonly` + expect(container.querySelector('.ant-select input')).toHaveAttribute('readonly'); + }); }); diff --git a/components/pagination/index.en-US.md b/components/pagination/index.en-US.md index 7729c20f75..f78023a188 100644 --- a/components/pagination/index.en-US.md +++ b/components/pagination/index.en-US.md @@ -47,7 +47,7 @@ Common props ref:[Common props](/docs/react/common-props) | hideOnSinglePage | Whether to hide pager on single page | boolean | false | | | itemRender | To customize item's innerHTML | (page, type: 'page' \| 'prev' \| 'next', originalElement) => React.ReactNode | - | | | pageSize | Number of data items per page | number | - | | -| pageSizeOptions | Specify the sizeChanger options | string\[] \| number\[] | \[`10`, `20`, `50`, `100`] | | +| pageSizeOptions | Specify the sizeChanger options | number\[] | \[`10`, `20`, `50`, `100`] | | | responsive | If `size` is not specified, `Pagination` would resize according to the width of the window | boolean | - | | | showLessItems | Show less page items | boolean | false | | | showQuickJumper | Determine whether you can jump to pages directly | boolean \| { goButton: ReactNode } | false | | diff --git a/components/pagination/index.zh-CN.md b/components/pagination/index.zh-CN.md index 7d86134356..130b58a21e 100644 --- a/components/pagination/index.zh-CN.md +++ b/components/pagination/index.zh-CN.md @@ -48,7 +48,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*WM86SrBC8TsAAA | hideOnSinglePage | 只有一页时是否隐藏分页器 | boolean | false | | | itemRender | 用于自定义页码的结构,可用于优化 SEO | (page, type: 'page' \| 'prev' \| 'next', originalElement) => React.ReactNode | - | | | pageSize | 每页条数 | number | - | | -| pageSizeOptions | 指定每页可以显示多少条 | string\[] \| number\[] | \[`10`, `20`, `50`, `100`] | | +| pageSizeOptions | 指定每页可以显示多少条 | number\[] | \[`10`, `20`, `50`, `100`] | | | responsive | 当 size 未指定时,根据屏幕宽度自动调整尺寸 | boolean | - | | | showLessItems | 是否显示较少页面内容 | boolean | false | | | showQuickJumper | 是否可以快速跳转至某页 | boolean \| { goButton: ReactNode } | false | | diff --git a/components/pagination/useShowSizeChanger.ts b/components/pagination/useShowSizeChanger.ts new file mode 100644 index 0000000000..7cef761ad3 --- /dev/null +++ b/components/pagination/useShowSizeChanger.ts @@ -0,0 +1,18 @@ +import { useMemo } from 'react'; + +import type { PaginationProps } from '.'; +import type { SelectProps } from '../select'; + +export default function useShowSizeChanger(showSizeChanger?: PaginationProps['showSizeChanger']) { + return useMemo<[show: boolean | undefined, selectProps: SelectProps | undefined]>(() => { + if (typeof showSizeChanger === 'boolean') { + return [showSizeChanger, {}]; + } + + if (showSizeChanger && typeof showSizeChanger === 'object') { + return [true, showSizeChanger]; + } + + return [undefined, undefined]; + }, [showSizeChanger]); +} diff --git a/package.json b/package.json index a60cdfff57..9e8677e43b 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "rc-menu": "~9.16.0", "rc-motion": "^2.9.3", "rc-notification": "~5.6.2", - "rc-pagination": "~4.3.0", + "rc-pagination": "~5.0.0", "rc-picker": "~4.8.3", "rc-progress": "~4.0.0", "rc-rate": "~2.13.0",