@memberjunction/ng-react 2.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,aAAa;AACb,OAAO,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAE7E,WAAW;AACX,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;;AAE3E;;;;;;;;;;;;;GAaG;AAiBH,MAAM,OAAO,aAAa;8EAAb,aAAa;mEAAb,aAAa;wEATb;YACT,mBAAmB;YACnB,kBAAkB;YAClB,qBAAqB;SACtB,YANC,YAAY;;iFAWH,aAAa;cAhBzB,QAAQ;eAAC;gBACR,YAAY,EAAE;oBACZ,gBAAgB;iBACjB;gBACD,OAAO,EAAE;oBACP,YAAY;iBACb;gBACD,SAAS,EAAE;oBACT,mBAAmB;oBACnB,kBAAkB;oBAClB,qBAAqB;iBACtB;gBACD,OAAO,EAAE;oBACP,gBAAgB;iBACjB;aACF;;wFACY,aAAa,mBAdtB,gBAAgB,aAGhB,YAAY,aAQZ,gBAAgB","sourcesContent":["/**\n * @fileoverview Angular module for React component integration in MemberJunction.\n * Provides components and services for hosting React components within Angular applications.\n * @module @memberjunction/ng-react\n */\n\nimport { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n// Components\nimport { MJReactComponent } from './components/mj-react-component.component';\n\n// Services\nimport { ScriptLoaderService } from './services/script-loader.service';\nimport { ReactBridgeService } from './services/react-bridge.service';\nimport { AngularAdapterService } from './services/angular-adapter.service';\n\n/**\n * Angular module that provides React component hosting capabilities.\n * Import this module to use React components within your Angular application.\n * \n * @example\n * ```typescript\n * import { MJReactModule } from '@memberjunction/ng-react';\n * \n * @NgModule({\n * imports: [MJReactModule]\n * })\n * export class MyModule {}\n * ```\n */\n@NgModule({\n declarations: [\n MJReactComponent\n ],\n imports: [\n CommonModule\n ],\n providers: [\n ScriptLoaderService,\n ReactBridgeService,\n AngularAdapterService\n ],\n exports: [\n MJReactComponent\n ]\n})\nexport class MJReactModule { }"]}
@@ -0,0 +1,97 @@
1
+ import { ComponentCompiler, ComponentRegistry, ComponentResolver, CompileOptions, RuntimeContext } from '@memberjunction/react-runtime';
2
+ import { ScriptLoaderService } from './script-loader.service';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Angular-specific adapter for the React runtime.
6
+ * Manages the integration between Angular services and the platform-agnostic React runtime.
7
+ */
8
+ export declare class AngularAdapterService {
9
+ private scriptLoader;
10
+ private runtime?;
11
+ private runtimeContext?;
12
+ constructor(scriptLoader: ScriptLoaderService);
13
+ /**
14
+ * Initialize the React runtime with Angular-specific configuration
15
+ * @returns Promise resolving when runtime is ready
16
+ */
17
+ initialize(): Promise<void>;
18
+ /**
19
+ * Get the component compiler
20
+ * @returns Component compiler instance
21
+ */
22
+ getCompiler(): ComponentCompiler;
23
+ /**
24
+ * Get the component registry
25
+ * @returns Component registry instance
26
+ */
27
+ getRegistry(): ComponentRegistry;
28
+ /**
29
+ * Get the component resolver
30
+ * @returns Component resolver instance
31
+ */
32
+ getResolver(): ComponentResolver;
33
+ /**
34
+ * Get the runtime context
35
+ * @returns Runtime context with React and libraries
36
+ */
37
+ getRuntimeContext(): RuntimeContext;
38
+ /**
39
+ * Convert SkipComponentStyles to ComponentStyles
40
+ * @param skipStyles - Skip component styles
41
+ * @returns Component styles for React runtime
42
+ */
43
+ private convertStyles;
44
+ /**
45
+ * Compile a component with Angular-specific defaults
46
+ * @param options - Compilation options
47
+ * @returns Promise resolving to compilation result
48
+ */
49
+ compileComponent(options: CompileOptions & {
50
+ styles?: any;
51
+ }): Promise<import("@memberjunction/react-runtime").CompilationResult>;
52
+ /**
53
+ * Register a component in the registry
54
+ * @param name - Component name
55
+ * @param component - Compiled component
56
+ * @param namespace - Component namespace
57
+ * @param version - Component version
58
+ * @returns Component metadata
59
+ */
60
+ registerComponent(name: string, component: any, namespace?: string, version?: string): import("@memberjunction/react-runtime").ComponentMetadata;
61
+ /**
62
+ * Get a component from the registry
63
+ * @param name - Component name
64
+ * @param namespace - Component namespace
65
+ * @param version - Component version
66
+ * @returns Component if found
67
+ */
68
+ getComponent(name: string, namespace?: string, version?: string): any;
69
+ /**
70
+ * Check if runtime is initialized
71
+ * @returns true if initialized
72
+ */
73
+ isInitialized(): boolean;
74
+ /**
75
+ * Get runtime version
76
+ * @returns Runtime version string
77
+ */
78
+ getVersion(): string;
79
+ /**
80
+ * Clean up resources
81
+ */
82
+ destroy(): void;
83
+ /**
84
+ * Get Babel instance for direct use
85
+ * @returns Babel instance
86
+ */
87
+ getBabel(): any;
88
+ /**
89
+ * Transpile JSX code directly
90
+ * @param code - JSX code to transpile
91
+ * @param filename - Optional filename for better error messages
92
+ * @returns Transpiled JavaScript code
93
+ */
94
+ transpileJSX(code: string, filename?: string): string;
95
+ static ɵfac: i0.ɵɵFactoryDeclaration<AngularAdapterService, never>;
96
+ static ɵprov: i0.ɵɵInjectableDeclaration<AngularAdapterService>;
97
+ }
@@ -0,0 +1,209 @@
1
+ /**
2
+ * @fileoverview Angular adapter service that bridges the React runtime with Angular.
3
+ * Provides Angular-specific functionality for the platform-agnostic React runtime.
4
+ * @module @memberjunction/ng-react
5
+ */
6
+ import { Injectable } from '@angular/core';
7
+ import { createReactRuntime } from '@memberjunction/react-runtime';
8
+ import { ScriptLoaderService } from './script-loader.service';
9
+ import { DEFAULT_STYLES } from '../default-styles';
10
+ import * as i0 from "@angular/core";
11
+ import * as i1 from "./script-loader.service";
12
+ /**
13
+ * Angular-specific adapter for the React runtime.
14
+ * Manages the integration between Angular services and the platform-agnostic React runtime.
15
+ */
16
+ export class AngularAdapterService {
17
+ constructor(scriptLoader) {
18
+ this.scriptLoader = scriptLoader;
19
+ }
20
+ /**
21
+ * Initialize the React runtime with Angular-specific configuration
22
+ * @returns Promise resolving when runtime is ready
23
+ */
24
+ async initialize() {
25
+ if (this.runtime) {
26
+ return; // Already initialized
27
+ }
28
+ // Load React ecosystem
29
+ const ecosystem = await this.scriptLoader.loadReactEcosystem();
30
+ // Create runtime context
31
+ this.runtimeContext = {
32
+ React: ecosystem.React,
33
+ ReactDOM: ecosystem.ReactDOM,
34
+ libraries: ecosystem.libraries,
35
+ utilities: {
36
+ // Add any Angular-specific utilities here
37
+ }
38
+ };
39
+ // Create the React runtime
40
+ this.runtime = createReactRuntime(ecosystem.Babel, {
41
+ compiler: {
42
+ cache: true,
43
+ maxCacheSize: 100
44
+ },
45
+ registry: {
46
+ maxComponents: 1000,
47
+ cleanupInterval: 60000,
48
+ useLRU: true,
49
+ enableNamespaces: true
50
+ }
51
+ });
52
+ }
53
+ /**
54
+ * Get the component compiler
55
+ * @returns Component compiler instance
56
+ */
57
+ getCompiler() {
58
+ if (!this.runtime) {
59
+ throw new Error('React runtime not initialized. Call initialize() first.');
60
+ }
61
+ return this.runtime.compiler;
62
+ }
63
+ /**
64
+ * Get the component registry
65
+ * @returns Component registry instance
66
+ */
67
+ getRegistry() {
68
+ if (!this.runtime) {
69
+ throw new Error('React runtime not initialized. Call initialize() first.');
70
+ }
71
+ return this.runtime.registry;
72
+ }
73
+ /**
74
+ * Get the component resolver
75
+ * @returns Component resolver instance
76
+ */
77
+ getResolver() {
78
+ if (!this.runtime) {
79
+ throw new Error('React runtime not initialized. Call initialize() first.');
80
+ }
81
+ return this.runtime.resolver;
82
+ }
83
+ /**
84
+ * Get the runtime context
85
+ * @returns Runtime context with React and libraries
86
+ */
87
+ getRuntimeContext() {
88
+ if (!this.runtimeContext) {
89
+ throw new Error('React runtime not initialized. Call initialize() first.');
90
+ }
91
+ return this.runtimeContext;
92
+ }
93
+ /**
94
+ * Convert SkipComponentStyles to ComponentStyles
95
+ * @param skipStyles - Skip component styles
96
+ * @returns Component styles for React runtime
97
+ */
98
+ convertStyles(skipStyles) {
99
+ if (!skipStyles)
100
+ return undefined;
101
+ // Extract CSS-compatible properties
102
+ return {
103
+ className: skipStyles.className,
104
+ style: skipStyles.style,
105
+ globalCss: skipStyles.globalCss
106
+ };
107
+ }
108
+ /**
109
+ * Compile a component with Angular-specific defaults
110
+ * @param options - Compilation options
111
+ * @returns Promise resolving to compilation result
112
+ */
113
+ async compileComponent(options) {
114
+ await this.initialize();
115
+ // Apply default styles if not provided
116
+ const optionsWithDefaults = {
117
+ ...options,
118
+ styles: options.styles || DEFAULT_STYLES
119
+ };
120
+ return this.runtime.compiler.compile(optionsWithDefaults);
121
+ }
122
+ /**
123
+ * Register a component in the registry
124
+ * @param name - Component name
125
+ * @param component - Compiled component
126
+ * @param namespace - Component namespace
127
+ * @param version - Component version
128
+ * @returns Component metadata
129
+ */
130
+ registerComponent(name, component, namespace = 'Global', version = 'v1') {
131
+ if (!this.runtime) {
132
+ throw new Error('React runtime not initialized. Call initialize() first.');
133
+ }
134
+ return this.runtime.registry.register(name, component, namespace, version);
135
+ }
136
+ /**
137
+ * Get a component from the registry
138
+ * @param name - Component name
139
+ * @param namespace - Component namespace
140
+ * @param version - Component version
141
+ * @returns Component if found
142
+ */
143
+ getComponent(name, namespace = 'Global', version) {
144
+ if (!this.runtime) {
145
+ throw new Error('React runtime not initialized. Call initialize() first.');
146
+ }
147
+ return this.runtime.registry.get(name, namespace, version);
148
+ }
149
+ /**
150
+ * Check if runtime is initialized
151
+ * @returns true if initialized
152
+ */
153
+ isInitialized() {
154
+ return !!this.runtime && !!this.runtimeContext;
155
+ }
156
+ /**
157
+ * Get runtime version
158
+ * @returns Runtime version string
159
+ */
160
+ getVersion() {
161
+ return this.runtime?.version || 'unknown';
162
+ }
163
+ /**
164
+ * Clean up resources
165
+ */
166
+ destroy() {
167
+ if (this.runtime) {
168
+ this.runtime.registry.destroy();
169
+ this.runtime = undefined;
170
+ this.runtimeContext = undefined;
171
+ }
172
+ }
173
+ /**
174
+ * Get Babel instance for direct use
175
+ * @returns Babel instance
176
+ */
177
+ getBabel() {
178
+ return this.runtimeContext?.libraries?.Babel || window.Babel;
179
+ }
180
+ /**
181
+ * Transpile JSX code directly
182
+ * @param code - JSX code to transpile
183
+ * @param filename - Optional filename for better error messages
184
+ * @returns Transpiled JavaScript code
185
+ */
186
+ transpileJSX(code, filename) {
187
+ const babel = this.getBabel();
188
+ if (!babel) {
189
+ throw new Error('Babel not loaded. Initialize the runtime first.');
190
+ }
191
+ try {
192
+ const result = babel.transform(code, {
193
+ presets: ['react'],
194
+ filename: filename || 'component.jsx'
195
+ });
196
+ return result.code;
197
+ }
198
+ catch (error) {
199
+ throw new Error(`Failed to transpile JSX: ${error.message}`);
200
+ }
201
+ }
202
+ static { this.ɵfac = function AngularAdapterService_Factory(t) { return new (t || AngularAdapterService)(i0.ɵɵinject(i1.ScriptLoaderService)); }; }
203
+ static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: AngularAdapterService, factory: AngularAdapterService.ɵfac, providedIn: 'root' }); }
204
+ }
205
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AngularAdapterService, [{
206
+ type: Injectable,
207
+ args: [{ providedIn: 'root' }]
208
+ }], () => [{ type: i1.ScriptLoaderService }], null); })();
209
+ //# sourceMappingURL=angular-adapter.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"angular-adapter.service.js","sourceRoot":"","sources":["../../../src/lib/services/angular-adapter.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Angular adapter service that bridges the React runtime with Angular.\n * Provides Angular-specific functionality for the platform-agnostic React runtime.\n * @module @memberjunction/ng-react\n */\n\nimport { Injectable } from '@angular/core';\nimport { \n ComponentCompiler,\n ComponentRegistry,\n ComponentResolver,\n createReactRuntime,\n CompileOptions,\n RuntimeContext,\n ComponentStyles\n} from '@memberjunction/react-runtime';\nimport { ScriptLoaderService } from './script-loader.service';\nimport { DEFAULT_STYLES } from '../default-styles';\n\n/**\n * Angular-specific adapter for the React runtime.\n * Manages the integration between Angular services and the platform-agnostic React runtime.\n */\n@Injectable({ providedIn: 'root' })\nexport class AngularAdapterService {\n private runtime?: {\n compiler: ComponentCompiler;\n registry: ComponentRegistry;\n resolver: ComponentResolver;\n version: string;\n };\n private runtimeContext?: RuntimeContext;\n\n constructor(private scriptLoader: ScriptLoaderService) {}\n\n /**\n * Initialize the React runtime with Angular-specific configuration\n * @returns Promise resolving when runtime is ready\n */\n async initialize(): Promise<void> {\n if (this.runtime) {\n return; // Already initialized\n }\n\n // Load React ecosystem\n const ecosystem = await this.scriptLoader.loadReactEcosystem();\n \n // Create runtime context\n this.runtimeContext = {\n React: ecosystem.React,\n ReactDOM: ecosystem.ReactDOM,\n libraries: ecosystem.libraries,\n utilities: {\n // Add any Angular-specific utilities here\n }\n };\n\n // Create the React runtime\n this.runtime = createReactRuntime(ecosystem.Babel, {\n compiler: {\n cache: true,\n maxCacheSize: 100\n },\n registry: {\n maxComponents: 1000,\n cleanupInterval: 60000,\n useLRU: true,\n enableNamespaces: true\n }\n });\n }\n\n /**\n * Get the component compiler\n * @returns Component compiler instance\n */\n getCompiler(): ComponentCompiler {\n if (!this.runtime) {\n throw new Error('React runtime not initialized. Call initialize() first.');\n }\n return this.runtime.compiler;\n }\n\n /**\n * Get the component registry\n * @returns Component registry instance\n */\n getRegistry(): ComponentRegistry {\n if (!this.runtime) {\n throw new Error('React runtime not initialized. Call initialize() first.');\n }\n return this.runtime.registry;\n }\n\n /**\n * Get the component resolver\n * @returns Component resolver instance\n */\n getResolver(): ComponentResolver {\n if (!this.runtime) {\n throw new Error('React runtime not initialized. Call initialize() first.');\n }\n return this.runtime.resolver;\n }\n\n /**\n * Get the runtime context\n * @returns Runtime context with React and libraries\n */\n getRuntimeContext(): RuntimeContext {\n if (!this.runtimeContext) {\n throw new Error('React runtime not initialized. Call initialize() first.');\n }\n return this.runtimeContext;\n }\n\n /**\n * Convert SkipComponentStyles to ComponentStyles\n * @param skipStyles - Skip component styles\n * @returns Component styles for React runtime\n */\n private convertStyles(skipStyles?: any): ComponentStyles | undefined {\n if (!skipStyles) return undefined;\n \n // Extract CSS-compatible properties\n return {\n className: skipStyles.className,\n style: skipStyles.style,\n globalCss: skipStyles.globalCss\n };\n }\n\n /**\n * Compile a component with Angular-specific defaults\n * @param options - Compilation options\n * @returns Promise resolving to compilation result\n */\n async compileComponent(options: CompileOptions & { styles?: any }) {\n await this.initialize();\n \n // Apply default styles if not provided\n const optionsWithDefaults = {\n ...options,\n styles: options.styles || DEFAULT_STYLES\n };\n\n return this.runtime!.compiler.compile(optionsWithDefaults);\n }\n\n /**\n * Register a component in the registry\n * @param name - Component name\n * @param component - Compiled component\n * @param namespace - Component namespace\n * @param version - Component version\n * @returns Component metadata\n */\n registerComponent(\n name: string,\n component: any,\n namespace: string = 'Global',\n version: string = 'v1'\n ) {\n if (!this.runtime) {\n throw new Error('React runtime not initialized. Call initialize() first.');\n }\n return this.runtime.registry.register(name, component, namespace, version);\n }\n\n /**\n * Get a component from the registry\n * @param name - Component name\n * @param namespace - Component namespace\n * @param version - Component version\n * @returns Component if found\n */\n getComponent(name: string, namespace: string = 'Global', version?: string) {\n if (!this.runtime) {\n throw new Error('React runtime not initialized. Call initialize() first.');\n }\n return this.runtime.registry.get(name, namespace, version);\n }\n\n /**\n * Check if runtime is initialized\n * @returns true if initialized\n */\n isInitialized(): boolean {\n return !!this.runtime && !!this.runtimeContext;\n }\n\n /**\n * Get runtime version\n * @returns Runtime version string\n */\n getVersion(): string {\n return this.runtime?.version || 'unknown';\n }\n\n /**\n * Clean up resources\n */\n destroy(): void {\n if (this.runtime) {\n this.runtime.registry.destroy();\n this.runtime = undefined;\n this.runtimeContext = undefined;\n }\n }\n\n /**\n * Get Babel instance for direct use\n * @returns Babel instance\n */\n getBabel(): any {\n return this.runtimeContext?.libraries?.Babel || (window as any).Babel;\n }\n\n /**\n * Transpile JSX code directly\n * @param code - JSX code to transpile\n * @param filename - Optional filename for better error messages\n * @returns Transpiled JavaScript code\n */\n transpileJSX(code: string, filename?: string): string {\n const babel = this.getBabel();\n if (!babel) {\n throw new Error('Babel not loaded. Initialize the runtime first.');\n }\n\n try {\n const result = babel.transform(code, {\n presets: ['react'],\n filename: filename || 'component.jsx'\n });\n return result.code;\n } catch (error: any) {\n throw new Error(`Failed to transpile JSX: ${error.message}`);\n }\n }\n}"]}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @fileoverview Service to manage React and ReactDOM instances with proper lifecycle.
3
+ * Bridges Angular components with React rendering capabilities.
4
+ * @module @memberjunction/ng-react
5
+ */
6
+ import { OnDestroy } from '@angular/core';
7
+ import { AngularAdapterService } from './angular-adapter.service';
8
+ import { RuntimeContext } from '@memberjunction/react-runtime';
9
+ import * as i0 from "@angular/core";
10
+ /**
11
+ * Service to manage React and ReactDOM instances with proper lifecycle.
12
+ * Provides methods for creating and managing React roots in Angular applications.
13
+ */
14
+ export declare class ReactBridgeService implements OnDestroy {
15
+ private adapter;
16
+ private reactRoots;
17
+ private reactReadySubject;
18
+ reactReady$: import("rxjs").Observable<boolean>;
19
+ private firstComponentAttempted;
20
+ private maxWaitTime;
21
+ private checkInterval;
22
+ constructor(adapter: AngularAdapterService);
23
+ ngOnDestroy(): void;
24
+ /**
25
+ * Bootstrap React early during service initialization
26
+ */
27
+ private bootstrapReact;
28
+ /**
29
+ * Wait for React to be ready, with special handling for first component
30
+ */
31
+ waitForReactReady(): Promise<void>;
32
+ /**
33
+ * Get the current React context if loaded
34
+ * @returns React context with React, ReactDOM, Babel, and libraries
35
+ */
36
+ getReactContext(): Promise<RuntimeContext>;
37
+ /**
38
+ * Get the current React context synchronously
39
+ * @returns React context or null if not loaded
40
+ */
41
+ getCurrentContext(): RuntimeContext | null;
42
+ /**
43
+ * Create a React root for rendering
44
+ * @param container - DOM element to render into
45
+ * @returns React root instance
46
+ */
47
+ createRoot(container: HTMLElement): any;
48
+ /**
49
+ * Unmount and clean up a React root
50
+ * @param root - React root to unmount
51
+ */
52
+ unmountRoot(root: any): void;
53
+ /**
54
+ * Transpile JSX code to JavaScript
55
+ * @param code - JSX code to transpile
56
+ * @param filename - Optional filename for error messages
57
+ * @returns Transpiled JavaScript code
58
+ */
59
+ transpileJSX(code: string, filename: string): string;
60
+ /**
61
+ * Clean up all React roots and reset context
62
+ */
63
+ private cleanup;
64
+ /**
65
+ * Check if React is currently ready
66
+ * @returns true if React is ready
67
+ */
68
+ isReady(): boolean;
69
+ /**
70
+ * Get the number of active React roots
71
+ * @returns Number of active roots
72
+ */
73
+ getActiveRootsCount(): number;
74
+ static ɵfac: i0.ɵɵFactoryDeclaration<ReactBridgeService, never>;
75
+ static ɵprov: i0.ɵɵInjectableDeclaration<ReactBridgeService>;
76
+ }
@@ -0,0 +1,189 @@
1
+ /**
2
+ * @fileoverview Service to manage React and ReactDOM instances with proper lifecycle.
3
+ * Bridges Angular components with React rendering capabilities.
4
+ * @module @memberjunction/ng-react
5
+ */
6
+ import { Injectable } from '@angular/core';
7
+ import { BehaviorSubject, firstValueFrom } from 'rxjs';
8
+ import { filter } from 'rxjs/operators';
9
+ import { AngularAdapterService } from './angular-adapter.service';
10
+ import * as i0 from "@angular/core";
11
+ import * as i1 from "./angular-adapter.service";
12
+ /**
13
+ * Service to manage React and ReactDOM instances with proper lifecycle.
14
+ * Provides methods for creating and managing React roots in Angular applications.
15
+ */
16
+ export class ReactBridgeService {
17
+ constructor(adapter) {
18
+ this.adapter = adapter;
19
+ this.reactRoots = new Set();
20
+ // Track React readiness state
21
+ this.reactReadySubject = new BehaviorSubject(false);
22
+ this.reactReady$ = this.reactReadySubject.asObservable();
23
+ // Track if this is the first component trying to use React
24
+ this.firstComponentAttempted = false;
25
+ this.maxWaitTime = 5000; // Maximum 5 seconds wait time
26
+ this.checkInterval = 200; // Check every 200ms
27
+ // Bootstrap React immediately on service initialization
28
+ this.bootstrapReact();
29
+ }
30
+ ngOnDestroy() {
31
+ this.cleanup();
32
+ }
33
+ /**
34
+ * Bootstrap React early during service initialization
35
+ */
36
+ async bootstrapReact() {
37
+ try {
38
+ await this.adapter.initialize();
39
+ console.log('React ecosystem pre-loaded successfully');
40
+ }
41
+ catch (error) {
42
+ console.error('Failed to pre-load React ecosystem:', error);
43
+ }
44
+ }
45
+ /**
46
+ * Wait for React to be ready, with special handling for first component
47
+ */
48
+ async waitForReactReady() {
49
+ // If already ready, return immediately
50
+ if (this.reactReadySubject.value) {
51
+ return;
52
+ }
53
+ // Check if this is the first component attempting to use React
54
+ const isFirstComponent = !this.firstComponentAttempted;
55
+ this.firstComponentAttempted = true;
56
+ if (isFirstComponent) {
57
+ // First component - check periodically until React is ready
58
+ console.log('First React component loading - checking for React initialization');
59
+ const startTime = Date.now();
60
+ while (Date.now() - startTime < this.maxWaitTime) {
61
+ try {
62
+ const testDiv = document.createElement('div');
63
+ const context = this.adapter.getRuntimeContext();
64
+ if (context.ReactDOM?.createRoot) {
65
+ // Try to create a test root
66
+ const testRoot = context.ReactDOM.createRoot(testDiv);
67
+ if (testRoot) {
68
+ testRoot.unmount();
69
+ // React is ready!
70
+ this.reactReadySubject.next(true);
71
+ console.log(`React is fully ready after ${Date.now() - startTime}ms`);
72
+ return;
73
+ }
74
+ }
75
+ }
76
+ catch (error) {
77
+ // Not ready yet, continue checking
78
+ }
79
+ // Wait before next check
80
+ await new Promise(resolve => setTimeout(resolve, this.checkInterval));
81
+ }
82
+ // If we've exhausted the wait time, throw error
83
+ console.error('React readiness test failed after maximum wait time');
84
+ this.firstComponentAttempted = false;
85
+ throw new Error(`ReactDOM.createRoot not available after ${this.maxWaitTime}ms`);
86
+ }
87
+ else {
88
+ // Subsequent components wait for the ready signal
89
+ await firstValueFrom(this.reactReady$.pipe(filter(ready => ready)));
90
+ }
91
+ }
92
+ /**
93
+ * Get the current React context if loaded
94
+ * @returns React context with React, ReactDOM, Babel, and libraries
95
+ */
96
+ async getReactContext() {
97
+ await this.adapter.initialize();
98
+ return this.adapter.getRuntimeContext();
99
+ }
100
+ /**
101
+ * Get the current React context synchronously
102
+ * @returns React context or null if not loaded
103
+ */
104
+ getCurrentContext() {
105
+ if (!this.adapter.isInitialized()) {
106
+ return null;
107
+ }
108
+ return this.adapter.getRuntimeContext();
109
+ }
110
+ /**
111
+ * Create a React root for rendering
112
+ * @param container - DOM element to render into
113
+ * @returns React root instance
114
+ */
115
+ createRoot(container) {
116
+ const context = this.getCurrentContext();
117
+ if (!context?.ReactDOM?.createRoot) {
118
+ throw new Error('ReactDOM.createRoot not available');
119
+ }
120
+ const root = context.ReactDOM.createRoot(container);
121
+ this.reactRoots.add(root);
122
+ return root;
123
+ }
124
+ /**
125
+ * Unmount and clean up a React root
126
+ * @param root - React root to unmount
127
+ */
128
+ unmountRoot(root) {
129
+ if (root && typeof root.unmount === 'function') {
130
+ try {
131
+ root.unmount();
132
+ }
133
+ catch (error) {
134
+ console.warn('Failed to unmount React root:', error);
135
+ }
136
+ }
137
+ this.reactRoots.delete(root);
138
+ }
139
+ /**
140
+ * Transpile JSX code to JavaScript
141
+ * @param code - JSX code to transpile
142
+ * @param filename - Optional filename for error messages
143
+ * @returns Transpiled JavaScript code
144
+ */
145
+ transpileJSX(code, filename) {
146
+ return this.adapter.transpileJSX(code, filename);
147
+ }
148
+ /**
149
+ * Clean up all React roots and reset context
150
+ */
151
+ cleanup() {
152
+ // Unmount all tracked React roots
153
+ for (const root of this.reactRoots) {
154
+ try {
155
+ root.unmount();
156
+ }
157
+ catch (error) {
158
+ console.warn('Failed to unmount React root:', error);
159
+ }
160
+ }
161
+ this.reactRoots.clear();
162
+ // Reset readiness state
163
+ this.reactReadySubject.next(false);
164
+ this.firstComponentAttempted = false;
165
+ // Clean up adapter
166
+ this.adapter.destroy();
167
+ }
168
+ /**
169
+ * Check if React is currently ready
170
+ * @returns true if React is ready
171
+ */
172
+ isReady() {
173
+ return this.reactReadySubject.value;
174
+ }
175
+ /**
176
+ * Get the number of active React roots
177
+ * @returns Number of active roots
178
+ */
179
+ getActiveRootsCount() {
180
+ return this.reactRoots.size;
181
+ }
182
+ static { this.ɵfac = function ReactBridgeService_Factory(t) { return new (t || ReactBridgeService)(i0.ɵɵinject(i1.AngularAdapterService)); }; }
183
+ static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: ReactBridgeService, factory: ReactBridgeService.ɵfac, providedIn: 'root' }); }
184
+ }
185
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ReactBridgeService, [{
186
+ type: Injectable,
187
+ args: [{ providedIn: 'root' }]
188
+ }], () => [{ type: i1.AngularAdapterService }], null); })();
189
+ //# sourceMappingURL=react-bridge.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-bridge.service.js","sourceRoot":"","sources":["../../../src/lib/services/react-bridge.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Service to manage React and ReactDOM instances with proper lifecycle.\n * Bridges Angular components with React rendering capabilities.\n * @module @memberjunction/ng-react\n */\n\nimport { Injectable, OnDestroy } from '@angular/core';\nimport { BehaviorSubject, firstValueFrom } from 'rxjs';\nimport { filter } from 'rxjs/operators';\nimport { AngularAdapterService } from './angular-adapter.service';\nimport { RuntimeContext } from '@memberjunction/react-runtime';\n\n/**\n * Service to manage React and ReactDOM instances with proper lifecycle.\n * Provides methods for creating and managing React roots in Angular applications.\n */\n@Injectable({ providedIn: 'root' })\nexport class ReactBridgeService implements OnDestroy {\n private reactRoots = new Set<any>();\n \n // Track React readiness state\n private reactReadySubject = new BehaviorSubject<boolean>(false);\n public reactReady$ = this.reactReadySubject.asObservable();\n \n // Track if this is the first component trying to use React\n private firstComponentAttempted = false;\n private maxWaitTime = 5000; // Maximum 5 seconds wait time\n private checkInterval = 200; // Check every 200ms\n\n constructor(private adapter: AngularAdapterService) {\n // Bootstrap React immediately on service initialization\n this.bootstrapReact();\n }\n\n ngOnDestroy(): void {\n this.cleanup();\n }\n\n /**\n * Bootstrap React early during service initialization\n */\n private async bootstrapReact(): Promise<void> {\n try {\n await this.adapter.initialize();\n console.log('React ecosystem pre-loaded successfully');\n } catch (error) {\n console.error('Failed to pre-load React ecosystem:', error);\n }\n }\n\n /**\n * Wait for React to be ready, with special handling for first component\n */\n async waitForReactReady(): Promise<void> {\n // If already ready, return immediately\n if (this.reactReadySubject.value) {\n return;\n }\n\n // Check if this is the first component attempting to use React\n const isFirstComponent = !this.firstComponentAttempted;\n this.firstComponentAttempted = true;\n\n if (isFirstComponent) {\n // First component - check periodically until React is ready\n console.log('First React component loading - checking for React initialization');\n \n const startTime = Date.now();\n \n while (Date.now() - startTime < this.maxWaitTime) {\n try {\n const testDiv = document.createElement('div');\n const context = this.adapter.getRuntimeContext();\n \n if (context.ReactDOM?.createRoot) {\n // Try to create a test root\n const testRoot = context.ReactDOM.createRoot(testDiv);\n if (testRoot) {\n testRoot.unmount();\n // React is ready!\n this.reactReadySubject.next(true);\n console.log(`React is fully ready after ${Date.now() - startTime}ms`);\n return;\n }\n }\n } catch (error) {\n // Not ready yet, continue checking\n }\n \n // Wait before next check\n await new Promise(resolve => setTimeout(resolve, this.checkInterval));\n }\n \n // If we've exhausted the wait time, throw error\n console.error('React readiness test failed after maximum wait time');\n this.firstComponentAttempted = false;\n throw new Error(`ReactDOM.createRoot not available after ${this.maxWaitTime}ms`);\n } else {\n // Subsequent components wait for the ready signal\n await firstValueFrom(this.reactReady$.pipe(filter(ready => ready)));\n }\n }\n\n /**\n * Get the current React context if loaded\n * @returns React context with React, ReactDOM, Babel, and libraries\n */\n async getReactContext(): Promise<RuntimeContext> {\n await this.adapter.initialize();\n return this.adapter.getRuntimeContext();\n }\n\n /**\n * Get the current React context synchronously\n * @returns React context or null if not loaded\n */\n getCurrentContext(): RuntimeContext | null {\n if (!this.adapter.isInitialized()) {\n return null;\n }\n return this.adapter.getRuntimeContext();\n }\n\n /**\n * Create a React root for rendering\n * @param container - DOM element to render into\n * @returns React root instance\n */\n createRoot(container: HTMLElement): any {\n const context = this.getCurrentContext();\n if (!context?.ReactDOM?.createRoot) {\n throw new Error('ReactDOM.createRoot not available');\n }\n\n const root = context.ReactDOM.createRoot(container);\n this.reactRoots.add(root);\n return root;\n }\n\n /**\n * Unmount and clean up a React root\n * @param root - React root to unmount\n */\n unmountRoot(root: any): void {\n if (root && typeof root.unmount === 'function') {\n try {\n root.unmount();\n } catch (error) {\n console.warn('Failed to unmount React root:', error);\n }\n }\n this.reactRoots.delete(root);\n }\n\n /**\n * Transpile JSX code to JavaScript\n * @param code - JSX code to transpile\n * @param filename - Optional filename for error messages\n * @returns Transpiled JavaScript code\n */\n transpileJSX(code: string, filename: string): string {\n return this.adapter.transpileJSX(code, filename);\n }\n\n /**\n * Clean up all React roots and reset context\n */\n private cleanup(): void {\n // Unmount all tracked React roots\n for (const root of this.reactRoots) {\n try {\n root.unmount();\n } catch (error) {\n console.warn('Failed to unmount React root:', error);\n }\n }\n this.reactRoots.clear();\n \n // Reset readiness state\n this.reactReadySubject.next(false);\n this.firstComponentAttempted = false;\n\n // Clean up adapter\n this.adapter.destroy();\n }\n\n /**\n * Check if React is currently ready\n * @returns true if React is ready\n */\n isReady(): boolean {\n return this.reactReadySubject.value;\n }\n\n /**\n * Get the number of active React roots\n * @returns Number of active roots\n */\n getActiveRootsCount(): number {\n return this.reactRoots.size;\n }\n}"]}