add paginations

This commit is contained in:
Mohamadzadeh 2026-06-11 19:03:23 +03:30
parent f3c1990af4
commit 3c1574a393
6 changed files with 993 additions and 8 deletions

411
dist/index.js vendored
View File

@ -1,6 +1,407 @@
const e = (r) => new Intl.NumberFormat("fa-IR").format(Number(r)), i = (r) => String(r).replace(/\d/g, (t) => "۰۱۲۳۴۵۶۷۸۹"[Number(t)]), o = (r) => String(r).replace(/[۰-۹]/g, (n) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(n)));
export {
o as toEnDigits,
i as toFaDigits,
e as toFaNumber
import { jsxs as I, jsx as o } from "react/jsx-runtime";
import { useState as y, useRef as M, useEffect as A, useCallback as _ } from "react";
import { HStack as B, IconButton as N, Button as S, Input as E, Text as v } from "@chakra-ui/react";
import { IoChevronForwardOutline as z, IoChevronBackOutline as V } from "react-icons/io5";
const K = (i) => new Intl.NumberFormat("fa-IR").format(Number(i)), t = (i) => String(i).replace(/\d/g, (n) => "۰۱۲۳۴۵۶۷۸۹"[Number(n)]), D = (i) => String(i).replace(/[۰-۹]/g, (C) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(C))), O = ({
currentPage: i,
totalPages: n,
totalCount: C,
onPageChange: d
}) => {
const [c, l] = y(t(i)), [a, f] = y(!1), [b, s] = y(null), x = M(null), w = [.../* @__PURE__ */ new Set([1, i, n])].filter(
(e) => e >= 1 && e <= n
);
A(() => {
if (b !== null) {
i === b && (s(null), f(!1), l(t(i)));
return;
}
a || l(t(i));
}, [i, a, b]), A(() => {
if (!a || !c || b !== null) return;
const e = parseInt(D(c), 10);
if (isNaN(e)) return;
const u = setTimeout(() => {
var m;
const r = Math.min(Math.max(e, 1), n);
r !== i ? (s(r), l(t(r)), d(r)) : (f(!1), l(t(i))), (m = x.current) == null || m.blur();
}, 1e3);
return () => clearTimeout(u);
}, [
c,
a,
b,
n,
i,
d
]);
const k = () => {
var r, m;
const e = parseInt(D(c), 10);
if (isNaN(e)) {
l(t(i)), f(!1), s(null), (r = x.current) == null || r.blur();
return;
}
const u = Math.min(Math.max(e, 1), n);
u !== i ? (s(u), l(t(u)), d(u)) : (l(t(i)), f(!1), s(null)), (m = x.current) == null || m.blur();
};
return n === 0 || !C ? null : /* @__PURE__ */ I(
B,
{
justifyContent: "space-around",
backgroundColor: "white",
py: "10px",
px: "16px",
rounded: "lg",
border: "1px",
borderColor: "blue.200",
w: "100%",
children: [
/* @__PURE__ */ I(B, { spacing: 2, alignItems: "center", justifyContent: "center", children: [
/* @__PURE__ */ o(
N,
{
size: "md",
bg: "#e6e6f1",
color: "#4B49AC",
_hover: { bg: "#cbcbe8" },
onClick: () => d(i - 1),
isDisabled: i === 1,
icon: /* @__PURE__ */ o(z, {}),
"aria-label": "صفحه قبلی"
}
),
w.map((e) => /* @__PURE__ */ o(
S,
{
size: "md",
px: 2,
bg: i === e ? "#4B49AC" : "#e6e6f1",
color: i === e ? "#e6e6f1" : "#4B49AC",
_hover: { bg: i === e ? "#4B49AC" : "#cbcbe8" },
onClick: () => d(e),
variant: "soft",
children: t(e)
},
e
)),
/* @__PURE__ */ o(
N,
{
size: "md",
bg: "#e6e6f1",
color: "#4B49AC",
_hover: { bg: "#cbcbe8" },
onClick: () => d(i + 1),
isDisabled: i === n,
icon: /* @__PURE__ */ o(V, {}),
"aria-label": "صفحه بعدی"
}
),
/* @__PURE__ */ o(
E,
{
ref: x,
type: "text",
inputMode: "numeric",
placeholder: "صفحه",
w: "56px",
value: c,
onFocus: () => {
f(!0), s(null), l("");
},
onChange: (e) => {
const u = e.target.value, r = D(u).replace(/\D/g, "");
l(t(r));
},
onBlur: () => {
c || (l(t(i)), f(!1), s(null));
},
onKeyDown: (e) => {
e.key === "Enter" && k();
},
textAlign: "center",
color: "#1D2939",
px: 1,
minW: 0,
dir: "ltr"
}
)
] }),
/* @__PURE__ */ I(B, { spacing: 2, children: [
/* @__PURE__ */ o(v, { w: "auto", fontWeight: "bold", whiteSpace: "nowrap", children: "تعداد کل:" }),
/* @__PURE__ */ o(v, { children: t(C) })
] })
]
}
);
}, L = ({
currentPage: i,
totalPages: n,
totalCount: C,
onPageChange: d
}) => {
const [c, l] = y(t(i)), [a, f] = y(!1), [b, s] = y(null), x = M(null), w = Array.from(
/* @__PURE__ */ new Set([1, i, i + 1, n])
).filter((e) => e >= 1 && e <= n).sort((e, u) => e - u);
A(() => {
if (b !== null) {
i === b && (s(null), f(!1), l(t(i)));
return;
}
a || l(t(i));
}, [i, a, b]), A(() => {
if (!a || !c || b !== null) return;
const e = parseInt(D(c), 10);
if (isNaN(e)) return;
const u = setTimeout(() => {
var m;
const r = Math.min(Math.max(e, 1), n);
r !== i ? (s(r), l(t(r)), d(r)) : (f(!1), l(t(i))), (m = x.current) == null || m.blur();
}, 1e3);
return () => clearTimeout(u);
}, [
c,
a,
b,
n,
i,
d
]);
const k = () => {
var r, m;
const e = parseInt(D(c), 10);
if (isNaN(e)) {
l(t(i)), f(!1), s(null), (r = x.current) == null || r.blur();
return;
}
const u = Math.min(Math.max(e, 1), n);
u !== i ? (s(u), l(t(u)), d(u)) : (l(t(i)), f(!1), s(null)), (m = x.current) == null || m.blur();
};
return n === 0 || !C ? null : /* @__PURE__ */ I(
B,
{
justifyContent: "space-around",
backgroundColor: "white",
py: "10px",
px: "16px",
rounded: "lg",
border: "1px",
borderColor: "blue.200",
w: "100%",
children: [
/* @__PURE__ */ I(B, { spacing: 2, whiteSpace: "nowrap", children: [
/* @__PURE__ */ o(v, { fontWeight: "bold", children: "صفحه" }),
/* @__PURE__ */ o(v, { children: t(i) }),
/* @__PURE__ */ o(v, { fontWeight: "bold", children: "از" }),
/* @__PURE__ */ o(v, { children: t(n) })
] }),
/* @__PURE__ */ I(B, { spacing: 2, alignItems: "center", justifyContent: "center", children: [
/* @__PURE__ */ o(
N,
{
size: "md",
bg: "#e6e6f1",
color: "#4B49AC",
_hover: { bg: "#cbcbe8" },
onClick: () => d(i - 1),
isDisabled: i === 1,
icon: /* @__PURE__ */ o(z, {}),
"aria-label": "صفحه قبلی"
}
),
w.map((e) => /* @__PURE__ */ o(
S,
{
size: "md",
bg: i === e ? "#4B49AC" : "#e6e6f1",
color: i === e ? "#e6e6f1" : "#4B49AC",
_hover: { bg: i === e ? "#4B49AC" : "#cbcbe8" },
onClick: () => d(e),
variant: "soft",
children: t(e)
},
e
)),
/* @__PURE__ */ o(
N,
{
size: "md",
bg: "#e6e6f1",
color: "#4B49AC",
_hover: { bg: "#cbcbe8" },
onClick: () => d(i + 1),
isDisabled: i === n,
icon: /* @__PURE__ */ o(V, {}),
"aria-label": "صفحه بعدی"
}
),
/* @__PURE__ */ o(
E,
{
ref: x,
type: "text",
inputMode: "numeric",
placeholder: "صفحه",
w: "100px",
value: c,
onFocus: () => {
f(!0), s(null), l("");
},
onChange: (e) => {
const u = e.target.value, r = D(u).replace(/\D/g, "");
l(t(r));
},
onBlur: () => {
c || (l(t(i)), f(!1), s(null));
},
onKeyDown: (e) => {
e.key === "Enter" && k();
},
textAlign: "center",
color: "#1D2939",
px: 1,
minW: 0,
dir: "ltr"
}
)
] }),
/* @__PURE__ */ I(B, { spacing: 2, whiteSpace: "nowrap", children: [
/* @__PURE__ */ o(v, { fontWeight: "bold", children: "تعداد کل:" }),
/* @__PURE__ */ o(v, { children: t(C) })
] })
]
}
);
}, H = ({
currentPage: i,
totalPages: n,
totalCount: C,
onPageChange: d
}) => {
const [c, l] = y(""), [a, f] = y(!1), [b, s] = y(null), x = M(null), w = b ?? i, k = _(
(p) => {
const h = Math.min(Math.max(p, 1), n);
f(!1), l(""), s(null), h !== i && d(h);
},
[i, n, d]
), e = _(() => {
if (!c) {
f(!1), l(""), s(null);
return;
}
const p = parseInt(D(c), 10);
if (isNaN(p)) {
f(!1), l(""), s(null);
return;
}
const h = Math.min(Math.max(p, 1), n);
f(!1), l(""), h !== i ? (s(h), d(h)) : s(null);
}, [c, i, n, d]);
A(() => {
var p;
a && ((p = x.current) == null || p.focus());
}, [a]), A(() => {
b !== null && i === b && s(null);
}, [i, b]), A(() => {
if (!a || !c) return;
const p = setTimeout(() => {
e();
}, 1e3);
return () => clearTimeout(p);
}, [c, a, e]);
const u = () => {
s(null), l(""), f(!0);
}, r = (p, h = !1) => /* @__PURE__ */ o(
S,
{
size: "md",
bg: h ? "#4B49AC" : "#e6e6f1",
color: h ? "#e6e6f1" : "#4B49AC",
_hover: { bg: h ? "#4B49AC" : "#cbcbe8" },
onClick: h ? u : () => k(p),
variant: "soft",
children: t(p)
},
p
);
if (n === 0 || !C) return null;
const m = n > 1 && w !== 1, j = n > 1 && w !== n;
return /* @__PURE__ */ o(
B,
{
justifyContent: "center",
backgroundColor: "white",
py: "10px",
px: "16px",
rounded: "lg",
border: "1px",
borderColor: "blue.200",
w: "100%",
children: /* @__PURE__ */ I(B, { spacing: 2, alignItems: "center", justifyContent: "center", children: [
/* @__PURE__ */ o(
N,
{
size: "md",
bg: "#e6e6f1",
color: "#4B49AC",
_hover: { bg: "#cbcbe8" },
onClick: () => k(w - 1),
isDisabled: w === 1,
icon: /* @__PURE__ */ o(z, {}),
"aria-label": "صفحه قبلی"
}
),
m && r(1),
a ? /* @__PURE__ */ o(
E,
{
ref: x,
type: "text",
inputMode: "numeric",
placeholder: "صفحه",
w: "48px",
value: c,
onChange: (p) => {
const h = p.target.value, T = D(h).replace(/\D/g, "");
l(t(T));
},
onBlur: () => {
c ? e() : (l(""), f(!1), s(null));
},
onKeyDown: (p) => {
p.key === "Enter" && e(), p.key === "Escape" && (l(""), f(!1), s(null));
},
textAlign: "center",
color: "#1D2939",
px: 1,
minW: 0,
dir: "ltr"
}
) : r(w, !0),
j && r(n),
/* @__PURE__ */ o(
N,
{
size: "md",
bg: "#e6e6f1",
color: "#4B49AC",
_hover: { bg: "#cbcbe8" },
onClick: () => k(w + 1),
isDisabled: w === n,
icon: /* @__PURE__ */ o(V, {}),
"aria-label": "صفحه بعدی"
}
)
] })
}
);
};
export {
O as LightPagination,
L as Pagination,
H as SimplePagination,
D as toEnDigits,
t as toFaDigits,
K as toFaNumber
};

