@memberjunction/ng-react 2.72.0 → 2.73.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.
|
@@ -7,6 +7,7 @@ import { EventEmitter, ElementRef, AfterViewInit, OnDestroy, ChangeDetectorRef }
|
|
|
7
7
|
import { ComponentRootSpec, ComponentStyles } from '@memberjunction/interactive-component-types';
|
|
8
8
|
import { ReactBridgeService } from '../services/react-bridge.service';
|
|
9
9
|
import { AngularAdapterService } from '../services/angular-adapter.service';
|
|
10
|
+
import { CompositeKey } from '@memberjunction/core';
|
|
10
11
|
import * as i0 from "@angular/core";
|
|
11
12
|
/**
|
|
12
13
|
* Event emitted by React components
|
|
@@ -45,16 +46,19 @@ export declare class MJReactComponent implements AfterViewInit, OnDestroy {
|
|
|
45
46
|
refreshData: EventEmitter<void>;
|
|
46
47
|
openEntityRecord: EventEmitter<{
|
|
47
48
|
entityName: string;
|
|
48
|
-
|
|
49
|
+
key: CompositeKey;
|
|
49
50
|
}>;
|
|
50
51
|
container: ElementRef<HTMLDivElement>;
|
|
51
52
|
private reactRoot;
|
|
52
53
|
private compiledComponent;
|
|
53
54
|
private destroyed$;
|
|
55
|
+
private currentCallbacks;
|
|
54
56
|
private currentState;
|
|
55
57
|
isInitialized: boolean;
|
|
56
58
|
private isRendering;
|
|
57
59
|
private pendingRender;
|
|
60
|
+
private isDestroying;
|
|
61
|
+
private renderTimeout;
|
|
58
62
|
hasError: boolean;
|
|
59
63
|
constructor(reactBridge: ReactBridgeService, adapter: AngularAdapterService, cdr: ChangeDetectorRef);
|
|
60
64
|
ngAfterViewInit(): Promise<void>;
|
|
@@ -7,8 +7,8 @@ import { Component, Input, Output, EventEmitter, ViewChild, ElementRef, ChangeDe
|
|
|
7
7
|
import { Subject } from 'rxjs';
|
|
8
8
|
import { ReactBridgeService } from '../services/react-bridge.service';
|
|
9
9
|
import { AngularAdapterService } from '../services/angular-adapter.service';
|
|
10
|
-
import { buildComponentProps, createErrorBoundary, ComponentHierarchyRegistrar } from '@memberjunction/react-runtime';
|
|
11
|
-
import { LogError } from '@memberjunction/core';
|
|
10
|
+
import { buildComponentProps, cleanupPropBuilder, createErrorBoundary, ComponentHierarchyRegistrar } from '@memberjunction/react-runtime';
|
|
11
|
+
import { LogError, CompositeKey } from '@memberjunction/core';
|
|
12
12
|
import * as i0 from "@angular/core";
|
|
13
13
|
import * as i1 from "../services/react-bridge.service";
|
|
14
14
|
import * as i2 from "../services/angular-adapter.service";
|
|
@@ -64,10 +64,13 @@ export class MJReactComponent {
|
|
|
64
64
|
this.reactRoot = null;
|
|
65
65
|
this.compiledComponent = null;
|
|
66
66
|
this.destroyed$ = new Subject();
|
|
67
|
+
this.currentCallbacks = null;
|
|
67
68
|
this.currentState = {};
|
|
68
69
|
this.isInitialized = false;
|
|
69
70
|
this.isRendering = false;
|
|
70
71
|
this.pendingRender = false;
|
|
72
|
+
this.isDestroying = false;
|
|
73
|
+
this.renderTimeout = null;
|
|
71
74
|
this.hasError = false;
|
|
72
75
|
}
|
|
73
76
|
async ngAfterViewInit() {
|
|
@@ -76,6 +79,10 @@ export class MJReactComponent {
|
|
|
76
79
|
await this.initializeComponent();
|
|
77
80
|
}
|
|
78
81
|
ngOnDestroy() {
|
|
82
|
+
// Set destroying flag immediately
|
|
83
|
+
this.isDestroying = true;
|
|
84
|
+
// Cancel any pending renders
|
|
85
|
+
this.pendingRender = false;
|
|
79
86
|
this.destroyed$.next();
|
|
80
87
|
this.destroyed$.complete();
|
|
81
88
|
this.cleanup();
|
|
@@ -148,6 +155,10 @@ export class MJReactComponent {
|
|
|
148
155
|
* Render the React component
|
|
149
156
|
*/
|
|
150
157
|
renderComponent() {
|
|
158
|
+
// Don't render if component is being destroyed
|
|
159
|
+
if (this.isDestroying) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
151
162
|
if (!this.compiledComponent || !this.reactRoot) {
|
|
152
163
|
return;
|
|
153
164
|
}
|
|
@@ -164,8 +175,13 @@ export class MJReactComponent {
|
|
|
164
175
|
const { React } = context;
|
|
165
176
|
// Get components from resolver
|
|
166
177
|
const components = this.adapter.getResolver().resolveComponents(this.component);
|
|
178
|
+
// Create callbacks once per component instance
|
|
179
|
+
if (!this.currentCallbacks) {
|
|
180
|
+
this.currentCallbacks = this.createCallbacks();
|
|
181
|
+
}
|
|
167
182
|
// Build props - pass styles as-is for Skip components
|
|
168
|
-
const props = buildComponentProps(this._data || {}, this.currentState, this.utilities || {}, this.
|
|
183
|
+
const props = buildComponentProps(this._data || {}, this.currentState, this.utilities || {}, this.currentCallbacks, components, this.styles, // Skip components expect the full SkipComponentStyles structure
|
|
184
|
+
{ debounceUpdateUserState: 3000 } // 3 second debounce by default
|
|
169
185
|
);
|
|
170
186
|
// Create error boundary
|
|
171
187
|
const ErrorBoundary = createErrorBoundary(React, {
|
|
@@ -175,21 +191,33 @@ export class MJReactComponent {
|
|
|
175
191
|
});
|
|
176
192
|
// Create element with error boundary
|
|
177
193
|
const element = React.createElement(ErrorBoundary, null, React.createElement(this.compiledComponent.component, props));
|
|
194
|
+
// Clear any existing render timeout
|
|
195
|
+
if (this.renderTimeout) {
|
|
196
|
+
clearTimeout(this.renderTimeout);
|
|
197
|
+
}
|
|
178
198
|
// Render with timeout protection
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
199
|
+
this.renderTimeout = setTimeout(() => {
|
|
200
|
+
// Check if still rendering and not destroyed
|
|
201
|
+
if (this.isRendering && !this.isDestroying) {
|
|
202
|
+
this.componentEvent.emit({
|
|
203
|
+
type: 'error',
|
|
204
|
+
payload: {
|
|
205
|
+
error: 'Component render timeout - possible infinite loop detected',
|
|
206
|
+
source: 'render'
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
187
210
|
}, 5000);
|
|
188
211
|
try {
|
|
189
212
|
this.reactRoot.render(element);
|
|
190
|
-
clearTimeout(renderTimeout);
|
|
213
|
+
clearTimeout(this.renderTimeout);
|
|
214
|
+
this.renderTimeout = null;
|
|
191
215
|
// Reset rendering flag after a microtask to allow React to complete
|
|
192
216
|
Promise.resolve().then(() => {
|
|
217
|
+
// Don't update state if component is destroyed
|
|
218
|
+
if (this.isDestroying) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
193
221
|
this.isRendering = false;
|
|
194
222
|
// If there was a pending render request, execute it now
|
|
195
223
|
if (this.pendingRender) {
|
|
@@ -199,7 +227,8 @@ export class MJReactComponent {
|
|
|
199
227
|
});
|
|
200
228
|
}
|
|
201
229
|
catch (error) {
|
|
202
|
-
clearTimeout(renderTimeout);
|
|
230
|
+
clearTimeout(this.renderTimeout);
|
|
231
|
+
this.renderTimeout = null;
|
|
203
232
|
this.isRendering = false;
|
|
204
233
|
this.handleReactError(error);
|
|
205
234
|
}
|
|
@@ -213,16 +242,29 @@ export class MJReactComponent {
|
|
|
213
242
|
this.refreshData.emit();
|
|
214
243
|
},
|
|
215
244
|
OpenEntityRecord: (entityName, key) => {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
245
|
+
let keyToUse = null;
|
|
246
|
+
if (key instanceof Array) {
|
|
247
|
+
keyToUse = CompositeKey.FromKeyValuePairs(key);
|
|
248
|
+
}
|
|
249
|
+
else if (typeof key === 'object' && !!key.GetValueByFieldName) {
|
|
250
|
+
keyToUse = key;
|
|
251
|
+
}
|
|
252
|
+
else if (typeof key === 'object') {
|
|
253
|
+
//} && !!key.FieldName && !!key.Value) {
|
|
254
|
+
// possible that have an object that is a simple key/value pair with
|
|
255
|
+
// FieldName and value properties
|
|
256
|
+
const keyAny = key;
|
|
257
|
+
if (keyAny.FieldName && keyAny.Value) {
|
|
258
|
+
keyToUse = CompositeKey.FromKeyValuePairs([keyAny]);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (keyToUse) {
|
|
262
|
+
this.openEntityRecord.emit({ entityName, key: keyToUse });
|
|
263
|
+
}
|
|
222
264
|
},
|
|
223
265
|
UpdateUserState: (userState) => {
|
|
224
|
-
// Prevent updates during rendering
|
|
225
|
-
if (this.isRendering) {
|
|
266
|
+
// Prevent updates during rendering or destruction
|
|
267
|
+
if (this.isRendering || this.isDestroying) {
|
|
226
268
|
return;
|
|
227
269
|
}
|
|
228
270
|
// Deep comparison to detect actual changes
|
|
@@ -269,8 +311,24 @@ export class MJReactComponent {
|
|
|
269
311
|
* Clean up resources
|
|
270
312
|
*/
|
|
271
313
|
cleanup() {
|
|
272
|
-
//
|
|
314
|
+
// Clear any pending render timeout
|
|
315
|
+
if (this.renderTimeout) {
|
|
316
|
+
clearTimeout(this.renderTimeout);
|
|
317
|
+
this.renderTimeout = null;
|
|
318
|
+
}
|
|
319
|
+
// Clean up prop builder subscriptions
|
|
320
|
+
if (this.currentCallbacks) {
|
|
321
|
+
cleanupPropBuilder(this.currentCallbacks);
|
|
322
|
+
this.currentCallbacks = null;
|
|
323
|
+
}
|
|
324
|
+
// Unmount React root only if not currently rendering
|
|
273
325
|
if (this.reactRoot) {
|
|
326
|
+
// If still rendering, wait for completion before unmounting
|
|
327
|
+
if (this.isRendering) {
|
|
328
|
+
// Force stop rendering
|
|
329
|
+
this.isRendering = false;
|
|
330
|
+
this.pendingRender = false;
|
|
331
|
+
}
|
|
274
332
|
this.reactBridge.unmountRoot(this.reactRoot);
|
|
275
333
|
this.reactRoot = null;
|
|
276
334
|
}
|
|
@@ -377,5 +435,5 @@ export class MJReactComponent {
|
|
|
377
435
|
type: ViewChild,
|
|
378
436
|
args: ['container', { read: ElementRef, static: true }]
|
|
379
437
|
}] }); })();
|
|
380
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJReactComponent, { className: "MJReactComponent", filePath: "lib/components/mj-react-component.component.ts", lineNumber:
|
|
438
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJReactComponent, { className: "MJReactComponent", filePath: "lib/components/mj-react-component.component.ts", lineNumber: 115 }); })();
|
|
381
439
|
//# 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 { ComponentRootSpec, 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 ComponentError,\n createErrorBoundary,\n ComponentHierarchyRegistrar,\n HierarchyRegistrationResult\n} from '@memberjunction/react-runtime';\nimport { LogError, CompositeKey } 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!: ComponentRootSpec;\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; recordId: string }>();\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 currentState: any = {};\n isInitialized = false;\n private isRendering = false;\n private pendingRender = false;\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 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.componentName,\n componentCode: this.component.componentCode,\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 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 // Build props - pass styles as-is for Skip components\n const props = buildComponentProps(\n this._data || {},\n this.currentState,\n this.utilities || {},\n this.createCallbacks(),\n components,\n this.styles as any // Skip components expect the full SkipComponentStyles structure\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\n const renderTimeout = setTimeout(() => {\n this.componentEvent.emit({\n type: 'error',\n payload: {\n error: 'Component render timeout - possible infinite loop detected',\n source: 'render'\n }\n });\n }, 5000);\n\n try {\n this.reactRoot.render(element);\n clearTimeout(renderTimeout);\n \n // Reset rendering flag after a microtask to allow React to complete\n Promise.resolve().then(() => {\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(renderTimeout);\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 // Convert CompositeKey to a simple recordId for the event\n // Try to get the ID field first, otherwise get the first value\n const recordId = key.GetValueByFieldName('ID')?.toString() || \n key.GetValueByIndex(0)?.toString() || \n '';\n this.openEntityRecord.emit({ entityName, recordId });\n },\n UpdateUserState: (userState: any) => {\n // Prevent updates during rendering\n if (this.isRendering) {\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 // Unmount React root\n if (this.reactRoot) {\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":"AAAA;;;;GAIG;AAEH,OAAO,EACL,SAAS,EACT,KAAK,EACL,MAAM,EACN,YAAY,EACZ,SAAS,EACT,UAAU,EAGV,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAa,MAAM,MAAM,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAElB,mBAAmB,EACnB,2BAA2B,EAE5B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAgB,MAAM,sBAAsB,CAAC;;;;;;IA8BlE,AADF,8BAA6B,aACE;IAC3B,uBAA2C;IAC7C,iBAAM;IACN,8BAA0B;IAAA,oCAAoB;IAChD,AADgD,iBAAM,EAChD;;AAhBd;;;;GAIG;AA8DH,MAAM,OAAO,gBAAgB;IAI3B,IACI,IAAI,CAAC,KAAU;QACjB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QAEnB,uEAAuE;QACvE,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;YACxD,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IACD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAGD,IACI,KAAK,CAAC,KAAU;QAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QAEpB,yDAAyD;QACzD,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;YACzD,IAAI,CAAC,YAAY,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;YACjC,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IACD,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAwBD,YACU,WAA+B,EAC/B,OAA8B,EAC9B,GAAsB;QAFtB,gBAAW,GAAX,WAAW,CAAoB;QAC/B,YAAO,GAAP,OAAO,CAAuB;QAC9B,QAAG,GAAH,GAAG,CAAmB;QAxDxB,UAAK,GAAQ,EAAE,CAAC;QAehB,WAAM,GAAQ,EAAE,CAAC;QAgBhB,cAAS,GAAQ,EAAE,CAAC;QAGnB,gBAAW,GAAG,IAAI,YAAY,EAAoB,CAAC;QACnD,mBAAc,GAAG,IAAI,YAAY,EAAuB,CAAC;QACzD,gBAAW,GAAG,IAAI,YAAY,EAAQ,CAAC;QACvC,qBAAgB,GAAG,IAAI,YAAY,EAA6C,CAAC;QAInF,cAAS,GAAQ,IAAI,CAAC;QACtB,sBAAiB,GAAQ,IAAI,CAAC;QAC9B,eAAU,GAAG,IAAI,OAAO,EAAQ,CAAC;QACjC,qBAAgB,GAA8B,IAAI,CAAC;QACnD,iBAAY,GAAQ,EAAE,CAAC;QAC/B,kBAAa,GAAG,KAAK,CAAC;QACd,gBAAW,GAAG,KAAK,CAAC;QACpB,kBAAa,GAAG,KAAK,CAAC;QACtB,iBAAY,GAAG,KAAK,CAAC;QACrB,kBAAa,GAAQ,IAAI,CAAC;QAClC,aAAQ,GAAG,KAAK,CAAC;IAMd,CAAC;IAEJ,KAAK,CAAC,eAAe;QACnB,iDAAiD;QACjD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QACzB,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;IACnC,CAAC;IAED,WAAW;QACT,kCAAkC;QAClC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAEzB,6BAA6B;QAC7B,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAE3B,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;IAGD;;OAEG;IACK,KAAK,CAAC,mBAAmB;QAC/B,IAAI,CAAC;YACH,yBAAyB;YACzB,MAAM,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,CAAC;YAEzC,8DAA8D;YAC9D,MAAM,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,CAAC;YAE3C,+BAA+B;YAC/B,MAAM,IAAI,CAAC,0BAA0B,EAAE,CAAC;YAExC,yBAAyB;YACzB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC;gBACjD,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa;gBAC3C,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa;gBAC3C,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,8BAA8B,CAAC,CAAC;YAC3E,CAAC;YAED,oDAAoD;YACpD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC;YACjD,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC,SAAU,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAC3E,IAAI,CAAC,YAAY,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAEvC,oBAAoB;YACpB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YAE3E,iBAAiB;YACjB,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAE1B,oDAAoD;YACpD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAE3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,QAAQ,CAAC,yCAAyC,KAAK,EAAE,CAAC,CAAC;YAC3D,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;gBACvB,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE;oBACP,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;oBAC7D,MAAM,EAAE,gBAAgB;iBACzB;aACF,CAAC,CAAC;YACH,+CAA+C;YAC/C,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,0BAA0B;QACtC,sEAAsE;QACtE,MAAM,SAAS,GAAG,IAAI,2BAA2B,CAC/C,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAC1B,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAC1B,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CACjC,CAAC;QAEF,gCAAgC;QAChC,MAAM,MAAM,GAAgC,MAAM,SAAS,CAAC,iBAAiB,CAC3E,IAAI,CAAC,SAAS,EACd;YACE,MAAM,EAAE,IAAI,CAAC,MAAa,EAAE,8DAA8D;YAC1F,SAAS,EAAE,QAAQ;YACnB,OAAO,EAAE,IAAI;SACd,CACF,CAAC;QAEF,mBAAmB;QACnB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAC1C,GAAG,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,KAAK,EAAE,CACjC,CAAC;YACF,MAAM,IAAI,KAAK,CAAC,kCAAkC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IAED;;OAEG;IACK,eAAe;QACrB,+CAA+C;QAC/C,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,iBAAiB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YAC/C,OAAO;QACT,CAAC;QAED,6BAA6B;QAC7B,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,CAAC;QACrD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;QAE1B,+BAA+B;QAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAEhF,+CAA+C;QAC/C,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACjD,CAAC;QAED,sDAAsD;QACtD,MAAM,KAAK,GAAG,mBAAmB,CAC/B,IAAI,CAAC,KAAK,IAAI,EAAE,EAChB,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,SAAS,IAAI,EAAE,EACpB,IAAI,CAAC,gBAAgB,EACrB,UAAU,EACV,IAAI,CAAC,MAAa,EAAE,gEAAgE;QACpF,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC,+BAA+B;SAClE,CAAC;QAEF,wBAAwB;QACxB,MAAM,aAAa,GAAG,mBAAmB,CAAC,KAAK,EAAE;YAC/C,OAAO,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;YACzC,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QAEH,qCAAqC;QACrC,MAAM,OAAO,GAAG,KAAK,CAAC,aAAa,CACjC,aAAa,EACb,IAAI,EACJ,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,CAC7D,CAAC;QAEF,oCAAoC;QACpC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC;QAED,iCAAiC;QACjC,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;YACnC,6CAA6C;YAC7C,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;gBAC3C,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;oBACvB,IAAI,EAAE,OAAO;oBACb,OAAO,EAAE;wBACP,KAAK,EAAE,4DAA4D;wBACnE,MAAM,EAAE,QAAQ;qBACjB;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,CAAC;QAET,IAAI,CAAC;YACH,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC/B,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAE1B,oEAAoE;YACpE,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC1B,+CAA+C;gBAC/C,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;oBACtB,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;gBAEzB,wDAAwD;gBACxD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBACvB,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;oBAC3B,IAAI,CAAC,eAAe,EAAE,CAAC;gBACzB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YACzB,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED;;OAEG;IACK,eAAe;QACrB,OAAO;YACL,WAAW,EAAE,GAAG,EAAE;gBAChB,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;YAC1B,CAAC;YACD,gBAAgB,EAAE,CAAC,UAAkB,EAAE,GAAiB,EAAE,EAAE;gBAC1D,IAAI,QAAQ,GAAwB,IAAI,CAAC;gBACzC,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;oBACzB,QAAQ,GAAG,YAAY,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;gBACjD,CAAC;qBACI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;oBAC9D,QAAQ,GAAG,GAAmB,CAAC;gBACjC,CAAC;qBACI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;oBACjC,wCAAwC;oBACxC,oEAAoE;oBACpE,iCAAiC;oBACjC,MAAM,MAAM,GAAG,GAAU,CAAC;oBAC1B,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;wBACrC,QAAQ,GAAG,YAAY,CAAC,iBAAiB,CAAC,CAAC,MAAsB,CAAC,CAAC,CAAC;oBACtE,CAAC;gBACH,CAAC;gBACD,IAAI,QAAQ,EAAE,CAAC;oBACb,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC;YACD,eAAe,EAAE,CAAC,SAAc,EAAE,EAAE;gBAClC,kDAAkD;gBAClD,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;oBAC1C,OAAO;gBACT,CAAC;gBAED,2CAA2C;gBAC3C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;oBACnD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;oBAC5C,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;oBAChC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;gBAC/C,CAAC,CAAC,CAAC;gBAEH,IAAI,CAAC,UAAU,EAAE,CAAC;oBAChB,0DAA0D;oBAC1D,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,YAAY,GAAG;oBAClB,GAAG,IAAI,CAAC,YAAY;oBACpB,GAAG,SAAS;iBACb,CAAC;gBAEF,+CAA+C;gBAC/C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;oBACpC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC1D,CAAC,CAAC,CAAC;gBAEH,qBAAqB;gBACrB,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,CAAC;YACD,WAAW,EAAE,CAAC,KAAa,EAAE,IAAS,EAAE,EAAE;gBACxC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3D,CAAC;SACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,KAAU,EAAE,SAAe;QAClD,QAAQ,CAAC,0BAA0B,KAAK,EAAE,QAAQ,EAAE,IAAI,eAAe,EAAE,EAAE,SAAS,CAAC,CAAC;QACtF,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;YACvB,IAAI,EAAE,OAAO;YACb,OAAO,EAAE;gBACP,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,eAAe;gBAC3C,SAAS;gBACT,MAAM,EAAE,OAAO;aAChB;SACF,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,OAAO;QACb,mCAAmC;QACnC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC5B,CAAC;QAED,sCAAsC;QACtC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,kBAAkB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC/B,CAAC;QAED,qDAAqD;QACrD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,4DAA4D;YAC5D,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,uBAAuB;gBACvB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;gBACzB,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;YAC7B,CAAC;YAED,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC7C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,CAAC;QAED,mBAAmB;QACnB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAE3B,2BAA2B;QAC3B,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,CAAC;IACvC,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,OAAa;QACnB,IAAI,OAAO,EAAE,CAAC;YACZ,6CAA6C;YAC7C,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,OAAO,EAAE,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,WAAW,CAAC,IAAY,EAAE,KAAU;QAClC,IAAI,CAAC,YAAY,GAAG;YAClB,GAAG,IAAI,CAAC,YAAY;YACpB,CAAC,IAAI,CAAC,EAAE,KAAK;SACd,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC,eAAe,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACK,OAAO,CAAC,CAAM,EAAE,CAAM;QAC5B,8BAA8B;QAC9B,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACzB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI;YAAE,OAAO,KAAK,CAAC;QAEzC,0CAA0C;QAC1C,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC;iFAjbU,gBAAgB;oEAAhB,gBAAgB;mCA0CK,UAAU;;;;;YApGxC,8BAAqC;YACnC,4BAAyF;YACzF,yEAAmC;YAQrC,iBAAM;;YAT8C,cAAgC;YAAhC,6CAAgC;YAClF,eAOC;YAPD,8DAOC;;;iFAiDM,gBAAgB;cA7D5B,SAAS;2BACE,oBAAoB,YACpB;;;;;;;;;;;;GAYT,mBA6CgB,uBAAuB,CAAC,MAAM;uHAGtC,SAAS;kBAAjB,KAAK;YAIF,IAAI;kBADP,KAAK;YAgBF,KAAK;kBADR,KAAK;YAeG,SAAS;kBAAjB,KAAK;YACG,MAAM;kBAAd,KAAK;YAEI,WAAW;kBAApB,MAAM;YACG,cAAc;kBAAvB,MAAM;YACG,WAAW;kBAApB,MAAM;YACG,gBAAgB;kBAAzB,MAAM;YAEqD,SAAS;kBAApE,SAAS;mBAAC,WAAW,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE;;kFA1C/C,gBAAgB","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 { ComponentRootSpec, 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!: ComponentRootSpec;\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.componentName,\n componentCode: this.component.componentCode,\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}"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.73.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.73.0",
|
|
44
|
+
"@memberjunction/react-runtime": "2.73.0",
|
|
45
|
+
"@memberjunction/interactive-component-types": "^2.73.0",
|
|
46
46
|
"@angular/common": ">=18.0.0",
|
|
47
47
|
"@angular/core": ">=18.0.0",
|
|
48
48
|
"@angular/platform-browser": ">=18.0.0",
|