UNPKG

@availity/pagination

Version:
469 lines (463 loc) 16.1 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __objRest = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols) for (var prop of __getOwnPropSymbols(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) target[prop] = source[prop]; } return target; }; var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; // src/Pagination.tsx import { createContext, useState, useContext, useEffect, useRef } from "react"; import isFunction from "lodash/isFunction"; import { useDebounce } from "react-use"; import { jsx } from "react/jsx-runtime"; var PaginationContext = createContext(null); function usePagination() { const ctx = useContext(PaginationContext); if (!ctx) throw new Error("usePagination must be used inside the Pagination Provider"); return ctx; } var defaultValues = { items: [], watchList: [], resetParams: [], itemsPerPage: 10, defaultPage: 1, debounceTimeout: 0, shouldReturnPrevious: false }; function Pagination({ items: theItems = defaultValues.items, page: propsCurrentPage, itemsPerPage = defaultValues.itemsPerPage, onPageChange, children, watchList = defaultValues.watchList, resetParams = defaultValues.resetParams, defaultPage = defaultValues.defaultPage, debounceTimeout = defaultValues.debounceTimeout, shouldReturnPrevious = defaultValues.shouldReturnPrevious, onError }) { const ref = useRef(null); const [stateCurrentPage, setPage] = useState(defaultPage); const [doFocusRefOnPageChange, setDoFocusRefOnPageChange] = useState(false); const [pageData, setPageData] = useState({ total: theItems != null && !isFunction(theItems) ? theItems.length : 0, pageCount: 0, page: [], allPages: [], lower: 0, upper: 0, hasMore: false }); const currentPage = propsCurrentPage || stateCurrentPage; const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const toggleLoading = (isLoading) => { setLoading((prev) => isLoading !== void 0 ? isLoading : !prev); }; useEffect(() => { if (onError && error) onError(error); }, [error, onError]); const getPageData = () => __async(this, null, function* () { try { toggleLoading(true); const { items, totalCount } = isFunction(theItems) ? yield theItems(currentPage, itemsPerPage) : { items: theItems, totalCount: theItems.length }; const lower = currentPage === 1 ? 1 : (currentPage - 1) * itemsPerPage + 1; const upper = items.length - currentPage * itemsPerPage > 0 ? itemsPerPage * currentPage : items.length; const page = isFunction(theItems) ? items : items.slice(lower - 1, upper); const total = totalCount || items.length; const pageCount = Math.ceil(total / itemsPerPage); setPageData({ total, pageCount, page, allPages: [...pageData.allPages, ...page], lower, upper, hasMore: currentPage < pageCount }); if (doFocusRefOnPageChange && ref.current && ref.current.nextSibling) { ref.current.nextSibling.focus(); setDoFocusRefOnPageChange(false); } } catch (error_) { setError(error_); } finally { toggleLoading(false); } }); useDebounce( () => { if (!shouldReturnPrevious) { getPageData(); } }, debounceTimeout, [currentPage, itemsPerPage, isFunction(theItems) ? null : theItems, shouldReturnPrevious, ...watchList] ); const updatePage = (page) => { if (page !== currentPage) { toggleLoading(true); if (!propsCurrentPage) { setPage(page); } if (onPageChange) { onPageChange(page); } } }; const firstUpdate = useRef(true); useDebounce( () => { if (firstUpdate.current) { firstUpdate.current = false; } else { setPageData(__spreadProps(__spreadValues({}, pageData), { allPages: [] })); const current = currentPage; updatePage(1); if (current === 1 && isFunction(theItems)) { getPageData(); } } }, debounceTimeout, [...resetParams] ); return /* @__PURE__ */ jsx( PaginationContext.Provider, { value: __spreadProps(__spreadValues({}, pageData), { setPage: updatePage, currentPage, loading, error, setError, itemsPerPage, ref, setDoFocusRefOnPageChange }), children } ); } var Pagination_default = Pagination; // src/PaginationContent.tsx import React2, { useMemo } from "react"; import { Button } from "reactstrap"; import InfiniteScroll from "react-infinite-scroll-component"; import BlockUI from "@availity/block-ui"; import isFunction2 from "lodash/isFunction"; import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime"; import { createElement } from "react"; var PaginationContent = (_a) => { var _b = _a, { component: Component, loadingMessage, itemKey, loader = false, containerTag = "div", containerProps = {}, infiniteScroll = false, infiniteScrollProps, children } = _b, rest = __objRest(_b, [ "component", "loadingMessage", "itemKey", "loader", "containerTag", "containerProps", "infiniteScroll", "infiniteScrollProps", "children" ]); const { page, currentPage, setPage, allPages, hasMore, loading, lower, ref, setDoFocusRefOnPageChange } = usePagination(); const _children = useMemo(() => { let items; if (infiniteScroll) { const indexOfItemToReference = lower - 1; items = allPages && allPages.map((value, index) => { if (!value[itemKey]) { console.warn("Warning a Pagination Item doesn't have a key:", value); } if (indexOfItemToReference === index) { const ComponentWithRef = React2.forwardRef((props, innerRef) => /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx2("span", { className: "sr-only", ref: innerRef }), /* @__PURE__ */ jsx2(Component, __spreadValues({}, props)) ] })); return /* @__PURE__ */ createElement(ComponentWithRef, __spreadValues(__spreadProps(__spreadValues({ ref }, rest), { key: value[itemKey] || index }), value)); } return /* @__PURE__ */ createElement(Component, __spreadValues(__spreadProps(__spreadValues({}, rest), { key: value[itemKey] || index }), value)); }); } else { items = page && page.map((value, key) => { if (!value[itemKey]) { console.warn("Warning a Pagination Item doesn't have a key:", value); } return /* @__PURE__ */ createElement(Component, __spreadValues(__spreadProps(__spreadValues({}, rest), { key: value[itemKey] || key }), value)); }); } if (children) { return isFunction2(children) ? children({ items }) : children; } return items; }, [allPages, children, Component, infiniteScroll, itemKey, lower, page, ref, rest]); if (infiniteScroll) { return /* @__PURE__ */ jsxs( InfiniteScroll, __spreadProps(__spreadValues({ loader: loader && /* @__PURE__ */ jsx2("div", { className: "h3", children: loadingMessage }) }, infiniteScrollProps), { next: () => { setPage(currentPage + 1); }, hasMore, dataLength: allPages.length, children: [ _children, /* @__PURE__ */ jsx2( Button, { "data-testid": "sr-only-pagination-load-more-btn", className: "sr-only", "aria-label": "Load More", onClick: () => { setDoFocusRefOnPageChange(true); setPage(currentPage + 1); }, children: "Load More" } ) ] }) ); } return /* @__PURE__ */ jsx2( BlockUI, __spreadProps(__spreadValues({ "data-testid": "pagination-content-con", role: containerProps.role || "list", keepInView: true }, containerProps), { tag: containerTag, blocking: loader && loading, message: loadingMessage, children: _children }) ); }; var PaginationContent_default = PaginationContent; // src/PaginationControls.tsx import { Pagination as Pagination2, PaginationItem, PaginationLink } from "reactstrap"; import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime"; var leftCaret = "\u2039"; var rightCaret = "\u203A"; var PaginationControls = (_a) => { var _b = _a, { directionLinks = false, autoHide = true, pageRange = 5, marginPages = 2, breakLabel = true, showPaginationText = false, populatePaginationText } = _b, rest = __objRest(_b, [ "directionLinks", "autoHide", "pageRange", "marginPages", "breakLabel", "showPaginationText", "populatePaginationText" ]); const { pageCount, currentPage, setPage, lower, upper, total } = usePagination(); const createItem = (pageNumber) => /* @__PURE__ */ jsx3(PaginationItem, { active: currentPage === pageNumber, "data-testid": `control-page-${pageNumber}`, children: /* @__PURE__ */ jsx3( PaginationLink, { style: { zIndex: "auto" }, onClick: () => setPage(pageNumber), type: "button", "aria-label": `Go to page ${pageNumber}`, "aria-current": currentPage === pageNumber, children: pageNumber } ) }, pageNumber); const getForwardJump = () => { const forwardJump = currentPage + pageRange; return forwardJump >= pageCount ? pageCount : forwardJump; }; const getBackwardJump = () => { const backwardJump = currentPage - pageRange; return backwardJump < 1 ? 1 : backwardJump; }; const handleBreakClick = (index) => { setPage(currentPage < index ? getForwardJump() : getBackwardJump()); }; const createBreak = (index) => /* @__PURE__ */ jsx3(PaginationItem, { "data-testid": `control-page-${index}`, children: /* @__PURE__ */ jsx3( PaginationLink, { onClick: () => handleBreakClick(index), type: "button", "aria-label": currentPage < index ? `Jump forwards to page ${getForwardJump()}` : `Jump backwards to page ${getBackwardJump()}`, children: "\u2026" } ) }, index); const paginate = () => { const items = []; const selected = currentPage - 1; if (pageCount <= pageRange) { for (let index = 0; index < pageCount; index++) { items.push(createItem(index + 1)); } } else { let leftSide = pageRange / 2; let rightSide = pageRange - leftSide; if (selected > pageCount - leftSide) { rightSide = pageCount - selected; leftSide = pageRange - rightSide; } else if (selected < leftSide) { leftSide = selected; rightSide = pageRange - leftSide; } let breakView; let pageNumber; for (let index = 0; index < pageCount; index++) { pageNumber = index + 1; if (pageNumber <= marginPages || pageNumber > pageCount - marginPages || index >= selected - leftSide && index <= selected + rightSide) { items.push(createItem(pageNumber)); } else if (items[items.length - 1] !== breakView && breakLabel) { breakView = createBreak(pageNumber); items.push(breakView); } } } return items; }; return pageCount > 1 || !autoHide ? /* @__PURE__ */ jsxs2(Pagination2, __spreadProps(__spreadValues({ "data-testid": "pagination-controls-con" }, rest), { children: [ directionLinks ? /* @__PURE__ */ jsx3(PaginationItem, { disabled: currentPage === 1, "data-testid": "pagination-control-previous", children: /* @__PURE__ */ jsxs2( PaginationLink, { onClick: () => currentPage === 1 ? null : setPage(currentPage - 1), type: "button", "aria-disabled": currentPage === 1, previous: true, children: [ leftCaret, " Prev" ] } ) }) : "", paginate(), directionLinks ? /* @__PURE__ */ jsx3(PaginationItem, { disabled: currentPage === pageCount, "data-testid": "pagination-control-next", children: /* @__PURE__ */ jsxs2( PaginationLink, { "data-testid": "pagination-control-next-link", onClick: () => currentPage === pageCount ? null : setPage(currentPage + 1), type: "button", "aria-disabled": currentPage === pageCount, next: true, children: [ "Next ", rightCaret ] } ) }) : "", showPaginationText && /* @__PURE__ */ jsx3("li", { "data-testid": "pagination-text", className: "pagination-text pt-1 pl-2 pr-2", children: populatePaginationText ? populatePaginationText(lower, upper, total) : `${lower}-${upper} of ${total}` }) ] })) : null; }; var PaginationControls_default = PaginationControls; // src/AvResourcePagination.tsx import { jsx as jsx4 } from "react/jsx-runtime"; var AvResourcePagination = (_a) => { var _b = _a, { parameters = {}, resource, getResult, children } = _b, paginationProps = __objRest(_b, [ "parameters", "resource", "getResult", "children" ]); const loadPage = (page, itemsPerPage) => __async(void 0, null, function* () { const params = __spreadValues({ limit: itemsPerPage, offset: (page - 1) * itemsPerPage }, parameters.params || {}); const resp = yield resource.postGet(params, parameters || {}); const useGetResult = getResult || resource.getResult; const items = (typeof useGetResult === "function" ? useGetResult.call(resource, resp.data) : resp.data[useGetResult]) || resp.data; if (!Array.isArray(items)) { throw new TypeError( `Expected data to be an array but got \`${typeof items}\`. Use the \`getResult\` prop to specify how to get the data from the API response.` ); } return { items, totalCount: resp.data.totalCount }; }); return /* @__PURE__ */ jsx4(Pagination_default, __spreadProps(__spreadValues({}, paginationProps), { items: (page, itemsPerPage) => loadPage(page, itemsPerPage), children })); }; var AvResourcePagination_default = AvResourcePagination; // src/index.ts Pagination_default.Controls = PaginationControls_default; Pagination_default.Content = PaginationContent_default; var src_default = Pagination_default; export { AvResourcePagination_default as AvResourcePagination, Pagination_default as Pagination, PaginationContent_default as PaginationContent, PaginationContext, PaginationControls_default as PaginationControls, src_default as default, usePagination };