Pagination.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
  2. import _extends from "@babel/runtime/helpers/esm/extends";
  3. import _typeof from "@babel/runtime/helpers/esm/typeof";
  4. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  5. import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
  6. import classNames from 'classnames';
  7. import useMergedState from "rc-util/es/hooks/useMergedState";
  8. import KeyCode from "rc-util/es/KeyCode";
  9. import pickAttrs from "rc-util/es/pickAttrs";
  10. import warning from "rc-util/es/warning";
  11. import React, { useEffect } from 'react';
  12. import zhCN from "./locale/zh_CN";
  13. import Options from "./Options";
  14. import Pager from "./Pager";
  15. var defaultItemRender = function defaultItemRender(page, type, element) {
  16. return element;
  17. };
  18. function noop() {}
  19. function isInteger(v) {
  20. var value = Number(v);
  21. return typeof value === 'number' && !Number.isNaN(value) && isFinite(value) && Math.floor(value) === value;
  22. }
  23. function calculatePage(p, pageSize, total) {
  24. var _pageSize = typeof p === 'undefined' ? pageSize : p;
  25. return Math.floor((total - 1) / _pageSize) + 1;
  26. }
  27. var Pagination = function Pagination(props) {
  28. var _props$prefixCls = props.prefixCls,
  29. prefixCls = _props$prefixCls === void 0 ? 'rc-pagination' : _props$prefixCls,
  30. _props$selectPrefixCl = props.selectPrefixCls,
  31. selectPrefixCls = _props$selectPrefixCl === void 0 ? 'rc-select' : _props$selectPrefixCl,
  32. className = props.className,
  33. currentProp = props.current,
  34. _props$defaultCurrent = props.defaultCurrent,
  35. defaultCurrent = _props$defaultCurrent === void 0 ? 1 : _props$defaultCurrent,
  36. _props$total = props.total,
  37. total = _props$total === void 0 ? 0 : _props$total,
  38. pageSizeProp = props.pageSize,
  39. _props$defaultPageSiz = props.defaultPageSize,
  40. defaultPageSize = _props$defaultPageSiz === void 0 ? 10 : _props$defaultPageSiz,
  41. _props$onChange = props.onChange,
  42. onChange = _props$onChange === void 0 ? noop : _props$onChange,
  43. hideOnSinglePage = props.hideOnSinglePage,
  44. align = props.align,
  45. _props$showPrevNextJu = props.showPrevNextJumpers,
  46. showPrevNextJumpers = _props$showPrevNextJu === void 0 ? true : _props$showPrevNextJu,
  47. showQuickJumper = props.showQuickJumper,
  48. showLessItems = props.showLessItems,
  49. _props$showTitle = props.showTitle,
  50. showTitle = _props$showTitle === void 0 ? true : _props$showTitle,
  51. _props$onShowSizeChan = props.onShowSizeChange,
  52. onShowSizeChange = _props$onShowSizeChan === void 0 ? noop : _props$onShowSizeChan,
  53. _props$locale = props.locale,
  54. locale = _props$locale === void 0 ? zhCN : _props$locale,
  55. style = props.style,
  56. _props$totalBoundaryS = props.totalBoundaryShowSizeChanger,
  57. totalBoundaryShowSizeChanger = _props$totalBoundaryS === void 0 ? 50 : _props$totalBoundaryS,
  58. disabled = props.disabled,
  59. simple = props.simple,
  60. showTotal = props.showTotal,
  61. _props$showSizeChange = props.showSizeChanger,
  62. showSizeChanger = _props$showSizeChange === void 0 ? total > totalBoundaryShowSizeChanger : _props$showSizeChange,
  63. sizeChangerRender = props.sizeChangerRender,
  64. pageSizeOptions = props.pageSizeOptions,
  65. _props$itemRender = props.itemRender,
  66. itemRender = _props$itemRender === void 0 ? defaultItemRender : _props$itemRender,
  67. jumpPrevIcon = props.jumpPrevIcon,
  68. jumpNextIcon = props.jumpNextIcon,
  69. prevIcon = props.prevIcon,
  70. nextIcon = props.nextIcon;
  71. var paginationRef = React.useRef(null);
  72. var _useMergedState = useMergedState(10, {
  73. value: pageSizeProp,
  74. defaultValue: defaultPageSize
  75. }),
  76. _useMergedState2 = _slicedToArray(_useMergedState, 2),
  77. pageSize = _useMergedState2[0],
  78. setPageSize = _useMergedState2[1];
  79. var _useMergedState3 = useMergedState(1, {
  80. value: currentProp,
  81. defaultValue: defaultCurrent,
  82. postState: function postState(c) {
  83. return Math.max(1, Math.min(c, calculatePage(undefined, pageSize, total)));
  84. }
  85. }),
  86. _useMergedState4 = _slicedToArray(_useMergedState3, 2),
  87. current = _useMergedState4[0],
  88. setCurrent = _useMergedState4[1];
  89. var _React$useState = React.useState(current),
  90. _React$useState2 = _slicedToArray(_React$useState, 2),
  91. internalInputVal = _React$useState2[0],
  92. setInternalInputVal = _React$useState2[1];
  93. useEffect(function () {
  94. setInternalInputVal(current);
  95. }, [current]);
  96. var hasOnChange = onChange !== noop;
  97. var hasCurrent = ('current' in props);
  98. if (process.env.NODE_ENV !== 'production') {
  99. warning(hasCurrent ? hasOnChange : true, 'You provided a `current` prop to a Pagination component without an `onChange` handler. This will render a read-only component.');
  100. }
  101. var jumpPrevPage = Math.max(1, current - (showLessItems ? 3 : 5));
  102. var jumpNextPage = Math.min(calculatePage(undefined, pageSize, total), current + (showLessItems ? 3 : 5));
  103. function getItemIcon(icon, label) {
  104. var iconNode = icon || /*#__PURE__*/React.createElement("button", {
  105. type: "button",
  106. "aria-label": label,
  107. className: "".concat(prefixCls, "-item-link")
  108. });
  109. if (typeof icon === 'function') {
  110. iconNode = /*#__PURE__*/React.createElement(icon, _objectSpread({}, props));
  111. }
  112. return iconNode;
  113. }
  114. function getValidValue(e) {
  115. var inputValue = e.target.value;
  116. var allPages = calculatePage(undefined, pageSize, total);
  117. var value;
  118. if (inputValue === '') {
  119. value = inputValue;
  120. } else if (Number.isNaN(Number(inputValue))) {
  121. value = internalInputVal;
  122. } else if (inputValue >= allPages) {
  123. value = allPages;
  124. } else {
  125. value = Number(inputValue);
  126. }
  127. return value;
  128. }
  129. function isValid(page) {
  130. return isInteger(page) && page !== current && isInteger(total) && total > 0;
  131. }
  132. var shouldDisplayQuickJumper = total > pageSize ? showQuickJumper : false;
  133. /**
  134. * prevent "up arrow" key reseting cursor position within textbox
  135. * @see https://stackoverflow.com/a/1081114
  136. */
  137. function handleKeyDown(event) {
  138. if (event.keyCode === KeyCode.UP || event.keyCode === KeyCode.DOWN) {
  139. event.preventDefault();
  140. }
  141. }
  142. function handleKeyUp(event) {
  143. var value = getValidValue(event);
  144. if (value !== internalInputVal) {
  145. setInternalInputVal(value);
  146. }
  147. switch (event.keyCode) {
  148. case KeyCode.ENTER:
  149. handleChange(value);
  150. break;
  151. case KeyCode.UP:
  152. handleChange(value - 1);
  153. break;
  154. case KeyCode.DOWN:
  155. handleChange(value + 1);
  156. break;
  157. default:
  158. break;
  159. }
  160. }
  161. function handleBlur(event) {
  162. handleChange(getValidValue(event));
  163. }
  164. function changePageSize(size) {
  165. var newCurrent = calculatePage(size, pageSize, total);
  166. var nextCurrent = current > newCurrent && newCurrent !== 0 ? newCurrent : current;
  167. setPageSize(size);
  168. setInternalInputVal(nextCurrent);
  169. onShowSizeChange === null || onShowSizeChange === void 0 || onShowSizeChange(current, size);
  170. setCurrent(nextCurrent);
  171. onChange === null || onChange === void 0 || onChange(nextCurrent, size);
  172. }
  173. function handleChange(page) {
  174. if (isValid(page) && !disabled) {
  175. var currentPage = calculatePage(undefined, pageSize, total);
  176. var newPage = page;
  177. if (page > currentPage) {
  178. newPage = currentPage;
  179. } else if (page < 1) {
  180. newPage = 1;
  181. }
  182. if (newPage !== internalInputVal) {
  183. setInternalInputVal(newPage);
  184. }
  185. setCurrent(newPage);
  186. onChange === null || onChange === void 0 || onChange(newPage, pageSize);
  187. return newPage;
  188. }
  189. return current;
  190. }
  191. var hasPrev = current > 1;
  192. var hasNext = current < calculatePage(undefined, pageSize, total);
  193. function prevHandle() {
  194. if (hasPrev) handleChange(current - 1);
  195. }
  196. function nextHandle() {
  197. if (hasNext) handleChange(current + 1);
  198. }
  199. function jumpPrevHandle() {
  200. handleChange(jumpPrevPage);
  201. }
  202. function jumpNextHandle() {
  203. handleChange(jumpNextPage);
  204. }
  205. function runIfEnter(event, callback) {
  206. if (event.key === 'Enter' || event.charCode === KeyCode.ENTER || event.keyCode === KeyCode.ENTER) {
  207. for (var _len = arguments.length, restParams = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
  208. restParams[_key - 2] = arguments[_key];
  209. }
  210. callback.apply(void 0, restParams);
  211. }
  212. }
  213. function runIfEnterPrev(event) {
  214. runIfEnter(event, prevHandle);
  215. }
  216. function runIfEnterNext(event) {
  217. runIfEnter(event, nextHandle);
  218. }
  219. function runIfEnterJumpPrev(event) {
  220. runIfEnter(event, jumpPrevHandle);
  221. }
  222. function runIfEnterJumpNext(event) {
  223. runIfEnter(event, jumpNextHandle);
  224. }
  225. function renderPrev(prevPage) {
  226. var prevButton = itemRender(prevPage, 'prev', getItemIcon(prevIcon, 'prev page'));
  227. return /*#__PURE__*/React.isValidElement(prevButton) ? /*#__PURE__*/React.cloneElement(prevButton, {
  228. disabled: !hasPrev
  229. }) : prevButton;
  230. }
  231. function renderNext(nextPage) {
  232. var nextButton = itemRender(nextPage, 'next', getItemIcon(nextIcon, 'next page'));
  233. return /*#__PURE__*/React.isValidElement(nextButton) ? /*#__PURE__*/React.cloneElement(nextButton, {
  234. disabled: !hasNext
  235. }) : nextButton;
  236. }
  237. function handleGoTO(event) {
  238. if (event.type === 'click' || event.keyCode === KeyCode.ENTER) {
  239. handleChange(internalInputVal);
  240. }
  241. }
  242. var jumpPrev = null;
  243. var dataOrAriaAttributeProps = pickAttrs(props, {
  244. aria: true,
  245. data: true
  246. });
  247. var totalText = showTotal && /*#__PURE__*/React.createElement("li", {
  248. className: "".concat(prefixCls, "-total-text")
  249. }, showTotal(total, [total === 0 ? 0 : (current - 1) * pageSize + 1, current * pageSize > total ? total : current * pageSize]));
  250. var jumpNext = null;
  251. var allPages = calculatePage(undefined, pageSize, total);
  252. // ================== Render ==================
  253. // When hideOnSinglePage is true and there is only 1 page, hide the pager
  254. if (hideOnSinglePage && total <= pageSize) {
  255. return null;
  256. }
  257. var pagerList = [];
  258. var pagerProps = {
  259. rootPrefixCls: prefixCls,
  260. onClick: handleChange,
  261. onKeyPress: runIfEnter,
  262. showTitle: showTitle,
  263. itemRender: itemRender,
  264. page: -1
  265. };
  266. var prevPage = current - 1 > 0 ? current - 1 : 0;
  267. var nextPage = current + 1 < allPages ? current + 1 : allPages;
  268. var goButton = showQuickJumper && showQuickJumper.goButton;
  269. // ================== Simple ==================
  270. // FIXME: ts type
  271. var isReadOnly = _typeof(simple) === 'object' ? simple.readOnly : !simple;
  272. var gotoButton = goButton;
  273. var simplePager = null;
  274. if (simple) {
  275. // ====== Simple quick jump ======
  276. if (goButton) {
  277. if (typeof goButton === 'boolean') {
  278. gotoButton = /*#__PURE__*/React.createElement("button", {
  279. type: "button",
  280. onClick: handleGoTO,
  281. onKeyUp: handleGoTO
  282. }, locale.jump_to_confirm);
  283. } else {
  284. gotoButton = /*#__PURE__*/React.createElement("span", {
  285. onClick: handleGoTO,
  286. onKeyUp: handleGoTO
  287. }, goButton);
  288. }
  289. gotoButton = /*#__PURE__*/React.createElement("li", {
  290. title: showTitle ? "".concat(locale.jump_to).concat(current, "/").concat(allPages) : null,
  291. className: "".concat(prefixCls, "-simple-pager")
  292. }, gotoButton);
  293. }
  294. simplePager = /*#__PURE__*/React.createElement("li", {
  295. title: showTitle ? "".concat(current, "/").concat(allPages) : null,
  296. className: "".concat(prefixCls, "-simple-pager")
  297. }, isReadOnly ? internalInputVal : /*#__PURE__*/React.createElement("input", {
  298. type: "text",
  299. "aria-label": locale.jump_to,
  300. value: internalInputVal,
  301. disabled: disabled,
  302. onKeyDown: handleKeyDown,
  303. onKeyUp: handleKeyUp,
  304. onChange: handleKeyUp,
  305. onBlur: handleBlur,
  306. size: 3
  307. }), /*#__PURE__*/React.createElement("span", {
  308. className: "".concat(prefixCls, "-slash")
  309. }, "/"), allPages);
  310. }
  311. // ====================== Normal ======================
  312. var pageBufferSize = showLessItems ? 1 : 2;
  313. if (allPages <= 3 + pageBufferSize * 2) {
  314. if (!allPages) {
  315. pagerList.push( /*#__PURE__*/React.createElement(Pager, _extends({}, pagerProps, {
  316. key: "noPager",
  317. page: 1,
  318. className: "".concat(prefixCls, "-item-disabled")
  319. })));
  320. }
  321. for (var i = 1; i <= allPages; i += 1) {
  322. pagerList.push( /*#__PURE__*/React.createElement(Pager, _extends({}, pagerProps, {
  323. key: i,
  324. page: i,
  325. active: current === i
  326. })));
  327. }
  328. } else {
  329. var prevItemTitle = showLessItems ? locale.prev_3 : locale.prev_5;
  330. var nextItemTitle = showLessItems ? locale.next_3 : locale.next_5;
  331. var jumpPrevContent = itemRender(jumpPrevPage, 'jump-prev', getItemIcon(jumpPrevIcon, 'prev page'));
  332. var jumpNextContent = itemRender(jumpNextPage, 'jump-next', getItemIcon(jumpNextIcon, 'next page'));
  333. if (showPrevNextJumpers) {
  334. jumpPrev = jumpPrevContent ? /*#__PURE__*/React.createElement("li", {
  335. title: showTitle ? prevItemTitle : null,
  336. key: "prev",
  337. onClick: jumpPrevHandle,
  338. tabIndex: 0,
  339. onKeyDown: runIfEnterJumpPrev,
  340. className: classNames("".concat(prefixCls, "-jump-prev"), _defineProperty({}, "".concat(prefixCls, "-jump-prev-custom-icon"), !!jumpPrevIcon))
  341. }, jumpPrevContent) : null;
  342. jumpNext = jumpNextContent ? /*#__PURE__*/React.createElement("li", {
  343. title: showTitle ? nextItemTitle : null,
  344. key: "next",
  345. onClick: jumpNextHandle,
  346. tabIndex: 0,
  347. onKeyDown: runIfEnterJumpNext,
  348. className: classNames("".concat(prefixCls, "-jump-next"), _defineProperty({}, "".concat(prefixCls, "-jump-next-custom-icon"), !!jumpNextIcon))
  349. }, jumpNextContent) : null;
  350. }
  351. var left = Math.max(1, current - pageBufferSize);
  352. var right = Math.min(current + pageBufferSize, allPages);
  353. if (current - 1 <= pageBufferSize) {
  354. right = 1 + pageBufferSize * 2;
  355. }
  356. if (allPages - current <= pageBufferSize) {
  357. left = allPages - pageBufferSize * 2;
  358. }
  359. for (var _i = left; _i <= right; _i += 1) {
  360. pagerList.push( /*#__PURE__*/React.createElement(Pager, _extends({}, pagerProps, {
  361. key: _i,
  362. page: _i,
  363. active: current === _i
  364. })));
  365. }
  366. if (current - 1 >= pageBufferSize * 2 && current !== 1 + 2) {
  367. pagerList[0] = /*#__PURE__*/React.cloneElement(pagerList[0], {
  368. className: classNames("".concat(prefixCls, "-item-after-jump-prev"), pagerList[0].props.className)
  369. });
  370. pagerList.unshift(jumpPrev);
  371. }
  372. if (allPages - current >= pageBufferSize * 2 && current !== allPages - 2) {
  373. var lastOne = pagerList[pagerList.length - 1];
  374. pagerList[pagerList.length - 1] = /*#__PURE__*/React.cloneElement(lastOne, {
  375. className: classNames("".concat(prefixCls, "-item-before-jump-next"), lastOne.props.className)
  376. });
  377. pagerList.push(jumpNext);
  378. }
  379. if (left !== 1) {
  380. pagerList.unshift( /*#__PURE__*/React.createElement(Pager, _extends({}, pagerProps, {
  381. key: 1,
  382. page: 1
  383. })));
  384. }
  385. if (right !== allPages) {
  386. pagerList.push( /*#__PURE__*/React.createElement(Pager, _extends({}, pagerProps, {
  387. key: allPages,
  388. page: allPages
  389. })));
  390. }
  391. }
  392. var prev = renderPrev(prevPage);
  393. if (prev) {
  394. var prevDisabled = !hasPrev || !allPages;
  395. prev = /*#__PURE__*/React.createElement("li", {
  396. title: showTitle ? locale.prev_page : null,
  397. onClick: prevHandle,
  398. tabIndex: prevDisabled ? null : 0,
  399. onKeyDown: runIfEnterPrev,
  400. className: classNames("".concat(prefixCls, "-prev"), _defineProperty({}, "".concat(prefixCls, "-disabled"), prevDisabled)),
  401. "aria-disabled": prevDisabled
  402. }, prev);
  403. }
  404. var next = renderNext(nextPage);
  405. if (next) {
  406. var nextDisabled, nextTabIndex;
  407. if (simple) {
  408. nextDisabled = !hasNext;
  409. nextTabIndex = hasPrev ? 0 : null;
  410. } else {
  411. nextDisabled = !hasNext || !allPages;
  412. nextTabIndex = nextDisabled ? null : 0;
  413. }
  414. next = /*#__PURE__*/React.createElement("li", {
  415. title: showTitle ? locale.next_page : null,
  416. onClick: nextHandle,
  417. tabIndex: nextTabIndex,
  418. onKeyDown: runIfEnterNext,
  419. className: classNames("".concat(prefixCls, "-next"), _defineProperty({}, "".concat(prefixCls, "-disabled"), nextDisabled)),
  420. "aria-disabled": nextDisabled
  421. }, next);
  422. }
  423. var cls = classNames(prefixCls, className, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, "".concat(prefixCls, "-start"), align === 'start'), "".concat(prefixCls, "-center"), align === 'center'), "".concat(prefixCls, "-end"), align === 'end'), "".concat(prefixCls, "-simple"), simple), "".concat(prefixCls, "-disabled"), disabled));
  424. return /*#__PURE__*/React.createElement("ul", _extends({
  425. className: cls,
  426. style: style,
  427. ref: paginationRef
  428. }, dataOrAriaAttributeProps), totalText, prev, simple ? simplePager : pagerList, next, /*#__PURE__*/React.createElement(Options, {
  429. locale: locale,
  430. rootPrefixCls: prefixCls,
  431. disabled: disabled,
  432. selectPrefixCls: selectPrefixCls,
  433. changeSize: changePageSize,
  434. pageSize: pageSize,
  435. pageSizeOptions: pageSizeOptions,
  436. quickGo: shouldDisplayQuickJumper ? handleChange : null,
  437. goButton: gotoButton,
  438. showSizeChanger: showSizeChanger,
  439. sizeChangerRender: sizeChangerRender
  440. }));
  441. };
  442. if (process.env.NODE_ENV !== 'production') {
  443. Pagination.displayName = 'Pagination';
  444. }
  445. export default Pagination;