From 3c1574a3934da879f0dd9e4cbf13a86b2417986a Mon Sep 17 00:00:00 2001
From: Mohamadzadeh <7796733@gmail.com>
Date: Thu, 11 Jun 2026 19:03:23 +0330
Subject: [PATCH] add paginations
---
dist/index.js | 411 +++++++++++++++++-
package.json | 3 -
src/components/pagination/LightPagination.jsx | 191 ++++++++
src/components/pagination/Pagination.jsx | 197 +++++++++
.../pagination/SimplePagination.jsx | 195 +++++++++
src/index.js | 4 +
6 files changed, 993 insertions(+), 8 deletions(-)
create mode 100644 src/components/pagination/LightPagination.jsx
create mode 100644 src/components/pagination/Pagination.jsx
create mode 100644 src/components/pagination/SimplePagination.jsx
diff --git a/dist/index.js b/dist/index.js
index 949ffb8..e3f0550 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -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
};
diff --git a/package.json b/package.json
index 5861dcf..fc8bc10 100644
--- a/package.json
+++ b/package.json
@@ -7,9 +7,6 @@
"exports": {
".": "./dist/index.js"
},
- "files": [
- "dist"
- ],
"scripts": {
"build": "vite build"
},
diff --git a/src/components/pagination/LightPagination.jsx b/src/components/pagination/LightPagination.jsx
new file mode 100644
index 0000000..59303c6
--- /dev/null
+++ b/src/components/pagination/LightPagination.jsx
@@ -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 (
+
+
+ onPageChange(currentPage - 1)}
+ isDisabled={currentPage === 1}
+ icon={}
+ aria-label="صفحه قبلی"
+ />
+
+ {pageNumbers.map((number) => (
+
+ ))}
+
+ onPageChange(currentPage + 1)}
+ isDisabled={currentPage === totalPages}
+ icon={}
+ aria-label="صفحه بعدی"
+ />
+
+ {
+ 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"
+ />
+
+
+
+
+ تعداد کل:
+
+ {toFaDigits(totalCount)}
+
+
+ );
+};
diff --git a/src/components/pagination/Pagination.jsx b/src/components/pagination/Pagination.jsx
new file mode 100644
index 0000000..71b28bb
--- /dev/null
+++ b/src/components/pagination/Pagination.jsx
@@ -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 (
+
+
+ صفحه
+ {toFaDigits(currentPage)}
+ از
+ {toFaDigits(totalPages)}
+
+
+
+ onPageChange(currentPage - 1)}
+ isDisabled={currentPage === 1}
+ icon={}
+ aria-label="صفحه قبلی"
+ />
+
+ {pageNumbers.map((number) => (
+
+ ))}
+
+ onPageChange(currentPage + 1)}
+ isDisabled={currentPage === totalPages}
+ icon={}
+ aria-label="صفحه بعدی"
+ />
+
+ {
+ 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"
+ />
+
+
+
+ تعداد کل:
+ {toFaDigits(totalCount)}
+
+
+ );
+};
diff --git a/src/components/pagination/SimplePagination.jsx b/src/components/pagination/SimplePagination.jsx
new file mode 100644
index 0000000..5253dd5
--- /dev/null
+++ b/src/components/pagination/SimplePagination.jsx
@@ -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) => (
+
+ );
+
+ if (totalPages === 0 || !totalCount) return null;
+
+ const showFirstButton = totalPages > 1 && visibleCurrentPage !== 1;
+ const showLastButton = totalPages > 1 && visibleCurrentPage !== totalPages;
+
+ return (
+
+
+ goToPage(visibleCurrentPage - 1)}
+ isDisabled={visibleCurrentPage === 1}
+ icon={}
+ aria-label="صفحه قبلی"
+ />
+
+ {showFirstButton && renderPageButton(1)}
+
+ {isEditing ? (
+ {
+ 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)}
+
+ goToPage(visibleCurrentPage + 1)}
+ isDisabled={visibleCurrentPage === totalPages}
+ icon={}
+ aria-label="صفحه بعدی"
+ />
+
+
+ );
+};
diff --git a/src/index.js b/src/index.js
index e7678bb..06b64ec 100644
--- a/src/index.js
+++ b/src/index.js
@@ -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";