/** * Universal Component Factory * * Creates framework-agnostic components that automatically adapt to the * detected framework. Supports lazy loading and caching for performance. */ import { detectFramework, getFrameworkFamily } from './framework-detector'; export interface ComponentConfig { tag: string; class?: any; props?: Record; events?: string[]; slots?: string[]; styles?: any; } export interface FrameworkAdapter { name: string; family: string; createComponent: (config: ComponentConfig) => any; createHook?: (name: string, logic: any) => any; createProvider?: (config: any) => any; } class ComponentFactoryEngine { private adapters: Map = new Map(); private componentCache: Map = new Map(); constructor() { this.registerBuiltInAdapters(); } private registerBuiltInAdapters() { const detection = detectFramework(); const family = getFrameworkFamily(detection.framework); // Attempt internal registration for common frameworks to avoid async race conditions if (family === 'react') { // We can't use top-level await in many environments yet, // so we use a sync-check + microtask approach this.preloadAdapter('react'); } } registerAdapter(adapter: FrameworkAdapter): void { this.adapters.set(adapter.family, adapter); // When a new adapter is registered, clear cache to allow components to "upgrade" this.componentCache.clear(); } getAdapter(family: string): FrameworkAdapter | null { return this.adapters.get(family) || null; } createComponent(config: ComponentConfig): any { const cacheKey = config.tag; const detection = detectFramework(); const family = getFrameworkFamily(detection.framework); const adapter = this.getAdapter(family); // If we have a cached component but it might be from a different framework (e.g. vanilla fallback) // and we now have an adapter, we should re-create it. if (this.componentCache.has(cacheKey)) { const cached = this.componentCache.get(cacheKey); // Simple check: if we need an adapter but the cached one isn't from the adapter if (adapter && typeof cached === 'function' && !cached.__isFluentWrapper) { // Fall through to re-create } else { return cached; } } let component; if (adapter) { component = adapter.createComponent(config); if (typeof component === 'function') { (component as any).__isFluentWrapper = true; } } else { component = this.createWebComponent(config); } this.componentCache.set(cacheKey, component); return component; } createHook(name: string, logic: any): any { const detection = detectFramework(); const family = getFrameworkFamily(detection.framework); const adapter = this.getAdapter(family); if (!adapter || !adapter.createHook) { return logic; } return adapter.createHook(name, logic); } createProvider(config: any): any { const detection = detectFramework(); const family = getFrameworkFamily(detection.framework); const adapter = this.getAdapter(family); if (!adapter || !adapter.createProvider) { return null; } return adapter.createProvider(config); } private createWebComponent(config: ComponentConfig): any { return config.class || config.tag; } clearCache(): void { this.componentCache.clear(); } async preloadAdapter(family: string): Promise { if (this.adapters.has(family)) { return; } try { const adapterModule = await this.loadAdapterModule(family); if (adapterModule && adapterModule.default) { this.registerAdapter(adapterModule.default); } } catch (error) { console.warn(`Failed to preload adapter for ${family}:`, error); } } private async loadAdapterModule(family: string): Promise { if (family === 'react') { return import('./react-adapter'); } return null; } } const factoryEngine = new ComponentFactoryEngine(); export function createUniversalComponent

(config: ComponentConfig): any | P { return factoryEngine.createComponent(config); } export function createUniversalHook(name: string, logic: any): any { return factoryEngine.createHook(name, logic); } export function createUniversalProvider(config: any): any { return factoryEngine.createProvider(config); } export function registerFrameworkAdapter(adapter: FrameworkAdapter): void { factoryEngine.registerAdapter(adapter); } export function getFrameworkAdapter(family: string): FrameworkAdapter | null { return factoryEngine.getAdapter(family); } export function clearComponentCache(): void { factoryEngine.clearCache(); } export async function preloadFrameworkAdapter(family: string): Promise { await factoryEngine.preloadAdapter(family); } export async function autoPreloadAdapter(): Promise { const detection = detectFramework(); const family = getFrameworkFamily(detection.framework); await factoryEngine.preloadAdapter(family); }