View File

@ -7,9 +7,6 @@
"exports": {
".": "./dist/index.js"
},
"files": [
"dist"
],
"scripts": {
"build": "vite build"
},

View File

@ -0,0 +1,191 @@
import { useEffect, useRef, useState } from "react";
import { Button, HStack, IconButton, Input, Text } from "@chakra-ui/react";
import { IoChevronBackOutline, IoChevronForwardOutline } from "react-icons/io5";
import { toEnDigits, toFaDigits } from "../../utils/numbers.js";
export const LightPagination = ({
currentPage,
totalPages,
totalCount,
onPageChange,
}) => {
const [inputValue, setInputValue] = useState(toFaDigits(currentPage));
const [isEditing, setIsEditing] = useState(false);
const [pendingPage, setPendingPage] = useState(null);
const inputRef = useRef(null);
const pageNumbers = [...new Set([1, currentPage, totalPages])].filter(
(page) => page >= 1 && page <= totalPages,
);
useEffect(() => {
if (pendingPage !== null) {
if (currentPage === pendingPage) {
setPendingPage(null);
setIsEditing(false);
setInputValue(toFaDigits(currentPage));
}
return;
}
if (!isEditing) {
setInputValue(toFaDigits(currentPage));
}
}, [currentPage, isEditing, pendingPage]);
useEffect(() => {
if (!isEditing) return;
if (!inputValue) return;
if (pendingPage !== null) return;
const page = parseInt(toEnDigits(inputValue), 10);
if (isNaN(page)) return;
const timeout = setTimeout(() => {
const safePage = Math.min(Math.max(page, 1), totalPages);
if (safePage !== currentPage) {
setPendingPage(safePage);
setInputValue(toFaDigits(safePage));
onPageChange(safePage);
} else {
setIsEditing(false);
setInputValue(toFaDigits(currentPage));
}
inputRef.current?.blur();
}, 1000);
return () => clearTimeout(timeout);
}, [
inputValue,
isEditing,
pendingPage,
totalPages,
currentPage,
onPageChange,
]);
const handleSubmit = () => {
const page = parseInt(toEnDigits(inputValue), 10);
if (isNaN(page)) {
setInputValue(toFaDigits(currentPage));
setIsEditing(false);
setPendingPage(null);
inputRef.current?.blur();
return;
}
const safePage = Math.min(Math.max(page, 1), totalPages);
if (safePage !== currentPage) {
setPendingPage(safePage);
setInputValue(toFaDigits(safePage));
onPageChange(safePage);
} else {
setInputValue(toFaDigits(currentPage));
setIsEditing(false);
setPendingPage(null);
}
inputRef.current?.blur();
};
if (totalPages === 0 || !totalCount) return null;
return (
<HStack
justifyContent={"space-around"}
backgroundColor={"white"}
py={"10px"}
px={"16px"}
rounded={"lg"}
border={"1px"}
borderColor={"blue.200"}
w={"100%"}
>
<HStack spacing={2} alignItems={"center"} justifyContent={"center"}>
<IconButton
size={"md"}
bg={"#e6e6f1"}
color="#4B49AC"
_hover={{ bg: "#cbcbe8" }}
onClick={() => onPageChange(currentPage - 1)}
isDisabled={currentPage === 1}
icon={<IoChevronForwardOutline />}
aria-label="صفحه قبلی"
/>
{pageNumbers.map((number) => (
<Button
size={"md"}
px={2}
bg={currentPage === number ? "#4B49AC" : "#e6e6f1"}
color={currentPage === number ? "#e6e6f1" : "#4B49AC"}
_hover={{ bg: currentPage === number ? "#4B49AC" : "#cbcbe8" }}
key={number}
onClick={() => onPageChange(number)}
variant={"soft"}
>
{toFaDigits(number)}
</Button>
))}
<IconButton
size={"md"}
bg={"#e6e6f1"}
color="#4B49AC"
_hover={{ bg: "#cbcbe8" }}
onClick={() => onPageChange(currentPage + 1)}
isDisabled={currentPage === totalPages}
icon={<IoChevronBackOutline />}
aria-label="صفحه بعدی"
/>
<Input
ref={inputRef}
type="text"
inputMode="numeric"
placeholder="صفحه"
w="56px"
value={inputValue}
onFocus={() => {
setIsEditing(true);
setPendingPage(null);
setInputValue("");
}}
onChange={(e) => {
const rawValue = e.target.value;
const onlyDigits = toEnDigits(rawValue).replace(/\D/g, "");
setInputValue(toFaDigits(onlyDigits));
}}
onBlur={() => {
if (!inputValue) {
setInputValue(toFaDigits(currentPage));
setIsEditing(false);
setPendingPage(null);
}
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleSubmit();
}
}}
textAlign="center"
color="#1D2939"
px={1}
minW={0}
dir="ltr"
/>
</HStack>
<HStack spacing={2}>
<Text w={"auto"} fontWeight={"bold"} whiteSpace={"nowrap"}>
تعداد کل:
</Text>
<Text>{toFaDigits(totalCount)}</Text>
</HStack>
</HStack>
);
};

