"use client"; import React, { useEffect, useRef } from "react"; import { createRoot } from "react-dom/client"; const DEFAULT_REMOTE_URL = "https://uikit.d.aiengines.ir/AppSidebar.js"; const REACT_REMOTE_DEPS_KEY = "__UIKIT_REACT_REMOTE_DEPS__"; const APP_SIDEBAR_SLOT = Symbol.for("uikit.remote.app-sidebar.slot"); const remotePromises = new Map(); function ensureReactRemoteDeps() { if (typeof window === "undefined") return; const previous = window[REACT_REMOTE_DEPS_KEY] || {}; window[REACT_REMOTE_DEPS_KEY] = { ...previous, React: previous.React || React, createRoot: previous.createRoot || createRoot, }; } 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); } function createReactRemoteElementComponent({ componentName, tagName, defaultRemoteUrl, normalizeProps, }) { return function ReactRemoteElementComponent(props) { const containerRef = useRef(null); const elementRef = useRef(null); const latestPropsRef = useRef(null); latestPropsRef.current = normalizeProps ? normalizeProps(props) : props; useEffect(() => { let active = true; ensureReactRemoteDeps(); loadRemote(componentName, defaultRemoteUrl) .then(() => { if (!active || !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) { elementRef.current.componentProps = latestPropsRef.current; } }); return React.createElement("span", { ref: containerRef, style: { display: "contents" }, }); }; } function createAppSidebarSlot(name) { function AppSidebarSlot() { return null; } AppSidebarSlot[APP_SIDEBAR_SLOT] = name; return AppSidebarSlot; } const Exit = createAppSidebarSlot("exit"); function toPlainText(value) { if (value === null || value === undefined || typeof value === "boolean") return undefined; if (typeof value === "string" || typeof value === "number") return String(value); if (Array.isArray(value)) return value.map(toPlainText).filter(Boolean).join(""); if (React.isValidElement(value)) return toPlainText(value.props?.children); return undefined; } function extractExit(children) { const result = { showExit: false }; React.Children.forEach(children, (child) => { if (!React.isValidElement(child)) return; if (child.type?.[APP_SIDEBAR_SLOT] !== "exit") return; result.showExit = true; result.exitLabel = child.props.label || toPlainText(child.props.children) || "خروج"; result.onExit = child.props.onClick; result.exitDisabled = Boolean(child.props.disabled); }); return result; } function normalizeIcon(icon) { if (!icon || React.isValidElement(icon)) return icon; if (typeof icon === "function") return React.createElement(icon); if (typeof icon === "object" && icon?.$$typeof) { try { return React.createElement(icon); } catch (_) { return icon; } } return icon; } function normalizeItems(items) { if (!Array.isArray(items)) return []; return items.map((item) => ({ ...item, icon: normalizeIcon(item?.icon) })); } const RemoteAppSidebarElement = createReactRemoteElementComponent({ componentName: "AppSidebar", tagName: "uikit-app-sidebar", defaultRemoteUrl: DEFAULT_REMOTE_URL, normalizeProps: ({ children, items, ...props }) => ({ ...props, items: normalizeItems(items), ...(children !== undefined && children !== null ? extractExit(children) : {}), }), }); function AppSidebarRoot(props) { return React.createElement(RemoteAppSidebarElement, props); } export const AppSidebar = Object.assign(AppSidebarRoot, { Exit });