UNPKG

@helpscout/hsds-react

Version:

React component library for Help Scout's Design System

352 lines (301 loc) 12.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.pluralize = pluralize; exports.default = exports.Pagination = exports.usePaginationData = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _getValidProps = _interopRequireDefault(require("@helpscout/react-utils/dist/getValidProps")); var _classnames = _interopRequireDefault(require("classnames")); var _KeypressListener = _interopRequireDefault(require("../KeypressListener")); var _Keys = _interopRequireDefault(require("../../constants/Keys")); var _number = require("../../utilities/number"); var _PaginationCss = require("./Pagination.css.js"); var _Text = _interopRequireDefault(require("../Text")); var _Icon = _interopRequireDefault(require("../Icon")); var _jsxRuntime = require("react/jsx-runtime"); var usePaginationData = function usePaginationData(props) { var activePage = props.activePage, pluralizedSubjectProp = props.pluralizedSubject, rangePerPage = props.rangePerPage, subjectProp = props.subject, totalItemProp = props.totalItems; var _React$useMemo = _react.default.useMemo(function () { var totalItems = Math.max(totalItemProp, 0); var numberOfPages = Math.ceil(totalItems / rangePerPage); var currentPage = activePage >= 1 ? Math.min(numberOfPages, Math.round(activePage)) : 1; var startRange = (0, _number.formatNumber)(Math.max(currentPage * rangePerPage - rangePerPage + 1, 0)); var endRange = (0, _number.formatNumber)(Math.min(currentPage * rangePerPage, totalItems)); return { numberOfPages: numberOfPages, currentPage: currentPage, totalItems: totalItems, startRange: startRange, endRange: endRange }; }, [rangePerPage, totalItemProp, activePage]), numberOfPages = _React$useMemo.numberOfPages, currentPage = _React$useMemo.currentPage, totalItems = _React$useMemo.totalItems, startRange = _React$useMemo.startRange, endRange = _React$useMemo.endRange; var pluralizedSubject = _react.default.useMemo(function () { if (totalItems === 0) return subjectProp; if (pluralizedSubjectProp && totalItems > 1) return pluralizedSubjectProp; return pluralize(subjectProp, totalItems); }, [totalItems, pluralizedSubjectProp, subjectProp]); return { currentPage: currentPage, endRange: endRange, numberOfPages: numberOfPages, pluralizedSubject: pluralizedSubject, startRange: startRange, totalItems: totalItems }; }; exports.usePaginationData = usePaginationData; var PaginationNavigation = function PaginationNavigation(props) { var isLoading = props.isLoading, currentPage = props.currentPage, numberOfPages = props.numberOfPages, onChange = props.onChange; var isNotFirstPage = currentPage > 1; var isLastPage = currentPage >= numberOfPages; var handleFirstClick = function handleFirstClick(e) { e.preventDefault(); onChange && onChange(1); }; var handlePrevClick = function handlePrevClick(e) { e.preventDefault(); if (currentPage > 1) { onChange && onChange(currentPage - 1); } }; var handleNextClick = function handleNextClick(e) { e.preventDefault(); if (currentPage < numberOfPages) { onChange && onChange(currentPage + 1); } }; var handleEndClick = function handleEndClick(e) { e.preventDefault(); onChange && onChange(numberOfPages); }; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_PaginationCss.NavigationUI, { "data-testid": "Pagination.Navigation", children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_KeypressListener.default, { keyCode: _Keys.default.KEY_J, handler: handlePrevClick, noModifier: true, type: "keyup" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_KeypressListener.default, { keyCode: _Keys.default.KEY_K, handler: handleNextClick, noModifier: true, type: "keyup" }), isNotFirstPage && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_PaginationCss.ButtonIconUI, { theme: "grey", outlined: true, onClick: handleFirstClick, className: "c-Pagination__firstButton", disabled: isLoading, title: "First page", "data-cy": "Pagination-firstButton", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, { name: "arrow-left-double-large", size: "24", center: true }) }, "firstButton"), /*#__PURE__*/(0, _jsxRuntime.jsx)(_PaginationCss.ButtonIconUI, { theme: "grey", outlined: true, onClick: handlePrevClick, className: "c-Pagination__prevButton", disabled: isLoading, title: "Previous page (j)", "data-cy": "Pagination-prevButton", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, { name: "arrow-left-single-large", size: "24", center: true }) }, "prevButton")] }), !isLastPage && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_PaginationCss.ButtonIconUI, { theme: "grey", outlined: true, disabled: isLoading, onClick: handleNextClick, className: "c-Pagination__nextButton", title: "Next page (k)", "data-cy": "Pagination-nextButton", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, { name: "arrow-right-single-large", size: "24", center: true }) }, "nextButton"), /*#__PURE__*/(0, _jsxRuntime.jsx)(_PaginationCss.ButtonIconUI, { theme: "grey", outlined: true, disabled: isLoading, onClick: handleEndClick, className: "c-Pagination__lastButton", title: "Last page", "data-cy": "Pagination-lastButton", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, { name: "arrow-right-double-large", size: "24", center: true }) }, "lastButton")] })] }); }; var PaginationRange = function PaginationRange(_ref) { var totalItems = _ref.totalItems, shouldShowNavigation = _ref.shouldShowNavigation, pluralizedSubject = _ref.pluralizedSubject, startRange = _ref.startRange, endRange = _ref.endRange, separator = _ref.separator; var totalNode = /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "c-Pagination__total", "data-cy": "Pagination-totalItems", children: (0, _number.formatNumber)(totalItems) }); if (!totalItems || !shouldShowNavigation) { return pluralizedSubject ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_PaginationCss.RangeUI, { "data-testid": "Pagination.Range", children: totalNode }) : null; } return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Text.default, { className: "c-Pagination__range", children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_PaginationCss.RangeUI, { "data-testid": "Pagination.Range", "data-cy": "Pagination-startRange", children: startRange }), " ", "-", " ", /*#__PURE__*/(0, _jsxRuntime.jsx)(_PaginationCss.RangeUI, { "data-testid": "Pagination.Range", "data-cy": "Pagination-endRange", children: endRange }), " ", separator, " ", totalNode] }); }; var Pagination = function Pagination(props) { var activePage = props.activePage, className = props.className, isLoading = props.isLoading, onChange = props.onChange, pluralizedSubjectProp = props.pluralizedSubject, rangePerPage = props.rangePerPage, renderCustomContent = props.renderCustomContent, separator = props.separator, showNavigation = props.showNavigation, subjectProp = props.subject, totalItemProp = props.totalItems, rest = (0, _objectWithoutPropertiesLoose2.default)(props, ["activePage", "className", "isLoading", "onChange", "pluralizedSubject", "rangePerPage", "renderCustomContent", "separator", "showNavigation", "subject", "totalItems"]); var _usePaginationData = usePaginationData(props), numberOfPages = _usePaginationData.numberOfPages, currentPage = _usePaginationData.currentPage, totalItems = _usePaginationData.totalItems, startRange = _usePaginationData.startRange, endRange = _usePaginationData.endRange, pluralizedSubject = _usePaginationData.pluralizedSubject; var shouldShowNavigation = showNavigation && numberOfPages > 1; var componentClassName = (0, _classnames.default)('c-Pagination', className); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_PaginationCss.PaginationUI, (0, _extends2.default)({ "data-testid": "Pagination", role: "navigation", "aria-label": "Pagination Navigation" }, (0, _getValidProps.default)(rest), { className: componentClassName, children: [renderCustomContent ? renderCustomContent({ currentPage: currentPage, endRange: endRange, numberOfPages: numberOfPages, startRange: startRange, pluralizedSubject: pluralizedSubject }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_PaginationCss.InformationUI, { "data-testid": "Pagination.Info", children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Text.default, { size: 13, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(PaginationRange, { totalItems: totalItems, shouldShowNavigation: shouldShowNavigation, pluralizedSubject: pluralizedSubject, startRange: startRange, endRange: endRange, separator: separator }), pluralizedSubject && /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "c-Pagination__subject", children: " " + pluralizedSubject })] }) }), shouldShowNavigation && /*#__PURE__*/(0, _jsxRuntime.jsx)(PaginationNavigation, { currentPage: currentPage, isLoading: isLoading, numberOfPages: numberOfPages, onChange: onChange })] })); }; exports.Pagination = Pagination; function noop() {} Pagination.defaultProps = { activePage: 1, 'data-cy': 'Pagination', innerRef: noop, isLoading: false, onChange: noop, rangePerPage: 50, separator: 'of', showNavigation: true, subject: '', totalItems: 0 }; Pagination.propTypes = { /** Current selected page */ activePage: _propTypes.default.number, /** Custom class names to be added to the component. */ className: _propTypes.default.string, /** Disables the navigation while `true` */ isLoading: _propTypes.default.bool, /** Callback when current page is changed. */ onChange: _propTypes.default.func, /** Pluralize subject. If empty subject will be automaticaly pluralize */ pluralizedSubject: _propTypes.default.string, /** Render prop that allows you to render your own custom content, gives you access to `{starRange, endRange, numberOfPages, currentPage, pluralizedSubject}` */ renderCustomContent: _propTypes.default.func, /** Number of items per page */ rangePerPage: _propTypes.default.number, /** Add a navigation to the component */ showNavigation: _propTypes.default.bool, /** Pagination label after the range */ subject: _propTypes.default.string, /** Total of items */ totalItems: _propTypes.default.number, /** Character between starting and ending range */ separator: _propTypes.default.string, /** Data attr for Cypress tests. */ 'data-cy': _propTypes.default.string }; /** * A super tiny, but naive, way to pluralize a word based on a count value. * @param word {string} The word to pluralize. * @param count {number} The count to check against. * @returns {string} The pluralized word. */ function pluralize(word, count) { if (count === void 0) { count = 1; } if (!word) return ''; if (word.lastIndexOf('s') === word.length - 1) return word; return count === 1 ? word : word + "s"; } var _default = Pagination; exports.default = _default;