@memberjunction/ng-react 2.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # @memberjunction/ng-react
2
+
3
+ Angular components for hosting React components in MemberJunction applications. This package provides a seamless bridge between Angular and React, allowing you to use React components within your Angular applications.
4
+
5
+ ## Overview
6
+
7
+ The `@memberjunction/ng-react` package enables Angular applications to render React components dynamically. It handles all the complexity of loading React, compiling JSX, managing component lifecycles, and bridging Angular/React data flow.
8
+
9
+ ## Features
10
+
11
+ - **Dynamic React Component Rendering**: Compile and render React components from source code
12
+ - **Automatic Dependency Loading**: Loads React, ReactDOM, and Babel from CDN
13
+ - **Component Registry**: Manages compiled components with namespace support
14
+ - **Error Boundaries**: Comprehensive error handling for React components
15
+ - **Two-Way Data Binding**: Seamless data flow between Angular and React
16
+ - **TypeScript Support**: Full type safety with TypeScript definitions
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install @memberjunction/ng-react
22
+ ```
23
+
24
+ ## Basic Usage
25
+
26
+ ### 1. Import the Module
27
+
28
+ ```typescript
29
+ import { MJReactModule } from '@memberjunction/ng-react';
30
+
31
+ @NgModule({
32
+ imports: [
33
+ CommonModule,
34
+ MJReactModule
35
+ ]
36
+ })
37
+ export class YourModule { }
38
+ ```
39
+
40
+ ### 2. Use in Templates
41
+
42
+ ```html
43
+ <mj-react-component
44
+ [component]="componentSpec"
45
+ [data]="componentData"
46
+ [state]="componentState"
47
+ [utilities]="utilities"
48
+ [styles]="styles"
49
+ (stateChange)="onStateChange($event)"
50
+ (componentEvent)="onComponentEvent($event)"
51
+ (refreshData)="onRefreshData()"
52
+ (openEntityRecord)="onOpenEntityRecord($event)">
53
+ </mj-react-component>
54
+ ```
55
+
56
+ ### 3. Component Controller
57
+
58
+ ```typescript
59
+ import { Component } from '@angular/core';
60
+ import { SkipComponentRootSpec } from '@memberjunction/skip-types';
61
+
62
+ @Component({
63
+ selector: 'app-example',
64
+ template: `
65
+ <mj-react-component
66
+ [component]="reactComponent"
67
+ [data]="data">
68
+ </mj-react-component>
69
+ `
70
+ })
71
+ export class ExampleComponent {
72
+ reactComponent: SkipComponentRootSpec = {
73
+ componentName: 'MyReactComponent',
74
+ componentCode: `
75
+ function MyReactComponent({ data, callbacks }) {
76
+ return (
77
+ <div>
78
+ <h1>Hello, {data.name}!</h1>
79
+ <button onClick={() => callbacks.RefreshData()}>
80
+ Refresh
81
+ </button>
82
+ </div>
83
+ );
84
+ }
85
+ `
86
+ };
87
+
88
+ data = {
89
+ name: 'World'
90
+ };
91
+ }
92
+ ```
93
+
94
+ ## Component Props
95
+
96
+ React components receive the following props:
97
+
98
+ ```typescript
99
+ interface ComponentProps {
100
+ data: any; // Data passed from Angular
101
+ userState: any; // Component state managed by Angular
102
+ utilities: any; // Utility functions
103
+ callbacks: { // Callbacks to Angular
104
+ RefreshData: () => void;
105
+ OpenEntityRecord: (entityName: string, key: any) => void;
106
+ UpdateUserState: (state: any) => void;
107
+ NotifyEvent: (event: string, data: any) => void;
108
+ };
109
+ components?: Record<string, any>; // Child components
110
+ styles?: ComponentStyles; // Style configuration
111
+ }
112
+ ```
113
+
114
+ ## Advanced Features
115
+
116
+ ### Component Hierarchies
117
+
118
+ ```typescript
119
+ const componentSpec: SkipComponentRootSpec = {
120
+ componentName: 'ParentComponent',
121
+ componentCode: '...',
122
+ childComponents: [
123
+ {
124
+ componentName: 'ChildComponent1',
125
+ componentCode: '...'
126
+ },
127
+ {
128
+ componentName: 'ChildComponent2',
129
+ componentCode: '...'
130
+ }
131
+ ]
132
+ };
133
+ ```
134
+
135
+ ### Custom Styles
136
+
137
+ ```typescript
138
+ const styles: SkipComponentStyles = {
139
+ colors: {
140
+ primary: '#5B4FE9',
141
+ secondary: '#64748B'
142
+ },
143
+ typography: {
144
+ fontFamily: 'Inter, sans-serif'
145
+ }
146
+ };
147
+ ```
148
+
149
+ ### State Management
150
+
151
+ ```typescript
152
+ // In your Angular component
153
+ onStateChange(event: StateChangeEvent) {
154
+ console.log(`State ${event.path} changed to:`, event.value);
155
+ // Update your Angular component state
156
+ }
157
+
158
+ // In your React component
159
+ function MyComponent({ userState, callbacks }) {
160
+ const updateState = () => {
161
+ callbacks.UpdateUserState({
162
+ counter: userState.counter + 1
163
+ });
164
+ };
165
+
166
+ return <button onClick={updateState}>Count: {userState.counter}</button>;
167
+ }
168
+ ```
169
+
170
+ ## Services
171
+
172
+ ### ScriptLoaderService
173
+
174
+ Manages loading of external scripts and CSS:
175
+
176
+ ```typescript
177
+ constructor(private scriptLoader: ScriptLoaderService) {}
178
+
179
+ async loadCustomLibrary() {
180
+ const lib = await this.scriptLoader.loadScript(
181
+ 'https://cdn.example.com/lib.js',
182
+ 'MyLibrary'
183
+ );
184
+ }
185
+ ```
186
+
187
+ ### ReactBridgeService
188
+
189
+ Manages React instances and roots:
190
+
191
+ ```typescript
192
+ constructor(private reactBridge: ReactBridgeService) {}
193
+
194
+ async checkReactStatus() {
195
+ const isReady = this.reactBridge.isReady();
196
+ const rootCount = this.reactBridge.getActiveRootsCount();
197
+ }
198
+ ```
199
+
200
+ ### AngularAdapterService
201
+
202
+ Provides access to the React runtime:
203
+
204
+ ```typescript
205
+ constructor(private adapter: AngularAdapterService) {}
206
+
207
+ async compileCustomComponent() {
208
+ const result = await this.adapter.compileComponent({
209
+ componentName: 'CustomComponent',
210
+ componentCode: '...'
211
+ });
212
+ }
213
+ ```
214
+
215
+ ## Error Handling
216
+
217
+ The component automatically wraps React components in error boundaries:
218
+
219
+ ```typescript
220
+ onComponentEvent(event: ReactComponentEvent) {
221
+ if (event.type === 'error') {
222
+ console.error('React component error:', event.payload);
223
+ // Handle error in Angular
224
+ }
225
+ }
226
+ ```
227
+
228
+ ## Performance Considerations
229
+
230
+ 1. **Component Caching**: Compiled components are cached automatically
231
+ 2. **Lazy Loading**: React libraries are loaded on-demand
232
+ 3. **Change Detection**: Uses OnPush strategy for optimal performance
233
+ 4. **Resource Cleanup**: Automatic cleanup of React roots on destroy
234
+
235
+ ## Browser Support
236
+
237
+ - Chrome (latest)
238
+ - Firefox (latest)
239
+ - Safari (latest)
240
+ - Edge (latest)
241
+
242
+ ## Dependencies
243
+
244
+ This package requires:
245
+ - Angular 18+
246
+ - React 18+
247
+ - @memberjunction/react-runtime
248
+ - @memberjunction/skip-types
249
+ - @memberjunction/core
250
+
251
+ ## License
252
+
253
+ See the main MemberJunction LICENSE file in the repository root.
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @fileoverview Entry point for @memberjunction/ng-react package
3
+ * @module @memberjunction/ng-react
4
+ */
5
+ export * from './public-api';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @fileoverview Entry point for @memberjunction/ng-react package
3
+ * @module @memberjunction/ng-react
4
+ */
5
+ export * from './public-api';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC","sourcesContent":["/**\n * @fileoverview Entry point for @memberjunction/ng-react package\n * @module @memberjunction/ng-react\n */\n\nexport * from './public-api';"]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @fileoverview CDN URLs for external React and related dependencies.
3
+ * These URLs are used to load React ecosystem libraries in the browser.
4
+ * @module @memberjunction/ng-react
5
+ */
6
+ /**
7
+ * CDN URLs for external dependencies
8
+ * These can be configured via environment variables in the future
9
+ */
10
+ export declare const CDN_URLS: {
11
+ BABEL_STANDALONE: string;
12
+ REACT: string;
13
+ REACT_DOM: string;
14
+ DAYJS: string;
15
+ ANTD_JS: string;
16
+ ANTD_CSS: string;
17
+ REACT_BOOTSTRAP_JS: string;
18
+ BOOTSTRAP_CSS: string;
19
+ D3_JS: string;
20
+ CHART_JS: string;
21
+ LODASH_JS: string;
22
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @fileoverview CDN URLs for external React and related dependencies.
3
+ * These URLs are used to load React ecosystem libraries in the browser.
4
+ * @module @memberjunction/ng-react
5
+ */
6
+ /**
7
+ * CDN URLs for external dependencies
8
+ * These can be configured via environment variables in the future
9
+ */
10
+ export const CDN_URLS = {
11
+ // Core React dependencies
12
+ BABEL_STANDALONE: 'https://unpkg.com/@babel/standalone@7/babel.min.js',
13
+ REACT: 'https://unpkg.com/react@18/umd/react.production.min.js',
14
+ REACT_DOM: 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js',
15
+ // Ant Design dependencies
16
+ DAYJS: 'https://unpkg.com/dayjs@1.11.10/dayjs.min.js',
17
+ // UI Libraries - Using UMD builds that work with global React
18
+ ANTD_JS: 'https://unpkg.com/antd@5.12.8/dist/antd.js',
19
+ ANTD_CSS: 'https://unpkg.com/antd@5.12.8/dist/reset.css',
20
+ REACT_BOOTSTRAP_JS: 'https://unpkg.com/react-bootstrap@2.9.1/dist/react-bootstrap.js',
21
+ BOOTSTRAP_CSS: 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css',
22
+ // Data Visualization
23
+ D3_JS: 'https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js',
24
+ CHART_JS: 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.js',
25
+ // Utilities
26
+ LODASH_JS: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js'
27
+ };
28
+ //# sourceMappingURL=cdn-urls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdn-urls.js","sourceRoot":"","sources":["../../src/lib/cdn-urls.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,0BAA0B;IAC1B,gBAAgB,EAAE,oDAAoD;IACtE,KAAK,EAAE,wDAAwD;IAC/D,SAAS,EAAE,gEAAgE;IAE3E,0BAA0B;IAC1B,KAAK,EAAE,8CAA8C;IAErD,8DAA8D;IAC9D,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,8CAA8C;IACxD,kBAAkB,EAAE,iEAAiE;IACrF,aAAa,EAAE,yEAAyE;IAExF,qBAAqB;IACrB,KAAK,EAAE,2DAA2D;IAClE,QAAQ,EAAE,oEAAoE;IAE9E,YAAY;IACZ,SAAS,EAAE,wEAAwE;CACpF,CAAC","sourcesContent":["/**\n * @fileoverview CDN URLs for external React and related dependencies.\n * These URLs are used to load React ecosystem libraries in the browser.\n * @module @memberjunction/ng-react\n */\n\n/**\n * CDN URLs for external dependencies\n * These can be configured via environment variables in the future\n */\nexport const CDN_URLS = {\n // Core React dependencies\n BABEL_STANDALONE: 'https://unpkg.com/@babel/standalone@7/babel.min.js',\n REACT: 'https://unpkg.com/react@18/umd/react.production.min.js',\n REACT_DOM: 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js',\n \n // Ant Design dependencies\n DAYJS: 'https://unpkg.com/dayjs@1.11.10/dayjs.min.js',\n \n // UI Libraries - Using UMD builds that work with global React\n ANTD_JS: 'https://unpkg.com/antd@5.12.8/dist/antd.js',\n ANTD_CSS: 'https://unpkg.com/antd@5.12.8/dist/reset.css',\n REACT_BOOTSTRAP_JS: 'https://unpkg.com/react-bootstrap@2.9.1/dist/react-bootstrap.js',\n BOOTSTRAP_CSS: 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css',\n \n // Data Visualization\n D3_JS: 'https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js',\n CHART_JS: 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.js',\n \n // Utilities\n LODASH_JS: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js'\n};"]}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @fileoverview Angular component that hosts React components with proper memory management.
3
+ * Provides a bridge between Angular and React ecosystems in MemberJunction applications.
4
+ * @module @memberjunction/ng-react
5
+ */
6
+ import { EventEmitter, ElementRef, AfterViewInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
7
+ import { SkipComponentRootSpec, SkipComponentStyles } from '@memberjunction/skip-types';
8
+ import { ReactBridgeService } from '../services/react-bridge.service';
9
+ import { AngularAdapterService } from '../services/angular-adapter.service';
10
+ import * as i0 from "@angular/core";
11
+ /**
12
+ * Event emitted by React components
13
+ */
14
+ export interface ReactComponentEvent {
15
+ type: string;
16
+ payload: any;
17
+ }
18
+ /**
19
+ * State change event emitted when component state updates
20
+ */
21
+ export interface StateChangeEvent {
22
+ path: string;
23
+ value: any;
24
+ }
25
+ /**
26
+ * Angular component that hosts React components with proper memory management.
27
+ * This component provides a bridge between Angular and React, allowing React components
28
+ * to be used seamlessly within Angular applications.
29
+ */
30
+ export declare class MJReactComponent implements AfterViewInit, OnDestroy {
31
+ private reactBridge;
32
+ private adapter;
33
+ private cdr;
34
+ component: SkipComponentRootSpec;
35
+ private _data;
36
+ set data(value: any);
37
+ get data(): any;
38
+ private _state;
39
+ set state(value: any);
40
+ get state(): any;
41
+ utilities: any;
42
+ styles?: Partial<SkipComponentStyles>;
43
+ stateChange: EventEmitter<StateChangeEvent>;
44
+ componentEvent: EventEmitter<ReactComponentEvent>;
45
+ refreshData: EventEmitter<void>;
46
+ openEntityRecord: EventEmitter<{
47
+ entityName: string;
48
+ recordId: string;
49
+ }>;
50
+ container: ElementRef<HTMLDivElement>;
51
+ private reactRoot;
52
+ private compiledComponent;
53
+ private destroyed$;
54
+ private currentState;
55
+ isInitialized: boolean;
56
+ private isRendering;
57
+ private pendingRender;
58
+ hasError: boolean;
59
+ constructor(reactBridge: ReactBridgeService, adapter: AngularAdapterService, cdr: ChangeDetectorRef);
60
+ ngAfterViewInit(): Promise<void>;
61
+ ngOnDestroy(): void;
62
+ /**
63
+ * Convert SkipComponentStyles to ComponentStyles
64
+ * @param skipStyles - Skip component styles
65
+ * @returns Component styles for React runtime
66
+ */
67
+ private convertStyles;
68
+ /**
69
+ * Initialize the React component
70
+ */
71
+ private initializeComponent;
72
+ /**
73
+ * Register all components in the hierarchy
74
+ */
75
+ private registerComponentHierarchy;
76
+ /**
77
+ * Render the React component
78
+ */
79
+ private renderComponent;
80
+ /**
81
+ * Create callbacks for the React component
82
+ */
83
+ private createCallbacks;
84
+ /**
85
+ * Handle React component errors
86
+ */
87
+ private handleReactError;
88
+ /**
89
+ * Clean up resources
90
+ */
91
+ private cleanup;
92
+ /**
93
+ * Public method to refresh the component
94
+ * @param newData - Optional new data to merge
95
+ */
96
+ refresh(newData?: any): void;
97
+ /**
98
+ * Public method to update state programmatically
99
+ * @param path - State path to update
100
+ * @param value - New value
101
+ */
102
+ updateState(path: string, value: any): void;
103
+ /**
104
+ * Deep equality check that handles null/undefined properly
105
+ */
106
+ private isEqual;
107
+ static ɵfac: i0.ɵɵFactoryDeclaration<MJReactComponent, never>;
108
+ 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>;
109
+ }