@memberjunction/react-runtime 2.74.0 → 2.75.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.
Files changed (37) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +14 -0
  3. package/README.md +96 -4
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +3 -5
  7. package/dist/registry/component-resolver.d.ts +1 -6
  8. package/dist/registry/component-resolver.d.ts.map +1 -1
  9. package/dist/registry/component-resolver.js +19 -19
  10. package/dist/registry/index.d.ts +2 -1
  11. package/dist/registry/index.d.ts.map +1 -1
  12. package/dist/registry/index.js +3 -1
  13. package/dist/runtime/component-hierarchy.d.ts +1 -1
  14. package/dist/runtime/component-hierarchy.d.ts.map +1 -1
  15. package/dist/runtime/component-hierarchy.js +25 -25
  16. package/dist/types/index.d.ts +1 -0
  17. package/dist/types/index.d.ts.map +1 -1
  18. package/dist/types/index.js +15 -0
  19. package/dist/types/library-config.d.ts +32 -0
  20. package/dist/types/library-config.d.ts.map +1 -0
  21. package/dist/types/library-config.js +2 -0
  22. package/dist/utilities/library-loader.d.ts +3 -2
  23. package/dist/utilities/library-loader.d.ts.map +1 -1
  24. package/dist/utilities/library-loader.js +54 -76
  25. package/dist/utilities/standard-libraries.d.ts +13 -24
  26. package/dist/utilities/standard-libraries.d.ts.map +1 -1
  27. package/dist/utilities/standard-libraries.js +58 -47
  28. package/package.json +4 -4
  29. package/src/index.ts +1 -4
  30. package/src/registry/component-resolver.ts +21 -30
  31. package/src/registry/index.ts +2 -1
  32. package/src/runtime/component-hierarchy.ts +26 -26
  33. package/src/types/index.ts +4 -1
  34. package/src/types/library-config.ts +75 -0
  35. package/src/utilities/library-loader.ts +94 -93
  36. package/src/utilities/standard-libraries.ts +104 -71
  37. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Configuration for external libraries used in React components
3
+ */
4
+
5
+ export interface ExternalLibraryConfig {
6
+ /** Unique identifier for the library */
7
+ id: string;
8
+
9
+ /** Library name (e.g., 'lodash') */
10
+ name: string;
11
+
12
+ /** Display name for UI (e.g., 'Lodash') */
13
+ displayName: string;
14
+
15
+ /** Library category */
16
+ category: 'core' | 'runtime' | 'ui' | 'charting' | 'utility';
17
+
18
+ /** Global variable name when loaded (e.g., '_' for lodash) */
19
+ globalVariable: string;
20
+
21
+ /** Library version */
22
+ version: string;
23
+
24
+ /** CDN URL for the library JavaScript */
25
+ cdnUrl: string;
26
+
27
+ /** Optional CDN URL for library CSS */
28
+ cdnCssUrl?: string;
29
+
30
+ /** Library description */
31
+ description: string;
32
+
33
+ /** Instructions for AI when using this library */
34
+ aiInstructions?: string;
35
+
36
+ /** Example usage code */
37
+ exampleUsage?: string;
38
+
39
+ /** Whether the library is enabled */
40
+ isEnabled: boolean;
41
+
42
+ /** Whether this is a core library (always loaded) */
43
+ isCore: boolean;
44
+
45
+ /** Whether this is runtime-only (not exposed to generated components) */
46
+ isRuntimeOnly?: boolean;
47
+ }
48
+
49
+ export interface LibraryConfigurationMetadata {
50
+ version: string;
51
+ lastUpdated: string;
52
+ description?: string;
53
+ }
54
+
55
+ export interface LibraryConfiguration {
56
+ libraries: ExternalLibraryConfig[];
57
+ metadata: LibraryConfigurationMetadata;
58
+ }
59
+
60
+ /**
61
+ * Library loading options
62
+ */
63
+ export interface LibraryLoadOptions {
64
+ /** Skip loading if already loaded */
65
+ skipIfLoaded?: boolean;
66
+
67
+ /** Timeout for loading (ms) */
68
+ timeout?: number;
69
+
70
+ /** Filter to specific categories */
71
+ categories?: Array<ExternalLibraryConfig['category']>;
72
+
73
+ /** Exclude runtime-only libraries */
74
+ excludeRuntimeOnly?: boolean;
75
+ }
@@ -5,12 +5,10 @@
5
5
  */
