UNPKG

@retailmenot/anchor

Version:

A React UI Library by RetailMeNot

414 lines (372 loc) 13 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var __chunk_1 = require('./anchor-chunk-24f232e7.js'); var __chunk_2 = require('./anchor-chunk-9d9a5df6.js'); var __chunk_7 = require('./anchor-chunk-eb382a51.js'); var form = require('./form.js'); var React = require('react'); var classNames = _interopDefault(require('classnames')); var styled = require('@xstyled/styled-components'); var styled__default = _interopDefault(styled); var system = require('@xstyled/system'); require('./addevent.js'); require('./anchor-chunk-31a3b978.js'); require('./arrowback.js'); require('./arrowforward.js'); require('./avataricon.js'); require('./avataroutline.js'); require('./barcode.js'); require('./bulletlist.js'); require('./calendar.js'); require('./camera.js'); require('./cart.js'); require('./cashback.js'); require('./cells.js'); require('./chat.js'); require('./check.js'); require('./checksmall.js'); require('./chevrondown.js'); require('./chevrondownsmall.js'); var chevronleft = require('./chevronleft.js'); require('./chevronleftsmall.js'); var chevronright = require('./chevronright.js'); require('./chevronrightsmall.js'); require('./chevronup.js'); require('./chevronupsmall.js'); require('./clock.js'); require('./close.js'); require('./closesmall.js'); require('./commentmore.js'); require('./creditcard.js'); require('./crosshairs.js'); require('./cut.js'); require('./disabled.js'); require('./dislike.js'); require('./download.js'); var ellipses = require('./ellipses.js'); require('./ellipsesvertical.js'); require('./envelope.js'); require('./envelopeopen.js'); require('./error.js'); require('./expand.js'); require('./gear.js'); require('./giftcard.js'); require('./hamburger.js'); require('./heart.js'); require('./heartoutline.js'); require('./home.js'); require('./info.js'); require('./infooutline.js'); require('./laptop.js'); require('./lightning.js'); require('./like.js'); require('./listicon.js'); require('./lock.js'); require('./map.js'); require('./marker.js'); require('./markeroutline.js'); require('./mobile.js'); require('./news.js'); require('./pencil.js'); require('./play.js'); require('./plus.js'); require('./plussmall.js'); require('./print.js'); require('./question.js'); require('./questionoutline.js'); require('./refresh.js'); require('./retailmenotlogo.js'); require('./sadface.js'); require('./search.js'); require('./share.js'); require('./sliders.js'); require('./star.js'); require('./starhalf.js'); require('./staroutline.js'); require('./success.js'); require('./successoutline.js'); require('./tag.js'); require('./upload.js'); require('./tagadd.js'); var __chunk_6 = require('./anchor-chunk-cd6fece5.js'); require('./anchor-chunk-1efd6395.js'); require('./anchor-chunk-598e53e1.js'); require('polished'); require('./anchor-chunk-f296150d.js'); require('./anchor-chunk-925bd1f9.js'); function _templateObject() { var data = __chunk_1._taggedTemplateLiteral(["\n width: 6rem;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 0 0.5rem;\n\n .anchor-input {\n margin-left: 0.5rem;\n }\n"]); _templateObject = function _templateObject() { return data; }; return data; } var EventKeyCodes = { ENTER: 13 }; var StyledGoto = styled__default('div')(_templateObject()); var Goto = function Goto(_a) { var onSubmit = _a.onSubmit, className = _a.className, props = __chunk_2.__rest(_a, ["onSubmit", "className"]); var _React$useState = React.useState(null), _React$useState2 = __chunk_1._slicedToArray(_React$useState, 2), value = _React$useState2[0], setValue = _React$useState2[1]; var handleSubmit = function handleSubmit() { if (onSubmit && value !== null) { onSubmit(value); setValue(null); } }; return React.createElement(StyledGoto, Object.assign({ className: classNames('anchor-pagination-goto', className) }, props), "Goto", React.createElement(form.Input, { type: "number", onChange: function onChange(num) { return setValue(num); }, onKeyDown: function onKeyDown(event) { if (event.keyCode === EventKeyCodes.ENTER) { handleSubmit(); } }, value: value === null ? '' : value })); }; /* eslint-disable prefer-arrow-callback */ // for detecting when values change // https://stackoverflow.com/a/58217148 // Named functions are for stack traceability var useIsMounted = function useIsMounted() { var isMounted = React.useRef(false); React.useEffect(function setIsMounted() { isMounted.current = true; return function cleanupSetIsMounted() { isMounted.current = false; }; }, []); return isMounted; }; var useUpdateEffect = function useUpdateEffect(effect, dependencies) { var isMounted = useIsMounted(); var isInitialMount = React.useRef(true); React.useEffect(function () { // eslint-disable-next-line @typescript-eslint/no-empty-function var effectCleanupFunc = function noop() {}; if (isInitialMount.current) { isInitialMount.current = false; } else { effectCleanupFunc = effect() || effectCleanupFunc; } return function () { effectCleanupFunc(); if (!isMounted.current) { isInitialMount.current = true; } }; }, dependencies); }; function _templateObject2() { var data = __chunk_1._taggedTemplateLiteral(["\n display: inline;\n margin: 0 1rem;\n"]); _templateObject2 = function _templateObject2() { return data; }; return data; } function _templateObject$1() { var data = __chunk_1._taggedTemplateLiteral(["\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n\n ", "\n"]); _templateObject$1 = function _templateObject() { return data; }; return data; } // Used primarily here to keep the current page // value between the first page and last page var constrain = function constrain(min, value, max) { return Math.min(Math.max(value, min), max); }; var Button = function Button(_a) { var _a$variant = _a.variant, variant = _a$variant === void 0 ? 'minimal' : _a$variant, _a$size = _a.size, size = _a$size === void 0 ? 'sm' : _a$size, props = __chunk_2.__rest(_a, ["variant", "size"]); return React.createElement(__chunk_7.Button, Object.assign({ variant: variant, size: size }, props)); }; var StyledPagination = styled__default('div')(_templateObject$1(), system.space); var AffixWrapper = styled__default('div')(_templateObject2()); function reducer(state, action) { switch (action.type) { case 'increment': return Object.assign(Object.assign({}, state), { current: Math.min(state.current + 1, action.total) }); case 'decrement': return Object.assign(Object.assign({}, state), { current: Math.max(state.current - 1, 1) }); case 'setCurrent': return Object.assign(Object.assign({}, state), { current: constrain(1, action.payload, action.total) }); case 'totalChanged': // This will make it so that if the current page is now beyond the // new page total then the current page changes to the new last page. // It might be that we want to revert to the first page instead. return Object.assign(Object.assign({}, state), { current: constrain(1, state.current, action.total) }); default: throw new Error("Unrecognized reducer action type: ".concat(action && action.type)); } } // We could improve this component by adding ways to show the total number of results, // allowing "Next" and "Prev" text instead of arrows, and having the Ellipses buttons // dropdown a Goto or decrement/increment the current page by 5, for instance. var Pagination = function Pagination(_a) { var className = _a.className, prefix = _a.prefix, suffix = _a.suffix, children = _a.children, totalPages = _a.totalPages, totalResults = _a.totalResults, _a$pageSize = _a.pageSize, pageSize = _a$pageSize === void 0 ? 10 : _a$pageSize, controlledCurrent = _a.current, showGoto = _a.showGoto, _a$showArrows = _a.showArrows, showArrows = _a$showArrows === void 0 ? true : _a$showArrows, _a$size2 = _a.size, size = _a$size2 === void 0 ? 'sm' : _a$size2, onChange = _a.onChange, _a$variant2 = _a.variant, variant = _a$variant2 === void 0 ? 'expanded' : _a$variant2, props = __chunk_2.__rest(_a, ["className", "prefix", "suffix", "children", "totalPages", "totalResults", "pageSize", "current", "showGoto", "showArrows", "size", "onChange", "variant"]); var _React$useReducer = React.useReducer(reducer, { current: controlledCurrent || 1 }), _React$useReducer2 = __chunk_1._slicedToArray(_React$useReducer, 2), state = _React$useReducer2[0], dispatch = _React$useReducer2[1]; // If the current page is controlled we want to // prefer that over internal state var current = controlledCurrent || state.current; // Prefer the totalPages prop over calculating from // the totalResults/pageSize var total = totalPages || totalResults && Math.ceil(totalResults / pageSize) || 1; useUpdateEffect(function () { dispatch({ type: 'totalChanged', total: total }); }, [total]); useUpdateEffect(function () { if (onChange) { onChange(state.current); } }, [state.current]); var pageButton = function pageButton(_ref) { var page = _ref.page, slot = _ref.slot; return React.createElement(Button, { className: current === page ? 'active' : undefined, size: size, key: "page".concat(page, ":").concat(slot), onClick: function onClick() { return dispatch({ type: 'setCurrent', payload: page, total: total }); }, variant: current === page ? 'filled' : undefined, prefix: React.createElement(React.Fragment, null, page) }); }; // Seven is enough to show the first and last page, the current page // and pages on either side, and potential ellipses in between. If the // page count is 7 or less, we can just display a button for each // page. var numButtonSlots = 7; var iconSize = size === 'sm' ? 'lg' : undefined; var renderProps = { current: current, totalPages: total, totalResults: totalResults, pageSize: pageSize, range: [(current - 1) * pageSize + 1, Math.min(pageSize * current, totalResults || Infinity)] }; return React.createElement(React.Fragment, null, React.createElement(StyledPagination, Object.assign({ className: classNames('anchor-pagination', className) }, props), prefix && React.createElement(AffixWrapper, null, prefix(renderProps)), showArrows && React.createElement(Button, { size: size, disabled: current <= 1, prefix: React.createElement(chevronleft.ChevronLeft, { scale: iconSize }), onClick: function onClick() { return dispatch({ type: 'decrement', total: total }); } }), variant === 'minimal' && React.createElement(__chunk_6.Typography, { scale: 20, margin: "0 0.5rem" }, current, " / ", total), variant === 'expanded' && (total <= numButtonSlots ? Array.from(Array(total)).map(function (_, i) { return pageButton({ page: i + 1, slot: i }); }) : React.createElement(React.Fragment, null, pageButton({ page: 1, slot: 1 }), constrain(2, current - 2, total - 5) === 2 ? pageButton({ page: 2, slot: 2 }) : React.createElement(Button, { size: size, prefix: React.createElement(ellipses.Ellipses, null) }), pageButton({ page: constrain(3, current - 1, total - 4), slot: 3 }), pageButton({ page: constrain(4, current, total - 3), slot: 4 }), pageButton({ page: constrain(5, current + 1, total - 2), slot: 5 }), constrain(6, current + 2, total - 1) === total - 1 ? pageButton({ page: total - 1, slot: 6 }) : React.createElement(Button, { size: size, prefix: React.createElement(ellipses.Ellipses, null) }), pageButton({ page: total, slot: 7 }))), showArrows && React.createElement(Button, { size: size, disabled: current === total, prefix: React.createElement(chevronright.ChevronRight, { scale: iconSize }), onClick: function onClick() { return dispatch({ type: 'increment', total: total }); } }), suffix && React.createElement(AffixWrapper, null, suffix(renderProps)), showGoto && React.createElement(Goto, { onSubmit: function onSubmit(page) { return dispatch({ type: 'setCurrent', payload: page, total: total }); } })), children && children(renderProps)); }; exports.Pagination = Pagination; //# sourceMappingURL=pagination.js.map