react-responsive-pagination
Version:
React component for responsive pagination
132 lines (131 loc) • 5.91 kB
JavaScript
import React, { memo, useEffect } from 'react';
import PropTypes from 'prop-types';
import { usePaginationItems } from "./hooks/usePaginationItems.js";
import { defaultLabelBehaviour } from "./labelBehaviour.js";
import { incRenderCount } from "./debug.js";
export * from "./narrowBehaviour.js";
export * from "./presets.js";
export * from "./labelBehaviour.js";
/**
* @public
*/
const ResponsivePaginationComponent = memo(ResponsivePagination);
export default ResponsivePaginationComponent;
function ResponsivePagination(props) {
incRenderCount();
if (process.env.NODE_ENV !== 'production') {
checkLegacyProps(props);
}
const { current, total, onPageChange: handlePageChange, maxWidth, narrowBehaviour, className, containerClassName, extraClassName = 'justify-content-center', pageItemClassName = 'page-item', pageLinkClassName = 'page-link', activeItemClassName = 'active', inactiveItemClassName = '', disabledItemClassName = 'disabled', navClassName, previousClassName, nextClassName, classMerge = defaultClassMerge, previousLabel, nextLabel, ariaPreviousLabel, ariaNextLabel, ariaPageLabel, renderNav = 'anchor-disabled-span', ariaCurrentAttr = true, linkHref = 'hash', labelBehaviour: getLabel = defaultLabelBehaviour, } = props;
const { visible, items, ref, clearCache } = usePaginationItems(current, total, {
handlePageChange,
previousLabel,
nextLabel,
ariaPreviousLabel,
ariaNextLabel,
ariaPageLabel,
ariaCurrentAttr,
linkHref,
maxWidth,
omitNav: ['none', false].includes(renderNav),
narrowBehaviour,
});
useEffect(() => {
return () => clearCache();
}, [
clearCache,
className,
containerClassName,
pageItemClassName,
pageLinkClassName,
activeItemClassName,
inactiveItemClassName,
disabledItemClassName,
navClassName,
previousClassName,
nextClassName,
classMerge,
]);
if (items.length === 0)
return null;
function getContainerClassName() {
if (className !== undefined) {
return className;
}
else if (containerClassName !== undefined) {
return containerClassName;
}
else if (extraClassName) {
return `pagination ${extraClassName}`;
}
else {
return 'pagination';
}
}
function getListItemClassName(item) {
return classNames(classMerge, [
pageItemClassName,
item.gotoPage === undefined
? disabledItemClassName
: item.active
? activeItemClassName
: inactiveItemClassName,
item.type === 'next' && (nextClassName ?? navClassName),
item.type === 'previous' && (previousClassName ?? navClassName),
]);
}
return (React.createElement("ul", { className: getContainerClassName(), ref: ref, ...(!visible && { style: { visibility: 'hidden' } }) }, items.map(item => (React.createElement("li", { key: item.key, className: getListItemClassName(item), ...item.listItemProps }, item.type === 'previous' || item.type === 'next' ? (renderNav === 'button' ? (React.createElement("button", { className: pageLinkClassName, ...item.buttonProps }, getLabel(item))) : item.gotoPage !== undefined || renderNav === 'anchor' ? (React.createElement("a", { className: pageLinkClassName, ...item.anchorProps }, getLabel(item))) : (React.createElement("span", { className: pageLinkClassName, ...item.spanAsAnchorProps }, getLabel(item)))) : item.type === 'ellipsis' ? (React.createElement("span", { className: pageLinkClassName }, getLabel(item))) : (React.createElement("a", { className: pageLinkClassName, ...item.anchorProps }, getLabel(item))))))));
}
function classNames(classMerge, names) {
return classMerge(names.filter((name) => Boolean(name)));
}
const defaultClassMerge = (classNames) => classNames.join(' ');
ResponsivePagination.propTypes = {
current: PropTypes.number.isRequired,
total: PropTypes.number.isRequired,
onPageChange: PropTypes.func.isRequired,
maxWidth: PropTypes.number,
narrowBehaviour: PropTypes.func,
className: PropTypes.string,
containerClassName: PropTypes.string,
extraClassName: PropTypes.string,
pageItemClassName: PropTypes.string,
pageLinkClassName: PropTypes.string,
activeItemClassName: PropTypes.string,
inactiveItemClassName: PropTypes.string,
disabledItemClassName: PropTypes.string,
disabledLinkClassName: PropTypes.string,
navClassName: PropTypes.string,
previousClassName: PropTypes.string,
nextClassName: PropTypes.string,
classMerge: PropTypes.func,
previousLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
nextLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
ariaPreviousLabel: PropTypes.string,
ariaNextLabel: PropTypes.string,
ariaPageLabel: PropTypes.func,
renderNav: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.oneOf(['none', 'anchor', 'anchor-disabled-span', 'button']),
]),
ariaCurrentAttr: PropTypes.bool,
linkHref: PropTypes.oneOfType([
PropTypes.func,
PropTypes.oneOf(['hash', 'omit']),
]),
labelBehaviour: PropTypes.func,
};
const legacyUsageWarnings = [];
function checkLegacyProps(props) {
for (const legacyProp of [
'srOnlyClassName',
'a11yActiveLabel',
'narrowStrategy',
]) {
if (props[legacyProp] !== undefined &&
!legacyUsageWarnings.includes(legacyProp)) {
console.warn(`react-responsive-pagination: '${legacyProp}' prop no longer supported, please see migration guide: https://react-responsive-pagination.elantha.com/migration`);
legacyUsageWarnings.push(legacyProp);
}
}
}