UNPKG

@retailmenot/anchor

Version:

A React UI Library by RetailMeNot

407 lines (368 loc) 12.5 kB
import { c as _slicedToArray, a as _taggedTemplateLiteral } from './anchor-chunk-7b9d8557.js'; import { a as __rest } from './anchor-chunk-27f34e54.js'; import { a as Button } from './anchor-chunk-e1ca097b.js'; import { Input } from './form.js'; import { forwardRef, createElement, useContext, useState, Children, Fragment, useEffect, useRef, createRef, Component, cloneElement, useReducer, PureComponent, isValidElement, createContext, useImperativeHandle } from 'react'; import classNames from 'classnames'; import styled from '@xstyled/styled-components'; import { space } from '@xstyled/system'; import './addevent.js'; import './anchor-chunk-25c07228.js'; import './arrowback.js'; import './arrowforward.js'; import './avataricon.js'; import './avataroutline.js'; import './barcode.js'; import './bulletlist.js'; import './calendar.js'; import './camera.js'; import './cart.js'; import './cashback.js'; import './cells.js'; import './chat.js'; import './check.js'; import './checksmall.js'; import './chevrondown.js'; import './chevrondownsmall.js'; import { ChevronLeft } from './chevronleft.js'; import './chevronleftsmall.js'; import { ChevronRight } from './chevronright.js'; import './chevronrightsmall.js'; import './chevronup.js'; import './chevronupsmall.js'; import './clock.js'; import './close.js'; import './closesmall.js'; import './commentmore.js'; import './creditcard.js'; import './crosshairs.js'; import './cut.js'; import './disabled.js'; import './dislike.js'; import './download.js'; import { Ellipses } from './ellipses.js'; import './ellipsesvertical.js'; import './envelope.js'; import './envelopeopen.js'; import './error.js'; import './expand.js'; import './gear.js'; import './giftcard.js'; import './hamburger.js'; import './heart.js'; import './heartoutline.js'; import './home.js'; import './info.js'; import './infooutline.js'; import './laptop.js'; import './lightning.js'; import './like.js'; import './listicon.js'; import './lock.js'; import './map.js'; import './marker.js'; import './markeroutline.js'; import './mobile.js'; import './news.js'; import './pencil.js'; import './play.js'; import './plus.js'; import './plussmall.js'; import './print.js'; import './question.js'; import './questionoutline.js'; import './refresh.js'; import './retailmenotlogo.js'; import './sadface.js'; import './search.js'; import './share.js'; import './sliders.js'; import './star.js'; import './starhalf.js'; import './staroutline.js'; import './success.js'; import './successoutline.js'; import './tag.js'; import './upload.js'; import './tagadd.js'; import { a as Typography } from './anchor-chunk-5b0bbe0b.js'; import './anchor-chunk-cd7ef49a.js'; import './anchor-chunk-20e4020f.js'; import 'polished'; import './anchor-chunk-6ebffda8.js'; import './anchor-chunk-210b63ef.js'; function _templateObject() { var data = _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('div')(_templateObject()); var Goto = function Goto(_a) { var onSubmit = _a.onSubmit, className = _a.className, props = __rest(_a, ["onSubmit", "className"]); var _React$useState = useState(null), _React$useState2 = _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 createElement(StyledGoto, Object.assign({ className: classNames('anchor-pagination-goto', className) }, props), "Goto", createElement(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 = useRef(false); 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 = useRef(true); 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 = _taggedTemplateLiteral(["\n display: inline;\n margin: 0 1rem;\n"]); _templateObject2 = function _templateObject2() { return data; }; return data; } function _templateObject$1() { var data = _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$1 = function Button$$1(_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 = __rest(_a, ["variant", "size"]); return createElement(Button, Object.assign({ variant: variant, size: size }, props)); }; var StyledPagination = styled('div')(_templateObject$1(), space); var AffixWrapper = styled('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 = __rest(_a, ["className", "prefix", "suffix", "children", "totalPages", "totalResults", "pageSize", "current", "showGoto", "showArrows", "size", "onChange", "variant"]); var _React$useReducer = useReducer(reducer, { current: controlledCurrent || 1 }), _React$useReducer2 = _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 createElement(Button$1, { 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: createElement(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 createElement(Fragment, null, createElement(StyledPagination, Object.assign({ className: classNames('anchor-pagination', className) }, props), prefix && createElement(AffixWrapper, null, prefix(renderProps)), showArrows && createElement(Button$1, { size: size, disabled: current <= 1, prefix: createElement(ChevronLeft, { scale: iconSize }), onClick: function onClick() { return dispatch({ type: 'decrement', total: total }); } }), variant === 'minimal' && createElement(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 }); }) : createElement(Fragment, null, pageButton({ page: 1, slot: 1 }), constrain(2, current - 2, total - 5) === 2 ? pageButton({ page: 2, slot: 2 }) : createElement(Button$1, { size: size, prefix: createElement(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 }) : createElement(Button$1, { size: size, prefix: createElement(Ellipses, null) }), pageButton({ page: total, slot: 7 }))), showArrows && createElement(Button$1, { size: size, disabled: current === total, prefix: createElement(ChevronRight, { scale: iconSize }), onClick: function onClick() { return dispatch({ type: 'increment', total: total }); } }), suffix && createElement(AffixWrapper, null, suffix(renderProps)), showGoto && createElement(Goto, { onSubmit: function onSubmit(page) { return dispatch({ type: 'setCurrent', payload: page, total: total }); } })), children && children(renderProps)); }; export { Pagination }; //# sourceMappingURL=pagination.js.map