important changes
All checks were successful
Build and Deploy Next.js + Nginx Docker Image / build-and-deploy (push) Successful in 50s
Build and Deploy Next.js + Nginx Docker Image / deploy (push) Successful in 7s

This commit is contained in:
Mohamadzadeh 2026-07-14 16:33:32 +03:30
parent e1f501fa48
commit c75420a91c
19 changed files with 692 additions and 720 deletions

1
dist/core.d.ts vendored
View File

@ -41,7 +41,6 @@ export type BiProviderProps = {
permissionEnabled?: boolean; permissionEnabled?: boolean;
theme?: any; theme?: any;
remoteUiEnabled?: boolean; remoteUiEnabled?: boolean;
remoteUiUrl?: string;
remoteUiChakraProviderProps?: Record<string, any>; remoteUiChakraProviderProps?: Record<string, any>;
}; };

523
dist/core.js vendored
View File

@ -1,78 +1,79 @@
import j from "axios"; import Q from "axios";
import { jsx as q, jsxs as M } from "react/jsx-runtime"; import { jsx as Z, jsxs as A } from "react/jsx-runtime";
import _ from "keycloak-js"; import j from "keycloak-js";
import $, { createContext as V, useState as z, useRef as N, useCallback as X, useEffect as g, useMemo as x, useContext as ee } from "react"; import _, { createContext as C, useState as X, useRef as L, useCallback as K, useEffect as z, useMemo as g, useContext as $ } from "react";
import { useQueryClient as te, useMutation as re, useQuery as f, QueryClient as ne, QueryClientProvider as oe } from "@tanstack/react-query"; import { useQueryClient as ee, useMutation as te, useQuery as f, QueryClient as re, QueryClientProvider as ne } from "@tanstack/react-query";
import { extendTheme as ie, withDefaultColorScheme as se, ChakraProvider as R, Spinner as ae, Badge as ue } from "@chakra-ui/react"; import { createRoot as oe } from "react-dom/client";
import { extendTheme as ie, withDefaultColorScheme as se, ChakraProvider as V, Spinner as ae, Badge as ue } from "@chakra-ui/react";
import { Global as de } from "@emotion/react"; import { Global as de } from "@emotion/react";
let W = null, o = null, O = null, v = !1; let W = null, o = null, Y = null, O = !1;
const ce = V(null), le = ({ url: e, realm: t, clientId: r }) => (o || (o = new _({ const ce = C(null), le = ({ url: e, realm: r, clientId: t }) => (o || (o = new j({
url: e, url: e,
realm: t, realm: r,
clientId: r clientId: t
})), o), he = (e) => (W = e, W), Fe = () => v, I = () => !!(o != null && o.authenticated), w = () => (o == null ? void 0 : o.token) ?? null, D = async (e = 30) => o ? o.updateToken(e) : !1, G = (e) => o == null ? void 0 : o.logout(e), Ge = (e) => o == null ? void 0 : o.login(e), J = ({ config: e, initOptions: t = {} } = {}) => { })), o), he = (e) => (W = e, W), Se = () => O, N = () => !!(o != null && o.authenticated), x = () => (o == null ? void 0 : o.token) ?? null, D = async (e = 30) => o ? o.updateToken(e) : !1, R = (e) => o == null ? void 0 : o.logout(e), Je = (e) => o == null ? void 0 : o.login(e), I = ({ config: e, initOptions: r = {} } = {}) => {
const r = e ?? W; const t = e ?? W;
if (!(r != null && r.url) || !(r != null && r.realm) || !(r != null && r.clientId)) if (!(t != null && t.url) || !(t != null && t.realm) || !(t != null && t.clientId))
throw new Error("Keycloak config is required."); throw new Error("Keycloak config is required.");
he(r); he(t);
const n = le(r); const n = le(t);
return O || (O = n.init({ return Y || (Y = n.init({
onLoad: "login-required", onLoad: "login-required",
checkLoginIframe: !1, checkLoginIframe: !1,
flow: "implicit", flow: "implicit",
...t ...r
}).then((u) => (v = !0, u)).catch((u) => { }).then((d) => (O = !0, d)).catch((d) => {
throw v = !0, u; throw O = !0, d;
})), O; })), Y;
}, Se = ({ }, Fe = ({
children: e, children: e,
config: t, config: r,
initOptions: r, initOptions: t,
loading: n = null loading: n = null
}) => { }) => {
const [u, h] = z(!1), [d, s] = z(!1), [a, S] = z(null), p = N(!1), i = X(() => { const [d, l] = X(!1), [u, s] = X(!1), [a, F] = X(null), p = L(!1), i = K(() => {
o && (s(!!o.authenticated), S(o.token ?? null)); o && (s(!!o.authenticated), F(o.token ?? null));
}, []); }, []);
g(() => (p.current = !0, J({ config: t, initOptions: r }).then((c) => { z(() => (p.current = !0, I({ config: r, initOptions: t }).then((h) => {
p.current && (s(!!c), S((o == null ? void 0 : o.token) ?? null), h(!0)); p.current && (s(!!h), F((o == null ? void 0 : o.token) ?? null), l(!0));
}).catch(() => { }).catch(() => {
p.current && (s(!1), S(null), h(!0)); p.current && (s(!1), F(null), l(!0));
}), () => { }), () => {
p.current = !1; p.current = !1;
}), [t, r]); }), [r, t]);
const l = X(() => o == null ? void 0 : o.login(), []), m = X((c) => o == null ? void 0 : o.logout(c), []), F = X( const c = K(() => o == null ? void 0 : o.login(), []), m = K((h) => o == null ? void 0 : o.logout(h), []), S = K(
async (c = 30) => { async (h = 30) => {
if (!o) return !1; if (!o) return !1;
const Z = await o.updateToken(c); const E = await o.updateToken(h);
return i(), Z; return i(), E;
}, },
[i] [i]
), E = x( ), q = g(
() => ({ () => ({
initialized: u, initialized: d,
authenticated: d, authenticated: u,
token: a, token: a,
login: l, login: c,
logout: m, logout: m,
updateToken: F updateToken: S
}), }),
[u, d, a, l, m, F] [d, u, a, c, m, S]
); );
return u ? /* @__PURE__ */ q(ce.Provider, { value: E, children: e }) : n; return d ? /* @__PURE__ */ Z(ce.Provider, { value: q, children: e }) : n;
}; };
let B = null; let B = null;
const pe = (e) => { const pe = (e) => {
const { api: t } = e, r = j.create({ const { api: r } = e, t = Q.create({
baseURL: t.baseUrl baseURL: r.baseUrl
}), n = async () => { }), n = async () => {
(!Fe() || !I()) && await J(); (!Se() || !N()) && await I();
}, u = !!e.keycloak, h = async (s) => { }, d = !!e.keycloak, l = async (s) => {
if (!u) return s; if (!d) return s;
await n(); await n();
let a = w(); let a = x();
if (a) { if (a) {
try { try {
await D(5), a = w(); await D(5), a = x();
} catch { } catch {
} }
s.headers = { s.headers = {
@ -81,271 +82,271 @@ const pe = (e) => {
}; };
} }
return s; return s;
}, d = async (s) => { }, u = async (s) => {
var S; var F;
const a = s.config; const a = s.config;
if (((S = s == null ? void 0 : s.response) == null ? void 0 : S.status) === 401 && !(a != null && a._retry)) { if (((F = s == null ? void 0 : s.response) == null ? void 0 : F.status) === 401 && !(a != null && a._retry)) {
a._retry = !0; a._retry = !0;
try { try {
await D(30); await D(30);
const p = w(); const p = x();
return a.headers = { return a.headers = {
...a.headers, ...a.headers,
Authorization: `Bearer ${p}` Authorization: `Bearer ${p}`
}, r(a); }, t(a);
} catch { } catch {
G({ redirectUri: window.location.origin }); R({ redirectUri: window.location.origin });
} }
} }
return Promise.reject(s); return Promise.reject(s);
}; };
return r.interceptors.request.use(h), r.interceptors.response.use( return t.interceptors.request.use(l), t.interceptors.response.use(
(s) => s, (s) => s,
d u
), { ), {
api: r api: t
}; };
}, me = (e) => (B = pe(e), B), Ee = () => { }, me = (e) => (B = pe(e), B), qe = () => {
if (!B) if (!B)
throw new Error("api is not configured. Call configureApi(config) first."); throw new Error("api is not configured. Call configureApi(config) first.");
return B.api; return B.api;
}, H = new Proxy( }, G = new Proxy(
{}, {},
{ {
get(e, t) { get(e, r) {
return Ee()[t]; return qe()[r];
} }
} }
), qe = async (e) => (await H.get(e)).data; ), Ee = async (e) => (await G.get(e)).data;
function P(e) { function v(e) {
return Array.isArray(e) ? e : [e]; return Array.isArray(e) ? e : [e];
} }
function Ze(e) { function Ze(e) {
return [...P(e), "list"]; return [...v(e), "list"];
} }
function C(e, t) { function M(e, r) {
return [...P(e), t]; return [...v(e), r];
} }
function be(e, t) { function be(e, r) {
if (!t) return e; if (!r) return e;
const r = new URLSearchParams(); const t = new URLSearchParams();
Object.entries(t).forEach(([u, h]) => { Object.entries(r).forEach(([d, l]) => {
h != null && h !== "" && r.append(u, h); l != null && l !== "" && t.append(d, l);
}); });
const n = r.toString(); const n = t.toString();
return n ? `${e}?${n}` : e; return n ? `${e}?${n}` : e;
} }
function ye(e, t) { function ye(e, r) {
return typeof e == "function" ? e(t == null ? void 0 : t.id, t) : e; return typeof e == "function" ? e(r == null ? void 0 : r.id, r) : e;
} }
function Te(e = {}) { function Te(e = {}) {
const { id: t, ...r } = e; const { id: r, ...t } = e;
return r; return t;
} }
function Ke(e, t) { function Ke(e, r) {
return `${e.replace(/\/$/, "")}/${t}`; return `${e.replace(/\/$/, "")}/${r}`;
} }
function Xe(e) { function Xe(e) {
return `use${e.charAt(0).toUpperCase()}${e.slice(1)}`; return `use${e.charAt(0).toUpperCase()}${e.slice(1)}`;
} }
function Je({ function He({
key: e, key: e,
url: t, url: r,
actions: r = {}, actions: t = {},
axiosInstance: n = H, axiosInstance: n = G,
fetcher: u = qe fetcher: d = Ee
}) { }) {
const h = P(e), d = Ze(e); const l = v(e), u = Ze(e);
function s(i, l = {}) { function s(i, c = {}) {
return f({ return f({
queryKey: i ? [...d, i] : d, queryKey: i ? [...u, i] : u,
queryFn: () => u(be(t, i)), queryFn: () => d(be(r, i)),
...l ...c
}); });
} }
function a(i, l = {}) { function a(i, c = {}) {
return f({ return f({
queryKey: C(e, i), queryKey: M(e, i),
queryFn: () => u(Ke(t, i)), queryFn: () => d(Ke(r, i)),
enabled: !!i, enabled: !!i,
...l ...c
}); });
} }
function S(i, l = {}) { function F(i, c = {}) {
const m = te(), F = r[i]; const m = ee(), S = t[i];
if (!F) if (!S)
throw new Error(`Action "${i}" is not defined.`); throw new Error(`Action "${i}" is not defined.`);
return re({ return te({
mutationKey: [...h, i], mutationKey: [...l, i],
mutationFn: async (E = {}) => { mutationFn: async (q = {}) => {
const c = F.method || "post", Z = ye(F.url || t, E), b = F.body ? F.body(E) : F.sendRawPayload ? E : Te(E); const h = S.method || "post", E = ye(S.url || r, q), b = S.body ? S.body(q) : S.sendRawPayload ? q : Te(q);
return (c === "delete" ? await n.delete( return (h === "delete" ? await n.delete(
Z, E,
b && Object.keys(b).length > 0 ? { data: b } : void 0 b && Object.keys(b).length > 0 ? { data: b } : void 0
) : await n[c](Z, b)).data; ) : await n[h](E, b)).data;
}, },
onSuccess: (...E) => { onSuccess: (...q) => {
var T; var T;
const [c, Z] = E; const [h, E] = q;
m.invalidateQueries({ m.invalidateQueries({
queryKey: d queryKey: u
}); });
const b = (Z == null ? void 0 : Z.id) ?? (c == null ? void 0 : c.id); const b = (E == null ? void 0 : E.id) ?? (h == null ? void 0 : h.id);
b && m.invalidateQueries({ b && m.invalidateQueries({
queryKey: C(e, b) queryKey: M(e, b)
}); });
const y = typeof F.invalidateKeys == "function" ? F.invalidateKeys(c, Z) : F.invalidateKeys; const y = typeof S.invalidateKeys == "function" ? S.invalidateKeys(h, E) : S.invalidateKeys;
y == null || y.forEach((K) => { y == null || y.forEach((k) => {
m.invalidateQueries({ queryKey: K }); m.invalidateQueries({ queryKey: k });
}), (T = l.onSuccess) == null || T.call(l, ...E); }), (T = c.onSuccess) == null || T.call(c, ...q);
}, },
...l ...c
}); });
} }
const p = Object.keys(r).reduce((i, l) => (i[Xe(l)] = (m = {}) => S(l, m), i), {}); const p = Object.keys(t).reduce((i, c) => (i[Xe(c)] = (m = {}) => F(c, m), i), {});
return { return {
key: h, key: l,
listKey: d, listKey: u,
useGet: s, useGet: s,
useItem: a, useItem: a,
useAction: S, useAction: F,
...p ...p
}; };
} }
const k = V(null), Y = "permissions", ze = (e) => (e == null ? void 0 : e.storageKey) || Y, ge = ({ const J = C(null), w = "permissions", ze = (e) => (e == null ? void 0 : e.storageKey) || w, xe = ({
user: e = null, user: e = null,
children: t, children: r,
config: r, config: t,
loading: n = /* @__PURE__ */ q("div", { children: "Loading permissions..." }), loading: n = /* @__PURE__ */ Z("div", { children: "Loading permissions..." }),
errorFallback: u = /* @__PURE__ */ q("div", { children: "Error loading permissions" }) errorFallback: d = /* @__PURE__ */ Z("div", { children: "Error loading permissions" })
}) => { }) => {
const h = ze(r), [d, s] = z( const l = ze(t), [u, s] = X(
() => we(h) () => ge(l)
), { data: a, isLoading: S, error: p } = fe(r), i = a ?? d; ), { data: a, isLoading: F, error: p } = We(t), i = a ?? u;
g(() => { z(() => {
a && (xe(h, a), s(a)); a && (Be(l, a), s(a));
}, [a, h]); }, [a, l]);
const l = x( const c = g(
() => Be(i), () => we(i),
[i] [i]
), m = X( ), m = K(
(c = "") => Ye(l, c), (h = "") => Ye(c, h),
[l] [c]
), F = X((c = "") => !m(c), [m]), E = x( ), S = K((h = "") => !m(h), [m]), q = g(
() => ({ () => ({
user: e, user: e,
can: m, can: m,
cannot: F, cannot: S,
permissions: i, permissions: i,
isLoading: S, isLoading: F,
error: p error: p
}), }),
[e, m, F, i, S, p] [e, m, S, i, F, p]
); );
return p && !i ? u : S && !i ? n : /* @__PURE__ */ q(k.Provider, { value: E, children: t }); return p && !i ? d : F && !i ? n : /* @__PURE__ */ Z(J.Provider, { value: q, children: r });
}, we = (e = Y) => { }, ge = (e = w) => {
if (!(typeof window > "u")) if (!(typeof window > "u"))
try { try {
const t = localStorage.getItem(e); const r = localStorage.getItem(e);
return t ? JSON.parse(t) : void 0; return r ? JSON.parse(r) : void 0;
} catch { } catch {
return; return;
} }
}, xe = (e = Y, t) => { }, Be = (e = w, r) => {
if (!(typeof window > "u")) if (!(typeof window > "u"))
try { try {
localStorage.setItem(e, JSON.stringify(t)); localStorage.setItem(e, JSON.stringify(r));
} catch { } catch {
} }
}, He = (e = Y) => { }, ke = (e = w) => {
if (!(typeof window > "u")) if (!(typeof window > "u"))
try { try {
localStorage.removeItem(e); localStorage.removeItem(e);
} catch { } catch {
} }
}, Be = (e) => e ? new Set(e.map((t) => t.name)) : /* @__PURE__ */ new Set(), Ye = (e, t = "") => { }, we = (e) => e ? new Set(e.map((r) => r.name)) : /* @__PURE__ */ new Set(), Ye = (e, r = "") => {
if (!t) return !1; if (!r) return !1;
if (e.has(t) || [...e].some((n) => n.startsWith(t))) return !0; if (e.has(r) || [...e].some((n) => n.startsWith(r))) return !0;
let r = t; let t = r;
for (; r.includes(":"); ) for (; t.includes(":"); )
if (r = r.slice(0, r.lastIndexOf(":")), e.has(`${r}:*`)) return !0; if (t = t.slice(0, t.lastIndexOf(":")), e.has(`${t}:*`)) return !0;
return !1; return !1;
}, Q = { }, H = {
all: ["permissions"], all: ["permissions"],
list: (e) => [...Q.all, e] list: (e) => [...H.all, e]
}, Oe = async (e) => { }, fe = async (e) => {
if (!(e != null && e.url) || !(e != null && e.clientId)) if (!(e != null && e.url) || !(e != null && e.clientId))
throw new Error("Permission config requires url and clientId."); throw new Error("Permission config requires url and clientId.");
const t = w(), r = new URL(e.url); const r = x(), t = new URL(e.url);
r.searchParams.set("client_id", e.clientId); t.searchParams.set("client_id", e.clientId);
const n = await fetch(r.toString(), { const n = await fetch(t.toString(), {
method: "GET", method: "GET",
headers: { headers: {
...t ? { Authorization: `Bearer ${t}` } : {} ...r ? { Authorization: `Bearer ${r}` } : {}
} }
}); });
if (!n.ok) if (!n.ok)
throw new Error("Failed to load permissions"); throw new Error("Failed to load permissions");
return n.json(); return n.json();
}, A = () => { }, P = () => {
const e = ee(k); const e = $(J);
if (!e) if (!e)
throw new Error("usePermission must be used within PermissionProvider"); throw new Error("usePermission must be used within PermissionProvider");
return e; return e;
}, fe = (e) => f({ }, We = (e) => f({
queryKey: Q.list(e == null ? void 0 : e.clientId), queryKey: H.list(e == null ? void 0 : e.clientId),
queryFn: () => Oe(e), queryFn: () => fe(e),
enabled: !!(e != null && e.url) && !!(e != null && e.clientId) && I(), enabled: !!(e != null && e.url) && !!(e != null && e.clientId) && N(),
staleTime: 1 / 0, staleTime: 1 / 0,
refetchOnWindowFocus: !1, refetchOnWindowFocus: !1,
refetchOnReconnect: !1 refetchOnReconnect: !1
}), ke = ({ }), Qe = ({
perm: e, perm: e,
children: t, children: r,
fallback: r = /* @__PURE__ */ q("div", { children: "You are not allowed to do this" }) fallback: t = /* @__PURE__ */ Z("div", { children: "You are not allowed to do this" })
}) => { }) => {
const { can: n } = A(); const { can: n } = P();
return n(e) ? t : r; return n(e) ? r : t;
}, Qe = ({ children: e }) => { }, je = ({ children: e }) => {
const { can: t, permissions: r } = A(); const { can: r, permissions: t } = P();
return r && t("admin") ? e : null; return t && r("admin") ? e : null;
}, je = ({ children: e, forceNoAccess: t = !1 }) => { }, _e = ({ children: e, forceNoAccess: r = !1 }) => {
const { can: r, isLoading: n } = A(); const { can: t, isLoading: n } = P();
return g(() => { return z(() => {
n || (t || !r("panel_access")) && G(); n || (r || !t("panel_access")) && R();
}, [n, r, t]), e; }, [n, t, r]), e;
}; };
function We() { function Oe() {
const [e, t] = z(!1), r = N(null); const [e, r] = X(!1), t = L(null);
return g(() => { return z(() => {
if (process.env.NODE_ENV !== "production") return; if (process.env.NODE_ENV !== "production") return;
let n; let n;
const u = async () => { const d = async () => {
const d = await fetch(`/version.json?t=${Date.now()}`, { const u = await fetch(`/version.json?t=${Date.now()}`, {
cache: "no-store" cache: "no-store"
}); });
if (!d.ok) if (!u.ok)
throw new Error(`Failed to fetch version: ${d.status}`); throw new Error(`Failed to fetch version: ${u.status}`);
const s = await d.json(); const s = await u.json();
return String(s.version); return String(s.version);
}; };
return (async () => { return (async () => {
try { try {
r.current = await u(), n = setInterval(async () => { t.current = await d(), n = setInterval(async () => {
try { try {
const d = await u(); const u = await d();
r.current && d !== r.current && (t(!0), clearInterval(n)); t.current && u !== t.current && (r(!0), clearInterval(n));
} catch (d) { } catch (u) {
console.error("Update check failed:", d); console.error("Update check failed:", u);
} }
}, 3e4); }, 3e4);
} catch (d) { } catch (u) {
console.error("Initial version fetch failed:", d); console.error("Initial version fetch failed:", u);
} }
})(), () => { })(), () => {
n && clearInterval(n); n && clearInterval(n);
}; };
}, []), e ? /* @__PURE__ */ q( }, []), e ? /* @__PURE__ */ Z(
"div", "div",
{ {
style: { style: {
@ -364,7 +365,7 @@ function We() {
} }
) : null; ) : null;
} }
const ve = new ne({ const ve = new re({
defaultOptions: { defaultOptions: {
queries: { queries: {
retry: 1, retry: 1,
@ -395,7 +396,7 @@ const ve = new ne({
} }
}, },
se({ colorScheme: "facebook" }) se({ colorScheme: "facebook" })
), Me = () => /* @__PURE__ */ q( ), De = () => /* @__PURE__ */ Z(
de, de,
{ {
styles: ` styles: `
@ -408,115 +409,111 @@ const ve = new ne({
} }
` `
} }
), U = "__UIKIT_REMOTE_DEPS__", L = "__UIKIT_REMOTE_CONFIG__"; ), U = "__UIKIT_REMOTE_DEPS__";
function De({ theme: e, remoteUiUrl: t, chakraProviderProps: r } = {}) { function Me({ theme: e, chakraProviderProps: r } = {}) {
if (typeof window > "u") return; if (typeof window > "u") return;
const n = window[U] || {}, u = window[L] || {}; const t = window[U] || {};
window[U] = { window[U] = {
...n, ...t,
React: n.React || $, React: t.React || _,
ChakraProvider: n.ChakraProvider || R, createRoot: t.createRoot || oe,
Badge: n.Badge || ue, ChakraProvider: t.ChakraProvider || V,
theme: e ?? n.theme, Badge: t.Badge || ue,
theme: e ?? t.theme,
chakraProviderProps: { chakraProviderProps: {
...n.chakraProviderProps || {}, ...t.chakraProviderProps || {},
...r || {} ...r || {}
} }
}, window[L] = {
...u,
...t ? { GBadgeUrl: t } : {}
}; };
} }
function _e({ function $e({
children: e, children: e,
apiBaseUrl: t, apiBaseUrl: r,
keycloakClientId: r, keycloakClientId: t,
permissionClientId: n, permissionClientId: n,
loading: u = /* @__PURE__ */ q(ae, {}), loading: d = /* @__PURE__ */ Z(ae, {}),
updateChecker: h = !1, updateChecker: l = !1,
updateCheckerProps: d, updateCheckerProps: u,
keycloakUrl: s = "https://auth.ibagher.ir", keycloakUrl: s = "https://auth.ibagher.ir",
keycloakRealm: a = "bi", keycloakRealm: a = "bi",
permissionUrl: S = "https://api.d.aiengines.ir/user_api/v1/permissions/list", permissionUrl: F = "https://api.d.aiengines.ir/user_api/v1/permissions/list",
keycloakEnabled: p, keycloakEnabled: p,
permissionEnabled: i, permissionEnabled: i,
theme: l = Ae, theme: c = Ae,
remoteUiEnabled: m = !0, remoteUiEnabled: m = !0,
remoteUiUrl: F, remoteUiChakraProviderProps: S
remoteUiChakraProviderProps: E
}) { }) {
const [c, Z] = z(!1), b = p ?? !!r, y = i ?? !!n, T = x( const [q, h] = X(!1), E = p ?? !!t, b = i ?? !!n, y = g(
() => ({ () => ({
api: { api: {
baseUrl: t || "" baseUrl: r || ""
}, },
keycloak: b ? { keycloak: E ? {
url: s, url: s,
realm: a, realm: a,
clientId: r clientId: t
} : null, } : null,
permission: y ? { permission: b ? {
url: S, url: F,
clientId: n clientId: n
} : null } : null
}), }),
[ [
t, r,
E,
b, b,
y,
s, s,
a, a,
r, t,
S, F,
n n
] ]
); );
if (g(() => { if (z(() => {
Z(!0); h(!0);
}, []), g(() => { }, []), z(() => {
c && me(T); q && me(y);
}, [c, T]), !c) }, [q, y]), !q)
return null; return null;
m && De({ m && Me({
theme: l, theme: c,
remoteUiUrl: F, chakraProviderProps: S
chakraProviderProps: E
}); });
let K = e; let T = e;
return y && (K = /* @__PURE__ */ q(ge, { config: T.permission, loading: u, children: K })), b && (K = /* @__PURE__ */ q(Se, { config: T.keycloak, loading: u, children: K })), /* @__PURE__ */ M(R, { theme: l, children: [ return b && (T = /* @__PURE__ */ Z(xe, { config: y.permission, loading: d, children: T })), E && (T = /* @__PURE__ */ Z(Fe, { config: y.keycloak, loading: d, children: T })), /* @__PURE__ */ A(V, { theme: c, children: [
/* @__PURE__ */ q(Me, {}), /* @__PURE__ */ Z(De, {}),
/* @__PURE__ */ M(oe, { client: ve, children: [ /* @__PURE__ */ A(ne, { client: ve, children: [
h && /* @__PURE__ */ q(We, { ...d }), l && /* @__PURE__ */ Z(Oe, { ...u }),
K T
] }) ] })
] }); ] });
} }
export { export {
Qe as AdminGuard, je as AdminGuard,
_e as BiProvider, $e as BiProvider,
ke as Can, Qe as Can,
Se as KeycloakProvider, Fe as KeycloakProvider,
je as PanelAccessGuard, _e as PanelAccessGuard,
ge as PermissionProvider, xe as PermissionProvider,
H as api, G as api,
Ye as checkPermission, Ye as checkPermission,
He as clearCachedPermissions, ke as clearCachedPermissions,
me as configureApi, me as configureApi,
Je as createApi, He as createApi,
Be as createPermissionSet, we as createPermissionSet,
qe as fetcher, Ee as fetcher,
Ee as getApi, qe as getApi,
we as getCachedPermissions, ge as getCachedPermissions,
w as getKeycloakToken, x as getKeycloakToken,
Oe as getPermissions, fe as getPermissions,
J as initKeycloak, I as initKeycloak,
I as isKeycloakAuthenticated, N as isKeycloakAuthenticated,
Fe as isKeycloakInitialized, Se as isKeycloakInitialized,
Ge as loginKeycloak, Je as loginKeycloak,
G as logoutKeycloak, R as logoutKeycloak,
Q as permissionKeys, H as permissionKeys,
xe as setCachedPermissions, Be as setCachedPermissions,
D as updateKeycloakToken, D as updateKeycloakToken,
A as usePermission, P as usePermission,
fe as usePermissionsQuery We as usePermissionsQuery
}; };

68
dist/remote-ui.d.ts vendored
View File

@ -1,54 +1,24 @@
import type { BadgeProps, StackProps } from "@chakra-ui/react"; export {
import type { ReactNode } from "react"; setupUikitRemoteDeps,
} from "./_core/setupRemoteDeps";
export type UikitRemoteLevel = "full" | "compact" | "simple"; export type {
UikitRemoteSetupOptions,
} from "./_core/setupRemoteDeps";
export interface UikitRemoteSetupOptions { export {
React?: any; GBadge,
createRoot?: any; } from "./GBadge";
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. */ export type {
remoteUrl?: string; GBadgeProps,
GBadgeUrl?: string; } from "./GBadge";
PaginationUrl?: string;
remoteUrls?: {
GBadge?: string;
Pagination?: string;
};
}
export declare function setupUikitRemoteDeps( export {
options?: UikitRemoteSetupOptions, Pagination,
): void; } from "./Pagination";
export interface GBadgeProps extends BadgeProps { export type {
children?: ReactNode; PaginationLevel,
remoteUrl?: string; PaginationProps,
theme?: any; } from "./Pagination";
chakraProviderProps?: Record<string, any>;
}
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;

236
dist/remote-ui.js vendored
View File

@ -1,13 +1,120 @@
import { jsx as E } from "react/jsx-runtime"; import B, { useRef as d, useEffect as g } from "react";
import p, { useRef as s, useEffect as R } from "react";
import { createRoot as k } from "react-dom/client"; 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"; import { Text as v, Input as w, IconButton as E, HStack as y, Button as I, Badge as C, ChakraProvider as T } from "@chakra-ui/react";
import { jsx as _ } from "react/jsx-runtime";
const h = { const h = {
GBadge: "https://uikit.d.aiengines.ir/GBadge.js", GBadge: "https://uikit.d.aiengines.ir/GBadge.js",
Pagination: "https://uikit.d.aiengines.ir/Pagination.js" Pagination: "https://uikit.d.aiengines.ir/Pagination.js"
}, l = "__UIKIT_REMOTE_DEPS__", g = "__UIKIT_REMOTE_CONFIG__", u = /* @__PURE__ */ new Map(), y = { }, s = "__UIKIT_REMOTE_DEPS__";
GBadge: ["React", "createRoot", "ChakraProvider", "Badge"], function D(e = {}) {
Pagination: [ if (typeof window > "u") return;
const t = window[s] || {};
window[s] = {
...t,
React: e.React || t.React || B,
createRoot: e.createRoot || t.createRoot || k,
ChakraProvider: e.ChakraProvider || t.ChakraProvider || T,
Badge: e.Badge || t.Badge || C,
Button: e.Button || t.Button || I,
HStack: e.HStack || t.HStack || y,
IconButton: e.IconButton || t.IconButton || E,
Input: e.Input || t.Input || w,
Text: e.Text || t.Text || v,
...e.deps || {},
theme: Object.prototype.hasOwnProperty.call(e, "theme") ? e.theme : t.theme,
chakraProviderProps: {
...t.chakraProviderProps || {},
...e.chakraProviderProps || {}
}
};
}
const a = /* @__PURE__ */ new Map();
function x(e = []) {
if (typeof window > "u") return !1;
const t = window[s];
return e.every((r) => t == null ? void 0 : t[r]);
}
function S(e = []) {
typeof window > "u" || x(e) || D();
}
function G(e, t) {
const r = `${e}:${t}`;
return a.has(r) || a.set(
r,
import(
/* webpackIgnore: true */
/* @vite-ignore */
t
).catch((u) => {
throw a.delete(r), u;
})
), a.get(r);
}
function P({
componentName: e,
tagName: t,
defaultRemoteUrl: r,
requiredDeps: u,
normalizeProps: f
}) {
return function({
theme: m,
chakraProviderProps: l,
...p
}) {
const i = d(null), n = d(null), c = d(null);
return c.current = {
...f ? f(p) : p,
...m !== void 0 ? { theme: m } : {},
...l ? { chakraProviderProps: l } : {}
}, g(() => {
let R = !0;
return S(u), G(e, r).then(() => {
if (!R || !i.current) return;
const o = document.createElement(t);
o.componentProps = c.current, i.current.appendChild(o), n.current = o;
}).catch((o) => {
console.error(
`[uikit/remote/ui] Failed to load ${e}:`,
o
);
}), () => {
R = !1, n.current && (n.current.remove(), n.current = null);
};
}, [e, r, t]), g(() => {
n.current && (n.current.componentProps = c.current);
}), /* @__PURE__ */ _(
"span",
{
ref: i,
style: {
display: "contents"
}
}
);
};
}
function b(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 q = P({
componentName: "GBadge",
tagName: "uikit-g-badge",
defaultRemoteUrl: h.GBadge,
requiredDeps: ["React", "createRoot", "ChakraProvider", "Badge"],
normalizeProps: ({ children: e, ...t }) => ({
...t,
children: b(e)
})
}), K = P({
componentName: "Pagination",
tagName: "uikit-pagination",
defaultRemoteUrl: h.Pagination,
requiredDeps: [
"React", "React",
"createRoot", "createRoot",
"ChakraProvider", "ChakraProvider",
@ -17,122 +124,9 @@ const h = {
"Input", "Input",
"Text" "Text"
] ]
};
function D(e = {}) {
if (typeof window > "u") return;
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: {
...t.chakraProviderProps || {},
...e.chakraProviderProps || {}
}
};
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 O(e) {
if (typeof window > "u") return;
const t = window[l];
(y[e] || []).some((o) => !(t != null && t[o])) && D();
}
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 M(e, t) {
const r = S(e, t), n = `${e}:${r}`;
return u.has(n) || u.set(
n,
import(
/* webpackIgnore: true */
/* @vite-ignore */
r
).catch((o) => {
throw u.delete(n), o;
})
), u.get(n);
}
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."
);
}
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 { export {
F as GBadge, q as GBadge,
$ as Pagination, K as Pagination,
D as setupUikitRemoteDeps D as setupUikitRemoteDeps
}; };

View File

@ -1,4 +1,5 @@
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";
import { Badge, ChakraProvider, Spinner } from "@chakra-ui/react"; import { Badge, ChakraProvider, Spinner } from "@chakra-ui/react";
import { QueryClientProvider } from "@tanstack/react-query"; import { QueryClientProvider } from "@tanstack/react-query";
import { KeycloakProvider } from "./keycloak.jsx"; import { KeycloakProvider } from "./keycloak.jsx";
@ -9,17 +10,14 @@ import { queryClient } from "./query.js";
import { Fonts, theme as defaultTheme } from "./style.jsx"; import { Fonts, theme as defaultTheme } from "./style.jsx";
const REMOTE_DEPS_KEY = "__UIKIT_REMOTE_DEPS__"; const REMOTE_DEPS_KEY = "__UIKIT_REMOTE_DEPS__";
const REMOTE_CONFIG_KEY = "__UIKIT_REMOTE_CONFIG__"; function setupBiRemoteUiDeps({ theme, chakraProviderProps } = {}) {
function setupBiRemoteUiDeps({ theme, remoteUiUrl, chakraProviderProps } = {}) {
if (typeof window === "undefined") return; if (typeof window === "undefined") return;
const previousDeps = window[REMOTE_DEPS_KEY] || {}; const previousDeps = window[REMOTE_DEPS_KEY] || {};
const previousConfig = window[REMOTE_CONFIG_KEY] || {};
window[REMOTE_DEPS_KEY] = { window[REMOTE_DEPS_KEY] = {
...previousDeps, ...previousDeps,
React: previousDeps.React || React, React: previousDeps.React || React,
createRoot: previousDeps.createRoot || createRoot,
ChakraProvider: previousDeps.ChakraProvider || ChakraProvider, ChakraProvider: previousDeps.ChakraProvider || ChakraProvider,
Badge: previousDeps.Badge || Badge, Badge: previousDeps.Badge || Badge,
theme: theme ?? previousDeps.theme, theme: theme ?? previousDeps.theme,
@ -28,11 +26,6 @@ function setupBiRemoteUiDeps({ theme, remoteUiUrl, chakraProviderProps } = {}) {
...(chakraProviderProps || {}), ...(chakraProviderProps || {}),
}, },
}; };
window[REMOTE_CONFIG_KEY] = {
...previousConfig,
...(remoteUiUrl ? { GBadgeUrl: remoteUiUrl } : {}),
};
} }
export function BiProvider({ export function BiProvider({
@ -57,7 +50,6 @@ export function BiProvider({
theme = defaultTheme, theme = defaultTheme,
remoteUiEnabled = true, remoteUiEnabled = true,
remoteUiUrl,
remoteUiChakraProviderProps, remoteUiChakraProviderProps,
}) { }) {
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
@ -115,7 +107,6 @@ export function BiProvider({
if (remoteUiEnabled) { if (remoteUiEnabled) {
setupBiRemoteUiDeps({ setupBiRemoteUiDeps({
theme, theme,
remoteUiUrl,
chakraProviderProps: remoteUiChakraProviderProps, chakraProviderProps: remoteUiChakraProviderProps,
}); });
} }

1
src/core/index.d.ts vendored
View File

@ -41,7 +41,6 @@ export type BiProviderProps = {
permissionEnabled?: boolean; permissionEnabled?: boolean;
theme?: any; theme?: any;
remoteUiEnabled?: boolean; remoteUiEnabled?: boolean;
remoteUiUrl?: string;
remoteUiChakraProviderProps?: Record<string, any>; remoteUiChakraProviderProps?: Record<string, any>;
}; };

10
src/remote/ui/GBadge/index.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
import type { BadgeProps } from "@chakra-ui/react";
import type { ReactNode } from "react";
export interface GBadgeProps extends BadgeProps {
children?: ReactNode;
theme?: any;
chakraProviderProps?: Record<string, any>;
}
export declare const GBadge: (props: GBadgeProps) => JSX.Element;

View File

@ -0,0 +1,31 @@
"use client";
import { DEFAULT_REMOTE_URLS } from "../_core/constants";
import { createRemoteElementComponent } from "../_core/createRemoteElementComponent";
function normalizeChildren(children) {
if (typeof children === "string" || typeof children === "number") {
return children;
}
if (children === null || children === undefined) {
return undefined;
}
console.warn(
"[uikit/remote/ui] GBadge only accepts text/number children across the remote boundary.",
);
return undefined;
}
export const GBadge = createRemoteElementComponent({
componentName: "GBadge",
tagName: "uikit-g-badge",
defaultRemoteUrl: DEFAULT_REMOTE_URLS.GBadge,
requiredDeps: ["React", "createRoot", "ChakraProvider", "Badge"],
normalizeProps: ({ children, ...props }) => ({
...props,
children: normalizeChildren(children),
}),
});

16
src/remote/ui/Pagination/index.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
import type { StackProps } from "@chakra-ui/react";
export type PaginationLevel = "full" | "compact" | "simple";
export interface PaginationProps extends Omit<StackProps, "onChange"> {
currentPage?: number;
totalCount?: number;
totalPages?: number;
pageSize?: number;
onPageChange?: (page: number) => void;
level?: PaginationLevel;
theme?: any;
chakraProviderProps?: Record<string, any>;
}
export declare const Pagination: (props: PaginationProps) => JSX.Element;

View File

@ -0,0 +1,20 @@
"use client";
import { DEFAULT_REMOTE_URLS } from "../_core/constants";
import { createRemoteElementComponent } from "../_core/createRemoteElementComponent";
export const Pagination = createRemoteElementComponent({
componentName: "Pagination",
tagName: "uikit-pagination",
defaultRemoteUrl: DEFAULT_REMOTE_URLS.Pagination,
requiredDeps: [
"React",
"createRoot",
"ChakraProvider",
"Button",
"HStack",
"IconButton",
"Input",
"Text",
],
});

View File

@ -0,0 +1,6 @@
export const DEFAULT_REMOTE_URLS = {
GBadge: "https://uikit.d.aiengines.ir/GBadge.js",
Pagination: "https://uikit.d.aiengines.ir/Pagination.js",
};
export const REMOTE_DEPS_KEY = "__UIKIT_REMOTE_DEPS__";

View File

@ -0,0 +1,117 @@
"use client";
import React, { useEffect, useRef } from "react";
import { REMOTE_DEPS_KEY } from "./constants";
import { setupUikitRemoteDeps } from "./setupRemoteDeps";
const remotePromises = new Map();
function hasRequiredDeps(requiredDeps = []) {
if (typeof window === "undefined") return false;
const deps = window[REMOTE_DEPS_KEY];
return requiredDeps.every((key) => deps?.[key]);
}
function ensureRemoteDeps(requiredDeps = []) {
if (typeof window === "undefined") return;
if (!hasRequiredDeps(requiredDeps)) {
setupUikitRemoteDeps();
}
}
function loadRemote(componentName, remoteFileUrl) {
const cacheKey = `${componentName}:${remoteFileUrl}`;
if (!remotePromises.has(cacheKey)) {
remotePromises.set(
cacheKey,
import(
/* webpackIgnore: true */
/* @vite-ignore */
remoteFileUrl
).catch((error) => {
remotePromises.delete(cacheKey);
throw error;
}),
);
}
return remotePromises.get(cacheKey);
}
export function createRemoteElementComponent({
componentName,
tagName,
defaultRemoteUrl,
requiredDeps,
normalizeProps,
}) {
return function RemoteElementComponent({
theme,
chakraProviderProps,
...props
}) {
const containerRef = useRef(null);
const elementRef = useRef(null);
const latestPropsRef = useRef(null);
latestPropsRef.current = {
...(normalizeProps ? normalizeProps(props) : props),
...(theme !== undefined ? { theme } : {}),
...(chakraProviderProps ? { chakraProviderProps } : {}),
};
useEffect(() => {
let active = true;
ensureRemoteDeps(requiredDeps);
loadRemote(componentName, defaultRemoteUrl)
.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, defaultRemoteUrl, tagName]);
useEffect(() => {
if (!elementRef.current) return;
elementRef.current.componentProps = latestPropsRef.current;
});
return (
<span
ref={containerRef}
style={{
display: "contents",
}}
/>
);
};
}

View File

@ -0,0 +1,22 @@
export interface UikitRemoteSetupOptions {
React?: any;
createRoot?: any;
ChakraProvider?: any;
Badge?: any;
Button?: any;
HStack?: any;
IconButton?: any;
Input?: any;
Text?: any;
deps?: Record<string, any>;
theme?: any;
chakraProviderProps?: Record<string, any>;
}
export declare function setupUikitRemoteDeps(
options?: UikitRemoteSetupOptions,
): void;

View File

@ -0,0 +1,49 @@
"use client";
import React from "react";
import { createRoot } from "react-dom/client";
import {
Badge,
Button,
ChakraProvider,
HStack,
IconButton,
Input,
Text,
} from "@chakra-ui/react";
import { REMOTE_DEPS_KEY } from "./constants";
export function setupUikitRemoteDeps(options = {}) {
if (typeof window === "undefined") return;
const previousDeps = window[REMOTE_DEPS_KEY] || {};
window[REMOTE_DEPS_KEY] = {
...previousDeps,
React: options.React || previousDeps.React || React,
createRoot: options.createRoot || previousDeps.createRoot || createRoot,
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,
...(options.deps || {}),
theme: Object.prototype.hasOwnProperty.call(options, "theme")
? options.theme
: previousDeps.theme,
chakraProviderProps: {
...(previousDeps.chakraProviderProps || {}),
...(options.chakraProviderProps || {}),
},
};
}

View File

@ -1,54 +1,24 @@
import type { BadgeProps, StackProps } from "@chakra-ui/react"; export {
import type { ReactNode } from "react"; setupUikitRemoteDeps,
} from "./_core/setupRemoteDeps";
export type UikitRemoteLevel = "full" | "compact" | "simple"; export type {
UikitRemoteSetupOptions,
} from "./_core/setupRemoteDeps";
export interface UikitRemoteSetupOptions { export {
React?: any; GBadge,
createRoot?: any; } from "./GBadge";
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. */ export type {
remoteUrl?: string; GBadgeProps,
GBadgeUrl?: string; } from "./GBadge";
PaginationUrl?: string;
remoteUrls?: {
GBadge?: string;
Pagination?: string;
};
}
export declare function setupUikitRemoteDeps( export {
options?: UikitRemoteSetupOptions, Pagination,
): void; } from "./Pagination";
export interface GBadgeProps extends BadgeProps { export type {
children?: ReactNode; PaginationLevel,
remoteUrl?: string; PaginationProps,
theme?: any; } from "./Pagination";
chakraProviderProps?: Record<string, any>;
}
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;

View File

@ -1,225 +1,6 @@
"use client"; "use client";
import React, { useEffect, useRef } from "react"; export { setupUikitRemoteDeps } from "./_core/setupRemoteDeps";
import { createRoot } from "react-dom/client";
import {
Badge,
Button,
ChakraProvider,
HStack,
IconButton,
Input,
Text,
} from "@chakra-ui/react";
const DEFAULT_REMOTE_URLS = { export { GBadge } from "./GBadge";
GBadge: "https://uikit.d.aiengines.ir/GBadge.js", export { Pagination } from "./Pagination";
Pagination: "https://uikit.d.aiengines.ir/Pagination.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;
const previousDeps = window[REMOTE_DEPS_KEY] || {};
const previousConfig = window[REMOTE_CONFIG_KEY] || {};
window[REMOTE_DEPS_KEY] = {
...previousDeps,
React: options.React || previousDeps.React || React,
createRoot: options.createRoot || previousDeps.createRoot || createRoot,
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,
chakraProviderProps: {
...(previousDeps.chakraProviderProps || {}),
...(options.chakraProviderProps || {}),
},
};
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(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 (hasMissingDeps) {
setupUikitRemoteDeps();
}
}
function getRemoteUrl(componentName, explicitRemoteUrl) {
if (explicitRemoteUrl) return explicitRemoteUrl;
if (typeof window === "undefined") {
return DEFAULT_REMOTE_URLS[componentName];
}
return (
window[REMOTE_CONFIG_KEY]?.[`${componentName}Url`] ||
DEFAULT_REMOTE_URLS[componentName]
);
}
function loadRemote(componentName, explicitRemoteUrl) {
const remoteUrl = getRemoteUrl(componentName, explicitRemoteUrl);
const cacheKey = `${componentName}:${remoteUrl}`;
if (!remotePromises.has(cacheKey)) {
remotePromises.set(
cacheKey,
import(
/* webpackIgnore: true */
/* @vite-ignore */
remoteUrl
).catch((error) => {
remotePromises.delete(cacheKey);
throw error;
}),
);
}
return remotePromises.get(cacheKey);
}
function normalizeBadgeChildren(children) {
if (typeof children === "string" || typeof children === "number") {
return children;
}
if (children === null || children === undefined) {
return undefined;
}
console.warn(
"[uikit/remote/ui] GBadge only accepts text/number children across the remote boundary.",
);
return undefined;
}
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 = {
...(normalizeProps ? normalizeProps(props) : props),
...(theme !== undefined ? { theme } : {}),
...(chakraProviderProps ? { chakraProviderProps } : {}),
};
useEffect(() => {
let active = true;
ensureRemoteDeps(componentName);
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",
});

View File

@ -51,11 +51,11 @@ export default defineConfig(({ mode }) => {
entry: { entry: {
GBadge: path.resolve( GBadge: path.resolve(
process.cwd(), process.cwd(),
"src/remote/ui/GBadge.remote.jsx", "src/remote/ui/GBadge/GBadge.remote.jsx",
), ),
Pagination: path.resolve( Pagination: path.resolve(
process.cwd(), process.cwd(),
"src/remote/ui/Pagination.remote.jsx", "src/remote/ui/Pagination/Pagination.remote.jsx",
), ),
}, },