@helpscout/hsds-react
Version:
React component library for Help Scout's Design System
352 lines (301 loc) • 12.3 kB
JavaScript
"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;