View File

@ -0,0 +1,197 @@
import { useEffect, useRef, useState } from "react";
import { Button, HStack, IconButton, Input, Text } from "@chakra-ui/react";
import { IoChevronBackOutline, IoChevronForwardOutline } from "react-icons/io5";
import { toEnDigits, toFaDigits } from "../../utils/numbers.js";
export const Pagination = ({
currentPage,
totalPages,
totalCount,
onPageChange,
}) => {
const [inputValue, setInputValue] = useState(toFaDigits(currentPage));
const [isEditing, setIsEditing] = useState(false);
const [pendingPage, setPendingPage] = useState(null);
const inputRef = useRef(null);
const pageNumbers = Array.from(
new Set([1, currentPage, currentPage + 1, totalPages]),
)
.filter((page) => page >= 1 && page <= totalPages)
.sort((a, b) => a - b);
useEffect(() => {
if (pendingPage !== null) {
if (currentPage === pendingPage) {
setPendingPage(null);
setIsEditing(false);
setInputValue(toFaDigits(currentPage));
}
return;
}
if (!isEditing) {
setInputValue(toFaDigits(currentPage));
}
}, [currentPage, isEditing, pendingPage]);
useEffect(() => {
if (!isEditing) return;
if (!inputValue) return;
if (pendingPage !== null) return;
const page = parseInt(toEnDigits(inputValue), 10);
if (isNaN(page)) return;
const timeout = setTimeout(() => {
const safePage = Math.min(Math.max(page, 1), totalPages);
if (safePage !== currentPage) {
setPendingPage(safePage);
setInputValue(toFaDigits(safePage));
onPageChange(safePage);
} else {
setIsEditing(false);
setInputValue(toFaDigits(currentPage));
}
inputRef.current?.blur();
}, 1000);
return () => clearTimeout(timeout);
}, [
inputValue,
isEditing,
pendingPage,
totalPages,
currentPage,
onPageChange,
]);
const handleSubmit = () => {
const page = parseInt(toEnDigits(inputValue), 10);
if (isNaN(page)) {
setInputValue(toFaDigits(currentPage));
setIsEditing(false);
setPendingPage(null);
inputRef.current?.blur();
return;
}
const safePage = Math.min(Math.max(page, 1), totalPages);
if (safePage !== currentPage) {
setPendingPage(safePage);
setInputValue(toFaDigits(safePage));
onPageChange(safePage);
} else {
setInputValue(toFaDigits(currentPage));
setIsEditing(false);
setPendingPage(null);
}
inputRef.current?.blur();
};
if (totalPages === 0 || !totalCount) return null;
return (
<HStack
justifyContent={"space-around"}
backgroundColor={"white"}
py={"10px"}
px={"16px"}
rounded={"lg"}
border={"1px"}
borderColor={"blue.200"}
w={"100%"}
>
<HStack spacing={2} whiteSpace={"nowrap"}>
<Text fontWeight={"bold"}>صفحه</Text>
<Text>{toFaDigits(currentPage)}</Text>
<Text fontWeight={"bold"}>از</Text>
<Text>{toFaDigits(totalPages)}</Text>
</HStack>
<HStack spacing={2} alignItems={"center"} justifyContent={"center"}>
<IconButton
size={"md"}
bg={"#e6e6f1"}
color="#4B49AC"
_hover={{ bg: "#cbcbe8" }}
onClick={() => onPageChange(currentPage - 1)}
isDisabled={currentPage === 1}
icon={<IoChevronForwardOutline />}
aria-label="صفحه قبلی"
/>
{pageNumbers.map((number) => (
<Button
size={"md"}
bg={currentPage === number ? "#4B49AC" : "#e6e6f1"}
color={currentPage === number ? "#e6e6f1" : "#4B49AC"}
_hover={{ bg: currentPage === number ? "#4B49AC" : "#cbcbe8" }}
key={number}
onClick={() => onPageChange(number)}
variant={"soft"}
>
{toFaDigits(number)}
</Button>
))}
<IconButton
size={"md"}
bg={"#e6e6f1"}
color="#4B49AC"
_hover={{ bg: "#cbcbe8" }}
onClick={() => onPageChange(currentPage + 1)}
isDisabled={currentPage === totalPages}
icon={<IoChevronBackOutline />}
aria-label="صفحه بعدی"
/>
<Input
ref={inputRef}
type="text"
inputMode="numeric"
placeholder="صفحه"
w="100px"
value={inputValue}
onFocus={() => {
setIsEditing(true);
setPendingPage(null);
setInputValue("");
}}
onChange={(e) => {
const rawValue = e.target.value;
const onlyDigits = toEnDigits(rawValue).replace(/\D/g, "");
setInputValue(toFaDigits(onlyDigits));
}}
onBlur={() => {
if (!inputValue) {
setInputValue(toFaDigits(currentPage));
setIsEditing(false);
setPendingPage(null);
}
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleSubmit();
}
}}
textAlign="center"
color="#1D2939"
px={1}
minW={0}
dir="ltr"
/>
</HStack>
<HStack spacing={2} whiteSpace={"nowrap"}>
<Text fontWeight={"bold"}>تعداد کل:</Text>
<Text>{toFaDigits(totalCount)}</Text>
</HStack>
</HStack>
);
};

