add remote Pagination
This commit is contained in:
parent
0a14270aaa
commit
c8ec2e3759
63
dist/remote-ui.d.ts
vendored
63
dist/remote-ui.d.ts
vendored
@ -1,23 +1,54 @@
|
||||
import type { ComponentType, ReactNode } from "react";
|
||||
import type { BadgeProps, StackProps } from "@chakra-ui/react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
export type UikitRemoteDepsOptions = {
|
||||
React?: unknown;
|
||||
createRoot?: unknown;
|
||||
ChakraProvider?: unknown;
|
||||
Badge?: unknown;
|
||||
theme?: unknown;
|
||||
chakraProviderProps?: Record<string, unknown>;
|
||||
export type UikitRemoteLevel = "full" | "compact" | "simple";
|
||||
|
||||
export interface UikitRemoteSetupOptions {
|
||||
React?: any;
|
||||
createRoot?: any;
|
||||
ChakraProvider?: any;
|
||||
Badge?: any;
|
||||
Button?: any;
|
||||
HStack?: any;
|
||||
IconButton?: any;
|
||||
Input?: any;
|
||||
Text?: any;
|
||||
theme?: any;
|
||||
chakraProviderProps?: Record<string, any>;
|
||||
|
||||
/** Backward compatible alias for GBadgeUrl. */
|
||||
remoteUrl?: string;
|
||||
};
|
||||
GBadgeUrl?: string;
|
||||
PaginationUrl?: string;
|
||||
remoteUrls?: {
|
||||
GBadge?: string;
|
||||
Pagination?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export declare function setupUikitRemoteDeps(options?: UikitRemoteDepsOptions): void;
|
||||
export declare function setupUikitRemoteDeps(
|
||||
options?: UikitRemoteSetupOptions,
|
||||
): void;
|
||||
|
||||
export type GBadgeProps = {
|
||||
export interface GBadgeProps extends BadgeProps {
|
||||
children?: ReactNode;
|
||||
remoteUrl?: string;
|
||||
theme?: unknown;
|
||||
chakraProviderProps?: Record<string, unknown>;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
theme?: any;
|
||||
chakraProviderProps?: Record<string, any>;
|
||||
}
|
||||
|
||||
export declare const GBadge: ComponentType<GBadgeProps>;
|
||||
export declare const GBadge: (props: GBadgeProps) => JSX.Element;
|
||||
|
||||
export interface PaginationProps extends Omit<StackProps, "onChange"> {
|
||||
currentPage?: number;
|
||||
totalCount?: number;
|
||||
totalPages?: number;
|
||||
pageSize?: number;
|
||||
onPageChange?: (page: number) => void;
|
||||
level?: UikitRemoteLevel;
|
||||
remoteUrl?: string;
|
||||
theme?: any;
|
||||
chakraProviderProps?: Record<string, any>;
|
||||
}
|
||||
|
||||
export declare const Pagination: (props: PaginationProps) => JSX.Element;
|
||||
|
||||
185
dist/remote-ui.js
vendored
185
dist/remote-ui.js
vendored
@ -1,93 +1,138 @@
|
||||
import { jsx as g } from "react/jsx-runtime";
|
||||
import h, { useRef as u, useEffect as m } from "react";
|
||||
import { createRoot as _ } from "react-dom/client";
|
||||
import { Badge as E, ChakraProvider as P } from "@chakra-ui/react";
|
||||
const R = "https://uikit.d.aiengines.ir/GBadge.js", d = "__UIKIT_REMOTE_DEPS__", f = "__UIKIT_REMOTE_CONFIG__", i = /* @__PURE__ */ new Map();
|
||||
function w(e = {}) {
|
||||
import { jsx as E } from "react/jsx-runtime";
|
||||
import p, { useRef as s, useEffect as R } from "react";
|
||||
import { createRoot as k } from "react-dom/client";
|
||||
import { Text as U, Input as _, IconButton as I, HStack as v, Button as G, Badge as C, ChakraProvider as T } from "@chakra-ui/react";
|
||||
const h = {
|
||||
GBadge: "https://uikit.d.aiengines.ir/GBadge.js",
|
||||
Pagination: "https://uikit.d.aiengines.ir/Pagination.js"
|
||||
}, l = "__UIKIT_REMOTE_DEPS__", g = "__UIKIT_REMOTE_CONFIG__", u = /* @__PURE__ */ new Map(), y = {
|
||||
GBadge: ["React", "createRoot", "ChakraProvider", "Badge"],
|
||||
Pagination: [
|
||||
"React",
|
||||
"createRoot",
|
||||
"ChakraProvider",
|
||||
"Button",
|
||||
"HStack",
|
||||
"IconButton",
|
||||
"Input",
|
||||
"Text"
|
||||
]
|
||||
};
|
||||
function D(e = {}) {
|
||||
if (typeof window > "u") return;
|
||||
const r = window[d] || {}, n = window[f] || {};
|
||||
window[d] = {
|
||||
...r,
|
||||
React: e.React || r.React || h,
|
||||
createRoot: e.createRoot || r.createRoot || _,
|
||||
ChakraProvider: e.ChakraProvider || r.ChakraProvider || P,
|
||||
Badge: e.Badge || r.Badge || E,
|
||||
theme: Object.prototype.hasOwnProperty.call(e, "theme") ? e.theme : r.theme,
|
||||
const t = window[l] || {}, r = window[g] || {};
|
||||
window[l] = {
|
||||
...t,
|
||||
React: e.React || t.React || p,
|
||||
createRoot: e.createRoot || t.createRoot || k,
|
||||
ChakraProvider: e.ChakraProvider || t.ChakraProvider || T,
|
||||
Badge: e.Badge || t.Badge || C,
|
||||
Button: e.Button || t.Button || G,
|
||||
HStack: e.HStack || t.HStack || v,
|
||||
IconButton: e.IconButton || t.IconButton || I,
|
||||
Input: e.Input || t.Input || _,
|
||||
Text: e.Text || t.Text || U,
|
||||
theme: Object.prototype.hasOwnProperty.call(e, "theme") ? e.theme : t.theme,
|
||||
chakraProviderProps: {
|
||||
...r.chakraProviderProps || {},
|
||||
...t.chakraProviderProps || {},
|
||||
...e.chakraProviderProps || {}
|
||||
}
|
||||
}, window[f] = {
|
||||
...n,
|
||||
...e.remoteUrl ? { GBadgeUrl: e.remoteUrl } : {}
|
||||
};
|
||||
const n = e.remoteUrls || {};
|
||||
window[g] = {
|
||||
...r,
|
||||
...e.remoteUrl ? { GBadgeUrl: e.remoteUrl } : {},
|
||||
...e.GBadgeUrl ? { GBadgeUrl: e.GBadgeUrl } : {},
|
||||
...e.PaginationUrl ? { PaginationUrl: e.PaginationUrl } : {},
|
||||
...n.GBadge ? { GBadgeUrl: n.GBadge } : {},
|
||||
...n.Pagination ? { PaginationUrl: n.Pagination } : {}
|
||||
};
|
||||
}
|
||||
function v() {
|
||||
function O(e) {
|
||||
if (typeof window > "u") return;
|
||||
const e = window[d];
|
||||
(!(e != null && e.React) || !(e != null && e.createRoot) || !(e != null && e.ChakraProvider) || !(e != null && e.Badge)) && w();
|
||||
const t = window[l];
|
||||
(y[e] || []).some((o) => !(t != null && t[o])) && D();
|
||||
}
|
||||
function k() {
|
||||
var e;
|
||||
return typeof window > "u" ? R : ((e = window[f]) == null ? void 0 : e.GBadgeUrl) || R;
|
||||
function S(e, t) {
|
||||
var r;
|
||||
return t || (typeof window > "u" ? h[e] : ((r = window[g]) == null ? void 0 : r[`${e}Url`]) || h[e]);
|
||||
}
|
||||
function y() {
|
||||
const e = k();
|
||||
return i.has(e) || i.set(
|
||||
e,
|
||||
function M(e, t) {
|
||||
const r = S(e, t), n = `${e}:${r}`;
|
||||
return u.has(n) || u.set(
|
||||
n,
|
||||
import(
|
||||
/* webpackIgnore: true */
|
||||
/* @vite-ignore */
|
||||
e
|
||||
).catch((r) => {
|
||||
throw i.delete(e), r;
|
||||
r
|
||||
).catch((o) => {
|
||||
throw u.delete(n), o;
|
||||
})
|
||||
), i.get(e);
|
||||
), u.get(n);
|
||||
}
|
||||
function B(e) {
|
||||
function x(e) {
|
||||
if (typeof e == "string" || typeof e == "number")
|
||||
return e;
|
||||
e != null && console.warn(
|
||||
"[uikit/remote/ui] GBadge only accepts text/number children across the remote boundary."
|
||||
);
|
||||
}
|
||||
const T = ({
|
||||
children: e,
|
||||
remoteUrl: r,
|
||||
theme: n,
|
||||
chakraProviderProps: s,
|
||||
...p
|
||||
}) => {
|
||||
const a = u(null), t = u(null), c = u(null);
|
||||
return c.current = {
|
||||
...p,
|
||||
children: B(e),
|
||||
...n !== void 0 ? { theme: n } : {},
|
||||
...s ? { chakraProviderProps: s } : {}
|
||||
}, m(() => {
|
||||
let l = !0;
|
||||
return v(), r && w({ remoteUrl: r }), y().then(() => {
|
||||
if (!l || !a.current) return;
|
||||
const o = document.createElement("uikit-g-badge");
|
||||
o.componentProps = c.current, a.current.appendChild(o), t.current = o;
|
||||
}).catch((o) => {
|
||||
console.error("[uikit/remote/ui] Failed to load GBadge:", o);
|
||||
}), () => {
|
||||
l = !1, t.current && (t.current.remove(), t.current = null);
|
||||
};
|
||||
}, [r]), m(() => {
|
||||
t.current && (t.current.componentProps = c.current);
|
||||
}), /* @__PURE__ */ g(
|
||||
"span",
|
||||
{
|
||||
ref: a,
|
||||
style: {
|
||||
display: "contents"
|
||||
function w({
|
||||
componentName: e,
|
||||
tagName: t,
|
||||
normalizeProps: r
|
||||
}) {
|
||||
return function({
|
||||
remoteUrl: o,
|
||||
theme: f,
|
||||
chakraProviderProps: m,
|
||||
...B
|
||||
}) {
|
||||
const c = s(null), a = s(null), d = s(null);
|
||||
return d.current = {
|
||||
...r ? r(B) : B,
|
||||
...f !== void 0 ? { theme: f } : {},
|
||||
...m ? { chakraProviderProps: m } : {}
|
||||
}, R(() => {
|
||||
let P = !0;
|
||||
return O(e), M(e, o).then(() => {
|
||||
if (!P || !c.current) return;
|
||||
const i = document.createElement(t);
|
||||
i.componentProps = d.current, c.current.appendChild(i), a.current = i;
|
||||
}).catch((i) => {
|
||||
console.error(
|
||||
`[uikit/remote/ui] Failed to load ${e}:`,
|
||||
i
|
||||
);
|
||||
}), () => {
|
||||
P = !1, a.current && (a.current.remove(), a.current = null);
|
||||
};
|
||||
}, [e, o, t]), R(() => {
|
||||
a.current && (a.current.componentProps = d.current);
|
||||
}), /* @__PURE__ */ E(
|
||||
"span",
|
||||
{
|
||||
ref: c,
|
||||
style: {
|
||||
display: "contents"
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
);
|
||||
};
|
||||
}
|
||||
const F = w({
|
||||
componentName: "GBadge",
|
||||
tagName: "uikit-g-badge",
|
||||
normalizeProps: ({ children: e, ...t }) => ({
|
||||
...t,
|
||||
children: x(e)
|
||||
})
|
||||
}), $ = w({
|
||||
componentName: "Pagination",
|
||||
tagName: "uikit-pagination"
|
||||
});
|
||||
export {
|
||||
T as GBadge,
|
||||
w as setupUikitRemoteDeps
|
||||
F as GBadge,
|
||||
$ as Pagination,
|
||||
D as setupUikitRemoteDeps
|
||||
};
|
||||
|
||||
335
dist/remote/Pagination.js
vendored
Normal file
335
dist/remote/Pagination.js
vendored
Normal file
@ -0,0 +1,335 @@
|
||||
const H = {
|
||||
full: {
|
||||
showPageSummary: !0,
|
||||
showTotalCount: !0,
|
||||
showInput: !0,
|
||||
inputWidth: "100px",
|
||||
justifyContent: "space-around",
|
||||
pageButtonPx: void 0,
|
||||
getPageNumbers: ({ currentPage: t, totalPages: e }) => [
|
||||
1,
|
||||
t,
|
||||
t + 1,
|
||||
e
|
||||
]
|
||||
},
|
||||
compact: {
|
||||
showPageSummary: !1,
|
||||
showTotalCount: !0,
|
||||
showInput: !0,
|
||||
inputWidth: "56px",
|
||||
justifyContent: "space-around",
|
||||
pageButtonPx: 2,
|
||||
getPageNumbers: ({ currentPage: t, totalPages: e }) => [
|
||||
1,
|
||||
t,
|
||||
e
|
||||
]
|
||||
},
|
||||
simple: {
|
||||
showPageSummary: !1,
|
||||
showTotalCount: !1,
|
||||
showInput: !1,
|
||||
inputWidth: "48px",
|
||||
justifyContent: "center",
|
||||
pageButtonPx: void 0,
|
||||
getPageNumbers: () => []
|
||||
}
|
||||
}, V = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"], ne = /[۰-۹]/g, oe = /[٠-٩]/g;
|
||||
function k() {
|
||||
const t = window.__UIKIT_REMOTE_DEPS__, e = [];
|
||||
if (t?.React || e.push("React"), t?.createRoot || e.push("createRoot"), t?.ChakraProvider || e.push("ChakraProvider"), t?.Button || e.push("Button"), t?.HStack || e.push("HStack"), t?.IconButton || e.push("IconButton"), t?.Input || e.push("Input"), t?.Text || e.push("Text"), e.length)
|
||||
throw new Error(
|
||||
`[uikit-pagination] Missing remote dependencies: ${e.join(", ")}. Set window.__UIKIT_REMOTE_DEPS__ before loading the remote component.`
|
||||
);
|
||||
return t;
|
||||
}
|
||||
function a(t) {
|
||||
return t == null ? "" : String(t).replace(/\d/g, (e) => V[Number(e)]);
|
||||
}
|
||||
function G(t) {
|
||||
return t == null ? "" : String(t).replace(
|
||||
ne,
|
||||
(e) => String(V.indexOf(e))
|
||||
).replace(oe, (e) => String(e.charCodeAt(0) - 1632));
|
||||
}
|
||||
function re(t) {
|
||||
return H[t] ? t : "full";
|
||||
}
|
||||
function W(t, e) {
|
||||
const m = Number(t), g = Number(e);
|
||||
return !g || g <= 0 || !m || Number.isNaN(m) ? 1 : Math.min(Math.max(m, 1), g);
|
||||
}
|
||||
function ie(t) {
|
||||
const { React: e } = k();
|
||||
return e.createElement(
|
||||
"svg",
|
||||
{
|
||||
width: "20",
|
||||
height: "20",
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "none",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
"aria-hidden": "true",
|
||||
...t
|
||||
},
|
||||
e.createElement("path", {
|
||||
d: "M15 18L9 12L15 6",
|
||||
stroke: "currentColor",
|
||||
strokeWidth: "2",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round"
|
||||
})
|
||||
);
|
||||
}
|
||||
function se(t) {
|
||||
const { React: e } = k();
|
||||
return e.createElement(
|
||||
"svg",
|
||||
{
|
||||
width: "20",
|
||||
height: "20",
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "none",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
"aria-hidden": "true",
|
||||
...t
|
||||
},
|
||||
e.createElement("path", {
|
||||
d: "M9 18L15 12L9 6",
|
||||
stroke: "currentColor",
|
||||
strokeWidth: "2",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round"
|
||||
})
|
||||
);
|
||||
}
|
||||
function ue({
|
||||
currentPage: t = 1,
|
||||
totalCount: e = 0,
|
||||
totalPages: m,
|
||||
pageSize: g = 10,
|
||||
onPageChange: h,
|
||||
level: v = "full",
|
||||
...B
|
||||
}) {
|
||||
const { React: n, Button: K, HStack: S, IconButton: j, Input: O, Text: P } = k(), { useCallback: I, useEffect: N, useMemo: U, useRef: X, useState: R } = n, F = re(v), f = H[F], r = F === "simple", y = Number(g), $ = Number.isFinite(y) && y > 0 ? y : 10, L = Number(e), D = Number.isFinite(L) && L > 0 ? L : 0, A = Number(m), u = Number.isFinite(A) && A > 0 ? Math.ceil(A) : Math.ceil(D / $), i = W(t, u), [d, c] = R(
|
||||
r ? "" : a(i)
|
||||
), [E, b] = R(!1), [p, l] = R(null), C = X(null), w = p ?? i, q = D > 0, J = U(() => r || u <= 0 ? [] : Array.from(
|
||||
new Set(
|
||||
f.getPageNumbers({
|
||||
currentPage: i,
|
||||
totalPages: u
|
||||
})
|
||||
)
|
||||
).filter((o) => o >= 1 && o <= u).sort((o, s) => o - s), [f, r, i, u]), _ = I(() => {
|
||||
c(r ? "" : a(i)), b(!1), l(null);
|
||||
}, [r, i]), M = I(
|
||||
(o) => {
|
||||
const s = W(o, u);
|
||||
b(!1), c(r ? "" : a(i)), l(null), s !== i && h?.(s);
|
||||
},
|
||||
[r, h, i, u]
|
||||
), x = I(() => {
|
||||
if (!d) {
|
||||
_(), C.current?.blur();
|
||||
return;
|
||||
}
|
||||
const o = parseInt(G(d), 10);
|
||||
if (Number.isNaN(o)) {
|
||||
_(), C.current?.blur();
|
||||
return;
|
||||
}
|
||||
const s = W(o, u);
|
||||
if (r) {
|
||||
b(!1), c(""), s !== i ? (l(s), h?.(s)) : l(null), C.current?.blur();
|
||||
return;
|
||||
}
|
||||
s !== i ? (l(s), c(a(s)), h?.(s)) : (c(a(i)), b(!1), l(null)), C.current?.blur();
|
||||
}, [
|
||||
d,
|
||||
r,
|
||||
h,
|
||||
_,
|
||||
i,
|
||||
u
|
||||
]), Q = I(() => {
|
||||
l(null), c(""), b(!0);
|
||||
}, []), Y = I((o) => {
|
||||
const s = o.target.value, te = G(s).replace(/\D/g, "");
|
||||
c(a(te));
|
||||
}, []);
|
||||
if (N(() => {
|
||||
if (r) {
|
||||
p !== null && i === p && l(null);
|
||||
return;
|
||||
}
|
||||
if (p !== null) {
|
||||
i === p && (l(null), b(!1), c(a(i)));
|
||||
return;
|
||||
}
|
||||
E || c(a(i));
|
||||
}, [E, r, p, i]), N(() => {
|
||||
r && E && C.current?.focus();
|
||||
}, [E, r]), N(() => {
|
||||
if (!E || !d || !r && p !== null) return;
|
||||
const o = setTimeout(() => {
|
||||
x();
|
||||
}, 1e3);
|
||||
return () => clearTimeout(o);
|
||||
}, [x, d, E, r, p]), u <= 0) return null;
|
||||
const z = () => n.createElement(O, {
|
||||
ref: C,
|
||||
type: "text",
|
||||
inputMode: "numeric",
|
||||
placeholder: "صفحه",
|
||||
w: f.inputWidth,
|
||||
value: d,
|
||||
onFocus: () => {
|
||||
r || (b(!0), l(null), c(""));
|
||||
},
|
||||
onChange: Y,
|
||||
onBlur: () => {
|
||||
if (d) {
|
||||
r && x();
|
||||
return;
|
||||
}
|
||||
_();
|
||||
},
|
||||
onKeyDown: (o) => {
|
||||
o.key === "Enter" && x(), o.key === "Escape" && _();
|
||||
},
|
||||
textAlign: "center",
|
||||
color: "#1D2939",
|
||||
px: 1,
|
||||
minW: 0,
|
||||
dir: "ltr"
|
||||
}), T = (o, s = !1) => n.createElement(
|
||||
K,
|
||||
{
|
||||
key: o,
|
||||
size: "md",
|
||||
px: f.pageButtonPx,
|
||||
bg: s ? "#4B49AC" : "#e6e6f1",
|
||||
color: s ? "#e6e6f1" : "#4B49AC",
|
||||
_hover: { bg: s ? "#4B49AC" : "#cbcbe8" },
|
||||
onClick: r && s ? Q : () => M(o),
|
||||
variant: "soft"
|
||||
},
|
||||
a(o)
|
||||
), Z = r && u > 1 && w !== 1, ee = r && u > 1 && w !== u;
|
||||
return n.createElement(
|
||||
S,
|
||||
{
|
||||
justifyContent: f.justifyContent,
|
||||
backgroundColor: "white",
|
||||
py: "10px",
|
||||
px: "16px",
|
||||
rounded: "lg",
|
||||
border: "1px",
|
||||
borderColor: "blue.200",
|
||||
w: "100%",
|
||||
...B
|
||||
},
|
||||
f.showPageSummary && n.createElement(
|
||||
S,
|
||||
{ spacing: 2, whiteSpace: "nowrap" },
|
||||
n.createElement(P, { fontWeight: "bold" }, "صفحه"),
|
||||
n.createElement(P, null, a(i)),
|
||||
n.createElement(P, { fontWeight: "bold" }, "از"),
|
||||
n.createElement(P, null, a(u))
|
||||
),
|
||||
n.createElement(
|
||||
S,
|
||||
{ spacing: 2, alignItems: "center", justifyContent: "center" },
|
||||
n.createElement(j, {
|
||||
size: "md",
|
||||
bg: "#e6e6f1",
|
||||
color: "#4B49AC",
|
||||
_hover: { bg: "#cbcbe8" },
|
||||
onClick: () => M(w - 1),
|
||||
isDisabled: w === 1,
|
||||
icon: n.createElement(ie),
|
||||
"aria-label": "صفحه قبلی"
|
||||
}),
|
||||
r ? [
|
||||
Z ? T(1) : null,
|
||||
E ? n.createElement(
|
||||
n.Fragment,
|
||||
{ key: "input" },
|
||||
z()
|
||||
) : T(w, !0),
|
||||
ee ? T(u) : null
|
||||
] : [
|
||||
...J.map(
|
||||
(o) => T(o, i === o)
|
||||
),
|
||||
f.showInput ? n.createElement(
|
||||
n.Fragment,
|
||||
{ key: "input" },
|
||||
z()
|
||||
) : null
|
||||
],
|
||||
n.createElement(j, {
|
||||
size: "md",
|
||||
bg: "#e6e6f1",
|
||||
color: "#4B49AC",
|
||||
_hover: { bg: "#cbcbe8" },
|
||||
onClick: () => M(w + 1),
|
||||
isDisabled: w === u,
|
||||
icon: n.createElement(se),
|
||||
"aria-label": "صفحه بعدی"
|
||||
})
|
||||
),
|
||||
f.showTotalCount && q && n.createElement(
|
||||
S,
|
||||
{ spacing: 2, whiteSpace: "nowrap" },
|
||||
n.createElement(
|
||||
P,
|
||||
{ w: "auto", fontWeight: "bold" },
|
||||
"تعداد کل:"
|
||||
),
|
||||
n.createElement(P, null, a(D))
|
||||
)
|
||||
);
|
||||
}
|
||||
class ae extends HTMLElement {
|
||||
constructor() {
|
||||
super(), this._props = {}, this._root = null;
|
||||
}
|
||||
connectedCallback() {
|
||||
const { createRoot: e } = k();
|
||||
this._root || (this._root = e(this)), this.renderComponent();
|
||||
}
|
||||
disconnectedCallback() {
|
||||
this._root && (this._root.unmount(), this._root = null);
|
||||
}
|
||||
set componentProps(e) {
|
||||
this._props = e ?? {}, this.isConnected && this.renderComponent();
|
||||
}
|
||||
get componentProps() {
|
||||
return this._props;
|
||||
}
|
||||
renderComponent() {
|
||||
if (!this._root) return;
|
||||
const {
|
||||
React: e,
|
||||
ChakraProvider: m,
|
||||
theme: g,
|
||||
chakraProviderProps: h
|
||||
} = k(), { theme: v, chakraProviderProps: B, ...n } = this._props || {};
|
||||
this._root.render(
|
||||
e.createElement(
|
||||
m,
|
||||
{
|
||||
theme: v || g,
|
||||
resetCSS: !1,
|
||||
...h || {},
|
||||
...B || {}
|
||||
},
|
||||
e.createElement(ue, n)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
customElements.get("uikit-pagination") || customElements.define("uikit-pagination", ae);
|
||||
560
src/remote/ui/Pagination.remote.jsx
Normal file
560
src/remote/ui/Pagination.remote.jsx
Normal file
@ -0,0 +1,560 @@
|
||||
// Remote Web Component for Pagination.
|
||||
// No imports. React, createRoot and Chakra components are provided by the host via window.__UIKIT_REMOTE_DEPS__.
|
||||
|
||||
const LEVELS = {
|
||||
full: {
|
||||
showPageSummary: true,
|
||||
showTotalCount: true,
|
||||
showInput: true,
|
||||
inputWidth: "100px",
|
||||
justifyContent: "space-around",
|
||||
pageButtonPx: undefined,
|
||||
getPageNumbers: ({ currentPage, totalPages }) => [
|
||||
1,
|
||||
currentPage,
|
||||
currentPage + 1,
|
||||
totalPages,
|
||||
],
|
||||
},
|
||||
|
||||
compact: {
|
||||
showPageSummary: false,
|
||||
showTotalCount: true,
|
||||
showInput: true,
|
||||
inputWidth: "56px",
|
||||
justifyContent: "space-around",
|
||||
pageButtonPx: 2,
|
||||
getPageNumbers: ({ currentPage, totalPages }) => [
|
||||
1,
|
||||
currentPage,
|
||||
totalPages,
|
||||
],
|
||||
},
|
||||
|
||||
simple: {
|
||||
showPageSummary: false,
|
||||
showTotalCount: false,
|
||||
showInput: false,
|
||||
inputWidth: "48px",
|
||||
justifyContent: "center",
|
||||
pageButtonPx: undefined,
|
||||
getPageNumbers: () => [],
|
||||
},
|
||||
};
|
||||
|
||||
const PERSIAN_DIGITS = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"];
|
||||
const PERSIAN_DIGIT_REGEX = /[۰-۹]/g;
|
||||
const ARABIC_DIGIT_REGEX = /[٠-٩]/g;
|
||||
|
||||
function getRemoteDeps() {
|
||||
const deps = window.__UIKIT_REMOTE_DEPS__;
|
||||
const missing = [];
|
||||
|
||||
if (!deps?.React) missing.push("React");
|
||||
if (!deps?.createRoot) missing.push("createRoot");
|
||||
if (!deps?.ChakraProvider) missing.push("ChakraProvider");
|
||||
if (!deps?.Button) missing.push("Button");
|
||||
if (!deps?.HStack) missing.push("HStack");
|
||||
if (!deps?.IconButton) missing.push("IconButton");
|
||||
if (!deps?.Input) missing.push("Input");
|
||||
if (!deps?.Text) missing.push("Text");
|
||||
|
||||
if (missing.length) {
|
||||
throw new Error(
|
||||
`[uikit-pagination] Missing remote dependencies: ${missing.join(", ")}. ` +
|
||||
"Set window.__UIKIT_REMOTE_DEPS__ before loading the remote component.",
|
||||
);
|
||||
}
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
function toFaDigits(value) {
|
||||
if (value === undefined || value === null) return "";
|
||||
|
||||
return String(value).replace(/\d/g, (digit) => PERSIAN_DIGITS[Number(digit)]);
|
||||
}
|
||||
|
||||
function toEnDigits(value) {
|
||||
if (value === undefined || value === null) return "";
|
||||
|
||||
return String(value)
|
||||
.replace(PERSIAN_DIGIT_REGEX, (digit) =>
|
||||
String(PERSIAN_DIGITS.indexOf(digit)),
|
||||
)
|
||||
.replace(ARABIC_DIGIT_REGEX, (digit) => String(digit.charCodeAt(0) - 1632));
|
||||
}
|
||||
|
||||
function normalizeLevel(level) {
|
||||
if (LEVELS[level]) return level;
|
||||
|
||||
return "full";
|
||||
}
|
||||
|
||||
function getSafePage(page, totalPages) {
|
||||
const numericPage = Number(page);
|
||||
const numericTotalPages = Number(totalPages);
|
||||
|
||||
if (!numericTotalPages || numericTotalPages <= 0) return 1;
|
||||
if (!numericPage || Number.isNaN(numericPage)) return 1;
|
||||
|
||||
return Math.min(Math.max(numericPage, 1), numericTotalPages);
|
||||
}
|
||||
|
||||
function ChevronRightIcon(props) {
|
||||
const { React } = getRemoteDeps();
|
||||
|
||||
return React.createElement(
|
||||
"svg",
|
||||
{
|
||||
width: "20",
|
||||
height: "20",
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "none",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
"aria-hidden": "true",
|
||||
...props,
|
||||
},
|
||||
React.createElement("path", {
|
||||
d: "M15 18L9 12L15 6",
|
||||
stroke: "currentColor",
|
||||
strokeWidth: "2",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function ChevronLeftIcon(props) {
|
||||
const { React } = getRemoteDeps();
|
||||
|
||||
return React.createElement(
|
||||
"svg",
|
||||
{
|
||||
width: "20",
|
||||
height: "20",
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "none",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
"aria-hidden": "true",
|
||||
...props,
|
||||
},
|
||||
React.createElement("path", {
|
||||
d: "M9 18L15 12L9 6",
|
||||
stroke: "currentColor",
|
||||
strokeWidth: "2",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function RemotePagination({
|
||||
currentPage = 1,
|
||||
totalCount = 0,
|
||||
totalPages,
|
||||
pageSize = 10,
|
||||
onPageChange,
|
||||
level = "full",
|
||||
...containerProps
|
||||
}) {
|
||||
const { React, Button, HStack, IconButton, Input, Text } = getRemoteDeps();
|
||||
|
||||
const { useCallback, useEffect, useMemo, useRef, useState } = React;
|
||||
|
||||
const resolvedLevel = normalizeLevel(level);
|
||||
const config = LEVELS[resolvedLevel];
|
||||
const isSimple = resolvedLevel === "simple";
|
||||
|
||||
const numericPageSize = Number(pageSize);
|
||||
const safePageSize =
|
||||
Number.isFinite(numericPageSize) && numericPageSize > 0
|
||||
? numericPageSize
|
||||
: 10;
|
||||
|
||||
const numericTotalCount = Number(totalCount);
|
||||
const safeTotalCount =
|
||||
Number.isFinite(numericTotalCount) && numericTotalCount > 0
|
||||
? numericTotalCount
|
||||
: 0;
|
||||
|
||||
const numericTotalPages = Number(totalPages);
|
||||
const safeTotalPages =
|
||||
Number.isFinite(numericTotalPages) && numericTotalPages > 0
|
||||
? Math.ceil(numericTotalPages)
|
||||
: Math.ceil(safeTotalCount / safePageSize);
|
||||
|
||||
const safeCurrentPage = getSafePage(currentPage, safeTotalPages);
|
||||
|
||||
const [inputValue, setInputValue] = useState(
|
||||
isSimple ? "" : toFaDigits(safeCurrentPage),
|
||||
);
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [pendingPage, setPendingPage] = useState(null);
|
||||
const inputRef = useRef(null);
|
||||
|
||||
const visibleCurrentPage = pendingPage ?? safeCurrentPage;
|
||||
const hasTotalCount = safeTotalCount > 0;
|
||||
|
||||
const pageNumbers = useMemo(() => {
|
||||
if (isSimple || safeTotalPages <= 0) return [];
|
||||
|
||||
return Array.from(
|
||||
new Set(
|
||||
config.getPageNumbers({
|
||||
currentPage: safeCurrentPage,
|
||||
totalPages: safeTotalPages,
|
||||
}),
|
||||
),
|
||||
)
|
||||
.filter((page) => page >= 1 && page <= safeTotalPages)
|
||||
.sort((a, b) => a - b);
|
||||
}, [config, isSimple, safeCurrentPage, safeTotalPages]);
|
||||
|
||||
const resetInput = useCallback(() => {
|
||||
setInputValue(isSimple ? "" : toFaDigits(safeCurrentPage));
|
||||
setIsEditing(false);
|
||||
setPendingPage(null);
|
||||
}, [isSimple, safeCurrentPage]);
|
||||
|
||||
const goToPage = useCallback(
|
||||
(page) => {
|
||||
const safePage = getSafePage(page, safeTotalPages);
|
||||
|
||||
setIsEditing(false);
|
||||
setInputValue(isSimple ? "" : toFaDigits(safeCurrentPage));
|
||||
setPendingPage(null);
|
||||
|
||||
if (safePage !== safeCurrentPage) {
|
||||
onPageChange?.(safePage);
|
||||
}
|
||||
},
|
||||
[isSimple, onPageChange, safeCurrentPage, safeTotalPages],
|
||||
);
|
||||
|
||||
const commitInput = useCallback(() => {
|
||||
if (!inputValue) {
|
||||
resetInput();
|
||||
inputRef.current?.blur();
|
||||
return;
|
||||
}
|
||||
|
||||
const page = parseInt(toEnDigits(inputValue), 10);
|
||||
|
||||
if (Number.isNaN(page)) {
|
||||
resetInput();
|
||||
inputRef.current?.blur();
|
||||
return;
|
||||
}
|
||||
|
||||
const safePage = getSafePage(page, safeTotalPages);
|
||||
|
||||
if (isSimple) {
|
||||
setIsEditing(false);
|
||||
setInputValue("");
|
||||
|
||||
if (safePage !== safeCurrentPage) {
|
||||
setPendingPage(safePage);
|
||||
onPageChange?.(safePage);
|
||||
} else {
|
||||
setPendingPage(null);
|
||||
}
|
||||
|
||||
inputRef.current?.blur();
|
||||
return;
|
||||
}
|
||||
|
||||
if (safePage !== safeCurrentPage) {
|
||||
setPendingPage(safePage);
|
||||
setInputValue(toFaDigits(safePage));
|
||||
onPageChange?.(safePage);
|
||||
} else {
|
||||
setInputValue(toFaDigits(safeCurrentPage));
|
||||
setIsEditing(false);
|
||||
setPendingPage(null);
|
||||
}
|
||||
|
||||
inputRef.current?.blur();
|
||||
}, [
|
||||
inputValue,
|
||||
isSimple,
|
||||
onPageChange,
|
||||
resetInput,
|
||||
safeCurrentPage,
|
||||
safeTotalPages,
|
||||
]);
|
||||
|
||||
const startEditing = useCallback(() => {
|
||||
setPendingPage(null);
|
||||
setInputValue("");
|
||||
setIsEditing(true);
|
||||
}, []);
|
||||
|
||||
const handleInputChange = useCallback((event) => {
|
||||
const rawValue = event.target.value;
|
||||
const onlyDigits = toEnDigits(rawValue).replace(/\D/g, "");
|
||||
|
||||
setInputValue(toFaDigits(onlyDigits));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isSimple) {
|
||||
if (pendingPage !== null && safeCurrentPage === pendingPage) {
|
||||
setPendingPage(null);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingPage !== null) {
|
||||
if (safeCurrentPage === pendingPage) {
|
||||
setPendingPage(null);
|
||||
setIsEditing(false);
|
||||
setInputValue(toFaDigits(safeCurrentPage));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEditing) {
|
||||
setInputValue(toFaDigits(safeCurrentPage));
|
||||
}
|
||||
}, [isEditing, isSimple, pendingPage, safeCurrentPage]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isSimple && isEditing) {
|
||||
inputRef.current?.focus();
|
||||
}
|
||||
}, [isEditing, isSimple]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isEditing) return;
|
||||
if (!inputValue) return;
|
||||
if (!isSimple && pendingPage !== null) return;
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
commitInput();
|
||||
}, 1000);
|
||||
|
||||
return () => clearTimeout(timeout);
|
||||
}, [commitInput, inputValue, isEditing, isSimple, pendingPage]);
|
||||
|
||||
if (safeTotalPages <= 0) return null;
|
||||
|
||||
const renderInput = () =>
|
||||
React.createElement(Input, {
|
||||
ref: inputRef,
|
||||
type: "text",
|
||||
inputMode: "numeric",
|
||||
placeholder: "صفحه",
|
||||
w: config.inputWidth,
|
||||
value: inputValue,
|
||||
onFocus: () => {
|
||||
if (!isSimple) {
|
||||
setIsEditing(true);
|
||||
setPendingPage(null);
|
||||
setInputValue("");
|
||||
}
|
||||
},
|
||||
onChange: handleInputChange,
|
||||
onBlur: () => {
|
||||
if (inputValue) {
|
||||
if (isSimple) {
|
||||
commitInput();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
resetInput();
|
||||
},
|
||||
onKeyDown: (event) => {
|
||||
if (event.key === "Enter") {
|
||||
commitInput();
|
||||
}
|
||||
|
||||
if (event.key === "Escape") {
|
||||
resetInput();
|
||||
}
|
||||
},
|
||||
textAlign: "center",
|
||||
color: "#1D2939",
|
||||
px: 1,
|
||||
minW: 0,
|
||||
dir: "ltr",
|
||||
});
|
||||
|
||||
const renderPageButton = (number, isCurrent = false) =>
|
||||
React.createElement(
|
||||
Button,
|
||||
{
|
||||
key: number,
|
||||
size: "md",
|
||||
px: config.pageButtonPx,
|
||||
bg: isCurrent ? "#4B49AC" : "#e6e6f1",
|
||||
color: isCurrent ? "#e6e6f1" : "#4B49AC",
|
||||
_hover: { bg: isCurrent ? "#4B49AC" : "#cbcbe8" },
|
||||
onClick: isSimple && isCurrent ? startEditing : () => goToPage(number),
|
||||
variant: "soft",
|
||||
},
|
||||
toFaDigits(number),
|
||||
);
|
||||
|
||||
const showFirstButton =
|
||||
isSimple && safeTotalPages > 1 && visibleCurrentPage !== 1;
|
||||
const showLastButton =
|
||||
isSimple && safeTotalPages > 1 && visibleCurrentPage !== safeTotalPages;
|
||||
|
||||
return React.createElement(
|
||||
HStack,
|
||||
{
|
||||
justifyContent: config.justifyContent,
|
||||
backgroundColor: "white",
|
||||
py: "10px",
|
||||
px: "16px",
|
||||
rounded: "lg",
|
||||
border: "1px",
|
||||
borderColor: "blue.200",
|
||||
w: "100%",
|
||||
...containerProps,
|
||||
},
|
||||
config.showPageSummary &&
|
||||
React.createElement(
|
||||
HStack,
|
||||
{ spacing: 2, whiteSpace: "nowrap" },
|
||||
React.createElement(Text, { fontWeight: "bold" }, "صفحه"),
|
||||
React.createElement(Text, null, toFaDigits(safeCurrentPage)),
|
||||
React.createElement(Text, { fontWeight: "bold" }, "از"),
|
||||
React.createElement(Text, null, toFaDigits(safeTotalPages)),
|
||||
),
|
||||
React.createElement(
|
||||
HStack,
|
||||
{ spacing: 2, alignItems: "center", justifyContent: "center" },
|
||||
React.createElement(IconButton, {
|
||||
size: "md",
|
||||
bg: "#e6e6f1",
|
||||
color: "#4B49AC",
|
||||
_hover: { bg: "#cbcbe8" },
|
||||
onClick: () => goToPage(visibleCurrentPage - 1),
|
||||
isDisabled: visibleCurrentPage === 1,
|
||||
icon: React.createElement(ChevronRightIcon),
|
||||
"aria-label": "صفحه قبلی",
|
||||
}),
|
||||
isSimple
|
||||
? [
|
||||
showFirstButton ? renderPageButton(1) : null,
|
||||
isEditing
|
||||
? React.createElement(
|
||||
React.Fragment,
|
||||
{ key: "input" },
|
||||
renderInput(),
|
||||
)
|
||||
: renderPageButton(visibleCurrentPage, true),
|
||||
showLastButton ? renderPageButton(safeTotalPages) : null,
|
||||
]
|
||||
: [
|
||||
...pageNumbers.map((number) =>
|
||||
renderPageButton(number, safeCurrentPage === number),
|
||||
),
|
||||
config.showInput
|
||||
? React.createElement(
|
||||
React.Fragment,
|
||||
{ key: "input" },
|
||||
renderInput(),
|
||||
)
|
||||
: null,
|
||||
],
|
||||
React.createElement(IconButton, {
|
||||
size: "md",
|
||||
bg: "#e6e6f1",
|
||||
color: "#4B49AC",
|
||||
_hover: { bg: "#cbcbe8" },
|
||||
onClick: () => goToPage(visibleCurrentPage + 1),
|
||||
isDisabled: visibleCurrentPage === safeTotalPages,
|
||||
icon: React.createElement(ChevronLeftIcon),
|
||||
"aria-label": "صفحه بعدی",
|
||||
}),
|
||||
),
|
||||
config.showTotalCount &&
|
||||
hasTotalCount &&
|
||||
React.createElement(
|
||||
HStack,
|
||||
{ spacing: 2, whiteSpace: "nowrap" },
|
||||
React.createElement(
|
||||
Text,
|
||||
{ w: "auto", fontWeight: "bold" },
|
||||
"تعداد کل:",
|
||||
),
|
||||
React.createElement(Text, null, toFaDigits(safeTotalCount)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class PaginationElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._props = {};
|
||||
this._root = null;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
const { createRoot } = getRemoteDeps();
|
||||
|
||||
if (!this._root) {
|
||||
this._root = createRoot(this);
|
||||
}
|
||||
|
||||
this.renderComponent();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this._root) {
|
||||
this._root.unmount();
|
||||
this._root = null;
|
||||
}
|
||||
}
|
||||
|
||||
set componentProps(value) {
|
||||
this._props = value ?? {};
|
||||
|
||||
if (this.isConnected) {
|
||||
this.renderComponent();
|
||||
}
|
||||
}
|
||||
|
||||
get componentProps() {
|
||||
return this._props;
|
||||
}
|
||||
|
||||
renderComponent() {
|
||||
if (!this._root) return;
|
||||
|
||||
const {
|
||||
React,
|
||||
ChakraProvider,
|
||||
theme: defaultTheme,
|
||||
chakraProviderProps: defaultProviderProps,
|
||||
} = getRemoteDeps();
|
||||
|
||||
const { theme, chakraProviderProps, ...paginationProps } =
|
||||
this._props || {};
|
||||
|
||||
this._root.render(
|
||||
React.createElement(
|
||||
ChakraProvider,
|
||||
{
|
||||
theme: theme || defaultTheme,
|
||||
resetCSS: false,
|
||||
...(defaultProviderProps || {}),
|
||||
...(chakraProviderProps || {}),
|
||||
},
|
||||
React.createElement(RemotePagination, paginationProps),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!customElements.get("uikit-pagination")) {
|
||||
customElements.define("uikit-pagination", PaginationElement);
|
||||
}
|
||||
63
src/remote/ui/index.d.ts
vendored
63
src/remote/ui/index.d.ts
vendored
@ -1,23 +1,54 @@
|
||||
import type { ComponentType, ReactNode } from "react";
|
||||
import type { BadgeProps, StackProps } from "@chakra-ui/react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
export type UikitRemoteDepsOptions = {
|
||||
React?: unknown;
|
||||
createRoot?: unknown;
|
||||
ChakraProvider?: unknown;
|
||||
Badge?: unknown;
|
||||
theme?: unknown;
|
||||
chakraProviderProps?: Record<string, unknown>;
|
||||
export type UikitRemoteLevel = "full" | "compact" | "simple";
|
||||
|
||||
export interface UikitRemoteSetupOptions {
|
||||
React?: any;
|
||||
createRoot?: any;
|
||||
ChakraProvider?: any;
|
||||
Badge?: any;
|
||||
Button?: any;
|
||||
HStack?: any;
|
||||
IconButton?: any;
|
||||
Input?: any;
|
||||
Text?: any;
|
||||
theme?: any;
|
||||
chakraProviderProps?: Record<string, any>;
|
||||
|
||||
/** Backward compatible alias for GBadgeUrl. */
|
||||
remoteUrl?: string;
|
||||
};
|
||||
GBadgeUrl?: string;
|
||||
PaginationUrl?: string;
|
||||
remoteUrls?: {
|
||||
GBadge?: string;
|
||||
Pagination?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export declare function setupUikitRemoteDeps(options?: UikitRemoteDepsOptions): void;
|
||||
export declare function setupUikitRemoteDeps(
|
||||
options?: UikitRemoteSetupOptions,
|
||||
): void;
|
||||
|
||||
export type GBadgeProps = {
|
||||
export interface GBadgeProps extends BadgeProps {
|
||||
children?: ReactNode;
|
||||
remoteUrl?: string;
|
||||
theme?: unknown;
|
||||
chakraProviderProps?: Record<string, unknown>;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
theme?: any;
|
||||
chakraProviderProps?: Record<string, any>;
|
||||
}
|
||||
|
||||
export declare const GBadge: ComponentType<GBadgeProps>;
|
||||
export declare const GBadge: (props: GBadgeProps) => JSX.Element;
|
||||
|
||||
export interface PaginationProps extends Omit<StackProps, "onChange"> {
|
||||
currentPage?: number;
|
||||
totalCount?: number;
|
||||
totalPages?: number;
|
||||
pageSize?: number;
|
||||
onPageChange?: (page: number) => void;
|
||||
level?: UikitRemoteLevel;
|
||||
remoteUrl?: string;
|
||||
theme?: any;
|
||||
chakraProviderProps?: Record<string, any>;
|
||||
}
|
||||
|
||||
export declare const Pagination: (props: PaginationProps) => JSX.Element;
|
||||
|
||||
@ -2,14 +2,40 @@
|
||||
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { Badge, ChakraProvider } from "@chakra-ui/react";
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
ChakraProvider,
|
||||
HStack,
|
||||
IconButton,
|
||||
Input,
|
||||
Text,
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
const DEFAULT_REMOTE_URLS = {
|
||||
GBadge: "https://uikit.d.aiengines.ir/GBadge.js",
|
||||
Pagination: "https://uikit.d.aiengines.ir/Pagination.js",
|
||||
};
|
||||
|
||||
const DEFAULT_REMOTE_URL = "https://uikit.d.aiengines.ir/GBadge.js";
|
||||
const REMOTE_DEPS_KEY = "__UIKIT_REMOTE_DEPS__";
|
||||
const REMOTE_CONFIG_KEY = "__UIKIT_REMOTE_CONFIG__";
|
||||
|
||||
const remotePromises = new Map();
|
||||
|
||||
const REQUIRED_DEPS = {
|
||||
GBadge: ["React", "createRoot", "ChakraProvider", "Badge"],
|
||||
Pagination: [
|
||||
"React",
|
||||
"createRoot",
|
||||
"ChakraProvider",
|
||||
"Button",
|
||||
"HStack",
|
||||
"IconButton",
|
||||
"Input",
|
||||
"Text",
|
||||
],
|
||||
};
|
||||
|
||||
export function setupUikitRemoteDeps(options = {}) {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
@ -23,6 +49,11 @@ export function setupUikitRemoteDeps(options = {}) {
|
||||
ChakraProvider:
|
||||
options.ChakraProvider || previousDeps.ChakraProvider || ChakraProvider,
|
||||
Badge: options.Badge || previousDeps.Badge || Badge,
|
||||
Button: options.Button || previousDeps.Button || Button,
|
||||
HStack: options.HStack || previousDeps.HStack || HStack,
|
||||
IconButton: options.IconButton || previousDeps.IconButton || IconButton,
|
||||
Input: options.Input || previousDeps.Input || Input,
|
||||
Text: options.Text || previousDeps.Text || Text,
|
||||
theme: Object.prototype.hasOwnProperty.call(options, "theme")
|
||||
? options.theme
|
||||
: previousDeps.theme,
|
||||
@ -32,54 +63,65 @@ export function setupUikitRemoteDeps(options = {}) {
|
||||
},
|
||||
};
|
||||
|
||||
const remoteUrls = options.remoteUrls || {};
|
||||
|
||||
window[REMOTE_CONFIG_KEY] = {
|
||||
...previousConfig,
|
||||
...(options.remoteUrl ? { GBadgeUrl: options.remoteUrl } : {}),
|
||||
...(options.GBadgeUrl ? { GBadgeUrl: options.GBadgeUrl } : {}),
|
||||
...(options.PaginationUrl ? { PaginationUrl: options.PaginationUrl } : {}),
|
||||
...(remoteUrls.GBadge ? { GBadgeUrl: remoteUrls.GBadge } : {}),
|
||||
...(remoteUrls.Pagination ? { PaginationUrl: remoteUrls.Pagination } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function ensureRemoteDeps() {
|
||||
function ensureRemoteDeps(componentName) {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
const deps = window[REMOTE_DEPS_KEY];
|
||||
const requiredDeps = REQUIRED_DEPS[componentName] || [];
|
||||
const hasMissingDeps = requiredDeps.some((key) => !deps?.[key]);
|
||||
|
||||
if (
|
||||
!deps?.React ||
|
||||
!deps?.createRoot ||
|
||||
!deps?.ChakraProvider ||
|
||||
!deps?.Badge
|
||||
) {
|
||||
if (hasMissingDeps) {
|
||||
setupUikitRemoteDeps();
|
||||
}
|
||||
}
|
||||
|
||||
function getRemoteUrl() {
|
||||
if (typeof window === "undefined") return DEFAULT_REMOTE_URL;
|
||||
function getRemoteUrl(componentName, explicitRemoteUrl) {
|
||||
if (explicitRemoteUrl) return explicitRemoteUrl;
|
||||
|
||||
return window[REMOTE_CONFIG_KEY]?.GBadgeUrl || DEFAULT_REMOTE_URL;
|
||||
if (typeof window === "undefined") {
|
||||
return DEFAULT_REMOTE_URLS[componentName];
|
||||
}
|
||||
|
||||
return (
|
||||
window[REMOTE_CONFIG_KEY]?.[`${componentName}Url`] ||
|
||||
DEFAULT_REMOTE_URLS[componentName]
|
||||
);
|
||||
}
|
||||
|
||||
function loadRemote() {
|
||||
const remoteUrl = getRemoteUrl();
|
||||
function loadRemote(componentName, explicitRemoteUrl) {
|
||||
const remoteUrl = getRemoteUrl(componentName, explicitRemoteUrl);
|
||||
const cacheKey = `${componentName}:${remoteUrl}`;
|
||||
|
||||
if (!remotePromises.has(remoteUrl)) {
|
||||
if (!remotePromises.has(cacheKey)) {
|
||||
remotePromises.set(
|
||||
remoteUrl,
|
||||
cacheKey,
|
||||
import(
|
||||
/* webpackIgnore: true */
|
||||
/* @vite-ignore */
|
||||
remoteUrl
|
||||
).catch((error) => {
|
||||
remotePromises.delete(remoteUrl);
|
||||
remotePromises.delete(cacheKey);
|
||||
throw error;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return remotePromises.get(remoteUrl);
|
||||
return remotePromises.get(cacheKey);
|
||||
}
|
||||
|
||||
function normalizeChildren(children) {
|
||||
function normalizeBadgeChildren(children) {
|
||||
if (typeof children === "string" || typeof children === "number") {
|
||||
return children;
|
||||
}
|
||||
@ -95,72 +137,89 @@ function normalizeChildren(children) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export const GBadge = ({
|
||||
children,
|
||||
remoteUrl,
|
||||
theme,
|
||||
chakraProviderProps,
|
||||
...props
|
||||
}) => {
|
||||
const containerRef = useRef(null);
|
||||
const elementRef = useRef(null);
|
||||
const latestPropsRef = useRef(null);
|
||||
function createRemoteElementComponent({
|
||||
componentName,
|
||||
tagName,
|
||||
normalizeProps,
|
||||
}) {
|
||||
return function RemoteElementComponent({
|
||||
remoteUrl,
|
||||
theme,
|
||||
chakraProviderProps,
|
||||
...props
|
||||
}) {
|
||||
const containerRef = useRef(null);
|
||||
const elementRef = useRef(null);
|
||||
const latestPropsRef = useRef(null);
|
||||
|
||||
latestPropsRef.current = {
|
||||
...props,
|
||||
children: normalizeChildren(children),
|
||||
...(theme !== undefined ? { theme } : {}),
|
||||
...(chakraProviderProps ? { chakraProviderProps } : {}),
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
|
||||
ensureRemoteDeps();
|
||||
|
||||
if (remoteUrl) {
|
||||
setupUikitRemoteDeps({ remoteUrl });
|
||||
}
|
||||
|
||||
loadRemote()
|
||||
.then(() => {
|
||||
if (!active) return;
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const element = document.createElement("uikit-g-badge");
|
||||
|
||||
element.componentProps = latestPropsRef.current;
|
||||
|
||||
containerRef.current.appendChild(element);
|
||||
|
||||
elementRef.current = element;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("[uikit/remote/ui] Failed to load GBadge:", error);
|
||||
});
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
|
||||
if (elementRef.current) {
|
||||
elementRef.current.remove();
|
||||
elementRef.current = null;
|
||||
}
|
||||
latestPropsRef.current = {
|
||||
...(normalizeProps ? normalizeProps(props) : props),
|
||||
...(theme !== undefined ? { theme } : {}),
|
||||
...(chakraProviderProps ? { chakraProviderProps } : {}),
|
||||
};
|
||||
}, [remoteUrl]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!elementRef.current) return;
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
|
||||
elementRef.current.componentProps = latestPropsRef.current;
|
||||
});
|
||||
ensureRemoteDeps(componentName);
|
||||
|
||||
return (
|
||||
<span
|
||||
ref={containerRef}
|
||||
style={{
|
||||
display: "contents",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
loadRemote(componentName, remoteUrl)
|
||||
.then(() => {
|
||||
if (!active) return;
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const element = document.createElement(tagName);
|
||||
|
||||
element.componentProps = latestPropsRef.current;
|
||||
|
||||
containerRef.current.appendChild(element);
|
||||
|
||||
elementRef.current = element;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
`[uikit/remote/ui] Failed to load ${componentName}:`,
|
||||
error,
|
||||
);
|
||||
});
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
|
||||
if (elementRef.current) {
|
||||
elementRef.current.remove();
|
||||
elementRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [componentName, remoteUrl, tagName]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!elementRef.current) return;
|
||||
|
||||
elementRef.current.componentProps = latestPropsRef.current;
|
||||
});
|
||||
|
||||
return (
|
||||
<span
|
||||
ref={containerRef}
|
||||
style={{
|
||||
display: "contents",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const GBadge = createRemoteElementComponent({
|
||||
componentName: "GBadge",
|
||||
tagName: "uikit-g-badge",
|
||||
normalizeProps: ({ children, ...props }) => ({
|
||||
...props,
|
||||
children: normalizeBadgeChildren(children),
|
||||
}),
|
||||
});
|
||||
|
||||
export const Pagination = createRemoteElementComponent({
|
||||
componentName: "Pagination",
|
||||
tagName: "uikit-pagination",
|
||||
});
|
||||
|
||||
449
src/ui/Pagination.jsx
Normal file
449
src/ui/Pagination.jsx
Normal file
@ -0,0 +1,449 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Button, HStack, IconButton, Input, Text } from "@chakra-ui/react";
|
||||
|
||||
const LEVELS = {
|
||||
full: {
|
||||
showPageSummary: true,
|
||||
showTotalCount: true,
|
||||
showInput: true,
|
||||
inputWidth: "100px",
|
||||
justifyContent: "space-around",
|
||||
pageButtonPx: undefined,
|
||||
getPageNumbers: ({ currentPage, totalPages }) => [
|
||||
1,
|
||||
currentPage,
|
||||
currentPage + 1,
|
||||
totalPages,
|
||||
],
|
||||
},
|
||||
|
||||
compact: {
|
||||
showPageSummary: false,
|
||||
showTotalCount: true,
|
||||
showInput: true,
|
||||
inputWidth: "56px",
|
||||
justifyContent: "space-around",
|
||||
pageButtonPx: 2,
|
||||
getPageNumbers: ({ currentPage, totalPages }) => [
|
||||
1,
|
||||
currentPage,
|
||||
totalPages,
|
||||
],
|
||||
},
|
||||
|
||||
simple: {
|
||||
showPageSummary: false,
|
||||
showTotalCount: false,
|
||||
showInput: false,
|
||||
inputWidth: "48px",
|
||||
justifyContent: "center",
|
||||
pageButtonPx: undefined,
|
||||
getPageNumbers: () => [],
|
||||
},
|
||||
};
|
||||
|
||||
const PERSIAN_DIGITS = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"];
|
||||
const PERSIAN_DIGIT_REGEX = /[۰-۹]/g;
|
||||
const ARABIC_DIGIT_REGEX = /[٠-٩]/g;
|
||||
|
||||
const toFaDigits = (value) => {
|
||||
if (value === undefined || value === null) return "";
|
||||
|
||||
return String(value).replace(/\d/g, (digit) => PERSIAN_DIGITS[Number(digit)]);
|
||||
};
|
||||
|
||||
const toEnDigits = (value) => {
|
||||
if (value === undefined || value === null) return "";
|
||||
|
||||
return String(value)
|
||||
.replace(PERSIAN_DIGIT_REGEX, (digit) =>
|
||||
String(PERSIAN_DIGITS.indexOf(digit)),
|
||||
)
|
||||
.replace(ARABIC_DIGIT_REGEX, (digit) => String(digit.charCodeAt(0) - 1632));
|
||||
};
|
||||
|
||||
const normalizeLevel = (level) => {
|
||||
if (LEVELS[level]) return level;
|
||||
|
||||
return "full";
|
||||
};
|
||||
|
||||
const getSafePage = (page, totalPages) => {
|
||||
const numericPage = Number(page);
|
||||
const numericTotalPages = Number(totalPages);
|
||||
|
||||
if (!numericTotalPages || numericTotalPages <= 0) return 1;
|
||||
if (!numericPage || Number.isNaN(numericPage)) return 1;
|
||||
|
||||
return Math.min(Math.max(numericPage, 1), numericTotalPages);
|
||||
};
|
||||
|
||||
const ChevronRightIcon = (props) => (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M15 18L9 12L15 6"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const ChevronLeftIcon = (props) => (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M9 18L15 12L9 6"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export function Pagination({
|
||||
currentPage = 1,
|
||||
totalCount = 0,
|
||||
totalPages,
|
||||
pageSize = 10,
|
||||
onPageChange,
|
||||
level = "full",
|
||||
...containerProps
|
||||
}) {
|
||||
const resolvedLevel = normalizeLevel(level);
|
||||
const config = LEVELS[resolvedLevel];
|
||||
const isSimple = resolvedLevel === "simple";
|
||||
|
||||
const numericPageSize = Number(pageSize);
|
||||
const safePageSize =
|
||||
Number.isFinite(numericPageSize) && numericPageSize > 0
|
||||
? numericPageSize
|
||||
: 10;
|
||||
|
||||
const numericTotalCount = Number(totalCount);
|
||||
const safeTotalCount =
|
||||
Number.isFinite(numericTotalCount) && numericTotalCount > 0
|
||||
? numericTotalCount
|
||||
: 0;
|
||||
|
||||
const numericTotalPages = Number(totalPages);
|
||||
const safeTotalPages =
|
||||
Number.isFinite(numericTotalPages) && numericTotalPages > 0
|
||||
? Math.ceil(numericTotalPages)
|
||||
: Math.ceil(safeTotalCount / safePageSize);
|
||||
const safeCurrentPage = getSafePage(currentPage, safeTotalPages);
|
||||
|
||||
const [inputValue, setInputValue] = useState(
|
||||
isSimple ? "" : toFaDigits(safeCurrentPage),
|
||||
);
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [pendingPage, setPendingPage] = useState(null);
|
||||
const inputRef = useRef(null);
|
||||
|
||||
const visibleCurrentPage = pendingPage ?? safeCurrentPage;
|
||||
const hasTotalCount = safeTotalCount > 0;
|
||||
|
||||
const pageNumbers = useMemo(() => {
|
||||
if (isSimple || safeTotalPages <= 0) return [];
|
||||
|
||||
return Array.from(
|
||||
new Set(
|
||||
config.getPageNumbers({
|
||||
currentPage: safeCurrentPage,
|
||||
totalPages: safeTotalPages,
|
||||
}),
|
||||
),
|
||||
)
|
||||
.filter((page) => page >= 1 && page <= safeTotalPages)
|
||||
.sort((a, b) => a - b);
|
||||
}, [config, isSimple, safeCurrentPage, safeTotalPages]);
|
||||
|
||||
const resetInput = useCallback(() => {
|
||||
setInputValue(isSimple ? "" : toFaDigits(safeCurrentPage));
|
||||
setIsEditing(false);
|
||||
setPendingPage(null);
|
||||
}, [isSimple, safeCurrentPage]);
|
||||
|
||||
const goToPage = useCallback(
|
||||
(page) => {
|
||||
const safePage = getSafePage(page, safeTotalPages);
|
||||
|
||||
setIsEditing(false);
|
||||
setInputValue(isSimple ? "" : toFaDigits(safeCurrentPage));
|
||||
setPendingPage(null);
|
||||
|
||||
if (safePage !== safeCurrentPage) {
|
||||
onPageChange?.(safePage);
|
||||
}
|
||||
},
|
||||
[isSimple, onPageChange, safeCurrentPage, safeTotalPages],
|
||||
);
|
||||
|
||||
const commitInput = useCallback(() => {
|
||||
if (!inputValue) {
|
||||
resetInput();
|
||||
inputRef.current?.blur();
|
||||
return;
|
||||
}
|
||||
|
||||
const page = parseInt(toEnDigits(inputValue), 10);
|
||||
|
||||
if (Number.isNaN(page)) {
|
||||
resetInput();
|
||||
inputRef.current?.blur();
|
||||
return;
|
||||
}
|
||||
|
||||
const safePage = getSafePage(page, safeTotalPages);
|
||||
|
||||
if (isSimple) {
|
||||
setIsEditing(false);
|
||||
setInputValue("");
|
||||
|
||||
if (safePage !== safeCurrentPage) {
|
||||
setPendingPage(safePage);
|
||||
onPageChange?.(safePage);
|
||||
} else {
|
||||
setPendingPage(null);
|
||||
}
|
||||
|
||||
inputRef.current?.blur();
|
||||
return;
|
||||
}
|
||||
|
||||
if (safePage !== safeCurrentPage) {
|
||||
setPendingPage(safePage);
|
||||
setInputValue(toFaDigits(safePage));
|
||||
onPageChange?.(safePage);
|
||||
} else {
|
||||
setInputValue(toFaDigits(safeCurrentPage));
|
||||
setIsEditing(false);
|
||||
setPendingPage(null);
|
||||
}
|
||||
|
||||
inputRef.current?.blur();
|
||||
}, [
|
||||
inputValue,
|
||||
isSimple,
|
||||
onPageChange,
|
||||
resetInput,
|
||||
safeCurrentPage,
|
||||
safeTotalPages,
|
||||
]);
|
||||
|
||||
const startEditing = useCallback(() => {
|
||||
setPendingPage(null);
|
||||
setInputValue("");
|
||||
setIsEditing(true);
|
||||
}, []);
|
||||
|
||||
const handleInputChange = useCallback((event) => {
|
||||
const rawValue = event.target.value;
|
||||
const onlyDigits = toEnDigits(rawValue).replace(/\D/g, "");
|
||||
|
||||
setInputValue(toFaDigits(onlyDigits));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isSimple) {
|
||||
if (pendingPage !== null && safeCurrentPage === pendingPage) {
|
||||
setPendingPage(null);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingPage !== null) {
|
||||
if (safeCurrentPage === pendingPage) {
|
||||
setPendingPage(null);
|
||||
setIsEditing(false);
|
||||
setInputValue(toFaDigits(safeCurrentPage));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEditing) {
|
||||
setInputValue(toFaDigits(safeCurrentPage));
|
||||
}
|
||||
}, [isEditing, isSimple, pendingPage, safeCurrentPage]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isSimple && isEditing) {
|
||||
inputRef.current?.focus();
|
||||
}
|
||||
}, [isEditing, isSimple]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isEditing) return;
|
||||
if (!inputValue) return;
|
||||
if (!isSimple && pendingPage !== null) return;
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
commitInput();
|
||||
}, 1000);
|
||||
|
||||
return () => clearTimeout(timeout);
|
||||
}, [commitInput, inputValue, isEditing, isSimple, pendingPage]);
|
||||
|
||||
if (safeTotalPages <= 0) return null;
|
||||
|
||||
const renderInput = () => (
|
||||
<Input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
placeholder="صفحه"
|
||||
w={config.inputWidth}
|
||||
value={inputValue}
|
||||
onFocus={() => {
|
||||
if (!isSimple) {
|
||||
setIsEditing(true);
|
||||
setPendingPage(null);
|
||||
setInputValue("");
|
||||
}
|
||||
}}
|
||||
onChange={handleInputChange}
|
||||
onBlur={() => {
|
||||
if (inputValue) {
|
||||
if (isSimple) {
|
||||
commitInput();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
resetInput();
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter") {
|
||||
commitInput();
|
||||
}
|
||||
|
||||
if (event.key === "Escape") {
|
||||
resetInput();
|
||||
}
|
||||
}}
|
||||
textAlign="center"
|
||||
color="#1D2939"
|
||||
px={1}
|
||||
minW={0}
|
||||
dir="ltr"
|
||||
/>
|
||||
);
|
||||
|
||||
const renderPageButton = (number, isCurrent = false) => (
|
||||
<Button
|
||||
key={number}
|
||||
size="md"
|
||||
px={config.pageButtonPx}
|
||||
bg={isCurrent ? "#4B49AC" : "#e6e6f1"}
|
||||
color={isCurrent ? "#e6e6f1" : "#4B49AC"}
|
||||
_hover={{ bg: isCurrent ? "#4B49AC" : "#cbcbe8" }}
|
||||
onClick={isSimple && isCurrent ? startEditing : () => goToPage(number)}
|
||||
variant="soft"
|
||||
>
|
||||
{toFaDigits(number)}
|
||||
</Button>
|
||||
);
|
||||
|
||||
const showFirstButton =
|
||||
isSimple && safeTotalPages > 1 && visibleCurrentPage !== 1;
|
||||
const showLastButton =
|
||||
isSimple && safeTotalPages > 1 && visibleCurrentPage !== safeTotalPages;
|
||||
|
||||
return (
|
||||
<HStack
|
||||
justifyContent={config.justifyContent}
|
||||
backgroundColor="white"
|
||||
py="10px"
|
||||
px="16px"
|
||||
rounded="lg"
|
||||
border="1px"
|
||||
borderColor="blue.200"
|
||||
w="100%"
|
||||
{...containerProps}
|
||||
>
|
||||
{config.showPageSummary && (
|
||||
<HStack spacing={2} whiteSpace="nowrap">
|
||||
<Text fontWeight="bold">صفحه</Text>
|
||||
<Text>{toFaDigits(safeCurrentPage)}</Text>
|
||||
<Text fontWeight="bold">از</Text>
|
||||
<Text>{toFaDigits(safeTotalPages)}</Text>
|
||||
</HStack>
|
||||
)}
|
||||
|
||||
<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={<ChevronRightIcon />}
|
||||
aria-label="صفحه قبلی"
|
||||
/>
|
||||
|
||||
{isSimple ? (
|
||||
<>
|
||||
{showFirstButton && renderPageButton(1)}
|
||||
|
||||
{isEditing
|
||||
? renderInput()
|
||||
: renderPageButton(visibleCurrentPage, true)}
|
||||
|
||||
{showLastButton && renderPageButton(safeTotalPages)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{pageNumbers.map((number) =>
|
||||
renderPageButton(number, safeCurrentPage === number),
|
||||
)}
|
||||
|
||||
{config.showInput && renderInput()}
|
||||
</>
|
||||
)}
|
||||
|
||||
<IconButton
|
||||
size="md"
|
||||
bg="#e6e6f1"
|
||||
color="#4B49AC"
|
||||
_hover={{ bg: "#cbcbe8" }}
|
||||
onClick={() => goToPage(visibleCurrentPage + 1)}
|
||||
isDisabled={visibleCurrentPage === safeTotalPages}
|
||||
icon={<ChevronLeftIcon />}
|
||||
aria-label="صفحه بعدی"
|
||||
/>
|
||||
</HStack>
|
||||
|
||||
{config.showTotalCount && hasTotalCount && (
|
||||
<HStack spacing={2} whiteSpace="nowrap">
|
||||
<Text w="auto" fontWeight="bold">
|
||||
تعداد کل:
|
||||
</Text>
|
||||
<Text>{toFaDigits(safeTotalCount)}</Text>
|
||||
</HStack>
|
||||
)}
|
||||
</HStack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Pagination;
|
||||
@ -43,8 +43,21 @@ export default defineConfig(({ mode }) => {
|
||||
|
||||
target: "es2020",
|
||||
|
||||
minify: "esbuild",
|
||||
|
||||
sourcemap: false,
|
||||
|
||||
lib: {
|
||||
entry: path.resolve(process.cwd(), "src/remote/ui/GBadge.remote.jsx"),
|
||||
entry: {
|
||||
GBadge: path.resolve(
|
||||
process.cwd(),
|
||||
"src/remote/ui/GBadge.remote.jsx",
|
||||
),
|
||||
Pagination: path.resolve(
|
||||
process.cwd(),
|
||||
"src/remote/ui/Pagination.remote.jsx",
|
||||
),
|
||||
},
|
||||
|
||||
formats: ["es"],
|
||||
},
|
||||
@ -53,9 +66,11 @@ export default defineConfig(({ mode }) => {
|
||||
treeshake: true,
|
||||
|
||||
output: {
|
||||
entryFileNames: "remote/GBadge.js",
|
||||
entryFileNames: "remote/[name].js",
|
||||
|
||||
inlineDynamicImports: true,
|
||||
chunkFileNames: "remote/chunks/[name]-[hash].js",
|
||||
|
||||
assetFileNames: "remote/assets/[name]-[hash][extname]",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -94,6 +109,7 @@ export default defineConfig(({ mode }) => {
|
||||
external: (id) => {
|
||||
return (
|
||||
externalPackages.includes(id) ||
|
||||
id.startsWith("react-dom/") ||
|
||||
id.startsWith("react-icons/") ||
|
||||
id.startsWith("@emotion/") ||
|
||||
id.startsWith("react-select/")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user