@availity/pagination
Version:
component for displaying paginated data
508 lines (501 loc) • 19 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __getProtoOf = Object.getPrototypeOf;
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 __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
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/index.ts
var src_exports = {};
__export(src_exports, {
AvResourcePagination: () => AvResourcePagination_default,
Pagination: () => Pagination_default,
PaginationContent: () => PaginationContent_default,
PaginationContext: () => PaginationContext,
PaginationControls: () => PaginationControls_default,
default: () => src_default,
usePagination: () => usePagination
});
module.exports = __toCommonJS(src_exports);
// src/Pagination.tsx
var import_react = require("react");
var import_isFunction = __toESM(require("lodash/isFunction"));
var import_react_use = require("react-use");
var import_jsx_runtime = require("react/jsx-runtime");
var PaginationContext = (0, import_react.createContext)(null);
function usePagination() {
const ctx = (0, import_react.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 = (0, import_react.useRef)(null);
const [stateCurrentPage, setPage] = (0, import_react.useState)(defaultPage);
const [doFocusRefOnPageChange, setDoFocusRefOnPageChange] = (0, import_react.useState)(false);
const [pageData, setPageData] = (0, import_react.useState)({
total: theItems != null && !(0, import_isFunction.default)(theItems) ? theItems.length : 0,
pageCount: 0,
page: [],
allPages: [],
lower: 0,
upper: 0,
hasMore: false
});
const currentPage = propsCurrentPage || stateCurrentPage;
const [loading, setLoading] = (0, import_react.useState)(true);
const [error, setError] = (0, import_react.useState)(null);
const toggleLoading = (isLoading) => {
setLoading((prev) => isLoading !== void 0 ? isLoading : !prev);
};
(0, import_react.useEffect)(() => {
if (onError && error)
onError(error);
}, [error, onError]);
const getPageData = () => __async(this, null, function* () {
try {
toggleLoading(true);
const { items, totalCount } = (0, import_isFunction.default)(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 = (0, import_isFunction.default)(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);
}
});
(0, import_react_use.useDebounce)(
() => {
if (!shouldReturnPrevious) {
getPageData();
}
},
debounceTimeout,
[currentPage, itemsPerPage, (0, import_isFunction.default)(theItems) ? null : theItems, shouldReturnPrevious, ...watchList]
);
const updatePage = (page) => {
if (page !== currentPage) {
toggleLoading(true);
if (!propsCurrentPage) {
setPage(page);
}
if (onPageChange) {
onPageChange(page);
}
}
};
const firstUpdate = (0, import_react.useRef)(true);
(0, import_react_use.useDebounce)(
() => {
if (firstUpdate.current) {
firstUpdate.current = false;
} else {
setPageData(__spreadProps(__spreadValues({}, pageData), { allPages: [] }));
const current = currentPage;
updatePage(1);
if (current === 1 && (0, import_isFunction.default)(theItems)) {
getPageData();
}
}
},
debounceTimeout,
[...resetParams]
);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
PaginationContext.Provider,
{
value: __spreadProps(__spreadValues({}, pageData), {
setPage: updatePage,
currentPage,
loading,
error,
setError,
itemsPerPage,
ref,
setDoFocusRefOnPageChange
}),
children
}
);
}
var Pagination_default = Pagination;
// src/PaginationContent.tsx
var import_react2 = __toESM(require("react"));
var import_reactstrap = require("reactstrap");
var import_react_infinite_scroll_component = __toESM(require("react-infinite-scroll-component"));
var import_block_ui = __toESM(require("@availity/block-ui"));
var import_isFunction2 = __toESM(require("lodash/isFunction"));
var import_jsx_runtime2 = require("react/jsx-runtime");
var import_react3 = require("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 = (0, import_react2.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 = import_react2.default.forwardRef((props, innerRef) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "sr-only", ref: innerRef }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Component, __spreadValues({}, props))
] }));
return /* @__PURE__ */ (0, import_react3.createElement)(ComponentWithRef, __spreadValues(__spreadProps(__spreadValues({ ref }, rest), { key: value[itemKey] || index }), value));
}
return /* @__PURE__ */ (0, import_react3.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__ */ (0, import_react3.createElement)(Component, __spreadValues(__spreadProps(__spreadValues({}, rest), { key: value[itemKey] || key }), value));
});
}
if (children) {
return (0, import_isFunction2.default)(children) ? children({ items }) : children;
}
return items;
}, [allPages, children, Component, infiniteScroll, itemKey, lower, page, ref, rest]);
if (infiniteScroll) {
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
import_react_infinite_scroll_component.default,
__spreadProps(__spreadValues({
loader: loader && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "h3", children: loadingMessage })
}, infiniteScrollProps), {
next: () => {
setPage(currentPage + 1);
},
hasMore,
dataLength: allPages.length,
children: [
_children,
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_reactstrap.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__ */ (0, import_jsx_runtime2.jsx)(
import_block_ui.default,
__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
var import_reactstrap2 = require("reactstrap");
var import_jsx_runtime3 = require("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__ */ (0, import_jsx_runtime3.jsx)(import_reactstrap2.PaginationItem, { active: currentPage === pageNumber, "data-testid": `control-page-${pageNumber}`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
import_reactstrap2.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__ */ (0, import_jsx_runtime3.jsx)(import_reactstrap2.PaginationItem, { "data-testid": `control-page-${index}`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
import_reactstrap2.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__ */ (0, import_jsx_runtime3.jsxs)(import_reactstrap2.Pagination, __spreadProps(__spreadValues({ "data-testid": "pagination-controls-con" }, rest), { children: [
directionLinks ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_reactstrap2.PaginationItem, { disabled: currentPage === 1, "data-testid": "pagination-control-previous", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
import_reactstrap2.PaginationLink,
{
onClick: () => currentPage === 1 ? null : setPage(currentPage - 1),
type: "button",
"aria-disabled": currentPage === 1,
previous: true,
children: [
leftCaret,
" Prev"
]
}
) }) : "",
paginate(),
directionLinks ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_reactstrap2.PaginationItem, { disabled: currentPage === pageCount, "data-testid": "pagination-control-next", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
import_reactstrap2.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__ */ (0, import_jsx_runtime3.jsx)("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
var import_jsx_runtime4 = require("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__ */ (0, import_jsx_runtime4.jsx)(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;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AvResourcePagination,
Pagination,
PaginationContent,
PaginationContext,
PaginationControls,
usePagination
});