@memberjunction/ng-react 2.78.0 → 2.80.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.
@@ -41,12 +41,6 @@ export declare class MJReactComponent implements AfterViewInit, OnDestroy {
41
41
  private adapter;
42
42
  private cdr;
43
43
  component: ComponentSpec;
44
- private _data;
45
- set data(value: any);
46
- get data(): any;
47
- private _state;
48
- set state(value: any);
49
- get state(): any;
50
44
  utilities: any;
51
45
  styles?: Partial<ComponentStyles>;
52
46
  private _savedUserSettings;
@@ -65,7 +59,6 @@ export declare class MJReactComponent implements AfterViewInit, OnDestroy {
65
59
  private compiledComponent;
66
60
  private destroyed$;
67
61
  private currentCallbacks;
68
- private currentState;
69
62
  isInitialized: boolean;
70
63
  private isRendering;
71
64
  private pendingRender;
@@ -106,19 +99,16 @@ export declare class MJReactComponent implements AfterViewInit, OnDestroy {
106
99
  private cleanup;
107
100
  /**
108
101
  * Public method to refresh the component
109
- * @param newData - Optional new data to merge
102
+ * @deprecated Components manage their own state and data now
110
103
  */
111
- refresh(newData?: any): void;
104
+ refresh(): void;
112
105
  /**
113
106
  * Public method to update state programmatically
114
107
  * @param path - State path to update
115
108
  * @param value - New value
109
+ * @deprecated Components manage their own state now
116
110
  */
117
111
  updateState(path: string, value: any): void;
118
- /**
119
- * Deep equality check that handles null/undefined properly
120
- */
121
- private isEqual;
122
112
  static ɵfac: i0.ɵɵFactoryDeclaration<MJReactComponent, 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>;
113
+ static ɵcmp: i0.ɵɵComponentDeclaration<MJReactComponent, "mj-react-component", never, { "component": { "alias": "component"; "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>;
124
114
  }
@@ -28,29 +28,6 @@ function MJReactComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
28
28
  * to be used seamlessly within Angular applications.
29
29
  */
30
30
  export class MJReactComponent {
31
- set data(value) {
32
- const oldData = this._data;
33
- this._data = value;
34
- // Only re-render if data actually changed and component is initialized
35
- if (this.isInitialized && !this.isEqual(oldData, value)) {
36
- this.renderComponent();
37
- }
38
- }
39
- get data() {
40
- return this._data;
41
- }
42
- set state(value) {
43
- const oldState = this._state;
44
- this._state = value;
45
- // Only update state and re-render if it actually changed
46
- if (this.isInitialized && !this.isEqual(oldState, value)) {
47
- this.currentState = { ...value };
48
- this.renderComponent();
49
- }
50
- }
51
- get state() {
52
- return this._state;
53
- }
54
31
  set savedUserSettings(value) {
55
32
  this._savedUserSettings = value || {};
56
33
  // Re-render if component is initialized
@@ -65,8 +42,6 @@ export class MJReactComponent {
65
42
  this.reactBridge = reactBridge;
66
43
  this.adapter = adapter;
67
44
  this.cdr = cdr;
68
- this._data = {};
69
- this._state = {};
70
45
  this.utilities = {};
71
46
  this._savedUserSettings = {};
72
47
  this.stateChange = new EventEmitter();
@@ -78,7 +53,6 @@ export class MJReactComponent {
78
53
  this.compiledComponent = null;
79
54
  this.destroyed$ = new Subject();
80
55
  this.currentCallbacks = null;
81
- this.currentState = {};
82
56
  this.isInitialized = false;
83
57
  this.isRendering = false;
84
58
  this.pendingRender = false;
@@ -123,8 +97,20 @@ export class MJReactComponent {
123
97
  }
124
98
  // Get runtime context and execute component factory
125
99
  const context = this.adapter.getRuntimeContext();
126
- this.compiledComponent = result.component.component(context, this.styles);
127
- this.currentState = { ...this._state };
100
+ // Call the factory function to get the component wrapper
101
+ // result.component is a CompiledComponent object with a 'component' property that's the factory
102
+ const componentWrapper = result.component.component(context, this.styles);
103
+ // Validate the component wrapper structure
104
+ if (!componentWrapper || typeof componentWrapper !== 'object') {
105
+ throw new Error(`Invalid component wrapper returned for ${this.component.name}: ${typeof componentWrapper}`);
106
+ }
107
+ if (!componentWrapper.component) {
108
+ throw new Error(`Component wrapper missing 'component' property for ${this.component.name}`);
109
+ }
110
+ if (typeof componentWrapper.component !== 'function') {
111
+ throw new Error(`Component is not a function for ${this.component.name}: ${typeof componentWrapper.component}`);
112
+ }
113
+ this.compiledComponent = componentWrapper;
128
114
  // Create managed React root
129
115
  const reactContext = this.reactBridge.getCurrentContext();
130
116
  if (!reactContext) {
@@ -199,7 +185,6 @@ export class MJReactComponent {
199
185
  }
200
186
  // Build props with savedUserSettings pattern
201
187
  const props = {
202
- ...this._data, // Spread data properties directly
203
188
  utilities: this.utilities || {},
204
189
  callbacks: this.currentCallbacks,
205
190
  components,
@@ -207,6 +192,11 @@ export class MJReactComponent {
207
192
  savedUserSettings: this._savedUserSettings,
208
193
  onSaveUserSettings: this.handleSaveUserSettings.bind(this)
209
194
  };
195
+ // Validate component before creating element
196
+ if (!this.compiledComponent.component) {
197
+ LogError(`Component is undefined for ${this.component.name} during render`);
198
+ return;
199
+ }
210
200
  // Create error boundary
211
201
  const ErrorBoundary = createErrorBoundary(React, {
212
202
  onError: this.handleReactError.bind(this),
@@ -291,22 +281,16 @@ export class MJReactComponent {
291
281
  * This implements the SavedUserSettings pattern
292
282
  */
293
283
  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
284
+ // Just bubble the event up to parent containers for persistence
285
+ // We don't need to store anything here
303
286
  this.userSettingsChanged.emit({
304
- settings: this._savedUserSettings,
287
+ settings: newSettings,
305
288
  componentName: this.component?.name,
306
289
  timestamp: new Date()
307
290
  });
308
- // Schedule re-render
309
- this.renderComponent();
291
+ // DO NOT re-render the component!
292
+ // The component already has the correct state - it's the one that told us about the change.
293
+ // Re-rendering would cause unnecessary DOM updates and visual flashing.
310
294
  }
311
295
  /**
312
296
  * Clean up resources
@@ -329,51 +313,27 @@ export class MJReactComponent {
329
313
  }
330
314
  // Clear references
331
315
  this.compiledComponent = null;
332
- this.currentState = {};
333
316
  this.isInitialized = false;
334
317
  // Trigger registry cleanup
335
318
  this.adapter.getRegistry().cleanup();
336
319
  }
337
320
  /**
338
321
  * Public method to refresh the component
339
- * @param newData - Optional new data to merge
322
+ * @deprecated Components manage their own state and data now
340
323
  */
341
- refresh(newData) {
342
- if (newData) {
343
- // Use the setter to trigger change detection
344
- this.data = { ...this._data, ...newData };
345
- }
346
- else {
347
- this.renderComponent();
348
- }
324
+ refresh() {
325
+ // Just trigger a re-render if needed
326
+ this.renderComponent();
349
327
  }
350
328
  /**
351
329
  * Public method to update state programmatically
352
330
  * @param path - State path to update
353
331
  * @param value - New value
332
+ * @deprecated Components manage their own state now
354
333
  */
355
334
  updateState(path, value) {
356
- this.currentState = {
357
- ...this.currentState,
358
- [path]: value
359
- };
335
+ // Just emit the event, don't manage state here
360
336
  this.stateChange.emit({ path, value });
361
- this.renderComponent();
362
- }
363
- /**
364
- * Deep equality check that handles null/undefined properly
365
- */
366
- isEqual(a, b) {
367
- // Handle null/undefined cases
368
- if (a === b)
369
- return true;
370
- if (a == null || b == null)
371
- return false;
372
- // For objects/arrays, use JSON comparison
373
- if (typeof a === 'object' && typeof b === 'object') {
374
- return JSON.stringify(a) === JSON.stringify(b);
375
- }
376
- return a === b;
377
337
  }
378
338
  static { this.ɵfac = function MJReactComponent_Factory(t) { return new (t || MJReactComponent)(i0.ɵɵdirectiveInject(i1.ReactBridgeService), i0.ɵɵdirectiveInject(i2.AngularAdapterService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); }; }
379
339
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJReactComponent, selectors: [["mj-react-component"]], viewQuery: function MJReactComponent_Query(rf, ctx) { if (rf & 1) {
@@ -381,7 +341,7 @@ export class MJReactComponent {
381
341
  } if (rf & 2) {
382
342
  let _t;
383
343
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.container = _t.first);
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) {
344
+ } }, inputs: { component: "component", 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) {
385
345
  i0.ɵɵelementStart(0, "div", 1);
386
346
  i0.ɵɵelement(1, "div", 2, 0);
387
347
  i0.ɵɵtemplate(3, MJReactComponent_Conditional_3_Template, 5, 0, "div", 3);
@@ -410,10 +370,6 @@ export class MJReactComponent {
410
370
  `, changeDetection: ChangeDetectionStrategy.OnPush, 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 "] }]
411
371
  }], () => [{ type: i1.ReactBridgeService }, { type: i2.AngularAdapterService }, { type: i0.ChangeDetectorRef }], { component: [{
412
372
  type: Input
413
- }], data: [{
414
- type: Input
415
- }], state: [{
416
- type: Input
417
373
  }], utilities: [{
418
374
  type: Input
419
375
  }], styles: [{
@@ -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 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
+ {"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 @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 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 \n // Call the factory function to get the component wrapper\n // result.component is a CompiledComponent object with a 'component' property that's the factory\n const componentWrapper = result.component!.component(context, this.styles);\n \n // Validate the component wrapper structure\n if (!componentWrapper || typeof componentWrapper !== 'object') {\n throw new Error(`Invalid component wrapper returned for ${this.component.name}: ${typeof componentWrapper}`);\n }\n \n if (!componentWrapper.component) {\n throw new Error(`Component wrapper missing 'component' property for ${this.component.name}`);\n }\n \n if (typeof componentWrapper.component !== 'function') {\n throw new Error(`Component is not a function for ${this.component.name}: ${typeof componentWrapper.component}`);\n }\n \n this.compiledComponent = componentWrapper;\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 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 // Validate component before creating element\n if (!this.compiledComponent.component) {\n LogError(`Component is undefined for ${this.component.name} during render`);\n return;\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 // Just bubble the event up to parent containers for persistence\n // We don't need to store anything here\n this.userSettingsChanged.emit({\n settings: newSettings,\n componentName: this.component?.name,\n timestamp: new Date()\n });\n \n // DO NOT re-render the component!\n // The component already has the correct state - it's the one that told us about the change.\n // Re-rendering would cause unnecessary DOM updates and visual flashing.\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.isInitialized = false;\n\n // Trigger registry cleanup\n this.adapter.getRegistry().cleanup();\n }\n\n /**\n * Public method to refresh the component\n * @deprecated Components manage their own state and data now\n */\n refresh() {\n // Just trigger a re-render if needed\n this.renderComponent();\n }\n\n /**\n * Public method to update state programmatically\n * @param path - State path to update\n * @param value - New value\n * @deprecated Components manage their own state now\n */\n updateState(path: string, value: any) {\n // Just emit the event, don't manage state here\n this.stateChange.emit({ path, value });\n }\n\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-react",
3
- "version": "2.78.0",
3
+ "version": "2.80.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.78.0",
44
- "@memberjunction/react-runtime": "2.78.0",
45
- "@memberjunction/interactive-component-types": "^2.78.0",
43
+ "@memberjunction/core": "2.80.0",
44
+ "@memberjunction/react-runtime": "2.80.0",
45
+ "@memberjunction/interactive-component-types": "^2.80.0",
46
46
  "@angular/common": ">=18.0.0",
47
47
  "@angular/core": ">=18.0.0",
48
48
  "@angular/platform-browser": ">=18.0.0",