mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
Implement $ref resolution for JSON components (needs server restart)
Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
@@ -79,7 +79,7 @@ export default async function RootPage() {
|
||||
const component = pkg.components?.find(c => c.id === route.component || c.name === route.component)
|
||||
|
||||
if (component !== undefined) {
|
||||
return renderJSONComponent(component, {}, {})
|
||||
return renderJSONComponent(component, {}, {}, pkg.components)
|
||||
}
|
||||
} catch {
|
||||
// Package doesn't exist or can't be loaded, fall through
|
||||
@@ -116,7 +116,7 @@ export default async function RootPage() {
|
||||
) ?? pkg.components[0]
|
||||
|
||||
if (pageComponent !== undefined) {
|
||||
return renderJSONComponent(pageComponent, {}, {})
|
||||
return renderJSONComponent(pageComponent, {}, {}, pkg.components)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -22,11 +22,13 @@ export interface RenderContext {
|
||||
*
|
||||
* By default, uses the FAKEMUI_REGISTRY to render components.
|
||||
* Pass a custom ComponentRegistry to override specific components.
|
||||
* Pass allComponents to enable $ref resolution within the same package.
|
||||
*/
|
||||
export function renderJSONComponent(
|
||||
component: JSONComponent,
|
||||
props: Record<string, JsonValue> = {},
|
||||
ComponentRegistry: Record<string, React.ComponentType<Record<string, unknown>>> = FAKEMUI_REGISTRY
|
||||
ComponentRegistry: Record<string, React.ComponentType<Record<string, unknown>>> = FAKEMUI_REGISTRY,
|
||||
allComponents?: JSONComponent[]
|
||||
): React.ReactElement {
|
||||
if (component.render === undefined) {
|
||||
return (
|
||||
@@ -36,6 +38,11 @@ export function renderJSONComponent(
|
||||
)
|
||||
}
|
||||
|
||||
// Build component registry for $ref resolution
|
||||
const componentRegistry = allComponents
|
||||
? new Map(allComponents.map(c => [c.id, c]))
|
||||
: undefined
|
||||
|
||||
const context: RenderContext = {
|
||||
props,
|
||||
state: {},
|
||||
@@ -50,7 +57,7 @@ export function renderJSONComponent(
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return renderTemplate(template, context, ComponentRegistry)
|
||||
return renderTemplate(template, context, ComponentRegistry, componentRegistry)
|
||||
} catch (error) {
|
||||
return (
|
||||
<div style={{ padding: '1rem', border: '1px solid red', borderRadius: '0.25rem' }}>
|
||||
@@ -67,7 +74,8 @@ export function renderJSONComponent(
|
||||
function renderTemplate(
|
||||
node: JsonValue,
|
||||
context: RenderContext,
|
||||
ComponentRegistry: Record<string, React.ComponentType<Record<string, unknown>>>
|
||||
ComponentRegistry: Record<string, React.ComponentType<Record<string, unknown>>>,
|
||||
componentRegistry?: Map<string, JSONComponent>
|
||||
): React.ReactElement {
|
||||
if (node === null || typeof node !== 'object') {
|
||||
return <>{String(node)}</>
|
||||
@@ -81,6 +89,20 @@ function renderTemplate(
|
||||
// Now TypeScript knows it's a JsonObject (non-array object)
|
||||
const nodeObj = node as Record<string, JsonValue>
|
||||
|
||||
// Handle $ref to other components in the same package
|
||||
if (typeof nodeObj.$ref === 'string' && componentRegistry !== undefined) {
|
||||
const referencedComponent = componentRegistry.get(nodeObj.$ref)
|
||||
if (referencedComponent !== undefined && referencedComponent.render?.template !== undefined) {
|
||||
return renderTemplate(referencedComponent.render.template, context, ComponentRegistry, componentRegistry)
|
||||
} else {
|
||||
return (
|
||||
<div style={{ padding: '0.5rem', border: '1px dashed orange', borderRadius: '0.25rem' }}>
|
||||
<strong>Warning:</strong> Component reference "${nodeObj.$ref}" not found
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle conditional rendering
|
||||
if (nodeObj.type === 'conditional') {
|
||||
const conditionValue = nodeObj.condition
|
||||
@@ -90,9 +112,9 @@ function renderTemplate(
|
||||
const condition = evaluateExpression(conditionValue, context)
|
||||
const conditionIsTrue = condition !== null && condition !== undefined && condition !== false && condition !== 0 && condition !== ''
|
||||
if (conditionIsTrue && nodeObj.then !== null && nodeObj.then !== undefined) {
|
||||
return renderTemplate(nodeObj.then, context, ComponentRegistry)
|
||||
return renderTemplate(nodeObj.then, context, ComponentRegistry, componentRegistry)
|
||||
} else if (!conditionIsTrue && nodeObj.else !== null && nodeObj.else !== undefined) {
|
||||
return renderTemplate(nodeObj.else, context, ComponentRegistry)
|
||||
return renderTemplate(nodeObj.else, context, ComponentRegistry, componentRegistry)
|
||||
}
|
||||
return <></>
|
||||
}
|
||||
@@ -128,12 +150,12 @@ function renderTemplate(
|
||||
}
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
{renderTemplate(child, context, ComponentRegistry)}
|
||||
{renderTemplate(child, context, ComponentRegistry, componentRegistry)}
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
} else {
|
||||
children = renderTemplate(nodeChildren, context, ComponentRegistry)
|
||||
children = renderTemplate(nodeChildren, context, ComponentRegistry, componentRegistry)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,12 +211,12 @@ function renderTemplate(
|
||||
}
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
{renderTemplate(child, context, ComponentRegistry)}
|
||||
{renderTemplate(child, context, ComponentRegistry, componentRegistry)}
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
} else {
|
||||
children = renderTemplate(nodeChildren, context, ComponentRegistry)
|
||||
children = renderTemplate(nodeChildren, context, ComponentRegistry, componentRegistry)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user