@memberjunction/ng-react 2.75.0 → 2.77.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.
- package/README.md +1 -21
- package/dist/lib/components/mj-react-component.component.d.ts +20 -3
- package/dist/lib/components/mj-react-component.component.js +88 -90
- package/dist/lib/components/mj-react-component.component.js.map +1 -1
- package/dist/lib/services/angular-adapter.service.d.ts +4 -2
- package/dist/lib/services/angular-adapter.service.js +23 -3
- package/dist/lib/services/angular-adapter.service.js.map +1 -1
- package/dist/lib/services/script-loader.service.d.ts +3 -2
- package/dist/lib/services/script-loader.service.js +3 -2
- package/dist/lib/services/script-loader.service.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -192,27 +192,7 @@ const styles: SkipComponentStyles = {
|
|
|
192
192
|
}
|
|
193
193
|
};
|
|
194
194
|
```
|
|
195
|
-
|
|
196
|
-
### State Management
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
// In your Angular component
|
|
200
|
-
onStateChange(event: StateChangeEvent) {
|
|
201
|
-
console.log(`State ${event.path} changed to:`, event.value);
|
|
202
|
-
// Update your Angular component state
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// In your React component
|
|
206
|
-
function MyComponent({ userState, callbacks }) {
|
|
207
|
-
const updateState = () => {
|
|
208
|
-
callbacks.UpdateUserState({
|
|
209
|
-
counter: userState.counter + 1
|
|
210
|
-
});
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
return <button onClick={updateState}>Count: {userState.counter}</button>;
|
|
214
|
-
}
|
|
215
|
-
```
|
|
195
|
+
|
|
216
196
|
|
|
217
197
|
## Services
|
|
218
198
|
|
|
@@ -23,6 +23,14 @@ export interface StateChangeEvent {
|
|
|
23
23
|
path: string;
|
|
24
24
|
value: any;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* User settings changed event emitted when component saves user preferences
|
|
28
|
+
*/
|
|
29
|
+
export interface UserSettingsChangedEvent {
|
|
30
|
+
settings: Record<string, any>;
|
|
31
|
+
componentName?: string;
|
|
32
|
+
timestamp: Date;
|
|
33
|
+
}
|
|
26
34
|
/**
|
|
27
35
|
* Angular component that hosts React components with proper memory management.
|
|
28
36
|
* This component provides a bridge between Angular and React, allowing React components
|
|
@@ -41,6 +49,9 @@ export declare class MJReactComponent implements AfterViewInit, OnDestroy {
|
|
|
41
49
|
get state(): any;
|
|
42
50
|
utilities: any;
|
|
43
51
|
styles?: Partial<ComponentStyles>;
|
|
52
|
+
private _savedUserSettings;
|
|
53
|
+
set savedUserSettings(value: any);
|
|
54
|
+
get savedUserSettings(): any;
|
|
44
55
|
stateChange: EventEmitter<StateChangeEvent>;
|
|
45
56
|
componentEvent: EventEmitter<ReactComponentEvent>;
|
|
46
57
|
refreshData: EventEmitter<void>;
|
|
@@ -48,8 +59,9 @@ export declare class MJReactComponent implements AfterViewInit, OnDestroy {
|
|
|
48
59
|
entityName: string;
|
|
49
60
|
key: CompositeKey;
|
|
50
61
|
}>;
|
|
62
|
+
userSettingsChanged: EventEmitter<UserSettingsChangedEvent>;
|
|
51
63
|
container: ElementRef<HTMLDivElement>;
|
|
52
|
-
private
|
|
64
|
+
private reactRootId;
|
|
53
65
|
private compiledComponent;
|
|
54
66
|
private destroyed$;
|
|
55
67
|
private currentCallbacks;
|
|
@@ -58,7 +70,7 @@ export declare class MJReactComponent implements AfterViewInit, OnDestroy {
|
|
|
58
70
|
private isRendering;
|
|
59
71
|
private pendingRender;
|
|
60
72
|
private isDestroying;
|
|
61
|
-
private
|
|
73
|
+
private componentId;
|
|
62
74
|
hasError: boolean;
|
|
63
75
|
constructor(reactBridge: ReactBridgeService, adapter: AngularAdapterService, cdr: ChangeDetectorRef);
|
|
64
76
|
ngAfterViewInit(): Promise<void>;
|
|
@@ -83,6 +95,11 @@ export declare class MJReactComponent implements AfterViewInit, OnDestroy {
|
|
|
83
95
|
* Handle React component errors
|
|
84
96
|
*/
|
|
85
97
|
private handleReactError;
|
|
98
|
+
/**
|
|
99
|
+
* Handle onSaveUserSettings from components
|
|
100
|
+
* This implements the SavedUserSettings pattern
|
|
101
|
+
*/
|
|
102
|
+
private handleSaveUserSettings;
|
|
86
103
|
/**
|
|
87
104
|
* Clean up resources
|
|
88
105
|
*/
|
|
@@ -103,5 +120,5 @@ export declare class MJReactComponent implements AfterViewInit, OnDestroy {
|
|
|
103
120
|
*/
|
|
104
121
|
private isEqual;
|
|
105
122
|
static ɵfac: i0.ɵɵFactoryDeclaration<MJReactComponent, never>;
|
|
106
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<MJReactComponent, "mj-react-component", never, { "component": { "alias": "component"; "required": false; }; "data": { "alias": "data"; "required": false; }; "state": { "alias": "state"; "required": false; }; "utilities": { "alias": "utilities"; "required": false; }; "styles": { "alias": "styles"; "required": false; }; }, { "stateChange": "stateChange"; "componentEvent": "componentEvent"; "refreshData": "refreshData"; "openEntityRecord": "openEntityRecord"; }, never, never, false, never>;
|
|
123
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MJReactComponent, "mj-react-component", never, { "component": { "alias": "component"; "required": false; }; "data": { "alias": "data"; "required": false; }; "state": { "alias": "state"; "required": false; }; "utilities": { "alias": "utilities"; "required": false; }; "styles": { "alias": "styles"; "required": false; }; "savedUserSettings": { "alias": "savedUserSettings"; "required": false; }; }, { "stateChange": "stateChange"; "componentEvent": "componentEvent"; "refreshData": "refreshData"; "openEntityRecord": "openEntityRecord"; "userSettingsChanged": "userSettingsChanged"; }, never, never, false, never>;
|
|
107
124
|
}
|
|
@@ -8,7 +8,7 @@ import { Subject } from 'rxjs';
|
|
|
8
8
|
import { ComponentSpec } from '@memberjunction/interactive-component-types';
|
|
9
9
|
import { ReactBridgeService } from '../services/react-bridge.service';
|
|
10
10
|
import { AngularAdapterService } from '../services/angular-adapter.service';
|
|
11
|
-
import {
|
|
11
|
+
import { createErrorBoundary, ComponentHierarchyRegistrar, resourceManager, reactRootManager } from '@memberjunction/react-runtime';
|
|
12
12
|
import { LogError, CompositeKey } from '@memberjunction/core';
|
|
13
13
|
import * as i0 from "@angular/core";
|
|
14
14
|
import * as i1 from "../services/react-bridge.service";
|
|
@@ -51,6 +51,16 @@ export class MJReactComponent {
|
|
|
51
51
|
get state() {
|
|
52
52
|
return this._state;
|
|
53
53
|
}
|
|
54
|
+
set savedUserSettings(value) {
|
|
55
|
+
this._savedUserSettings = value || {};
|
|
56
|
+
// Re-render if component is initialized
|
|
57
|
+
if (this.isInitialized) {
|
|
58
|
+
this.renderComponent();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
get savedUserSettings() {
|
|
62
|
+
return this._savedUserSettings;
|
|
63
|
+
}
|
|
54
64
|
constructor(reactBridge, adapter, cdr) {
|
|
55
65
|
this.reactBridge = reactBridge;
|
|
56
66
|
this.adapter = adapter;
|
|
@@ -58,11 +68,13 @@ export class MJReactComponent {
|
|
|
58
68
|
this._data = {};
|
|
59
69
|
this._state = {};
|
|
60
70
|
this.utilities = {};
|
|
71
|
+
this._savedUserSettings = {};
|
|
61
72
|
this.stateChange = new EventEmitter();
|
|
62
73
|
this.componentEvent = new EventEmitter();
|
|
63
74
|
this.refreshData = new EventEmitter();
|
|
64
75
|
this.openEntityRecord = new EventEmitter();
|
|
65
|
-
this.
|
|
76
|
+
this.userSettingsChanged = new EventEmitter();
|
|
77
|
+
this.reactRootId = null;
|
|
66
78
|
this.compiledComponent = null;
|
|
67
79
|
this.destroyed$ = new Subject();
|
|
68
80
|
this.currentCallbacks = null;
|
|
@@ -71,8 +83,9 @@ export class MJReactComponent {
|
|
|
71
83
|
this.isRendering = false;
|
|
72
84
|
this.pendingRender = false;
|
|
73
85
|
this.isDestroying = false;
|
|
74
|
-
this.renderTimeout = null;
|
|
75
86
|
this.hasError = false;
|
|
87
|
+
// Generate unique component ID for resource tracking
|
|
88
|
+
this.componentId = `mj-react-component-${Date.now()}-${Math.random()}`;
|
|
76
89
|
}
|
|
77
90
|
async ngAfterViewInit() {
|
|
78
91
|
// Trigger change detection to show loading state
|
|
@@ -112,8 +125,12 @@ export class MJReactComponent {
|
|
|
112
125
|
const context = this.adapter.getRuntimeContext();
|
|
113
126
|
this.compiledComponent = result.component.component(context, this.styles);
|
|
114
127
|
this.currentState = { ...this._state };
|
|
115
|
-
// Create React root
|
|
116
|
-
|
|
128
|
+
// Create managed React root
|
|
129
|
+
const reactContext = this.reactBridge.getCurrentContext();
|
|
130
|
+
if (!reactContext) {
|
|
131
|
+
throw new Error('React context not available');
|
|
132
|
+
}
|
|
133
|
+
this.reactRootId = reactRootManager.createRoot(this.container.nativeElement, (container) => reactContext.ReactDOM.createRoot(container), this.componentId);
|
|
117
134
|
// Initial render
|
|
118
135
|
this.renderComponent();
|
|
119
136
|
this.isInitialized = true;
|
|
@@ -160,7 +177,7 @@ export class MJReactComponent {
|
|
|
160
177
|
if (this.isDestroying) {
|
|
161
178
|
return;
|
|
162
179
|
}
|
|
163
|
-
if (!this.compiledComponent || !this.
|
|
180
|
+
if (!this.compiledComponent || !this.reactRootId) {
|
|
164
181
|
return;
|
|
165
182
|
}
|
|
166
183
|
// Prevent concurrent renders
|
|
@@ -180,10 +197,16 @@ export class MJReactComponent {
|
|
|
180
197
|
if (!this.currentCallbacks) {
|
|
181
198
|
this.currentCallbacks = this.createCallbacks();
|
|
182
199
|
}
|
|
183
|
-
// Build props
|
|
184
|
-
const props =
|
|
185
|
-
|
|
186
|
-
|
|
200
|
+
// Build props with savedUserSettings pattern
|
|
201
|
+
const props = {
|
|
202
|
+
...this._data, // Spread data properties directly
|
|
203
|
+
utilities: this.utilities || {},
|
|
204
|
+
callbacks: this.currentCallbacks,
|
|
205
|
+
components,
|
|
206
|
+
styles: this.styles,
|
|
207
|
+
savedUserSettings: this._savedUserSettings,
|
|
208
|
+
onSaveUserSettings: this.handleSaveUserSettings.bind(this)
|
|
209
|
+
};
|
|
187
210
|
// Create error boundary
|
|
188
211
|
const ErrorBoundary = createErrorBoundary(React, {
|
|
189
212
|
onError: this.handleReactError.bind(this),
|
|
@@ -192,12 +215,8 @@ export class MJReactComponent {
|
|
|
192
215
|
});
|
|
193
216
|
// Create element with error boundary
|
|
194
217
|
const element = React.createElement(ErrorBoundary, null, React.createElement(this.compiledComponent.component, props));
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
clearTimeout(this.renderTimeout);
|
|
198
|
-
}
|
|
199
|
-
// Render with timeout protection
|
|
200
|
-
this.renderTimeout = setTimeout(() => {
|
|
218
|
+
// Render with timeout protection using resource manager
|
|
219
|
+
const timeoutId = resourceManager.setTimeout(this.componentId, () => {
|
|
201
220
|
// Check if still rendering and not destroyed
|
|
202
221
|
if (this.isRendering && !this.isDestroying) {
|
|
203
222
|
this.componentEvent.emit({
|
|
@@ -208,40 +227,28 @@ export class MJReactComponent {
|
|
|
208
227
|
}
|
|
209
228
|
});
|
|
210
229
|
}
|
|
211
|
-
}, 5000);
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
this.
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
this.isRendering = false;
|
|
223
|
-
// If there was a pending render request, execute it now
|
|
224
|
-
if (this.pendingRender) {
|
|
225
|
-
this.pendingRender = false;
|
|
226
|
-
this.renderComponent();
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
catch (error) {
|
|
231
|
-
clearTimeout(this.renderTimeout);
|
|
232
|
-
this.renderTimeout = null;
|
|
230
|
+
}, 5000, { purpose: 'render-timeout-protection' });
|
|
231
|
+
// Use managed React root for rendering
|
|
232
|
+
reactRootManager.render(this.reactRootId, element, () => {
|
|
233
|
+
// Clear the timeout as render completed
|
|
234
|
+
resourceManager.clearTimeout(this.componentId, timeoutId);
|
|
235
|
+
// Don't update state if component is destroyed
|
|
236
|
+
if (this.isDestroying) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
233
239
|
this.isRendering = false;
|
|
234
|
-
|
|
235
|
-
|
|
240
|
+
// If there was a pending render request, execute it now
|
|
241
|
+
if (this.pendingRender) {
|
|
242
|
+
this.pendingRender = false;
|
|
243
|
+
this.renderComponent();
|
|
244
|
+
}
|
|
245
|
+
});
|
|
236
246
|
}
|
|
237
247
|
/**
|
|
238
248
|
* Create callbacks for the React component
|
|
239
249
|
*/
|
|
240
250
|
createCallbacks() {
|
|
241
251
|
return {
|
|
242
|
-
RefreshData: () => {
|
|
243
|
-
this.refreshData.emit();
|
|
244
|
-
},
|
|
245
252
|
OpenEntityRecord: (entityName, key) => {
|
|
246
253
|
let keyToUse = null;
|
|
247
254
|
if (key instanceof Array) {
|
|
@@ -262,35 +269,6 @@ export class MJReactComponent {
|
|
|
262
269
|
if (keyToUse) {
|
|
263
270
|
this.openEntityRecord.emit({ entityName, key: keyToUse });
|
|
264
271
|
}
|
|
265
|
-
},
|
|
266
|
-
UpdateUserState: (userState) => {
|
|
267
|
-
// Prevent updates during rendering or destruction
|
|
268
|
-
if (this.isRendering || this.isDestroying) {
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
// Deep comparison to detect actual changes
|
|
272
|
-
const hasChanges = Object.keys(userState).some(key => {
|
|
273
|
-
const currentValue = this.currentState[key];
|
|
274
|
-
const newValue = userState[key];
|
|
275
|
-
return !this.isEqual(currentValue, newValue);
|
|
276
|
-
});
|
|
277
|
-
if (!hasChanges) {
|
|
278
|
-
// No actual changes, skip update to prevent infinite loop
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
this.currentState = {
|
|
282
|
-
...this.currentState,
|
|
283
|
-
...userState
|
|
284
|
-
};
|
|
285
|
-
// Emit change for each key in the state update
|
|
286
|
-
Object.keys(userState).forEach(path => {
|
|
287
|
-
this.stateChange.emit({ path, value: userState[path] });
|
|
288
|
-
});
|
|
289
|
-
// Schedule re-render
|
|
290
|
-
this.renderComponent();
|
|
291
|
-
},
|
|
292
|
-
NotifyEvent: (event, data) => {
|
|
293
|
-
this.componentEvent.emit({ type: event, payload: data });
|
|
294
272
|
}
|
|
295
273
|
};
|
|
296
274
|
}
|
|
@@ -308,30 +286,46 @@ export class MJReactComponent {
|
|
|
308
286
|
}
|
|
309
287
|
});
|
|
310
288
|
}
|
|
289
|
+
/**
|
|
290
|
+
* Handle onSaveUserSettings from components
|
|
291
|
+
* This implements the SavedUserSettings pattern
|
|
292
|
+
*/
|
|
293
|
+
handleSaveUserSettings(newSettings) {
|
|
294
|
+
// Check if there are actual changes
|
|
295
|
+
const hasChanges = !this.isEqual(this._savedUserSettings, newSettings);
|
|
296
|
+
if (!hasChanges) {
|
|
297
|
+
// No actual changes, skip update to prevent infinite loop
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
// Update saved settings
|
|
301
|
+
this._savedUserSettings = { ...newSettings };
|
|
302
|
+
// Emit user settings changed event
|
|
303
|
+
this.userSettingsChanged.emit({
|
|
304
|
+
settings: this._savedUserSettings,
|
|
305
|
+
componentName: this.component?.name,
|
|
306
|
+
timestamp: new Date()
|
|
307
|
+
});
|
|
308
|
+
// Schedule re-render
|
|
309
|
+
this.renderComponent();
|
|
310
|
+
}
|
|
311
311
|
/**
|
|
312
312
|
* Clean up resources
|
|
313
313
|
*/
|
|
314
314
|
cleanup() {
|
|
315
|
-
//
|
|
316
|
-
|
|
317
|
-
clearTimeout(this.renderTimeout);
|
|
318
|
-
this.renderTimeout = null;
|
|
319
|
-
}
|
|
315
|
+
// Clean up all resources managed by resource manager
|
|
316
|
+
resourceManager.cleanupComponent(this.componentId);
|
|
320
317
|
// Clean up prop builder subscriptions
|
|
321
318
|
if (this.currentCallbacks) {
|
|
322
|
-
cleanupPropBuilder(this.currentCallbacks);
|
|
323
319
|
this.currentCallbacks = null;
|
|
324
320
|
}
|
|
325
|
-
// Unmount React root
|
|
326
|
-
if (this.
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
this.reactBridge.unmountRoot(this.reactRoot);
|
|
334
|
-
this.reactRoot = null;
|
|
321
|
+
// Unmount React root using managed unmount
|
|
322
|
+
if (this.reactRootId) {
|
|
323
|
+
// Force stop rendering flags
|
|
324
|
+
this.isRendering = false;
|
|
325
|
+
this.pendingRender = false;
|
|
326
|
+
// This will handle waiting for render completion if needed
|
|
327
|
+
reactRootManager.unmountRoot(this.reactRootId);
|
|
328
|
+
this.reactRootId = null;
|
|
335
329
|
}
|
|
336
330
|
// Clear references
|
|
337
331
|
this.compiledComponent = null;
|
|
@@ -387,7 +381,7 @@ export class MJReactComponent {
|
|
|
387
381
|
} if (rf & 2) {
|
|
388
382
|
let _t;
|
|
389
383
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.container = _t.first);
|
|
390
|
-
} }, inputs: { component: "component", data: "data", state: "state", utilities: "utilities", styles: "styles" }, outputs: { stateChange: "stateChange", componentEvent: "componentEvent", refreshData: "refreshData", openEntityRecord: "openEntityRecord" }, decls: 4, vars: 3, consts: [["container", ""], [1, "react-component-wrapper"], [1, "react-component-container"], [1, "loading-overlay"], [1, "loading-spinner"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "loading-text"]], template: function MJReactComponent_Template(rf, ctx) { if (rf & 1) {
|
|
384
|
+
} }, inputs: { component: "component", data: "data", state: "state", utilities: "utilities", styles: "styles", savedUserSettings: "savedUserSettings" }, outputs: { stateChange: "stateChange", componentEvent: "componentEvent", refreshData: "refreshData", openEntityRecord: "openEntityRecord", userSettingsChanged: "userSettingsChanged" }, decls: 4, vars: 3, consts: [["container", ""], [1, "react-component-wrapper"], [1, "react-component-container"], [1, "loading-overlay"], [1, "loading-spinner"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "loading-text"]], template: function MJReactComponent_Template(rf, ctx) { if (rf & 1) {
|
|
391
385
|
i0.ɵɵelementStart(0, "div", 1);
|
|
392
386
|
i0.ɵɵelement(1, "div", 2, 0);
|
|
393
387
|
i0.ɵɵtemplate(3, MJReactComponent_Conditional_3_Template, 5, 0, "div", 3);
|
|
@@ -424,6 +418,8 @@ export class MJReactComponent {
|
|
|
424
418
|
type: Input
|
|
425
419
|
}], styles: [{
|
|
426
420
|
type: Input
|
|
421
|
+
}], savedUserSettings: [{
|
|
422
|
+
type: Input
|
|
427
423
|
}], stateChange: [{
|
|
428
424
|
type: Output
|
|
429
425
|
}], componentEvent: [{
|
|
@@ -432,9 +428,11 @@ export class MJReactComponent {
|
|
|
432
428
|
type: Output
|
|
433
429
|
}], openEntityRecord: [{
|
|
434
430
|
type: Output
|
|
431
|
+
}], userSettingsChanged: [{
|
|
432
|
+
type: Output
|
|
435
433
|
}], container: [{
|
|
436
434
|
type: ViewChild,
|
|
437
435
|
args: ['container', { read: ElementRef, static: true }]
|
|
438
436
|
}] }); })();
|
|
439
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJReactComponent, { className: "MJReactComponent", filePath: "lib/components/mj-react-component.component.ts", lineNumber:
|
|
437
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJReactComponent, { className: "MJReactComponent", filePath: "lib/components/mj-react-component.component.ts", lineNumber: 124 }); })();
|
|
440
438
|
//# sourceMappingURL=mj-react-component.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mj-react-component.component.js","sourceRoot":"","sources":["../../../src/lib/components/mj-react-component.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Angular component that hosts React components with proper memory management.\n * Provides a bridge between Angular and React ecosystems in MemberJunction applications.\n * @module @memberjunction/ng-react\n */\n\nimport {\n Component,\n Input,\n Output,\n EventEmitter,\n ViewChild,\n ElementRef,\n AfterViewInit,\n OnDestroy,\n ChangeDetectionStrategy,\n ChangeDetectorRef\n} from '@angular/core';\nimport { Subject, takeUntil } from 'rxjs';\nimport { ComponentSpec, ComponentCallbacks, ComponentStyles } from '@memberjunction/interactive-component-types';\nimport { ReactBridgeService } from '../services/react-bridge.service';\nimport { AngularAdapterService } from '../services/angular-adapter.service';\nimport { \n buildComponentProps,\n cleanupPropBuilder,\n ComponentError,\n createErrorBoundary,\n ComponentHierarchyRegistrar,\n HierarchyRegistrationResult\n} from '@memberjunction/react-runtime';\nimport { LogError, CompositeKey, KeyValuePair } from '@memberjunction/core';\n\n/**\n * Event emitted by React components\n */\nexport interface ReactComponentEvent {\n type: string;\n payload: any;\n}\n\n/**\n * State change event emitted when component state updates\n */\nexport interface StateChangeEvent {\n path: string;\n value: any;\n}\n\n/**\n * Angular component that hosts React components with proper memory management.\n * This component provides a bridge between Angular and React, allowing React components\n * to be used seamlessly within Angular applications.\n */\n@Component({\n selector: 'mj-react-component',\n template: `\n <div class=\"react-component-wrapper\">\n <div #container class=\"react-component-container\" [class.loading]=\"!isInitialized\"></div>\n @if (!isInitialized && !hasError) {\n <div class=\"loading-overlay\">\n <div class=\"loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </div>\n <div class=\"loading-text\">Loading component...</div>\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n .react-component-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n }\n .react-component-container {\n width: 100%;\n height: 100%;\n transition: opacity 0.3s ease;\n }\n .react-component-container.loading {\n opacity: 0;\n }\n .loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.9);\n z-index: 1;\n }\n .loading-spinner {\n font-size: 48px;\n color: #5B4FE9;\n margin-bottom: 16px;\n }\n .loading-text {\n font-family: -apple-system, BlinkMacSystemFont, \"Inter\", \"Segoe UI\", Roboto, sans-serif;\n font-size: 14px;\n color: #64748B;\n margin-top: 8px;\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class MJReactComponent implements AfterViewInit, OnDestroy {\n @Input() component!: ComponentSpec;\n \n private _data: any = {};\n @Input() \n set data(value: any) {\n const oldData = this._data;\n this._data = value;\n \n // Only re-render if data actually changed and component is initialized\n if (this.isInitialized && !this.isEqual(oldData, value)) {\n this.renderComponent();\n }\n }\n get data(): any {\n return this._data;\n }\n \n private _state: any = {};\n @Input() \n set state(value: any) {\n const oldState = this._state;\n this._state = value;\n \n // Only update state and re-render if it actually changed\n if (this.isInitialized && !this.isEqual(oldState, value)) {\n this.currentState = { ...value };\n this.renderComponent();\n }\n }\n get state(): any {\n return this._state;\n }\n \n @Input() utilities: any = {};\n @Input() styles?: Partial<ComponentStyles>;\n \n @Output() stateChange = new EventEmitter<StateChangeEvent>();\n @Output() componentEvent = new EventEmitter<ReactComponentEvent>();\n @Output() refreshData = new EventEmitter<void>();\n @Output() openEntityRecord = new EventEmitter<{ entityName: string; key: CompositeKey }>();\n \n @ViewChild('container', { read: ElementRef, static: true }) container!: ElementRef<HTMLDivElement>;\n \n private reactRoot: any = null;\n private compiledComponent: any = null;\n private destroyed$ = new Subject<void>();\n private currentCallbacks: ComponentCallbacks | null = null;\n private currentState: any = {};\n isInitialized = false;\n private isRendering = false;\n private pendingRender = false;\n private isDestroying = false;\n private renderTimeout: any = null;\n hasError = false;\n\n constructor(\n private reactBridge: ReactBridgeService,\n private adapter: AngularAdapterService,\n private cdr: ChangeDetectorRef\n ) {}\n\n async ngAfterViewInit() {\n // Trigger change detection to show loading state\n this.cdr.detectChanges();\n await this.initializeComponent();\n }\n\n ngOnDestroy() {\n // Set destroying flag immediately\n this.isDestroying = true;\n \n // Cancel any pending renders\n this.pendingRender = false;\n \n this.destroyed$.next();\n this.destroyed$.complete();\n this.cleanup();\n }\n\n\n /**\n * Initialize the React component\n */\n private async initializeComponent() {\n try {\n // Ensure React is loaded\n await this.reactBridge.getReactContext();\n \n // Wait for React to be fully ready (handles first-load delay)\n await this.reactBridge.waitForReactReady();\n \n // Register component hierarchy\n await this.registerComponentHierarchy();\n \n // Compile main component\n const result = await this.adapter.compileComponent({\n componentName: this.component.name,\n componentCode: this.component.code,\n styles: this.styles\n });\n\n if (!result.success) {\n throw new Error(result.error?.message || 'Component compilation failed');\n }\n\n // Get runtime context and execute component factory\n const context = this.adapter.getRuntimeContext();\n this.compiledComponent = result.component!.component(context, this.styles);\n this.currentState = { ...this._state };\n \n // Create React root\n this.reactRoot = this.reactBridge.createRoot(this.container.nativeElement);\n \n // Initial render\n this.renderComponent();\n this.isInitialized = true;\n \n // Trigger change detection since we're using OnPush\n this.cdr.detectChanges();\n \n } catch (error) {\n this.hasError = true;\n LogError(`Failed to initialize React component: ${error}`);\n this.componentEvent.emit({\n type: 'error',\n payload: {\n error: error instanceof Error ? error.message : String(error),\n source: 'initialization'\n }\n });\n // Trigger change detection to show error state\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Register all components in the hierarchy\n */\n private async registerComponentHierarchy() {\n // Create the hierarchy registrar with adapter's compiler and registry\n const registrar = new ComponentHierarchyRegistrar(\n this.adapter.getCompiler(),\n this.adapter.getRegistry(),\n this.adapter.getRuntimeContext()\n );\n \n // Register the entire hierarchy\n const result: HierarchyRegistrationResult = await registrar.registerHierarchy(\n this.component,\n {\n styles: this.styles as any, // Skip components use SkipComponentStyles which is a superset\n namespace: 'Global',\n version: 'v1'\n }\n );\n \n // Check for errors\n if (!result.success) {\n const errorMessages = result.errors.map(e => \n `${e.componentName}: ${e.error}`\n );\n throw new Error(`Component registration failed: ${errorMessages.join(', ')}`);\n }\n }\n\n /**\n * Render the React component\n */\n private renderComponent() {\n // Don't render if component is being destroyed\n if (this.isDestroying) {\n return;\n }\n \n if (!this.compiledComponent || !this.reactRoot) {\n return;\n }\n\n // Prevent concurrent renders\n if (this.isRendering) {\n this.pendingRender = true;\n return;\n }\n\n const context = this.reactBridge.getCurrentContext();\n if (!context) {\n return;\n }\n\n this.isRendering = true;\n const { React } = context;\n \n // Get components from resolver\n const components = this.adapter.getResolver().resolveComponents(this.component);\n \n // Create callbacks once per component instance\n if (!this.currentCallbacks) {\n this.currentCallbacks = this.createCallbacks();\n }\n \n // Build props - pass styles as-is for Skip components\n const props = buildComponentProps(\n this._data || {},\n this.currentState,\n this.utilities || {},\n this.currentCallbacks,\n components,\n this.styles as any, // Skip components expect the full SkipComponentStyles structure\n { debounceUpdateUserState: 3000 } // 3 second debounce by default\n );\n\n // Create error boundary\n const ErrorBoundary = createErrorBoundary(React, {\n onError: this.handleReactError.bind(this),\n logErrors: true,\n recovery: 'retry'\n });\n\n // Create element with error boundary\n const element = React.createElement(\n ErrorBoundary,\n null,\n React.createElement(this.compiledComponent.component, props)\n );\n\n // Clear any existing render timeout\n if (this.renderTimeout) {\n clearTimeout(this.renderTimeout);\n }\n \n // Render with timeout protection\n this.renderTimeout = setTimeout(() => {\n // Check if still rendering and not destroyed\n if (this.isRendering && !this.isDestroying) {\n this.componentEvent.emit({\n type: 'error',\n payload: {\n error: 'Component render timeout - possible infinite loop detected',\n source: 'render'\n }\n });\n }\n }, 5000);\n\n try {\n this.reactRoot.render(element);\n clearTimeout(this.renderTimeout);\n this.renderTimeout = null;\n \n // Reset rendering flag after a microtask to allow React to complete\n Promise.resolve().then(() => {\n // Don't update state if component is destroyed\n if (this.isDestroying) {\n return;\n }\n \n this.isRendering = false;\n \n // If there was a pending render request, execute it now\n if (this.pendingRender) {\n this.pendingRender = false;\n this.renderComponent();\n }\n });\n } catch (error) {\n clearTimeout(this.renderTimeout);\n this.renderTimeout = null;\n this.isRendering = false;\n this.handleReactError(error);\n }\n }\n\n /**\n * Create callbacks for the React component\n */\n private createCallbacks(): ComponentCallbacks {\n return {\n RefreshData: () => {\n this.refreshData.emit();\n },\n OpenEntityRecord: (entityName: string, key: CompositeKey) => {\n let keyToUse: CompositeKey | null = null;\n if (key instanceof Array) {\n keyToUse = CompositeKey.FromKeyValuePairs(key);\n }\n else if (typeof key === 'object' && !!key.GetValueByFieldName) {\n keyToUse = key as CompositeKey;\n }\n else if (typeof key === 'object') {\n //} && !!key.FieldName && !!key.Value) {\n // possible that have an object that is a simple key/value pair with\n // FieldName and value properties\n const keyAny = key as any;\n if (keyAny.FieldName && keyAny.Value) {\n keyToUse = CompositeKey.FromKeyValuePairs([keyAny as KeyValuePair]);\n }\n }\n if (keyToUse) {\n this.openEntityRecord.emit({ entityName, key: keyToUse });\n } \n },\n UpdateUserState: (userState: any) => {\n // Prevent updates during rendering or destruction\n if (this.isRendering || this.isDestroying) {\n return;\n }\n \n // Deep comparison to detect actual changes\n const hasChanges = Object.keys(userState).some(key => {\n const currentValue = this.currentState[key];\n const newValue = userState[key];\n return !this.isEqual(currentValue, newValue);\n });\n \n if (!hasChanges) {\n // No actual changes, skip update to prevent infinite loop\n return;\n }\n \n this.currentState = {\n ...this.currentState,\n ...userState\n };\n \n // Emit change for each key in the state update\n Object.keys(userState).forEach(path => {\n this.stateChange.emit({ path, value: userState[path] });\n });\n \n // Schedule re-render\n this.renderComponent();\n },\n NotifyEvent: (event: string, data: any) => {\n this.componentEvent.emit({ type: event, payload: data });\n }\n };\n }\n\n /**\n * Handle React component errors\n */\n private handleReactError(error: any, errorInfo?: any) {\n LogError(`React component error: ${error?.toString() || 'Unknown error'}`, errorInfo);\n this.componentEvent.emit({\n type: 'error',\n payload: {\n error: error?.toString() || 'Unknown error',\n errorInfo,\n source: 'react'\n }\n });\n }\n\n /**\n * Clean up resources\n */\n private cleanup() {\n // Clear any pending render timeout\n if (this.renderTimeout) {\n clearTimeout(this.renderTimeout);\n this.renderTimeout = null;\n }\n \n // Clean up prop builder subscriptions\n if (this.currentCallbacks) {\n cleanupPropBuilder(this.currentCallbacks);\n this.currentCallbacks = null;\n }\n \n // Unmount React root only if not currently rendering\n if (this.reactRoot) {\n // If still rendering, wait for completion before unmounting\n if (this.isRendering) {\n // Force stop rendering\n this.isRendering = false;\n this.pendingRender = false;\n }\n \n this.reactBridge.unmountRoot(this.reactRoot);\n this.reactRoot = null;\n }\n\n // Clear references\n this.compiledComponent = null;\n this.currentState = {};\n this.isInitialized = false;\n\n // Trigger registry cleanup\n this.adapter.getRegistry().cleanup();\n }\n\n /**\n * Public method to refresh the component\n * @param newData - Optional new data to merge\n */\n refresh(newData?: any) {\n if (newData) {\n // Use the setter to trigger change detection\n this.data = { ...this._data, ...newData };\n } else {\n this.renderComponent();\n }\n }\n\n /**\n * Public method to update state programmatically\n * @param path - State path to update\n * @param value - New value\n */\n updateState(path: string, value: any) {\n this.currentState = {\n ...this.currentState,\n [path]: value\n };\n this.stateChange.emit({ path, value });\n this.renderComponent();\n }\n\n /**\n * Deep equality check that handles null/undefined properly\n */\n private isEqual(a: any, b: any): boolean {\n // Handle null/undefined cases\n if (a === b) return true;\n if (a == null || b == null) return false;\n \n // For objects/arrays, use JSON comparison\n if (typeof a === 'object' && typeof b === 'object') {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n \n return a === b;\n }\n}"]}
|
|
1
|
+
{"version":3,"file":"mj-react-component.component.js","sourceRoot":"","sources":["../../../src/lib/components/mj-react-component.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Angular component that hosts React components with proper memory management.\n * Provides a bridge between Angular and React ecosystems in MemberJunction applications.\n * @module @memberjunction/ng-react\n */\n\nimport {\n Component,\n Input,\n Output,\n EventEmitter,\n ViewChild,\n ElementRef,\n AfterViewInit,\n OnDestroy,\n ChangeDetectionStrategy,\n ChangeDetectorRef\n} from '@angular/core';\nimport { Subject, takeUntil } from 'rxjs';\nimport { ComponentSpec, ComponentCallbacks, ComponentStyles } from '@memberjunction/interactive-component-types';\nimport { ReactBridgeService } from '../services/react-bridge.service';\nimport { AngularAdapterService } from '../services/angular-adapter.service';\nimport { \n buildComponentProps,\n createErrorBoundary,\n ComponentHierarchyRegistrar,\n HierarchyRegistrationResult,\n resourceManager,\n reactRootManager\n} from '@memberjunction/react-runtime';\nimport { LogError, CompositeKey, KeyValuePair } from '@memberjunction/core';\n\n/**\n * Event emitted by React components\n */\nexport interface ReactComponentEvent {\n type: string;\n payload: any;\n}\n\n/**\n * State change event emitted when component state updates\n */\nexport interface StateChangeEvent {\n path: string;\n value: any;\n}\n\n/**\n * User settings changed event emitted when component saves user preferences\n */\nexport interface UserSettingsChangedEvent {\n settings: Record<string, any>;\n componentName?: string;\n timestamp: Date;\n}\n\n/**\n * Angular component that hosts React components with proper memory management.\n * This component provides a bridge between Angular and React, allowing React components\n * to be used seamlessly within Angular applications.\n */\n@Component({\n selector: 'mj-react-component',\n template: `\n <div class=\"react-component-wrapper\">\n <div #container class=\"react-component-container\" [class.loading]=\"!isInitialized\"></div>\n @if (!isInitialized && !hasError) {\n <div class=\"loading-overlay\">\n <div class=\"loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </div>\n <div class=\"loading-text\">Loading component...</div>\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n .react-component-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n }\n .react-component-container {\n width: 100%;\n height: 100%;\n transition: opacity 0.3s ease;\n }\n .react-component-container.loading {\n opacity: 0;\n }\n .loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.9);\n z-index: 1;\n }\n .loading-spinner {\n font-size: 48px;\n color: #5B4FE9;\n margin-bottom: 16px;\n }\n .loading-text {\n font-family: -apple-system, BlinkMacSystemFont, \"Inter\", \"Segoe UI\", Roboto, sans-serif;\n font-size: 14px;\n color: #64748B;\n margin-top: 8px;\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class MJReactComponent implements AfterViewInit, OnDestroy {\n @Input() component!: ComponentSpec;\n \n private _data: any = {};\n @Input() \n set data(value: any) {\n const oldData = this._data;\n this._data = value;\n \n // Only re-render if data actually changed and component is initialized\n if (this.isInitialized && !this.isEqual(oldData, value)) {\n this.renderComponent();\n }\n }\n get data(): any {\n return this._data;\n }\n \n private _state: any = {};\n @Input() \n set state(value: any) {\n const oldState = this._state;\n this._state = value;\n \n // Only update state and re-render if it actually changed\n if (this.isInitialized && !this.isEqual(oldState, value)) {\n this.currentState = { ...value };\n this.renderComponent();\n }\n }\n get state(): any {\n return this._state;\n }\n \n @Input() utilities: any = {};\n @Input() styles?: Partial<ComponentStyles>;\n \n private _savedUserSettings: any = {};\n @Input()\n set savedUserSettings(value: any) {\n this._savedUserSettings = value || {};\n // Re-render if component is initialized\n if (this.isInitialized) {\n this.renderComponent();\n }\n }\n get savedUserSettings(): any {\n return this._savedUserSettings;\n }\n \n @Output() stateChange = new EventEmitter<StateChangeEvent>();\n @Output() componentEvent = new EventEmitter<ReactComponentEvent>();\n @Output() refreshData = new EventEmitter<void>();\n @Output() openEntityRecord = new EventEmitter<{ entityName: string; key: CompositeKey }>();\n @Output() userSettingsChanged = new EventEmitter<UserSettingsChangedEvent>();\n \n @ViewChild('container', { read: ElementRef, static: true }) container!: ElementRef<HTMLDivElement>;\n \n private reactRootId: string | null = null;\n private compiledComponent: any = null;\n private destroyed$ = new Subject<void>();\n private currentCallbacks: ComponentCallbacks | null = null;\n private currentState: any = {};\n isInitialized = false;\n private isRendering = false;\n private pendingRender = false;\n private isDestroying = false;\n private componentId: string;\n hasError = false;\n\n constructor(\n private reactBridge: ReactBridgeService,\n private adapter: AngularAdapterService,\n private cdr: ChangeDetectorRef\n ) {\n // Generate unique component ID for resource tracking\n this.componentId = `mj-react-component-${Date.now()}-${Math.random()}`;\n }\n\n async ngAfterViewInit() {\n // Trigger change detection to show loading state\n this.cdr.detectChanges();\n await this.initializeComponent();\n }\n\n ngOnDestroy() {\n // Set destroying flag immediately\n this.isDestroying = true;\n \n // Cancel any pending renders\n this.pendingRender = false;\n \n this.destroyed$.next();\n this.destroyed$.complete();\n this.cleanup();\n }\n\n\n /**\n * Initialize the React component\n */\n private async initializeComponent() {\n try {\n // Ensure React is loaded\n await this.reactBridge.getReactContext();\n \n // Wait for React to be fully ready (handles first-load delay)\n await this.reactBridge.waitForReactReady();\n \n // Register component hierarchy\n await this.registerComponentHierarchy();\n \n // Compile main component\n const result = await this.adapter.compileComponent({\n componentName: this.component.name,\n componentCode: this.component.code,\n styles: this.styles\n });\n\n if (!result.success) {\n throw new Error(result.error?.message || 'Component compilation failed');\n }\n\n // Get runtime context and execute component factory\n const context = this.adapter.getRuntimeContext();\n this.compiledComponent = result.component!.component(context, this.styles);\n this.currentState = { ...this._state };\n \n // Create managed React root\n const reactContext = this.reactBridge.getCurrentContext();\n if (!reactContext) {\n throw new Error('React context not available');\n }\n \n this.reactRootId = reactRootManager.createRoot(\n this.container.nativeElement,\n (container: HTMLElement) => reactContext.ReactDOM.createRoot(container),\n this.componentId\n );\n \n // Initial render\n this.renderComponent();\n this.isInitialized = true;\n \n // Trigger change detection since we're using OnPush\n this.cdr.detectChanges();\n \n } catch (error) {\n this.hasError = true;\n LogError(`Failed to initialize React component: ${error}`);\n this.componentEvent.emit({\n type: 'error',\n payload: {\n error: error instanceof Error ? error.message : String(error),\n source: 'initialization'\n }\n });\n // Trigger change detection to show error state\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Register all components in the hierarchy\n */\n private async registerComponentHierarchy() {\n // Create the hierarchy registrar with adapter's compiler and registry\n const registrar = new ComponentHierarchyRegistrar(\n this.adapter.getCompiler(),\n this.adapter.getRegistry(),\n this.adapter.getRuntimeContext()\n );\n \n // Register the entire hierarchy\n const result: HierarchyRegistrationResult = await registrar.registerHierarchy(\n this.component,\n {\n styles: this.styles as any, // Skip components use SkipComponentStyles which is a superset\n namespace: 'Global',\n version: 'v1'\n }\n );\n \n // Check for errors\n if (!result.success) {\n const errorMessages = result.errors.map(e => \n `${e.componentName}: ${e.error}`\n );\n throw new Error(`Component registration failed: ${errorMessages.join(', ')}`);\n }\n }\n\n /**\n * Render the React component\n */\n private renderComponent() {\n // Don't render if component is being destroyed\n if (this.isDestroying) {\n return;\n }\n \n if (!this.compiledComponent || !this.reactRootId) {\n return;\n }\n\n // Prevent concurrent renders\n if (this.isRendering) {\n this.pendingRender = true;\n return;\n }\n\n const context = this.reactBridge.getCurrentContext();\n if (!context) {\n return;\n }\n\n this.isRendering = true;\n const { React } = context;\n \n // Get components from resolver\n const components = this.adapter.getResolver().resolveComponents(this.component);\n \n // Create callbacks once per component instance\n if (!this.currentCallbacks) {\n this.currentCallbacks = this.createCallbacks();\n }\n \n // Build props with savedUserSettings pattern\n const props = {\n ...this._data, // Spread data properties directly\n utilities: this.utilities || {},\n callbacks: this.currentCallbacks,\n components,\n styles: this.styles as any,\n savedUserSettings: this._savedUserSettings,\n onSaveUserSettings: this.handleSaveUserSettings.bind(this)\n };\n\n // Create error boundary\n const ErrorBoundary = createErrorBoundary(React, {\n onError: this.handleReactError.bind(this),\n logErrors: true,\n recovery: 'retry'\n });\n\n // Create element with error boundary\n const element = React.createElement(\n ErrorBoundary,\n null,\n React.createElement(this.compiledComponent.component, props)\n );\n\n // Render with timeout protection using resource manager\n const timeoutId = resourceManager.setTimeout(\n this.componentId,\n () => {\n // Check if still rendering and not destroyed\n if (this.isRendering && !this.isDestroying) {\n this.componentEvent.emit({\n type: 'error',\n payload: {\n error: 'Component render timeout - possible infinite loop detected',\n source: 'render'\n }\n });\n }\n },\n 5000,\n { purpose: 'render-timeout-protection' }\n );\n\n // Use managed React root for rendering\n reactRootManager.render(\n this.reactRootId,\n element,\n () => {\n // Clear the timeout as render completed\n resourceManager.clearTimeout(this.componentId, timeoutId);\n \n // Don't update state if component is destroyed\n if (this.isDestroying) {\n return;\n }\n \n this.isRendering = false;\n \n // If there was a pending render request, execute it now\n if (this.pendingRender) {\n this.pendingRender = false;\n this.renderComponent();\n }\n }\n );\n }\n\n /**\n * Create callbacks for the React component\n */\n private createCallbacks(): ComponentCallbacks {\n return {\n OpenEntityRecord: (entityName: string, key: CompositeKey) => {\n let keyToUse: CompositeKey | null = null;\n if (key instanceof Array) {\n keyToUse = CompositeKey.FromKeyValuePairs(key);\n }\n else if (typeof key === 'object' && !!key.GetValueByFieldName) {\n keyToUse = key as CompositeKey;\n }\n else if (typeof key === 'object') {\n //} && !!key.FieldName && !!key.Value) {\n // possible that have an object that is a simple key/value pair with\n // FieldName and value properties\n const keyAny = key as any;\n if (keyAny.FieldName && keyAny.Value) {\n keyToUse = CompositeKey.FromKeyValuePairs([keyAny as KeyValuePair]);\n }\n }\n if (keyToUse) {\n this.openEntityRecord.emit({ entityName, key: keyToUse });\n } \n } \n };\n }\n\n /**\n * Handle React component errors\n */\n private handleReactError(error: any, errorInfo?: any) {\n LogError(`React component error: ${error?.toString() || 'Unknown error'}`, errorInfo);\n this.componentEvent.emit({\n type: 'error',\n payload: {\n error: error?.toString() || 'Unknown error',\n errorInfo,\n source: 'react'\n }\n });\n }\n\n /**\n * Handle onSaveUserSettings from components\n * This implements the SavedUserSettings pattern\n */\n private handleSaveUserSettings(newSettings: Record<string, any>) {\n // Check if there are actual changes\n const hasChanges = !this.isEqual(this._savedUserSettings, newSettings);\n \n if (!hasChanges) {\n // No actual changes, skip update to prevent infinite loop\n return;\n }\n \n // Update saved settings\n this._savedUserSettings = { ...newSettings };\n \n // Emit user settings changed event\n this.userSettingsChanged.emit({\n settings: this._savedUserSettings,\n componentName: this.component?.name,\n timestamp: new Date()\n });\n \n // Schedule re-render\n this.renderComponent();\n }\n\n /**\n * Clean up resources\n */\n private cleanup() {\n // Clean up all resources managed by resource manager\n resourceManager.cleanupComponent(this.componentId);\n \n // Clean up prop builder subscriptions\n if (this.currentCallbacks) {\n this.currentCallbacks = null;\n }\n \n // Unmount React root using managed unmount\n if (this.reactRootId) {\n // Force stop rendering flags\n this.isRendering = false;\n this.pendingRender = false;\n \n // This will handle waiting for render completion if needed\n reactRootManager.unmountRoot(this.reactRootId);\n this.reactRootId = null;\n }\n\n // Clear references\n this.compiledComponent = null;\n this.currentState = {};\n this.isInitialized = false;\n\n // Trigger registry cleanup\n this.adapter.getRegistry().cleanup();\n }\n\n /**\n * Public method to refresh the component\n * @param newData - Optional new data to merge\n */\n refresh(newData?: any) {\n if (newData) {\n // Use the setter to trigger change detection\n this.data = { ...this._data, ...newData };\n } else {\n this.renderComponent();\n }\n }\n\n /**\n * Public method to update state programmatically\n * @param path - State path to update\n * @param value - New value\n */\n updateState(path: string, value: any) {\n this.currentState = {\n ...this.currentState,\n [path]: value\n };\n this.stateChange.emit({ path, value });\n this.renderComponent();\n }\n\n /**\n * Deep equality check that handles null/undefined properly\n */\n private isEqual(a: any, b: any): boolean {\n // Handle null/undefined cases\n if (a === b) return true;\n if (a == null || b == null) return false;\n \n // For objects/arrays, use JSON comparison\n if (typeof a === 'object' && typeof b === 'object') {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n \n return a === b;\n }\n}"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentCompiler, ComponentRegistry, ComponentResolver, CompileOptions, RuntimeContext } from '@memberjunction/react-runtime';
|
|
1
|
+
import { ComponentCompiler, ComponentRegistry, ComponentResolver, CompileOptions, RuntimeContext, ExternalLibraryConfig, LibraryConfiguration } from '@memberjunction/react-runtime';
|
|
2
2
|
import { ScriptLoaderService } from './script-loader.service';
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
/**
|
|
@@ -12,9 +12,11 @@ export declare class AngularAdapterService {
|
|
|
12
12
|
constructor(scriptLoader: ScriptLoaderService);
|
|
13
13
|
/**
|
|
14
14
|
* Initialize the React runtime with Angular-specific configuration
|
|
15
|
+
* @param config Optional library configuration
|
|
16
|
+
* @param additionalLibraries Optional additional libraries to merge
|
|
15
17
|
* @returns Promise resolving when runtime is ready
|
|
16
18
|
*/
|
|
17
|
-
initialize(): Promise<void>;
|
|
19
|
+
initialize(config?: LibraryConfiguration, additionalLibraries?: ExternalLibraryConfig[]): Promise<void>;
|
|
18
20
|
/**
|
|
19
21
|
* Get the component compiler
|
|
20
22
|
* @returns Component compiler instance
|
|
@@ -19,14 +19,16 @@ export class AngularAdapterService {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Initialize the React runtime with Angular-specific configuration
|
|
22
|
+
* @param config Optional library configuration
|
|
23
|
+
* @param additionalLibraries Optional additional libraries to merge
|
|
22
24
|
* @returns Promise resolving when runtime is ready
|
|
23
25
|
*/
|
|
24
|
-
async initialize() {
|
|
26
|
+
async initialize(config, additionalLibraries) {
|
|
25
27
|
if (this.runtime) {
|
|
26
28
|
return; // Already initialized
|
|
27
29
|
}
|
|
28
|
-
// Load React ecosystem
|
|
29
|
-
const ecosystem = await this.scriptLoader.loadReactEcosystem();
|
|
30
|
+
// Load React ecosystem with optional additional libraries
|
|
31
|
+
const ecosystem = await this.scriptLoader.loadReactEcosystem(config, additionalLibraries);
|
|
30
32
|
// Create runtime context
|
|
31
33
|
this.runtimeContext = {
|
|
32
34
|
React: ecosystem.React,
|
|
@@ -111,6 +113,24 @@ export class AngularAdapterService {
|
|
|
111
113
|
* @returns Promise resolving to compilation result
|
|
112
114
|
*/
|
|
113
115
|
async compileComponent(options) {
|
|
116
|
+
// Validate options before initialization
|
|
117
|
+
if (!options) {
|
|
118
|
+
throw new Error('Angular adapter error: No compilation options provided.\n' +
|
|
119
|
+
'This usually means the component spec is null or undefined.\n' +
|
|
120
|
+
'Please check that:\n' +
|
|
121
|
+
'1. Your component data is loaded properly\n' +
|
|
122
|
+
'2. The component spec has "name" and "code" properties\n' +
|
|
123
|
+
'3. The component input is not undefined');
|
|
124
|
+
}
|
|
125
|
+
if (!options.componentName || options.componentName.trim() === '') {
|
|
126
|
+
throw new Error('Angular adapter error: Component name is missing or empty.\n' +
|
|
127
|
+
`Received options: ${JSON.stringify(options, null, 2)}\n` +
|
|
128
|
+
'Make sure your component spec includes a "name" property.');
|
|
129
|
+
}
|
|
130
|
+
if (!options.componentCode || options.componentCode.trim() === '') {
|
|
131
|
+
throw new Error(`Angular adapter error: Component code is missing or empty for component "${options.componentName}".\n` +
|
|
132
|
+
'Make sure your component spec includes a "code" property with the React component source.');
|
|
133
|
+
}
|
|
114
134
|
await this.initialize();
|
|
115
135
|
// Apply default styles if not provided
|
|
116
136
|
const optionsWithDefaults = {
|
|
@@ -1 +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}"]}
|
|
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 ExternalLibraryConfig,\n LibraryConfiguration\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 * @param config Optional library configuration\n * @param additionalLibraries Optional additional libraries to merge\n * @returns Promise resolving when runtime is ready\n */\n async initialize(\n config?: LibraryConfiguration,\n additionalLibraries?: ExternalLibraryConfig[]\n ): Promise<void> {\n if (this.runtime) {\n return; // Already initialized\n }\n\n // Load React ecosystem with optional additional libraries\n const ecosystem = await this.scriptLoader.loadReactEcosystem(config, additionalLibraries);\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 // Validate options before initialization\n if (!options) {\n throw new Error(\n 'Angular adapter error: No compilation options provided.\\n' +\n 'This usually means the component spec is null or undefined.\\n' +\n 'Please check that:\\n' +\n '1. Your component data is loaded properly\\n' +\n '2. The component spec has \"name\" and \"code\" properties\\n' +\n '3. The component input is not undefined'\n );\n }\n\n if (!options.componentName || options.componentName.trim() === '') {\n throw new Error(\n 'Angular adapter error: Component name is missing or empty.\\n' +\n `Received options: ${JSON.stringify(options, null, 2)}\\n` +\n 'Make sure your component spec includes a \"name\" property.'\n );\n }\n\n if (!options.componentCode || options.componentCode.trim() === '') {\n throw new Error(\n `Angular adapter error: Component code is missing or empty for component \"${options.componentName}\".\\n` +\n 'Make sure your component spec includes a \"code\" property with the React component source.'\n );\n }\n\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}"]}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @module @memberjunction/ng-react
|
|
5
5
|
*/
|
|
6
6
|
import { OnDestroy } from '@angular/core';
|
|
7
|
-
import { LibraryConfiguration } from '@memberjunction/react-runtime';
|
|
7
|
+
import { LibraryConfiguration, ExternalLibraryConfig } from '@memberjunction/react-runtime';
|
|
8
8
|
import * as i0 from "@angular/core";
|
|
9
9
|
/**
|
|
10
10
|
* Service for loading external scripts and CSS with proper cleanup.
|
|
@@ -39,9 +39,10 @@ export declare class ScriptLoaderService implements OnDestroy {
|
|
|
39
39
|
/**
|
|
40
40
|
* Load common React libraries and UI frameworks
|
|
41
41
|
* @param config Optional library configuration
|
|
42
|
+
* @param additionalLibraries Optional additional libraries to merge
|
|
42
43
|
* @returns Promise resolving to React ecosystem objects
|
|
43
44
|
*/
|
|
44
|
-
loadReactEcosystem(config?: LibraryConfiguration): Promise<{
|
|
45
|
+
loadReactEcosystem(config?: LibraryConfiguration, additionalLibraries?: ExternalLibraryConfig[]): Promise<{
|
|
45
46
|
React: any;
|
|
46
47
|
ReactDOM: any;
|
|
47
48
|
Babel: any;
|
|
@@ -92,11 +92,12 @@ export class ScriptLoaderService {
|
|
|
92
92
|
/**
|
|
93
93
|
* Load common React libraries and UI frameworks
|
|
94
94
|
* @param config Optional library configuration
|
|
95
|
+
* @param additionalLibraries Optional additional libraries to merge
|
|
95
96
|
* @returns Promise resolving to React ecosystem objects
|
|
96
97
|
*/
|
|
97
|
-
async loadReactEcosystem(config) {
|
|
98
|
+
async loadReactEcosystem(config, additionalLibraries) {
|
|
98
99
|
// Use the new LibraryLoader from react-runtime for consistency
|
|
99
|
-
const result = await LibraryLoader.loadAllLibraries(config);
|
|
100
|
+
const result = await LibraryLoader.loadAllLibraries(config, additionalLibraries);
|
|
100
101
|
// The LibraryLoader handles all the loading, but we need to ensure
|
|
101
102
|
// ReactDOM.createRoot is available for Angular's specific needs
|
|
102
103
|
// The ReactBridgeService will handle the delayed validation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"script-loader.service.js","sourceRoot":"","sources":["../../../src/lib/services/script-loader.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAa,MAAM,eAAe,CAAC;AACtD,OAAO,EACL,aAAa,EAEd,MAAM,+BAA+B,CAAC;;AAUvC;;;GAGG;AAEH,MAAM,OAAO,mBAAmB;IADhC;QAEU,oBAAe,GAAG,IAAI,GAAG,EAAwB,CAAC;QACzC,qBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;KA8XvD;IA5XC,WAAW;QACT,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,UAAU,CAAC,GAAW,EAAE,UAAkB,EAAE,WAAW,GAAG,KAAK;QACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC,OAAO,CAAC;QAC1B,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,eAAe,GAAG,IAAI,CAAsB,CAAC;QAEpF,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YACpD,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,wBAAwB,CAC5B,GAAW,EACX,UAAkB,EAClB,SAAgC,EAChC,WAAW,GAAG,KAAK;QAEnB,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;YACnC,wCAAwC;YACxC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,+BAA+B,CAAC,CAAC;YAChE,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,iCAAiC,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QACnF,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,eAAe,GAAG,IAAI,CAAsB,CAAC;QAEpF,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YACpD,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,GAAW;QACjB,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAClC,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,QAAQ,CAAC,aAAa,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;QACnE,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAChB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAEhC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE;YAC5B,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE;SAC3B,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,kBAAkB,CAAC,MAA6B;QAMpD,+DAA+D;QAC/D,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAE5D,mEAAmE;QACnE,gEAAgE;QAChE,4DAA4D;QAE5D,qCAAqC;QACrC,aAAa,CAAC,kBAAkB,EAAE,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE;YAC3D,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACK,qBAAqB,CAAC,GAAW;QACvC,gDAAgD;QAChD,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAO,GAAG,CAAC;QACvC,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACpC,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC;QACtE,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC;QAC1C,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC;QACxC,IAAI,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAAE,OAAO,gBAAgB,CAAC;QAC7D,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,OAAO,UAAU,CAAC;QACjD,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC;QAC1C,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC;QAE1C,8CAA8C;QAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;QACtD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC;IAC7C,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,GAAW;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,QAAQ,EAAE,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YACrD,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;IAED;;OAEG;IACK,OAAO;QACb,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;IAChC,CAAC;IAED;;;;;OAKG;IACK,mBAAmB,CAAC,GAAW,EAAE,UAAkB;QACzD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,0BAA0B;YAC1B,IAAK,MAAc,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChC,OAAO,CAAE,MAAc,CAAC,UAAU,CAAC,CAAC,CAAC;gBACrC,OAAO;YACT,CAAC;YAED,6BAA6B;YAC7B,MAAM,cAAc,GAAG,QAAQ,CAAC,aAAa,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;YACtE,IAAI,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,iBAAiB,CAAC,cAAmC,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;gBACzF,OAAO;YACT,CAAC;YAED,oBAAoB;YACpB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAChD,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC;YACjB,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;YAEpB,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE;gBACnB,MAAM,MAAM,GAAI,MAAc,CAAC,UAAU,CAAC,CAAC;gBAC3C,IAAI,MAAM,EAAE,CAAC;oBACX,OAAO,CAAC,MAAM,CAAC,CAAC;gBAClB,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,UAAU,8BAA8B,CAAC,CAAC,CAAC;gBACjE,CAAC;YACH,CAAC,CAAC;YAEF,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;gBACpB,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC,CAAC;YACrD,CAAC,CAAC;YAEF,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACK,iCAAiC,CACvC,GAAW,EACX,UAAkB,EAClB,SAAgC;QAEhC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,oCAAoC;YACpC,MAAM,cAAc,GAAI,MAAc,CAAC,UAAU,CAAC,CAAC;YACnD,IAAI,cAAc,IAAI,SAAS,CAAC,cAAc,CAAC,EAAE,CAAC;gBAChD,OAAO,CAAC,cAAc,CAAC,CAAC;gBACxB,OAAO;YACT,CAAC;YAED,6BAA6B;YAC7B,MAAM,cAAc,GAAG,QAAQ,CAAC,aAAa,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;YACtE,IAAI,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,+BAA+B,CAClC,cAAmC,EACnC,UAAU,EACV,SAAS,EACT,OAAO,EACP,MAAM,CACP,CAAC;gBACF,OAAO;YACT,CAAC;YAED,oBAAoB;YACpB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAChD,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC;YACjB,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;YAEpB,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE;gBACnB,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YACjE,CAAC,CAAC;YAEF,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;gBACpB,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC,CAAC;YACrD,CAAC,CAAC;YAEF,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACK,iBAAiB,CACvB,UAAkB,EAClB,SAAgC,EAChC,OAA6B,EAC7B,MAA6B,EAC7B,QAAQ,GAAG,CAAC,EACZ,WAAW,GAAG,EAAE,CAAC,uCAAuC;;QAExD,MAAM,MAAM,GAAI,MAAc,CAAC,UAAU,CAAC,CAAC;QAE3C,IAAI,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,MAAM,CAAC,CAAC;YAChB,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,IAAI,WAAW,EAAE,CAAC;YAC5B,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,UAAU,uCAAuC,WAAW,WAAW,CAAC,CAAC,CAAC;YAChG,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,UAAU,oBAAoB,WAAW,WAAW,CAAC,CAAC,CAAC;YAC7E,CAAC;YACD,OAAO;QACT,CAAC;QAED,6EAA6E;QAC7E,MAAM,KAAK,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAChF,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAG,CAAC,EAAE,WAAW,CAAC,CAAC;QAC5F,CAAC,EAAE,KAAK,CAAC,CAAC;IACZ,CAAC;IAED;;;;;;OAMG;IACK,iBAAiB,CACvB,MAAyB,EACzB,UAAkB,EAClB,OAA6B,EAC7B,MAA6B;QAE7B,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,IAAK,MAAc,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChC,OAAO,CAAE,MAAc,CAAC,UAAU,CAAC,CAAC,CAAC;gBACrC,OAAO;YACT,CAAC;YACD,gDAAgD;YAChD,UAAU,CAAC,GAAG,EAAE;gBACd,IAAK,MAAc,CAAC,UAAU,CAAC,EAAE,CAAC;oBAChC,OAAO,CAAE,MAAc,CAAC,UAAU,CAAC,CAAC,CAAC;gBACvC,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,UAAU,8BAA8B,CAAC,CAAC,CAAC;gBACjE,CAAC;YACH,CAAC,EAAE,GAAG,CAAC,CAAC;QACV,CAAC,CAAC;QAEF,IAAI,YAAY,IAAI,MAAM,EAAE,CAAC;YAC3B,aAAa;YACZ,MAAc,CAAC,kBAAkB,GAAG,GAAG,EAAE;gBACxC,IAAK,MAAc,CAAC,UAAU,KAAK,QAAQ,IAAK,MAAc,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;oBACxF,MAAc,CAAC,kBAAkB,GAAG,IAAI,CAAC;oBAC1C,WAAW,EAAE,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,kBAAkB;YAClB,MAAM,WAAW,GAAG,GAAG,EAAE;gBACvB,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;gBAChD,WAAW,EAAE,CAAC;YAChB,CAAC,CAAC;YACF,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACK,+BAA+B,CACrC,MAAyB,EACzB,UAAkB,EAClB,SAAgC,EAChC,OAA6B,EAC7B,MAA6B;QAE7B,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACjE,CAAC,CAAC;QAEF,IAAI,YAAY,IAAI,MAAM,EAAE,CAAC;YAC3B,aAAa;YACZ,MAAc,CAAC,kBAAkB,GAAG,GAAG,EAAE;gBACxC,IAAK,MAAc,CAAC,UAAU,KAAK,QAAQ,IAAK,MAAc,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;oBACxF,MAAc,CAAC,kBAAkB,GAAG,IAAI,CAAC;oBAC1C,WAAW,EAAE,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,kBAAkB;YAClB,MAAM,WAAW,GAAG,GAAG,EAAE;gBACvB,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;gBAChD,WAAW,EAAE,CAAC;YAChB,CAAC,CAAC;YACF,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;oFA/XU,mBAAmB;uEAAnB,mBAAmB,WAAnB,mBAAmB,mBADN,MAAM;;iFACnB,mBAAmB;cAD/B,UAAU;eAAC,EAAE,UAAU,EAAE,MAAM,EAAE","sourcesContent":["/**\n * @fileoverview Service for loading external scripts and CSS in Angular applications.\n * Manages the lifecycle of dynamically loaded resources with proper cleanup.\n * @module @memberjunction/ng-react\n */\n\nimport { Injectable, OnDestroy } from '@angular/core';\nimport { \n LibraryLoader,\n LibraryConfiguration\n} from '@memberjunction/react-runtime';\n\n/**\n * Represents a loaded script or CSS resource\n */\ninterface LoadedScript {\n element: HTMLScriptElement | HTMLLinkElement;\n promise: Promise<any>;\n}\n\n/**\n * Service for loading external scripts and CSS with proper cleanup.\n * Provides methods to dynamically load React and related libraries from CDN.\n */\n@Injectable({ providedIn: 'root' })\nexport class ScriptLoaderService implements OnDestroy {\n private loadedResources = new Map<string, LoadedScript>();\n private readonly cleanupOnDestroy = new Set<string>();\n\n ngOnDestroy(): void {\n this.cleanup();\n }\n\n /**\n * Load a script from URL with automatic cleanup tracking\n * @param url - Script URL to load\n * @param globalName - Expected global variable name\n * @param autoCleanup - Whether to cleanup on service destroy\n * @returns Promise resolving to the global object\n */\n async loadScript(url: string, globalName: string, autoCleanup = false): Promise<any> {\n const existing = this.loadedResources.get(url);\n if (existing) {\n return existing.promise;\n }\n\n const promise = this.createScriptPromise(url, globalName);\n const element = document.querySelector(`script[src=\"${url}\"]`) as HTMLScriptElement;\n \n if (element) {\n this.loadedResources.set(url, { element, promise });\n if (autoCleanup) {\n this.cleanupOnDestroy.add(url);\n }\n }\n\n return promise;\n }\n\n /**\n * Load a script with additional validation function\n * @param url - Script URL to load\n * @param globalName - Expected global variable name\n * @param validator - Function to validate the loaded object\n * @param autoCleanup - Whether to cleanup on service destroy\n * @returns Promise resolving to the validated global object\n */\n async loadScriptWithValidation(\n url: string, \n globalName: string, \n validator: (obj: any) => boolean,\n autoCleanup = false\n ): Promise<any> {\n const existing = this.loadedResources.get(url);\n if (existing) {\n const obj = await existing.promise;\n // Re-validate even for cached resources\n if (!validator(obj)) {\n throw new Error(`${globalName} loaded but failed validation`);\n }\n return obj;\n }\n\n const promise = this.createScriptPromiseWithValidation(url, globalName, validator);\n const element = document.querySelector(`script[src=\"${url}\"]`) as HTMLScriptElement;\n \n if (element) {\n this.loadedResources.set(url, { element, promise });\n if (autoCleanup) {\n this.cleanupOnDestroy.add(url);\n }\n }\n\n return promise;\n }\n\n /**\n * Load CSS from URL\n * @param url - CSS URL to load\n */\n loadCSS(url: string): void {\n if (this.loadedResources.has(url)) {\n return;\n }\n\n const existingLink = document.querySelector(`link[href=\"${url}\"]`);\n if (existingLink) {\n return;\n }\n\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = url;\n document.head.appendChild(link);\n\n this.loadedResources.set(url, {\n element: link,\n promise: Promise.resolve()\n });\n }\n\n /**\n * Load common React libraries and UI frameworks\n * @param config Optional library configuration\n * @returns Promise resolving to React ecosystem objects\n */\n async loadReactEcosystem(config?: LibraryConfiguration): Promise<{\n React: any;\n ReactDOM: any;\n Babel: any;\n libraries: any;\n }> {\n // Use the new LibraryLoader from react-runtime for consistency\n const result = await LibraryLoader.loadAllLibraries(config);\n \n // The LibraryLoader handles all the loading, but we need to ensure\n // ReactDOM.createRoot is available for Angular's specific needs\n // The ReactBridgeService will handle the delayed validation\n \n // Track loaded resources for cleanup\n LibraryLoader.getLoadedResources().forEach((resource, url) => {\n this.loadedResources.set(url, resource);\n });\n \n return result;\n }\n\n /**\n * Get library name from URL for global variable mapping\n * @param url - Library URL\n * @returns Global variable name\n */\n private getLibraryNameFromUrl(url: string): string {\n // Map known URLs to their global variable names\n if (url.includes('lodash')) return '_';\n if (url.includes('d3')) return 'd3';\n if (url.includes('Chart.js') || url.includes('chart')) return 'Chart';\n if (url.includes('dayjs')) return 'dayjs';\n if (url.includes('antd')) return 'antd';\n if (url.includes('react-bootstrap')) return 'ReactBootstrap';\n if (url.includes('react-dom')) return 'ReactDOM';\n if (url.includes('react')) return 'React';\n if (url.includes('babel')) return 'Babel';\n \n // Default: extract library name from filename\n const match = url.match(/\\/([^/]+?)(?:\\.min)?\\.js$/i);\n return match ? match[1] : 'UnknownLibrary';\n }\n\n /**\n * Remove a specific loaded resource\n * @param url - URL of resource to remove\n */\n removeResource(url: string): void {\n const resource = this.loadedResources.get(url);\n if (resource?.element && resource.element.parentNode) {\n resource.element.parentNode.removeChild(resource.element);\n }\n this.loadedResources.delete(url);\n this.cleanupOnDestroy.delete(url);\n }\n\n /**\n * Clean up all resources marked for auto-cleanup\n */\n private cleanup(): void {\n for (const url of this.cleanupOnDestroy) {\n this.removeResource(url);\n }\n this.cleanupOnDestroy.clear();\n }\n\n /**\n * Create a promise that resolves when script loads\n * @param url - Script URL\n * @param globalName - Expected global variable\n * @returns Promise resolving to global object\n */\n private createScriptPromise(url: string, globalName: string): Promise<any> {\n return new Promise((resolve, reject) => {\n // Check if already loaded\n if ((window as any)[globalName]) {\n resolve((window as any)[globalName]);\n return;\n }\n\n // Check if script tag exists\n const existingScript = document.querySelector(`script[src=\"${url}\"]`);\n if (existingScript) {\n this.waitForScriptLoad(existingScript as HTMLScriptElement, globalName, resolve, reject);\n return;\n }\n\n // Create new script\n const script = document.createElement('script');\n script.src = url;\n script.async = true;\n\n script.onload = () => {\n const global = (window as any)[globalName];\n if (global) {\n resolve(global);\n } else {\n reject(new Error(`${globalName} not found after script load`));\n }\n };\n\n script.onerror = () => {\n reject(new Error(`Failed to load script: ${url}`));\n };\n\n document.head.appendChild(script);\n this.loadedResources.set(url, { element: script, promise: Promise.resolve() });\n });\n }\n\n /**\n * Create a promise that resolves when script loads and passes validation\n * @param url - Script URL\n * @param globalName - Expected global variable\n * @param validator - Validation function\n * @returns Promise resolving to validated global object\n */\n private createScriptPromiseWithValidation(\n url: string, \n globalName: string, \n validator: (obj: any) => boolean\n ): Promise<any> {\n return new Promise((resolve, reject) => {\n // Check if already loaded and valid\n const existingGlobal = (window as any)[globalName];\n if (existingGlobal && validator(existingGlobal)) {\n resolve(existingGlobal);\n return;\n }\n\n // Check if script tag exists\n const existingScript = document.querySelector(`script[src=\"${url}\"]`);\n if (existingScript) {\n this.waitForScriptLoadWithValidation(\n existingScript as HTMLScriptElement, \n globalName, \n validator,\n resolve, \n reject\n );\n return;\n }\n\n // Create new script\n const script = document.createElement('script');\n script.src = url;\n script.async = true;\n\n script.onload = () => {\n this.waitForValidation(globalName, validator, resolve, reject);\n };\n\n script.onerror = () => {\n reject(new Error(`Failed to load script: ${url}`));\n };\n\n document.head.appendChild(script);\n this.loadedResources.set(url, { element: script, promise: Promise.resolve() });\n });\n }\n\n /**\n * Wait for global object to be available and valid\n * @param globalName - Global variable name\n * @param validator - Validation function\n * @param resolve - Promise resolve function\n * @param reject - Promise reject function\n * @param attempts - Current attempt number\n * @param maxAttempts - Maximum attempts before failing\n */\n private waitForValidation(\n globalName: string,\n validator: (obj: any) => boolean,\n resolve: (value: any) => void,\n reject: (reason: any) => void,\n attempts = 0,\n maxAttempts = 50 // 5 seconds total with 100ms intervals\n ): void {\n const global = (window as any)[globalName];\n \n if (global && validator(global)) {\n resolve(global);\n return;\n }\n\n if (attempts >= maxAttempts) {\n if (global) {\n reject(new Error(`${globalName} loaded but validation failed after ${maxAttempts} attempts`));\n } else {\n reject(new Error(`${globalName} not found after ${maxAttempts} attempts`));\n }\n return;\n }\n\n // Retry with exponential backoff for first few attempts, then fixed interval\n const delay = attempts < 5 ? Math.min(100 * Math.pow(1.5, attempts), 500) : 100;\n setTimeout(() => {\n this.waitForValidation(globalName, validator, resolve, reject, attempts + 1, maxAttempts);\n }, delay);\n }\n\n /**\n * Wait for existing script to load\n * @param script - Script element\n * @param globalName - Expected global variable\n * @param resolve - Promise resolve function\n * @param reject - Promise reject function\n */\n private waitForScriptLoad(\n script: HTMLScriptElement,\n globalName: string,\n resolve: (value: any) => void,\n reject: (reason: any) => void\n ): void {\n const checkGlobal = () => {\n if ((window as any)[globalName]) {\n resolve((window as any)[globalName]);\n return;\n }\n // Give it a moment for the global to be defined\n setTimeout(() => {\n if ((window as any)[globalName]) {\n resolve((window as any)[globalName]);\n } else {\n reject(new Error(`${globalName} not found after script load`));\n }\n }, 100);\n };\n\n if ('readyState' in script) {\n // IE support\n (script as any).onreadystatechange = () => {\n if ((script as any).readyState === 'loaded' || (script as any).readyState === 'complete') {\n (script as any).onreadystatechange = null;\n checkGlobal();\n }\n };\n } else {\n // Modern browsers\n const loadHandler = () => {\n script.removeEventListener('load', loadHandler);\n checkGlobal();\n };\n script.addEventListener('load', loadHandler);\n }\n }\n\n /**\n * Wait for existing script to load with validation\n * @param script - Script element\n * @param globalName - Expected global variable\n * @param validator - Validation function\n * @param resolve - Promise resolve function\n * @param reject - Promise reject function\n */\n private waitForScriptLoadWithValidation(\n script: HTMLScriptElement,\n globalName: string,\n validator: (obj: any) => boolean,\n resolve: (value: any) => void,\n reject: (reason: any) => void\n ): void {\n const checkGlobal = () => {\n this.waitForValidation(globalName, validator, resolve, reject);\n };\n\n if ('readyState' in script) {\n // IE support\n (script as any).onreadystatechange = () => {\n if ((script as any).readyState === 'loaded' || (script as any).readyState === 'complete') {\n (script as any).onreadystatechange = null;\n checkGlobal();\n }\n };\n } else {\n // Modern browsers\n const loadHandler = () => {\n script.removeEventListener('load', loadHandler);\n checkGlobal();\n };\n script.addEventListener('load', loadHandler);\n }\n }\n}"]}
|
|
1
|
+
{"version":3,"file":"script-loader.service.js","sourceRoot":"","sources":["../../../src/lib/services/script-loader.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Service for loading external scripts and CSS in Angular applications.\n * Manages the lifecycle of dynamically loaded resources with proper cleanup.\n * @module @memberjunction/ng-react\n */\n\nimport { Injectable, OnDestroy } from '@angular/core';\nimport { \n LibraryLoader,\n LibraryConfiguration,\n ExternalLibraryConfig\n} from '@memberjunction/react-runtime';\n\n/**\n * Represents a loaded script or CSS resource\n */\ninterface LoadedScript {\n element: HTMLScriptElement | HTMLLinkElement;\n promise: Promise<any>;\n}\n\n/**\n * Service for loading external scripts and CSS with proper cleanup.\n * Provides methods to dynamically load React and related libraries from CDN.\n */\n@Injectable({ providedIn: 'root' })\nexport class ScriptLoaderService implements OnDestroy {\n private loadedResources = new Map<string, LoadedScript>();\n private readonly cleanupOnDestroy = new Set<string>();\n\n ngOnDestroy(): void {\n this.cleanup();\n }\n\n /**\n * Load a script from URL with automatic cleanup tracking\n * @param url - Script URL to load\n * @param globalName - Expected global variable name\n * @param autoCleanup - Whether to cleanup on service destroy\n * @returns Promise resolving to the global object\n */\n async loadScript(url: string, globalName: string, autoCleanup = false): Promise<any> {\n const existing = this.loadedResources.get(url);\n if (existing) {\n return existing.promise;\n }\n\n const promise = this.createScriptPromise(url, globalName);\n const element = document.querySelector(`script[src=\"${url}\"]`) as HTMLScriptElement;\n \n if (element) {\n this.loadedResources.set(url, { element, promise });\n if (autoCleanup) {\n this.cleanupOnDestroy.add(url);\n }\n }\n\n return promise;\n }\n\n /**\n * Load a script with additional validation function\n * @param url - Script URL to load\n * @param globalName - Expected global variable name\n * @param validator - Function to validate the loaded object\n * @param autoCleanup - Whether to cleanup on service destroy\n * @returns Promise resolving to the validated global object\n */\n async loadScriptWithValidation(\n url: string, \n globalName: string, \n validator: (obj: any) => boolean,\n autoCleanup = false\n ): Promise<any> {\n const existing = this.loadedResources.get(url);\n if (existing) {\n const obj = await existing.promise;\n // Re-validate even for cached resources\n if (!validator(obj)) {\n throw new Error(`${globalName} loaded but failed validation`);\n }\n return obj;\n }\n\n const promise = this.createScriptPromiseWithValidation(url, globalName, validator);\n const element = document.querySelector(`script[src=\"${url}\"]`) as HTMLScriptElement;\n \n if (element) {\n this.loadedResources.set(url, { element, promise });\n if (autoCleanup) {\n this.cleanupOnDestroy.add(url);\n }\n }\n\n return promise;\n }\n\n /**\n * Load CSS from URL\n * @param url - CSS URL to load\n */\n loadCSS(url: string): void {\n if (this.loadedResources.has(url)) {\n return;\n }\n\n const existingLink = document.querySelector(`link[href=\"${url}\"]`);\n if (existingLink) {\n return;\n }\n\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = url;\n document.head.appendChild(link);\n\n this.loadedResources.set(url, {\n element: link,\n promise: Promise.resolve()\n });\n }\n\n /**\n * Load common React libraries and UI frameworks\n * @param config Optional library configuration\n * @param additionalLibraries Optional additional libraries to merge\n * @returns Promise resolving to React ecosystem objects\n */\n async loadReactEcosystem(\n config?: LibraryConfiguration,\n additionalLibraries?: ExternalLibraryConfig[]\n ): Promise<{\n React: any;\n ReactDOM: any;\n Babel: any;\n libraries: any;\n }> {\n // Use the new LibraryLoader from react-runtime for consistency\n const result = await LibraryLoader.loadAllLibraries(config, additionalLibraries);\n \n // The LibraryLoader handles all the loading, but we need to ensure\n // ReactDOM.createRoot is available for Angular's specific needs\n // The ReactBridgeService will handle the delayed validation\n \n // Track loaded resources for cleanup\n LibraryLoader.getLoadedResources().forEach((resource, url) => {\n this.loadedResources.set(url, resource);\n });\n \n return result;\n }\n\n /**\n * Get library name from URL for global variable mapping\n * @param url - Library URL\n * @returns Global variable name\n */\n private getLibraryNameFromUrl(url: string): string {\n // Map known URLs to their global variable names\n if (url.includes('lodash')) return '_';\n if (url.includes('d3')) return 'd3';\n if (url.includes('Chart.js') || url.includes('chart')) return 'Chart';\n if (url.includes('dayjs')) return 'dayjs';\n if (url.includes('antd')) return 'antd';\n if (url.includes('react-bootstrap')) return 'ReactBootstrap';\n if (url.includes('react-dom')) return 'ReactDOM';\n if (url.includes('react')) return 'React';\n if (url.includes('babel')) return 'Babel';\n \n // Default: extract library name from filename\n const match = url.match(/\\/([^/]+?)(?:\\.min)?\\.js$/i);\n return match ? match[1] : 'UnknownLibrary';\n }\n\n /**\n * Remove a specific loaded resource\n * @param url - URL of resource to remove\n */\n removeResource(url: string): void {\n const resource = this.loadedResources.get(url);\n if (resource?.element && resource.element.parentNode) {\n resource.element.parentNode.removeChild(resource.element);\n }\n this.loadedResources.delete(url);\n this.cleanupOnDestroy.delete(url);\n }\n\n /**\n * Clean up all resources marked for auto-cleanup\n */\n private cleanup(): void {\n for (const url of this.cleanupOnDestroy) {\n this.removeResource(url);\n }\n this.cleanupOnDestroy.clear();\n }\n\n /**\n * Create a promise that resolves when script loads\n * @param url - Script URL\n * @param globalName - Expected global variable\n * @returns Promise resolving to global object\n */\n private createScriptPromise(url: string, globalName: string): Promise<any> {\n return new Promise((resolve, reject) => {\n // Check if already loaded\n if ((window as any)[globalName]) {\n resolve((window as any)[globalName]);\n return;\n }\n\n // Check if script tag exists\n const existingScript = document.querySelector(`script[src=\"${url}\"]`);\n if (existingScript) {\n this.waitForScriptLoad(existingScript as HTMLScriptElement, globalName, resolve, reject);\n return;\n }\n\n // Create new script\n const script = document.createElement('script');\n script.src = url;\n script.async = true;\n\n script.onload = () => {\n const global = (window as any)[globalName];\n if (global) {\n resolve(global);\n } else {\n reject(new Error(`${globalName} not found after script load`));\n }\n };\n\n script.onerror = () => {\n reject(new Error(`Failed to load script: ${url}`));\n };\n\n document.head.appendChild(script);\n this.loadedResources.set(url, { element: script, promise: Promise.resolve() });\n });\n }\n\n /**\n * Create a promise that resolves when script loads and passes validation\n * @param url - Script URL\n * @param globalName - Expected global variable\n * @param validator - Validation function\n * @returns Promise resolving to validated global object\n */\n private createScriptPromiseWithValidation(\n url: string, \n globalName: string, \n validator: (obj: any) => boolean\n ): Promise<any> {\n return new Promise((resolve, reject) => {\n // Check if already loaded and valid\n const existingGlobal = (window as any)[globalName];\n if (existingGlobal && validator(existingGlobal)) {\n resolve(existingGlobal);\n return;\n }\n\n // Check if script tag exists\n const existingScript = document.querySelector(`script[src=\"${url}\"]`);\n if (existingScript) {\n this.waitForScriptLoadWithValidation(\n existingScript as HTMLScriptElement, \n globalName, \n validator,\n resolve, \n reject\n );\n return;\n }\n\n // Create new script\n const script = document.createElement('script');\n script.src = url;\n script.async = true;\n\n script.onload = () => {\n this.waitForValidation(globalName, validator, resolve, reject);\n };\n\n script.onerror = () => {\n reject(new Error(`Failed to load script: ${url}`));\n };\n\n document.head.appendChild(script);\n this.loadedResources.set(url, { element: script, promise: Promise.resolve() });\n });\n }\n\n /**\n * Wait for global object to be available and valid\n * @param globalName - Global variable name\n * @param validator - Validation function\n * @param resolve - Promise resolve function\n * @param reject - Promise reject function\n * @param attempts - Current attempt number\n * @param maxAttempts - Maximum attempts before failing\n */\n private waitForValidation(\n globalName: string,\n validator: (obj: any) => boolean,\n resolve: (value: any) => void,\n reject: (reason: any) => void,\n attempts = 0,\n maxAttempts = 50 // 5 seconds total with 100ms intervals\n ): void {\n const global = (window as any)[globalName];\n \n if (global && validator(global)) {\n resolve(global);\n return;\n }\n\n if (attempts >= maxAttempts) {\n if (global) {\n reject(new Error(`${globalName} loaded but validation failed after ${maxAttempts} attempts`));\n } else {\n reject(new Error(`${globalName} not found after ${maxAttempts} attempts`));\n }\n return;\n }\n\n // Retry with exponential backoff for first few attempts, then fixed interval\n const delay = attempts < 5 ? Math.min(100 * Math.pow(1.5, attempts), 500) : 100;\n setTimeout(() => {\n this.waitForValidation(globalName, validator, resolve, reject, attempts + 1, maxAttempts);\n }, delay);\n }\n\n /**\n * Wait for existing script to load\n * @param script - Script element\n * @param globalName - Expected global variable\n * @param resolve - Promise resolve function\n * @param reject - Promise reject function\n */\n private waitForScriptLoad(\n script: HTMLScriptElement,\n globalName: string,\n resolve: (value: any) => void,\n reject: (reason: any) => void\n ): void {\n const checkGlobal = () => {\n if ((window as any)[globalName]) {\n resolve((window as any)[globalName]);\n return;\n }\n // Give it a moment for the global to be defined\n setTimeout(() => {\n if ((window as any)[globalName]) {\n resolve((window as any)[globalName]);\n } else {\n reject(new Error(`${globalName} not found after script load`));\n }\n }, 100);\n };\n\n if ('readyState' in script) {\n // IE support\n (script as any).onreadystatechange = () => {\n if ((script as any).readyState === 'loaded' || (script as any).readyState === 'complete') {\n (script as any).onreadystatechange = null;\n checkGlobal();\n }\n };\n } else {\n // Modern browsers\n const loadHandler = () => {\n script.removeEventListener('load', loadHandler);\n checkGlobal();\n };\n script.addEventListener('load', loadHandler);\n }\n }\n\n /**\n * Wait for existing script to load with validation\n * @param script - Script element\n * @param globalName - Expected global variable\n * @param validator - Validation function\n * @param resolve - Promise resolve function\n * @param reject - Promise reject function\n */\n private waitForScriptLoadWithValidation(\n script: HTMLScriptElement,\n globalName: string,\n validator: (obj: any) => boolean,\n resolve: (value: any) => void,\n reject: (reason: any) => void\n ): void {\n const checkGlobal = () => {\n this.waitForValidation(globalName, validator, resolve, reject);\n };\n\n if ('readyState' in script) {\n // IE support\n (script as any).onreadystatechange = () => {\n if ((script as any).readyState === 'loaded' || (script as any).readyState === 'complete') {\n (script as any).onreadystatechange = null;\n checkGlobal();\n }\n };\n } else {\n // Modern browsers\n const loadHandler = () => {\n script.removeEventListener('load', loadHandler);\n checkGlobal();\n };\n script.addEventListener('load', loadHandler);\n }\n }\n}"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.77.0",
|
|
4
4
|
"description": "Angular components for hosting React components in MemberJunction applications",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "ngc -p tsconfig.json",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"styles"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@memberjunction/core": "2.
|
|
44
|
-
"@memberjunction/react-runtime": "2.
|
|
45
|
-
"@memberjunction/interactive-component-types": "^2.
|
|
43
|
+
"@memberjunction/core": "2.77.0",
|
|
44
|
+
"@memberjunction/react-runtime": "2.77.0",
|
|
45
|
+
"@memberjunction/interactive-component-types": "^2.77.0",
|
|
46
46
|
"@angular/common": ">=18.0.0",
|
|
47
47
|
"@angular/core": ">=18.0.0",
|
|
48
48
|
"@angular/platform-browser": ">=18.0.0",
|