"use client"; import React, { useEffect, useRef } from "react"; const DEFAULT_REMOTE_URL = "https://uikit.d.aiengines.ir/AppHeader.js"; const APP_HEADER_SLOT = Symbol.for("uikit.remote.app-header.slot"); const remotePromises = new Map(); 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 createRemoteElementComponent({ componentName, tagName, defaultRemoteUrl, normalizeProps }) { return function RemoteElementComponent(props) { const containerRef = useRef(null); const elementRef = useRef(null); const latestPropsRef = useRef(null); latestPropsRef.current = normalizeProps ? normalizeProps(props) : props; useEffect(() => { let active = true; 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 createAppHeaderSlot(name) { function AppHeaderSlot() { return null; } AppHeaderSlot[APP_HEADER_SLOT] = name; return AppHeaderSlot; } const BrandSection = createAppHeaderSlot("brandSection"); const Logo = createAppHeaderSlot("logo"); const Brand = createAppHeaderSlot("brand"); const Title = createAppHeaderSlot("title"); const Description = createAppHeaderSlot("description"); const Bi = createAppHeaderSlot("bi"); 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 extractCompoundAppHeader(children) { const result = { showBi: false }; function visit(node) { React.Children.forEach(node, (child) => { if (!React.isValidElement(child)) return; const slot = child.type?.[APP_HEADER_SLOT]; if (slot === "logo") { result.logoSrc = child.props.src; result.logoAlt = child.props.alt; } else if (slot === "title") { result.title = toPlainText(child.props.children); } else if (slot === "description") { result.description = toPlainText(child.props.children); } else if (slot === "bi") { result.showBi = true; result.biLogoSrc = child.props.logoSrc || child.props.src; result.biLogoAlt = child.props.alt; result.biText = child.props.text; } if (child.props?.children) visit(child.props.children); }); } visit(children); return result; } const RemoteAppHeaderElement = createRemoteElementComponent({ componentName: "AppHeader", tagName: "uikit-app-header", defaultRemoteUrl: DEFAULT_REMOTE_URL, normalizeProps: ({ children, ...props }) => children === undefined || children === null ? props : { ...props, ...extractCompoundAppHeader(children) }, }); function AppHeaderRoot(props) { return React.createElement(RemoteAppHeaderElement, props); } export const AppHeader = Object.assign(AppHeaderRoot, { BrandSection, Logo, Brand, Title, Description, Bi, });