@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
123 lines (122 loc) • 4.54 kB
JavaScript
"use client";
import Select from "../Select/Select.mjs";
import { useEventCallback } from "../../hooks/useEventCallback.mjs";
import { clampPage, getPageCount, getPaginationItems } from "./helpers.mjs";
import { buttonVariants, ellipsisVariants, styles } from "./style.mjs";
import { memo, useEffect, useRef, useState } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
import { cx } from "antd-style";
import useMergeState from "use-merge-value";
import { ChevronLeft, ChevronRight } from "lucide-react";
//#region src/base-ui/Pagination/Pagination.tsx
const Pagination = memo(({ className, current, defaultCurrent = 1, defaultPageSize = 10, disabled, hideOnSinglePage, onChange, onPageSizeChange, pageSize, pageSizeOptions = [
10,
20,
50,
100
], ref, showSizeChanger = false, showTotal, size = "middle", style, total, ...rest }) => {
const [mergedPageSize, setMergedPageSize] = useMergeState(defaultPageSize, { value: pageSize });
const pageCount = getPageCount(total, mergedPageSize);
const [mergedCurrent, setMergedCurrent] = useMergeState(defaultCurrent, { value: current });
const onChangeStable = useEventCallback((nextCurrent, nextPageSize) => {
onChange?.(nextCurrent, nextPageSize);
});
const pendingNotifyRef = useRef(null);
const [prevPageCount, setPrevPageCount] = useState(pageCount);
if (pageCount !== prevPageCount) {
setPrevPageCount(pageCount);
if (mergedCurrent > pageCount && pageCount >= 1) {
setMergedCurrent(pageCount);
pendingNotifyRef.current = {
current: pageCount,
pageSize: mergedPageSize
};
}
}
useEffect(() => {
if (!pendingNotifyRef.current) return;
const { current: nextCurrent, pageSize: nextPageSize } = pendingNotifyRef.current;
pendingNotifyRef.current = null;
onChangeStable(nextCurrent, nextPageSize);
});
const displayCurrent = clampPage(mergedCurrent, pageCount);
if (hideOnSinglePage && pageCount <= 1) return null;
const commitCurrent = (nextCurrent, nextPageSize) => {
setMergedCurrent(nextCurrent);
onChange?.(nextCurrent, nextPageSize);
};
const goTo = (page) => {
commitCurrent(clampPage(page, pageCount), mergedPageSize);
};
const handlePageSizeChange = (value) => {
const nextSize = Number(value);
const nextPageCount = getPageCount(total, nextSize);
const nextCurrent = clampPage(displayCurrent, nextPageCount);
setMergedPageSize(nextSize);
commitCurrent(nextCurrent, nextSize);
onPageSizeChange?.(nextCurrent, nextSize);
};
const items = getPaginationItems(displayCurrent, pageCount);
const rangeStart = total === 0 ? 0 : (displayCurrent - 1) * mergedPageSize + 1;
const rangeEnd = Math.min(displayCurrent * mergedPageSize, total);
return /* @__PURE__ */ jsxs("nav", {
"aria-label": "Pagination",
className: cx(styles.root, className),
ref,
role: "navigation",
style,
...rest,
children: [
showTotal && /* @__PURE__ */ jsx("span", {
className: styles.total,
children: showTotal(total, [rangeStart, rangeEnd])
}),
/* @__PURE__ */ jsx("button", {
"aria-label": "Previous page",
className: buttonVariants({ size }),
disabled: disabled || displayCurrent <= 1,
type: "button",
onClick: () => goTo(displayCurrent - 1),
children: /* @__PURE__ */ jsx(ChevronLeft, { size: size === "small" ? 14 : 16 })
}),
items.map((item) => typeof item === "number" ? /* @__PURE__ */ jsx("button", {
"aria-current": item === displayCurrent ? "page" : void 0,
className: buttonVariants({ size }),
disabled,
type: "button",
onClick: () => goTo(item),
children: item
}, item) : /* @__PURE__ */ jsx("span", {
className: ellipsisVariants({ size }),
children: "···"
}, item)),
/* @__PURE__ */ jsx("button", {
"aria-label": "Next page",
className: buttonVariants({ size }),
disabled: disabled || displayCurrent >= pageCount,
type: "button",
onClick: () => goTo(displayCurrent + 1),
children: /* @__PURE__ */ jsx(ChevronRight, { size: size === "small" ? 14 : 16 })
}),
showSizeChanger && /* @__PURE__ */ jsx(Select, {
disabled,
size: size === "small" ? "small" : "middle",
style: {
flex: "none",
marginInlineStart: 8,
width: "auto"
},
value: String(mergedPageSize),
options: pageSizeOptions.map((option) => ({
label: `${option} / page`,
value: String(option)
})),
onChange: handlePageSizeChange
})
]
});
});
Pagination.displayName = "Pagination";
//#endregion
export { Pagination as default };
//# sourceMappingURL=Pagination.mjs.map