UNPKG

@memberjunction/ng-react

Version:

Angular components for hosting React components in MemberJunction applications

214 lines 7.97 kB
/** * @fileoverview Angular adapter service that bridges the React runtime with Angular. * Provides Angular-specific functionality for the platform-agnostic React runtime. * @module @memberjunction/ng-react */ import { Injectable } from '@angular/core'; import { createReactRuntime } from '@memberjunction/react-runtime'; import { ScriptLoaderService } from './script-loader.service'; import { DEFAULT_STYLES } from '../default-styles'; import * as i0 from "@angular/core"; import * as i1 from "./script-loader.service"; /** * Angular-specific adapter for the React runtime. * Manages the integration between Angular services and the platform-agnostic React runtime. */ export class AngularAdapterService { constructor(scriptLoader) { this.scriptLoader = scriptLoader; } /** * Initialize the React runtime with Angular-specific configuration * @param config Optional library configuration * @param additionalLibraries Optional additional libraries to merge * @returns Promise resolving when runtime is ready */ async initialize(config, additionalLibraries) { if (this.runtime) { return; // Already initialized } // Load React ecosystem with optional additional libraries const ecosystem = await this.scriptLoader.loadReactEcosystem(config, additionalLibraries); // Create runtime context this.runtimeContext = { React: ecosystem.React, ReactDOM: ecosystem.ReactDOM, libraries: ecosystem.libraries, utilities: { // Add any Angular-specific utilities here } }; // Create the React runtime this.runtime = createReactRuntime(ecosystem.Babel, { compiler: { cache: true, maxCacheSize: 100 }, registry: { maxComponents: 1000, cleanupInterval: 60000, useLRU: true, enableNamespaces: true } }); } /** * Get the component compiler * @returns Component compiler instance */ getCompiler() { if (!this.runtime) { throw new Error('React runtime not initialized. Call initialize() first.'); } return this.runtime.compiler; } /** * Get the component registry * @returns Component registry instance */ getRegistry() { if (!this.runtime) { throw new Error('React runtime not initialized. Call initialize() first.'); } return this.runtime.registry; } /** * Get the component resolver * @returns Component resolver instance */ getResolver() { if (!this.runtime) { throw new Error('React runtime not initialized. Call initialize() first.'); } return this.runtime.resolver; } /** * Get the runtime context * @returns Runtime context with React and libraries */ getRuntimeContext() { if (!this.runtimeContext) { throw new Error('React runtime not initialized. Call initialize() first.'); } return this.runtimeContext; } /** * Compile a component with Angular-specific defaults * @param options - Compilation options * @returns Promise resolving to compilation result */ async compileComponent(options) { // Validate options before initialization if (!options) { throw new Error('Angular adapter error: No compilation options provided.\n' + 'This usually means the component spec is null or undefined.\n' + 'Please check that:\n' + '1. Your component data is loaded properly\n' + '2. The component spec has "name" and "code" properties\n' + '3. The component input is not undefined'); } if (!options.componentName || options.componentName.trim() === '') { throw new Error('Angular adapter error: Component name is missing or empty.\n' + `Received options: ${JSON.stringify(options, null, 2)}\n` + 'Make sure your component spec includes a "name" property.'); } if (!options.componentCode || options.componentCode.trim() === '') { throw new Error(`Angular adapter error: Component code is missing or empty for component "${options.componentName}".\n` + 'Make sure your component spec includes a "code" property with the React component source.'); } await this.initialize(); // Apply default styles if not provided const optionsWithDefaults = { ...options, styles: options.styles || DEFAULT_STYLES }; return this.runtime.compiler.compile(optionsWithDefaults); } /** * Register a component in the registry * @param name - Component name * @param component - Compiled component * @param namespace - Component namespace * @param version - Component version * @returns Component metadata */ registerComponent(name, component, namespace = 'Global', version = 'v1') { if (!this.runtime) { throw new Error('React runtime not initialized. Call initialize() first.'); } return this.runtime.registry.register(name, component, namespace, version); } /** * Get a component from the registry * @param name - Component name * @param namespace - Component namespace * @param version - Component version * @returns Component if found */ getComponent(name, namespace = 'Global', version) { if (!this.runtime) { throw new Error('React runtime not initialized. Call initialize() first.'); } return this.runtime.registry.get(name, namespace, version); } /** * Check if runtime is initialized * @returns true if initialized */ isInitialized() { return !!this.runtime && !!this.runtimeContext; } /** * Get runtime version * @returns Runtime version string */ getVersion() { return this.runtime?.version || 'unknown'; } /** * Clean up resources */ destroy() { if (this.runtime) { this.runtime.registry.destroy(); this.runtime = undefined; this.runtimeContext = undefined; } } /** * Get Babel instance for direct use * @returns Babel instance */ getBabel() { return this.runtimeContext?.libraries?.Babel || window.Babel; } /** * Transpile JSX code directly * @param code - JSX code to transpile * @param filename - Optional filename for better error messages * @returns Transpiled JavaScript code */ transpileJSX(code, filename) { const babel = this.getBabel(); if (!babel) { throw new Error('Babel not loaded. Initialize the runtime first.'); } try { const result = babel.transform(code, { presets: ['react'], filename: filename || 'component.jsx' }); return result.code; } catch (error) { throw new Error(`Failed to transpile JSX: ${error.message}`); } } static { this.ɵfac = function AngularAdapterService_Factory(t) { return new (t || AngularAdapterService)(i0.ɵɵinject(i1.ScriptLoaderService)); }; } static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: AngularAdapterService, factory: AngularAdapterService.ɵfac, providedIn: 'root' }); } } (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AngularAdapterService, [{ type: Injectable, args: [{ providedIn: 'root' }] }], () => [{ type: i1.ScriptLoaderService }], null); })(); //# sourceMappingURL=angular-adapter.service.js.map