@memberjunction/react-runtime 2.74.0 → 2.76.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +27 -0
- package/README.md +96 -4
- package/dist/compiler/component-compiler.d.ts +0 -1
- package/dist/compiler/component-compiler.d.ts.map +1 -1
- package/dist/compiler/component-compiler.js +34 -25
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -6
- package/dist/registry/component-resolver.d.ts +1 -6
- package/dist/registry/component-resolver.d.ts.map +1 -1
- package/dist/registry/component-resolver.js +19 -19
- package/dist/registry/index.d.ts +2 -1
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +3 -1
- package/dist/runtime/component-hierarchy.d.ts +1 -1
- package/dist/runtime/component-hierarchy.d.ts.map +1 -1
- package/dist/runtime/component-hierarchy.js +25 -25
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +1 -2
- package/dist/runtime/prop-builder.d.ts +1 -2
- package/dist/runtime/prop-builder.d.ts.map +1 -1
- package/dist/runtime/prop-builder.js +4 -76
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +15 -0
- package/dist/types/library-config.d.ts +32 -0
- package/dist/types/library-config.d.ts.map +1 -0
- package/dist/types/library-config.js +2 -0
- package/dist/utilities/core-libraries.d.ts +5 -0
- package/dist/utilities/core-libraries.d.ts.map +1 -0
- package/dist/utilities/core-libraries.js +52 -0
- package/dist/utilities/library-loader.d.ts +3 -2
- package/dist/utilities/library-loader.d.ts.map +1 -1
- package/dist/utilities/library-loader.js +65 -76
- package/dist/utilities/standard-libraries.d.ts +13 -24
- package/dist/utilities/standard-libraries.d.ts.map +1 -1
- package/dist/utilities/standard-libraries.js +58 -47
- package/package.json +4 -4
- package/samples/entities-1.js +493 -0
- package/src/compiler/component-compiler.ts +64 -35
- package/src/index.ts +1 -5
- package/src/registry/component-resolver.ts +21 -30
- package/src/registry/index.ts +2 -1
- package/src/runtime/component-hierarchy.ts +26 -26
- package/src/runtime/index.ts +0 -1
- package/src/runtime/prop-builder.ts +5 -112
- package/src/types/index.ts +6 -1
- package/src/types/library-config.ts +75 -0
- package/src/utilities/core-libraries.ts +61 -0
- package/src/utilities/library-loader.ts +113 -93
- package/src/utilities/standard-libraries.ts +104 -71
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -5,16 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { ComponentRegistry } from './component-registry';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Component specification interface matching Skip component structure
|
|
11
|
-
*/
|
|
12
|
-
export interface ComponentSpec {
|
|
13
|
-
componentName: string;
|
|
14
|
-
componentCode?: string;
|
|
15
|
-
childComponents?: ComponentSpec[];
|
|
16
|
-
components?: ComponentSpec[]; // Alternative property name for children
|
|
17
|
-
}
|
|
8
|
+
import { ComponentSpec } from '@memberjunction/interactive-component-types';
|
|
18
9
|
|
|
19
10
|
/**
|
|
20
11
|
* Resolved component map for passing to React components
|
|
@@ -67,20 +58,20 @@ export class ComponentResolver {
|
|
|
67
58
|
visited: Set<string> = new Set()
|
|
68
59
|
): void {
|
|
69
60
|
// Prevent circular dependencies
|
|
70
|
-
if (visited.has(spec.
|
|
71
|
-
console.warn(`Circular dependency detected for component: ${spec.
|
|
61
|
+
if (visited.has(spec.name)) {
|
|
62
|
+
console.warn(`Circular dependency detected for component: ${spec.name}`);
|
|
72
63
|
return;
|
|
73
64
|
}
|
|
74
|
-
visited.add(spec.
|
|
65
|
+
visited.add(spec.name);
|
|
75
66
|
|
|
76
67
|
// Try to get component from registry
|
|
77
|
-
const component = this.registry.get(spec.
|
|
68
|
+
const component = this.registry.get(spec.name, namespace);
|
|
78
69
|
if (component) {
|
|
79
|
-
resolved[spec.
|
|
70
|
+
resolved[spec.name] = component;
|
|
80
71
|
}
|
|
81
72
|
|
|
82
|
-
// Process child components
|
|
83
|
-
const children = spec.
|
|
73
|
+
// Process child components
|
|
74
|
+
const children = spec.dependencies || [];
|
|
84
75
|
for (const child of children) {
|
|
85
76
|
this.resolveComponentHierarchy(child, resolved, namespace, visited);
|
|
86
77
|
}
|
|
@@ -114,16 +105,16 @@ export class ComponentResolver {
|
|
|
114
105
|
missing: string[],
|
|
115
106
|
checked: Set<string>
|
|
116
107
|
): void {
|
|
117
|
-
if (checked.has(spec.
|
|
118
|
-
checked.add(spec.
|
|
108
|
+
if (checked.has(spec.name)) return;
|
|
109
|
+
checked.add(spec.name);
|
|
119
110
|
|
|
120
111
|
// Check if component exists in registry
|
|
121
|
-
if (!this.registry.has(spec.
|
|
122
|
-
missing.push(spec.
|
|
112
|
+
if (!this.registry.has(spec.name, namespace)) {
|
|
113
|
+
missing.push(spec.name);
|
|
123
114
|
}
|
|
124
115
|
|
|
125
116
|
// Check children
|
|
126
|
-
const children = spec.
|
|
117
|
+
const children = spec.dependencies || [];
|
|
127
118
|
for (const child of children) {
|
|
128
119
|
this.checkDependencies(child, namespace, missing, checked);
|
|
129
120
|
}
|
|
@@ -154,13 +145,13 @@ export class ComponentResolver {
|
|
|
154
145
|
graph: Map<string, string[]>,
|
|
155
146
|
visited: Set<string>
|
|
156
147
|
): void {
|
|
157
|
-
if (visited.has(spec.
|
|
158
|
-
visited.add(spec.
|
|
148
|
+
if (visited.has(spec.name)) return;
|
|
149
|
+
visited.add(spec.name);
|
|
159
150
|
|
|
160
|
-
const children = spec.
|
|
161
|
-
const dependencies = children.map(child => child.
|
|
151
|
+
const children = spec.dependencies || [];
|
|
152
|
+
const dependencies = children.map(child => child.name);
|
|
162
153
|
|
|
163
|
-
graph.set(spec.
|
|
154
|
+
graph.set(spec.name, dependencies);
|
|
164
155
|
|
|
165
156
|
// Recursively process children
|
|
166
157
|
for (const child of children) {
|
|
@@ -262,12 +253,12 @@ export class ComponentResolver {
|
|
|
262
253
|
collected: ComponentSpec[],
|
|
263
254
|
visited: Set<string>
|
|
264
255
|
): void {
|
|
265
|
-
if (visited.has(spec.
|
|
266
|
-
visited.add(spec.
|
|
256
|
+
if (visited.has(spec.name)) return;
|
|
257
|
+
visited.add(spec.name);
|
|
267
258
|
|
|
268
259
|
collected.push(spec);
|
|
269
260
|
|
|
270
|
-
const children = spec.
|
|
261
|
+
const children = spec.dependencies || [];
|
|
271
262
|
for (const child of children) {
|
|
272
263
|
this.collectComponentSpecs(child, collected, visited);
|
|
273
264
|
}
|
package/src/registry/index.ts
CHANGED
|
@@ -4,4 +4,5 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export { ComponentRegistry } from './component-registry';
|
|
7
|
-
export { ComponentResolver,
|
|
7
|
+
export { ComponentResolver, ResolvedComponents } from './component-resolver';
|
|
8
|
+
export { ComponentSpec } from '@memberjunction/interactive-component-types';
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { ComponentCompiler } from '../compiler';
|
|
14
14
|
import { ComponentRegistry } from '../registry';
|
|
15
15
|
|
|
16
|
-
import { ComponentSpec } from '
|
|
16
|
+
import { ComponentSpec } from '@memberjunction/interactive-component-types';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Result of a hierarchy registration operation
|
|
@@ -89,7 +89,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
89
89
|
);
|
|
90
90
|
|
|
91
91
|
if (rootResult.success) {
|
|
92
|
-
registeredComponents.push(rootSpec.
|
|
92
|
+
registeredComponents.push(rootSpec.name);
|
|
93
93
|
} else {
|
|
94
94
|
errors.push(rootResult.error!);
|
|
95
95
|
if (!continueOnError) {
|
|
@@ -98,7 +98,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
// Register child components recursively
|
|
101
|
-
const childComponents = rootSpec.
|
|
101
|
+
const childComponents = rootSpec.dependencies || [];
|
|
102
102
|
if (childComponents.length > 0) {
|
|
103
103
|
const childResult = await this.registerChildComponents(
|
|
104
104
|
childComponents,
|
|
@@ -136,7 +136,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
136
136
|
|
|
137
137
|
try {
|
|
138
138
|
// Skip if no component code
|
|
139
|
-
if (!spec.
|
|
139
|
+
if (!spec.code) {
|
|
140
140
|
return {
|
|
141
141
|
success: true,
|
|
142
142
|
error: undefined
|
|
@@ -144,12 +144,12 @@ export class ComponentHierarchyRegistrar {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// Check if component already exists
|
|
147
|
-
const existingComponent = this.registry.get(spec.
|
|
147
|
+
const existingComponent = this.registry.get(spec.name, namespace, version);
|
|
148
148
|
if (existingComponent && !allowOverride) {
|
|
149
149
|
return {
|
|
150
150
|
success: false,
|
|
151
151
|
error: {
|
|
152
|
-
componentName: spec.
|
|
152
|
+
componentName: spec.name,
|
|
153
153
|
error: `Component already registered in ${namespace}/${version}`,
|
|
154
154
|
phase: 'registration'
|
|
155
155
|
}
|
|
@@ -158,8 +158,8 @@ export class ComponentHierarchyRegistrar {
|
|
|
158
158
|
|
|
159
159
|
// Compile the component
|
|
160
160
|
const compileOptions: CompileOptions = {
|
|
161
|
-
componentName: spec.
|
|
162
|
-
componentCode: spec.
|
|
161
|
+
componentName: spec.name,
|
|
162
|
+
componentCode: spec.code,
|
|
163
163
|
styles
|
|
164
164
|
};
|
|
165
165
|
|
|
@@ -169,7 +169,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
169
169
|
return {
|
|
170
170
|
success: false,
|
|
171
171
|
error: {
|
|
172
|
-
componentName: spec.
|
|
172
|
+
componentName: spec.name,
|
|
173
173
|
error: compilationResult.error?.message || 'Unknown compilation error',
|
|
174
174
|
phase: 'compilation'
|
|
175
175
|
}
|
|
@@ -181,7 +181,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
181
181
|
|
|
182
182
|
// Register the component
|
|
183
183
|
this.registry.register(
|
|
184
|
-
spec.
|
|
184
|
+
spec.name,
|
|
185
185
|
componentFactory.component,
|
|
186
186
|
namespace,
|
|
187
187
|
version
|
|
@@ -193,7 +193,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
193
193
|
return {
|
|
194
194
|
success: false,
|
|
195
195
|
error: {
|
|
196
|
-
componentName: spec.
|
|
196
|
+
componentName: spec.name,
|
|
197
197
|
error: error instanceof Error ? error.message : String(error),
|
|
198
198
|
phase: 'registration'
|
|
199
199
|
}
|
|
@@ -226,8 +226,8 @@ export class ComponentHierarchyRegistrar {
|
|
|
226
226
|
});
|
|
227
227
|
|
|
228
228
|
if (childResult.success) {
|
|
229
|
-
if (child.
|
|
230
|
-
registeredComponents.push(child.
|
|
229
|
+
if (child.code) {
|
|
230
|
+
registeredComponents.push(child.name);
|
|
231
231
|
}
|
|
232
232
|
} else {
|
|
233
233
|
errors.push(childResult.error!);
|
|
@@ -237,7 +237,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
// Register nested children recursively
|
|
240
|
-
const nestedChildren = child.
|
|
240
|
+
const nestedChildren = child.dependencies || [];
|
|
241
241
|
if (nestedChildren.length > 0) {
|
|
242
242
|
await this.registerChildComponents(
|
|
243
243
|
nestedChildren,
|
|
@@ -279,26 +279,26 @@ export async function registerComponentHierarchy(
|
|
|
279
279
|
export function validateComponentSpec(spec: ComponentSpec): string[] {
|
|
280
280
|
const errors: string[] = [];
|
|
281
281
|
|
|
282
|
-
if (!spec.
|
|
283
|
-
errors.push('Component specification must have a
|
|
282
|
+
if (!spec.name) {
|
|
283
|
+
errors.push('Component specification must have a name');
|
|
284
284
|
}
|
|
285
285
|
|
|
286
286
|
// If componentCode is provided, do basic validation
|
|
287
|
-
if (spec.
|
|
288
|
-
if (typeof spec.
|
|
289
|
-
errors.push(`Component code for ${spec.
|
|
287
|
+
if (spec.code) {
|
|
288
|
+
if (typeof spec.code !== 'string') {
|
|
289
|
+
errors.push(`Component code for ${spec.name} must be a string`);
|
|
290
290
|
}
|
|
291
|
-
if (spec.
|
|
292
|
-
errors.push(`Component code for ${spec.
|
|
291
|
+
if (spec.code.trim().length === 0) {
|
|
292
|
+
errors.push(`Component code for ${spec.name} cannot be empty`);
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
// Validate child components recursively
|
|
297
|
-
const children = spec.
|
|
297
|
+
const children = spec.dependencies || [];
|
|
298
298
|
children.forEach((child, index) => {
|
|
299
299
|
const childErrors = validateComponentSpec(child);
|
|
300
300
|
childErrors.forEach(error => {
|
|
301
|
-
errors.push(`Child ${index} (${child.
|
|
301
|
+
errors.push(`Child ${index} (${child.name || 'unnamed'}): ${error}`);
|
|
302
302
|
});
|
|
303
303
|
});
|
|
304
304
|
|
|
@@ -313,7 +313,7 @@ export function validateComponentSpec(spec: ComponentSpec): string[] {
|
|
|
313
313
|
export function flattenComponentHierarchy(rootSpec: ComponentSpec): ComponentSpec[] {
|
|
314
314
|
const components: ComponentSpec[] = [rootSpec];
|
|
315
315
|
|
|
316
|
-
const children = rootSpec.
|
|
316
|
+
const children = rootSpec.dependencies || [];
|
|
317
317
|
children.forEach(child => {
|
|
318
318
|
components.push(...flattenComponentHierarchy(child));
|
|
319
319
|
});
|
|
@@ -333,11 +333,11 @@ export function countComponentsInHierarchy(
|
|
|
333
333
|
): number {
|
|
334
334
|
let count = 0;
|
|
335
335
|
|
|
336
|
-
if (includeEmpty || rootSpec.
|
|
336
|
+
if (includeEmpty || rootSpec.code) {
|
|
337
337
|
count = 1;
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
const children = rootSpec.
|
|
340
|
+
const children = rootSpec.dependencies || [];
|
|
341
341
|
children.forEach(child => {
|
|
342
342
|
count += countComponentsInHierarchy(child, includeEmpty);
|
|
343
343
|
});
|
package/src/runtime/index.ts
CHANGED
|
@@ -41,7 +41,8 @@ export function buildComponentProps(
|
|
|
41
41
|
callbacks: ComponentCallbacks = {},
|
|
42
42
|
components: Record<string, any> = {},
|
|
43
43
|
styles?: ComponentStyles,
|
|
44
|
-
options: PropBuilderOptions = {}
|
|
44
|
+
options: PropBuilderOptions = {},
|
|
45
|
+
onStateChanged?: (stateUpdate: Record<string, any>) => void
|
|
45
46
|
): ComponentProps {
|
|
46
47
|
const {
|
|
47
48
|
validate = true,
|
|
@@ -61,7 +62,8 @@ export function buildComponentProps(
|
|
|
61
62
|
utilities,
|
|
62
63
|
callbacks: normalizeCallbacks(callbacks, debounceUpdateUserState),
|
|
63
64
|
components,
|
|
64
|
-
styles: normalizeStyles(styles)
|
|
65
|
+
styles: normalizeStyles(styles),
|
|
66
|
+
onStateChanged
|
|
65
67
|
};
|
|
66
68
|
|
|
67
69
|
// Validate if enabled
|
|
@@ -124,74 +126,6 @@ export function normalizeCallbacks(callbacks: any, debounceMs: number = 3000): C
|
|
|
124
126
|
normalized.OpenEntityRecord = callbacks.OpenEntityRecord;
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
if (callbacks.UpdateUserState && typeof callbacks.UpdateUserState === 'function') {
|
|
128
|
-
// Create a debounced version of UpdateUserState with loop detection
|
|
129
|
-
const originalCallback = callbacks.UpdateUserState;
|
|
130
|
-
|
|
131
|
-
// Get or create a subject for this callback
|
|
132
|
-
let subject = updateUserStateSubjects.get(originalCallback);
|
|
133
|
-
if (!subject) {
|
|
134
|
-
subject = new Subject<any>();
|
|
135
|
-
updateUserStateSubjects.set(originalCallback, subject);
|
|
136
|
-
|
|
137
|
-
// Subscribe to the subject with debounce
|
|
138
|
-
const subscription = subject.pipe(
|
|
139
|
-
debounceTime(debounceMs)
|
|
140
|
-
).subscribe(state => {
|
|
141
|
-
console.log(`[Skip Component] UpdateUserState called after ${debounceMs}ms debounce`);
|
|
142
|
-
originalCallback(state);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// Store the subscription for cleanup
|
|
146
|
-
updateUserStateSubscriptions.set(originalCallback, subscription);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Get or create loop detection state
|
|
150
|
-
let loopState = loopDetectionStates.get(originalCallback);
|
|
151
|
-
if (!loopState) {
|
|
152
|
-
loopState = { count: 0, lastUpdate: 0, lastState: null };
|
|
153
|
-
loopDetectionStates.set(originalCallback, loopState);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Return a function that prevents redundant updates
|
|
157
|
-
normalized.UpdateUserState = (state: any) => {
|
|
158
|
-
// Check if this is a redundant update
|
|
159
|
-
if (loopState!.lastState && deepEqual(state, loopState!.lastState)) {
|
|
160
|
-
console.log('[Skip Component] Skipping redundant state update');
|
|
161
|
-
return; // Don't process identical state updates
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const now = Date.now();
|
|
165
|
-
const timeSinceLastUpdate = now - loopState!.lastUpdate;
|
|
166
|
-
|
|
167
|
-
// Check for rapid updates
|
|
168
|
-
if (timeSinceLastUpdate < 100) {
|
|
169
|
-
loopState!.count++;
|
|
170
|
-
|
|
171
|
-
if (loopState!.count > 5) {
|
|
172
|
-
console.error('[Skip Component] Rapid state updates detected - possible infinite loop');
|
|
173
|
-
console.error('Updates in last 100ms:', loopState!.count);
|
|
174
|
-
// Still process the update but warn
|
|
175
|
-
}
|
|
176
|
-
} else {
|
|
177
|
-
// Reset counter if more than 100ms has passed
|
|
178
|
-
loopState!.count = 0;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
loopState!.lastUpdate = now;
|
|
182
|
-
loopState!.lastState = JSON.parse(JSON.stringify(state)); // Deep clone to preserve state
|
|
183
|
-
|
|
184
|
-
console.log('[Skip Component] Processing state update');
|
|
185
|
-
|
|
186
|
-
// Push to debounce subject (which already has 3 second debounce)
|
|
187
|
-
subject!.next(state);
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (callbacks.NotifyEvent && typeof callbacks.NotifyEvent === 'function') {
|
|
192
|
-
normalized.NotifyEvent = callbacks.NotifyEvent;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
129
|
return normalized;
|
|
196
130
|
}
|
|
197
131
|
|
|
@@ -284,34 +218,7 @@ export function mergeProps(...propsList: Partial<ComponentProps>[]): ComponentPr
|
|
|
284
218
|
|
|
285
219
|
return merged;
|
|
286
220
|
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Cleanup function for prop builder resources
|
|
290
|
-
* @param callbacks - The callbacks object that was used to build props
|
|
291
|
-
*/
|
|
292
|
-
export function cleanupPropBuilder(callbacks: ComponentCallbacks): void {
|
|
293
|
-
if (callbacks.UpdateUserState && typeof callbacks.UpdateUserState === 'function') {
|
|
294
|
-
const originalCallback = callbacks.UpdateUserState;
|
|
295
|
-
|
|
296
|
-
// Unsubscribe from the subject
|
|
297
|
-
const subscription = updateUserStateSubscriptions.get(originalCallback);
|
|
298
|
-
if (subscription) {
|
|
299
|
-
subscription.unsubscribe();
|
|
300
|
-
updateUserStateSubscriptions.delete(originalCallback);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// Complete and remove the subject
|
|
304
|
-
const subject = updateUserStateSubjects.get(originalCallback);
|
|
305
|
-
if (subject) {
|
|
306
|
-
subject.complete();
|
|
307
|
-
updateUserStateSubjects.delete(originalCallback);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Clear loop detection state
|
|
311
|
-
loopDetectionStates.delete(originalCallback);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
221
|
+
|
|
315
222
|
/**
|
|
316
223
|
* Creates a props transformer function
|
|
317
224
|
* @param transformations - Map of prop paths to transformer functions
|
|
@@ -372,20 +279,6 @@ export function wrapCallbacksWithLogging(
|
|
|
372
279
|
};
|
|
373
280
|
}
|
|
374
281
|
|
|
375
|
-
if (callbacks.UpdateUserState) {
|
|
376
|
-
wrapped.UpdateUserState = (state: any) => {
|
|
377
|
-
console.log(`[${componentName}] UpdateUserState called:`, state);
|
|
378
|
-
callbacks.UpdateUserState!(state);
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (callbacks.NotifyEvent) {
|
|
383
|
-
wrapped.NotifyEvent = (event: string, data: any) => {
|
|
384
|
-
console.log(`[${componentName}] NotifyEvent called:`, { event, data });
|
|
385
|
-
callbacks.NotifyEvent!(event, data);
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
|
|
389
282
|
return wrapped;
|
|
390
283
|
}
|
|
391
284
|
|
package/src/types/index.ts
CHANGED
|
@@ -114,6 +114,8 @@ export interface ComponentProps {
|
|
|
114
114
|
components?: Record<string, any>;
|
|
115
115
|
/** Component styles */
|
|
116
116
|
styles?: ComponentStyles;
|
|
117
|
+
/** Standard state change handler for controlled components */
|
|
118
|
+
onStateChanged?: (stateUpdate: Record<string, any>) => void;
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
/**
|
|
@@ -223,4 +225,7 @@ export interface ErrorBoundaryOptions {
|
|
|
223
225
|
logErrors?: boolean;
|
|
224
226
|
/** Error recovery strategy */
|
|
225
227
|
recovery?: 'retry' | 'reset' | 'none';
|
|
226
|
-
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Export library configuration types
|
|
231
|
+
export * from './library-config';
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ExternalLibraryConfig } from '../types/library-config';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Core runtime libraries required for the React runtime to function.
|
|
5
|
+
* These are not plugin libraries and are always loaded.
|
|
6
|
+
*/
|
|
7
|
+
export const CORE_RUNTIME_LIBRARIES: ExternalLibraryConfig[] = [
|
|
8
|
+
{
|
|
9
|
+
id: 'react',
|
|
10
|
+
name: 'react',
|
|
11
|
+
displayName: 'React',
|
|
12
|
+
category: 'runtime',
|
|
13
|
+
globalVariable: 'React',
|
|
14
|
+
version: '18.2.0',
|
|
15
|
+
cdnUrl: 'https://unpkg.com/react@18.2.0/umd/react.production.min.js',
|
|
16
|
+
description: 'React core library',
|
|
17
|
+
isEnabled: true,
|
|
18
|
+
isCore: true,
|
|
19
|
+
isRuntimeOnly: true
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 'react-dom',
|
|
23
|
+
name: 'react-dom',
|
|
24
|
+
displayName: 'ReactDOM',
|
|
25
|
+
category: 'runtime',
|
|
26
|
+
globalVariable: 'ReactDOM',
|
|
27
|
+
version: '18.2.0',
|
|
28
|
+
cdnUrl: 'https://unpkg.com/react-dom@18.2.0/umd/react-dom.production.min.js',
|
|
29
|
+
description: 'React DOM library',
|
|
30
|
+
isEnabled: true,
|
|
31
|
+
isCore: true,
|
|
32
|
+
isRuntimeOnly: true
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'babel-standalone',
|
|
36
|
+
name: '@babel/standalone',
|
|
37
|
+
displayName: 'Babel Standalone',
|
|
38
|
+
category: 'runtime',
|
|
39
|
+
globalVariable: 'Babel',
|
|
40
|
+
version: '7.24.4',
|
|
41
|
+
cdnUrl: 'https://unpkg.com/@babel/standalone@7.24.4/babel.min.js',
|
|
42
|
+
description: 'Babel compiler for JSX transformation',
|
|
43
|
+
isEnabled: true,
|
|
44
|
+
isCore: true,
|
|
45
|
+
isRuntimeOnly: true
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get the core runtime libraries configuration
|
|
51
|
+
*/
|
|
52
|
+
export function getCoreRuntimeLibraries(): ExternalLibraryConfig[] {
|
|
53
|
+
return CORE_RUNTIME_LIBRARIES;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if a library ID is a core runtime library
|
|
58
|
+
*/
|
|
59
|
+
export function isCoreRuntimeLibrary(libraryId: string): boolean {
|
|
60
|
+
return CORE_RUNTIME_LIBRARIES.some(lib => lib.id === libraryId);
|
|
61
|
+
}
|