View File

@ -0,0 +1,195 @@
import { Button, HStack, IconButton, Input } from "@chakra-ui/react";
import { useCallback, useEffect, useRef, useState } from "react";
import { IoChevronBackOutline, IoChevronForwardOutline } from "react-icons/io5";
import { toEnDigits, toFaDigits } from "../../utils/numbers.js";
export const SimplePagination = ({
currentPage,
totalPages,
totalCount,
onPageChange,
}) => {
const [inputValue, setInputValue] = useState("");
const [isEditing, setIsEditing] = useState(false);
const [pendingPage, setPendingPage] = useState(null);
const inputRef = useRef(null);
const visibleCurrentPage = pendingPage ?? currentPage;
const goToPage = useCallback(
(page) => {
const safePage = Math.min(Math.max(page, 1), totalPages);
setIsEditing(false);
setInputValue("");
setPendingPage(null);
if (safePage !== currentPage) {
onPageChange(safePage);
}
},
[currentPage, totalPages, onPageChange],
);
const commitInput = useCallback(() => {
if (!inputValue) {
setIsEditing(false);
setInputValue("");
setPendingPage(null);
return;
}
const page = parseInt(toEnDigits(inputValue), 10);
if (isNaN(page)) {
setIsEditing(false);
setInputValue("");
setPendingPage(null);
return;
}
const safePage = Math.min(Math.max(page, 1), totalPages);
setIsEditing(false);
setInputValue("");
if (safePage !== currentPage) {
setPendingPage(safePage);
onPageChange(safePage);
} else {
setPendingPage(null);
}
}, [inputValue, currentPage, totalPages, onPageChange]);
useEffect(() => {
if (isEditing) {
inputRef.current?.focus();
}
}, [isEditing]);
useEffect(() => {
if (pendingPage !== null && currentPage === pendingPage) {
setPendingPage(null);
}
}, [currentPage, pendingPage]);
useEffect(() => {
if (!isEditing) return;
if (!inputValue) return;
const timeout = setTimeout(() => {
commitInput();
}, 1000);
return () => clearTimeout(timeout);
}, [inputValue, isEditing, commitInput]);
const startEditing = () => {
setPendingPage(null);
setInputValue("");
setIsEditing(true);
};
const renderPageButton = (number, isCurrent = false) => (
<Button
size="md"
bg={isCurrent ? "#4B49AC" : "#e6e6f1"}
color={isCurrent ? "#e6e6f1" : "#4B49AC"}
_hover={{ bg: isCurrent ? "#4B49AC" : "#cbcbe8" }}
key={number}
onClick={isCurrent ? startEditing : () => goToPage(number)}
variant="soft"
>
{toFaDigits(number)}
</Button>
);
if (totalPages === 0 || !totalCount) return null;
const showFirstButton = totalPages > 1 && visibleCurrentPage !== 1;
const showLastButton = totalPages > 1 && visibleCurrentPage !== totalPages;
return (
<HStack
justifyContent="center"
backgroundColor="white"
py="10px"
px="16px"
rounded="lg"
border="1px"
borderColor="blue.200"
w="100%"
>
<HStack spacing={2} alignItems="center" justifyContent="center">
<IconButton
size="md"
bg="#e6e6f1"
color="#4B49AC"
_hover={{ bg: "#cbcbe8" }}
onClick={() => goToPage(visibleCurrentPage - 1)}
isDisabled={visibleCurrentPage === 1}
icon={<IoChevronForwardOutline />}
aria-label="صفحه قبلی"
/>
{showFirstButton && renderPageButton(1)}
{isEditing ? (
<Input
ref={inputRef}
type="text"
inputMode="numeric"
placeholder="صفحه"
w="48px"
value={inputValue}
onChange={(e) => {
const rawValue = e.target.value;
const onlyDigits = toEnDigits(rawValue).replace(/\D/g, "");
setInputValue(toFaDigits(onlyDigits));
}}
onBlur={() => {
if (inputValue) {
commitInput();
} else {
setInputValue("");
setIsEditing(false);
setPendingPage(null);
}
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
commitInput();
}
if (e.key === "Escape") {
setInputValue("");
setIsEditing(false);
setPendingPage(null);
}
}}
textAlign="center"
color="#1D2939"
px={1}
minW={0}
dir="ltr"
/>
) : (
renderPageButton(visibleCurrentPage, true)
)}
{showLastButton && renderPageButton(totalPages)}
<IconButton
size="md"
bg="#e6e6f1"
color="#4B49AC"
_hover={{ bg: "#cbcbe8" }}
onClick={() => goToPage(visibleCurrentPage + 1)}
isDisabled={visibleCurrentPage === totalPages}
icon={<IoChevronBackOutline />}
aria-label="صفحه بعدی"
/>
</HStack>
</HStack>
);
};

View File

@ -1 +1,5 @@
export { toFaNumber, toFaDigits, toEnDigits } from "./utils/numbers.js";
export { LightPagination } from "./components/pagination/LightPagination.jsx";
export { Pagination } from "./components/pagination/Pagination.jsx";
export { SimplePagination } from "./components/pagination/SimplePagination.jsx";