@trail-ui/react
Version:
217 lines (214 loc) • 7.82 kB
JavaScript
import {
customSelect_default
} from "./chunk-VCCE27QM.mjs";
import {
Positions
} from "./chunk-DFBZCBP4.mjs";
import {
_IconButton
} from "./chunk-CTOQKVKR.mjs";
// src/pagination/pagination.tsx
import { ChevronLeftIcon, ChevronRightIcon } from "@trail-ui/icons";
import { useEffect, useMemo, useRef } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
function Pagination({ readsResults = true, ...props }) {
var _a;
const paginationButtonsRef = useRef(null);
const lastClickedPageRef = useRef(null);
const totalPages = useMemo(() => {
return Math.ceil(props.totalCount / props.size);
}, [props.totalCount, props.size]);
const pageNumberArray = useMemo(() => {
const maxButtonsToShow = 5;
const pageNumbers = [];
if (totalPages <= maxButtonsToShow) {
for (let i = 1; i <= totalPages; i++) {
pageNumbers.push(i);
}
return pageNumbers;
}
let startPage, endPage;
const middleButtonsToShow = maxButtonsToShow - 2;
const halfMiddleButtonsToShow = Math.floor(middleButtonsToShow / 2);
if (props.currentPage <= halfMiddleButtonsToShow + 1) {
startPage = 2;
endPage = middleButtonsToShow + 1;
} else if (props.currentPage + halfMiddleButtonsToShow >= totalPages) {
startPage = totalPages - middleButtonsToShow;
endPage = totalPages - 1;
} else {
startPage = props.currentPage - halfMiddleButtonsToShow;
endPage = props.currentPage + halfMiddleButtonsToShow;
}
pageNumbers.push(1);
if (startPage > 2) {
pageNumbers.push("...");
}
for (let i = startPage; i <= endPage; i++) {
pageNumbers.push(i);
}
if (endPage < totalPages - 1) {
pageNumbers.push("...");
}
pageNumbers.push(totalPages);
return pageNumbers;
}, [props.totalCount, props.size, props.currentPage]);
useEffect(() => {
var _a2;
if (lastClickedPageRef.current !== null) {
const button = (_a2 = paginationButtonsRef.current) == null ? void 0 : _a2.querySelector(
`button[data-id="${lastClickedPageRef.current}"]`
);
if (button)
button.focus();
}
}, [pageNumberArray]);
return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between space-x-2", children: [
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
props.onPageSizeChange && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
/* @__PURE__ */ jsx("span", { className: "min-w-[fit-content] text-sm font-normal text-neutral-600", children: "Items per page" }),
/* @__PURE__ */ jsx(
customSelect_default,
{
label: "Items per page",
classNames: {
label: "hidden"
},
value: props.size,
isRequired: false,
options: ((_a = props.sizeOptions) == null ? void 0 : _a.map((size) => ({
label: size.toString(),
value: size
}))) || [
{ label: "100", value: 100 },
{ label: "250", value: 250 },
{ label: "500", value: 500 }
],
errorMessage: "",
errorId: "",
onChange: (e) => {
var _a2;
(_a2 = props.onPageSizeChange) == null ? void 0 : _a2.call(props, Number(e));
props.onPageChange(1);
},
position: Positions.topLeft,
popover: { width: 100 }
}
)
] }),
readsResults ? (
// biome-ignore lint/a11y/useSemanticElements: <explanation>
/* @__PURE__ */ jsxs(
"p",
{
role: "status",
"aria-live": "polite",
"aria-atomic": "true",
className: "text-sm text-neutral-600",
children: [
"Showing ",
(props.currentPage - 1) * props.size + 1,
"-",
Math.min(props.currentPage * props.size, props.totalCount),
" of ",
props.totalCount,
" ",
props.totalCount === 1 ? "result" : "results"
]
}
)
) : /* @__PURE__ */ jsxs("p", { className: "text-sm text-neutral-600", children: [
"Showing ",
(props.currentPage - 1) * props.size + 1,
"-",
Math.min(props.currentPage * props.size, props.totalCount),
" of ",
props.totalCount,
" ",
props.totalCount === 1 ? "result" : "results"
] })
] }),
props.selectedCount > 0 && /* @__PURE__ */ jsxs(
"p",
{
role: props.selectedCount < 1 ? "none" : "alert",
"aria-live": props.selectedCount < 1 ? "off" : "polite",
className: `${props.selectedCount < 1 ? "sr-only" : ""} text-sm font-medium text-purple-600`,
children: [
props.selectedCount,
" selected"
]
}
),
/* @__PURE__ */ jsx("nav", { "aria-label": "Pagination", className: "flex justify-end", children: /* @__PURE__ */ jsxs("ul", { className: "flex items-center justify-end gap-2", ref: paginationButtonsRef, children: [
/* @__PURE__ */ jsx("li", { className: "flex h-8 w-8 items-center justify-center", children: /* @__PURE__ */ jsx(
_IconButton,
{
"aria-label": "Previous Page",
appearance: "transparent",
isDisabled: props.currentPage === 1,
onPress: () => {
var _a2;
(_a2 = props.onPageChange) == null ? void 0 : _a2.call(props, props.currentPage - 1);
},
children: /* @__PURE__ */ jsx(
ChevronLeftIcon,
{
color: `${props.currentPage === 1 ? "#B0ACBB" : "#302E38"}`,
width: 24,
height: 24
}
)
}
) }),
pageNumberArray.map((pageNumber, index) => /* @__PURE__ */ jsx(
"li",
{
className: "flex h-8 w-8 items-center justify-center",
children: pageNumber === "..." ? /* @__PURE__ */ jsx("span", { children: "..." }) : /* @__PURE__ */ jsx(
"button",
{
"data-id": pageNumber,
...pageNumber === props.currentPage ? { "aria-current": "page" } : {},
"aria-current": pageNumber === props.currentPage ? "page" : void 0,
"aria-label": `Page ${pageNumber}`,
onClick: () => {
if (pageNumber !== "..." && props.onPageChange) {
lastClickedPageRef.current = pageNumber;
props.onPageChange(pageNumber);
}
},
className: `h-full w-full text-sm font-normal text-neutral-800 focus:outline-purple-600 ${pageNumber === props.currentPage ? "rounded border border-purple-600 bg-purple-100" : "bg-white"} `,
children: pageNumber
}
)
},
`${pageNumber}-${// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
index}`
)),
/* @__PURE__ */ jsx("li", { className: "flex h-8 w-8 items-center justify-center", children: /* @__PURE__ */ jsx(
_IconButton,
{
"aria-label": "Next Page",
appearance: "transparent",
isDisabled: props.currentPage >= totalPages,
onPress: () => {
var _a2;
(_a2 = props.onPageChange) == null ? void 0 : _a2.call(props, props.currentPage + 1);
},
children: /* @__PURE__ */ jsx(
ChevronRightIcon,
{
color: props.currentPage === totalPages ? "#B0ACBB" : "#302E38",
width: 24,
height: 24
}
)
}
) })
] }) })
] });
}
export {
Pagination
};