6
6
 
7
7
  import {
8
- STANDARD_LIBRARY_URLS,
9
8
  StandardLibraries,
10
- getCoreLibraryUrls,
11
- getUILibraryUrls,
12
- getCSSUrls
9
+ StandardLibraryManager
13
10
  } from './standard-libraries';
11
+ import { LibraryConfiguration, ExternalLibraryConfig, LibraryLoadOptions as ConfigLoadOptions } from '../types/library-config';
14
12
 
15
13
  /**
16
14
  * Represents a loaded script or CSS resource
@@ -22,6 +20,7 @@ interface LoadedResource {
22
20
 
23
21
  /**
24
22
  * Options for loading libraries
23
+ * @deprecated Use LibraryLoadOptions from library-config instead
25
24
  */
26
25
  export interface LibraryLoadOptions {
27
26
  /** Load core libraries (lodash, d3, Chart.js, dayjs) */
@@ -54,16 +53,80 @@ export class LibraryLoader {
54
53
  * Load all standard libraries (core + UI + CSS)
55
54
  * This is the main method that should be used by test harness and Angular wrapper
56
55
  */
57
- static async loadAllLibraries(): Promise<LibraryLoadResult> {
58
- return this.loadLibraries({
59
- loadCore: true,
60
- loadUI: true,
61
- loadCSS: true
56
+ static async loadAllLibraries(config?: LibraryConfiguration): Promise<LibraryLoadResult> {
57
+ if (config) {
58
+ StandardLibraryManager.setConfiguration(config);
59
+ }
60
+
61
+ return this.loadLibrariesFromConfig();
62
+ }
63
+
64
+ /**
65
+ * Load libraries based on the current configuration
66
+ */
67
+ static async loadLibrariesFromConfig(options?: ConfigLoadOptions): Promise<LibraryLoadResult> {
68
+ const config = StandardLibraryManager.getConfiguration();
69
+ const enabledLibraries = StandardLibraryManager.getEnabledLibraries();
70
+
71
+ // Apply options filters if provided
72
+ let librariesToLoad = enabledLibraries;
73
+ if (options) {
74
+ if (options.categories) {
75
+ librariesToLoad = librariesToLoad.filter(lib =>
76
+ options.categories!.includes(lib.category)
77
+ );
78
+ }
79
+ if (options.excludeRuntimeOnly) {
80
+ librariesToLoad = librariesToLoad.filter(lib => !lib.isRuntimeOnly);
81
+ }
82
+ }
83
+
84
+ // Separate runtime and component libraries
85
+ const runtimeLibs = librariesToLoad.filter(lib => lib.category === 'runtime');
86
+ const componentLibs = librariesToLoad.filter(lib => lib.category !== 'runtime');
87
+
88
+ // Load runtime libraries first (React, ReactDOM, Babel)
89
+ const runtimePromises = runtimeLibs.map(lib =>
90
+ this.loadScript(lib.cdnUrl, lib.globalVariable)
91
+ );
92
+
93
+ const runtimeResults = await Promise.all(runtimePromises);
94
+ const React = runtimeResults.find((_, i) => runtimeLibs[i].globalVariable === 'React');
95
+ const ReactDOM = runtimeResults.find((_, i) => runtimeLibs[i].globalVariable === 'ReactDOM');
96
+ const Babel = runtimeResults.find((_, i) => runtimeLibs[i].globalVariable === 'Babel');
97
+
98
+ // Load CSS files (non-blocking)
99
+ componentLibs.forEach(lib => {
100
+ if (lib.cdnCssUrl) {
101
+ this.loadCSS(lib.cdnCssUrl);
102
+ }
103
+ });
104
+
105
+ // Load component libraries
106
+ const componentPromises = componentLibs.map(lib =>
107
+ this.loadScript(lib.cdnUrl, lib.globalVariable)
108
+ );
109
+
110
+ const componentResults = await Promise.all(componentPromises);
111
+
112
+ // Build libraries object
113
+ const libraries: StandardLibraries = {};
114
+
115
+ componentLibs.forEach((lib, index) => {
116
+ libraries[lib.globalVariable] = componentResults[index];
62
117
  });
118
+
119
+ return {
120
+ React: React || (window as any).React,
121
+ ReactDOM: ReactDOM || (window as any).ReactDOM,
122
+ Babel: Babel || (window as any).Babel,
123
+ libraries
124
+ };
63
125
  }
64
126
 
65
127
  /**
66
- * Load libraries with specific options
128
+ * Load libraries with specific options (backward compatibility)
129
+ * @deprecated Use loadLibrariesFromConfig instead
67
130
  */
68
131
  static async loadLibraries(options: LibraryLoadOptions): Promise<LibraryLoadResult> {
69
132
  const {
@@ -73,78 +136,32 @@ export class LibraryLoader {
73
136
  customLibraries = []
74
137
  } = options;
75
138
 
76
- // Load React ecosystem first
77
- const [React, ReactDOM, Babel] = await Promise.all([
78
- this.loadScript(STANDARD_LIBRARY_URLS.REACT, 'React'),
79
- this.loadScript(STANDARD_LIBRARY_URLS.REACT_DOM, 'ReactDOM'),
80
- this.loadScript(STANDARD_LIBRARY_URLS.BABEL, 'Babel')
81
- ]);
82
-
83
- // Load CSS files if requested (non-blocking)
84
- if (loadCSS) {
85
- getCSSUrls().forEach(url => this.loadCSS(url));
86
- }
87
-
88
- // Prepare library loading promises
89
- const libraryPromises: Promise<any>[] = [];
90
- const libraryNames: string[] = [];
91
-
92
- // Core libraries
139
+ // Map old options to new configuration approach
140
+ const categoriesToLoad: Array<ExternalLibraryConfig['category']> = ['runtime'];
93
141
  if (loadCore) {
94
- const coreUrls = getCoreLibraryUrls();
95
- coreUrls.forEach(url => {
96
- const name = this.getLibraryNameFromUrl(url);
97
- libraryNames.push(name);
98
- libraryPromises.push(this.loadScript(url, name));
99
- });
142
+ categoriesToLoad.push('utility', 'charting');
100
143
  }
101
-
102
- // UI libraries
103
144
  if (loadUI) {
104
- const uiUrls = getUILibraryUrls();
105
- uiUrls.forEach(url => {
106
- const name = this.getLibraryNameFromUrl(url);
107
- libraryNames.push(name);
108
- libraryPromises.push(this.loadScript(url, name));
109
- });
145
+ categoriesToLoad.push('ui');
110
146
  }
111
-
112
- // Custom libraries
113
- customLibraries.forEach(({ url, globalName }) => {
114
- libraryNames.push(globalName);
115
- libraryPromises.push(this.loadScript(url, globalName));
116
- });
117
-
118
- // Load all libraries
119
- const loadedLibraries = await Promise.all(libraryPromises);
120
-
121
- // Build libraries object
122
- const libraries: StandardLibraries = {
123
- _: undefined // Initialize with required property
124
- };
125
- libraryNames.forEach((name, index) => {
126
- // Map common names
127
- if (name === '_') {
128
- libraries._ = loadedLibraries[index];
129
- } else {
130
- libraries[name] = loadedLibraries[index];
131
- }
147
+
148
+ const result = await this.loadLibrariesFromConfig({
149
+ categories: categoriesToLoad
132
150
  });
133
-
134
- // Ensure all standard properties exist
135
- if (!libraries._) libraries._ = (window as any)._;
136
- if (!libraries.d3) libraries.d3 = (window as any).d3;
137
- if (!libraries.Chart) libraries.Chart = (window as any).Chart;
138
- if (!libraries.dayjs) libraries.dayjs = (window as any).dayjs;
139
- if (!libraries.antd) libraries.antd = (window as any).antd;
140
- if (!libraries.ReactBootstrap) libraries.ReactBootstrap = (window as any).ReactBootstrap;
141
-
142
- return {
143
- React,
144
- ReactDOM,
145
- Babel,
146
- libraries
147
- };
151
+
152
+ // Load custom libraries if provided
153
+ if (customLibraries.length > 0) {
154
+ const customPromises = customLibraries.map(({ url, globalName }) =>
155
+ this.loadScript(url, globalName)
156
+ );
157
+
158
+ const customResults = await Promise.all(customPromises);
159
+ customLibraries.forEach(({ globalName }, index) => {
160
+ result.libraries[globalName] = customResults[index];
161
+ });
162
+ }
163
+
164
+ return result;
148
165
  }
149
166
 
150
167
  /**
@@ -274,22 +291,6 @@ export class LibraryLoader {
274
291
  script.addEventListener('load', loadHandler);
275
292
  }
276
293
 
277
- /**
278
- * Get library name from URL for global variable mapping
279
- */
280
- private static getLibraryNameFromUrl(url: string): string {
281
- // Map known URLs to their global variable names
282
- if (url.includes('lodash')) return '_';
283
- if (url.includes('d3')) return 'd3';
284
- if (url.includes('Chart.js') || url.includes('chart')) return 'Chart';
285
- if (url.includes('dayjs')) return 'dayjs';
286
- if (url.includes('antd')) return 'antd';
287
- if (url.includes('react-bootstrap')) return 'ReactBootstrap';
288
-
289
- // Default: extract name from URL
290
- const match = url.match(/\/([^\/]+)(?:\.min)?\.js$/);
291
- return match ? match[1] : 'unknown';
292
- }
293
294
 
294
295
  /**
295
296
  * Get all loaded resources (for cleanup)
@@ -3,95 +3,128 @@
3
3
  * @module @memberjunction/react-runtime/utilities
4
4
  */
5
5
 
6
- /**
7
- * CDN URLs for standard libraries used by React components
8
- */
9
- export const STANDARD_LIBRARY_URLS = {
10
- // Core React libraries
11
- REACT: 'https://unpkg.com/react@18/umd/react.development.js',
12
- REACT_DOM: 'https://unpkg.com/react-dom@18/umd/react-dom.development.js',
13
- BABEL: 'https://unpkg.com/@babel/standalone/babel.min.js',
14
-
15
- // Data Visualization
16
- D3: 'https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js',
17
- CHART_JS: 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.js',
18
-
19
- // Utilities
20
- LODASH: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js',
21
- DAYJS: 'https://unpkg.com/dayjs@1.11.10/dayjs.min.js',
22
-
23
- // UI Libraries (optional)
24
- ANTD: 'https://unpkg.com/antd@5.11.5/dist/antd.min.js',
25
- REACT_BOOTSTRAP: 'https://unpkg.com/react-bootstrap@2.9.1/dist/react-bootstrap.min.js',
26
-
27
- // CSS
28
- ANTD_CSS: 'https://unpkg.com/antd@5.11.5/dist/reset.css',
29
- BOOTSTRAP_CSS: 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css'
30
- };
6
+ import { LibraryConfiguration, ExternalLibraryConfig } from '../types/library-config';
31
7
 
32
- /**
33
- * Interface for standard libraries available to React components
34
- */
35
- export interface StandardLibraries {
36
- _: any; // lodash
37
- d3?: any;
38
- Chart?: any;
39
- dayjs?: any;
40
- antd?: any;
41
- ReactBootstrap?: any;
42
- [key: string]: any; // Allow additional libraries
43
- }
44
8
 
45
9
  /**
46
- * Get the list of core libraries that should always be loaded
10
+ * Type for dynamically loaded libraries available to React components
47
11
  */
48
- export function getCoreLibraryUrls(): string[] {
49
- return [
50
- STANDARD_LIBRARY_URLS.LODASH,
51
- STANDARD_LIBRARY_URLS.D3,
52
- STANDARD_LIBRARY_URLS.CHART_JS,
53
- STANDARD_LIBRARY_URLS.DAYJS
54
- ];
55
- }
12
+ export type StandardLibraries = Record<string, any>;
56
13
 
57
14
  /**
58
- * Get the list of optional UI library URLs
15
+ * Default empty library configuration
16
+ * Libraries should be configured dynamically at runtime
59
17
  */
60
- export function getUILibraryUrls(): string[] {
61
- return [
62
- STANDARD_LIBRARY_URLS.ANTD,
63
- STANDARD_LIBRARY_URLS.REACT_BOOTSTRAP
64
- ];
65
- }
18
+ const DEFAULT_LIBRARY_CONFIG: LibraryConfiguration = {
19
+ libraries: [],
20
+ metadata: {
21
+ version: '1.0.0',
22
+ lastUpdated: new Date().toISOString(),
23
+ description: 'Empty default configuration - libraries should be configured at runtime'
24
+ }
25
+ };
66
26
 
67
27
  /**
68
- * Get the list of CSS URLs for UI libraries
28
+ * Manages standard library configurations with dynamic loading support
69
29
  */
70
- export function getCSSUrls(): string[] {
71
- return [
72
- STANDARD_LIBRARY_URLS.ANTD_CSS,
73
- STANDARD_LIBRARY_URLS.BOOTSTRAP_CSS
74
- ];
30
+ export class StandardLibraryManager {
31
+ private static configuration: LibraryConfiguration = DEFAULT_LIBRARY_CONFIG;
32
+
33
+ /**
34
+ * Set a custom library configuration
35
+ */
36
+ static setConfiguration(config: LibraryConfiguration): void {
37
+ this.configuration = config;
38
+ }
39
+
40
+ /**
41
+ * Get the current library configuration
42
+ */
43
+ static getConfiguration(): LibraryConfiguration {
44
+ return this.configuration;
45
+ }
46
+
47
+ /**
48
+ * Get all enabled libraries
49
+ */
50
+ static getEnabledLibraries(): ExternalLibraryConfig[] {
51
+ return this.configuration.libraries.filter(lib => lib.isEnabled);
52
+ }
53
+
54
+ /**
55
+ * Get libraries by category
56
+ */
57
+ static getLibrariesByCategory(category: ExternalLibraryConfig['category']): ExternalLibraryConfig[] {
58
+ return this.configuration.libraries.filter(lib => lib.category === category && lib.isEnabled);
59
+ }
60
+
61
+ /**
62
+ * Get core libraries (runtime essentials)
63
+ */
64
+ static getCoreLibraries(): ExternalLibraryConfig[] {
65
+ return this.configuration.libraries.filter(lib => lib.isCore && lib.isEnabled);
66
+ }
67
+
68
+ /**
69
+ * Get component libraries (non-runtime)
70
+ */
71
+ static getComponentLibraries(): ExternalLibraryConfig[] {
72
+ return this.configuration.libraries.filter(lib => !lib.isRuntimeOnly && lib.isEnabled);
73
+ }
74
+
75
+ /**
76
+ * Get library by ID
77
+ */
78
+ static getLibraryById(id: string): ExternalLibraryConfig | undefined {
79
+ return this.configuration.libraries.find(lib => lib.id === id);
80
+ }
81
+
82
+ /**
83
+ * Get library URLs as a simple object (for backward compatibility)
84
+ */
85
+ static getLibraryUrls(): Record<string, string> {
86
+ const urls: Record<string, string> = {};
87
+ this.configuration.libraries
88
+ .filter(lib => lib.isEnabled)
89
+ .forEach(lib => {
90
+ // Use uppercase key for backward compatibility
91
+ const key = lib.id.replace(/-/g, '_').toUpperCase();
92
+ urls[key] = lib.cdnUrl;
93
+ if (lib.cdnCssUrl) {
94
+ urls[`${key}_CSS`] = lib.cdnCssUrl;
95
+ }
96
+ });
97
+ return urls;
98
+ }
99
+
100
+ /**
101
+ * Reset to default configuration
102
+ */
103
+ static resetToDefault(): void {
104
+ this.configuration = DEFAULT_LIBRARY_CONFIG;
105
+ }
75
106
  }
76
107
 
108
+
77
109
  /**
78
110
  * Creates a standard libraries object for browser environments
79
- * This assumes the libraries are already loaded as globals
111
+ * Dynamically collects all libraries based on current configuration
80
112
  */
81
113
  export function createStandardLibraries(): StandardLibraries {
82
114
  if (typeof window === 'undefined') {
83
115
  // Return empty object in Node.js environments
84
- return {
85
- _: undefined
86
- };
116
+ return {};
87
117
  }
88
118
 
89
- return {
90
- _: (window as any)._,
91
- d3: (window as any).d3,
92
- Chart: (window as any).Chart,
93
- dayjs: (window as any).dayjs,
94
- antd: (window as any).antd,
95
- ReactBootstrap: (window as any).ReactBootstrap
96
- };
119
+ const libs: StandardLibraries = {};
120
+
121
+ // Add all component libraries as globals based on configuration
122
+ StandardLibraryManager.getComponentLibraries().forEach(lib => {
123
+ const globalValue = (window as any)[lib.globalVariable];
124
+ if (globalValue !== undefined) {
125
+ libs[lib.globalVariable] = globalValue;
126
+ }
127
+ });
128
+
129
+ return libs;
97
130
  }