"use client"; import React, { type ComponentType, type ReactNode, useMemo } from "react"; import type { UIElement, UITree, Action, Catalog, ComponentDefinition, } from "@json-render/core"; import { useIsVisible } from "./contexts/visibility"; import { useActions } from "./contexts/actions"; import { useData } from "./contexts/data"; /** * Props passed to component renderers */ export interface ComponentRenderProps

> { /** The element being rendered */ element: UIElement; /** Rendered children */ children?: ReactNode; /** Execute an action */ onAction?: (action: Action) => void; /** Whether the parent is loading */ loading?: boolean; } /** * Component renderer type */ export type ComponentRenderer

> = ComponentType< ComponentRenderProps

>; /** * Registry of component renderers */ export type ComponentRegistry = Record>; /** * Props for the Renderer component */ export interface RendererProps { /** The UI tree to render */ tree: UITree | null; /** Component registry */ registry: ComponentRegistry; /** Whether the tree is currently loading/streaming */ loading?: boolean; /** Fallback component for unknown types */ fallback?: ComponentRenderer; } /** * Element renderer component */ function ElementRenderer({ element, tree, registry, loading, fallback, }: { element: UIElement; tree: UITree; registry: ComponentRegistry; loading?: boolean; fallback?: ComponentRenderer; }) { const isVisible = useIsVisible(element.visible); const { execute } = useActions(); // Don't render if not visible if (!isVisible) { return null; } // Get the component renderer const Component = registry[element.type] ?? fallback; if (!Component) { console.warn(`No renderer for component type: ${element.type}`); return null; } // Render children const children = element.children?.map((childKey) => { const childElement = tree.elements[childKey]; if (!childElement) { return null; } return ( ); }); return ( {children} ); } /** * Main renderer component */ export function Renderer({ tree, registry, loading, fallback }: RendererProps) { if (!tree || !tree.root) { return null; } const rootElement = tree.elements[tree.root]; if (!rootElement) { return null; } return ( ); } /** * Props for JSONUIProvider */ export interface JSONUIProviderProps { /** Component registry */ registry: ComponentRegistry; /** Initial data model */ initialData?: Record; /** Auth state */ authState?: { isSignedIn: boolean; user?: Record }; /** Action handlers */ actionHandlers?: Record< string, (params: Record) => Promise | unknown >; /** Navigation function */ navigate?: (path: string) => void; /** Custom validation functions */ validationFunctions?: Record< string, (value: unknown, args?: Record) => boolean >; /** Callback when data changes */ onDataChange?: (path: string, value: unknown) => void; children: ReactNode; } // Import the providers import { DataProvider } from "./contexts/data"; import { VisibilityProvider } from "./contexts/visibility"; import { ActionProvider } from "./contexts/actions"; import { ValidationProvider } from "./contexts/validation"; import { ConfirmDialog } from "./contexts/actions"; /** * Combined provider for all JSONUI contexts */ export function JSONUIProvider({ registry, initialData, authState, actionHandlers, navigate, validationFunctions, onDataChange, children, }: JSONUIProviderProps) { return ( {children} ); } /** * Renders the confirmation dialog when needed */ function ConfirmationDialogManager() { const { pendingConfirmation, confirm, cancel } = useActions(); if (!pendingConfirmation?.action.confirm) { return null; } return ( ); } /** * Helper to create a renderer component from a catalog */ export function createRendererFromCatalog< C extends Catalog>, >( _catalog: C, registry: ComponentRegistry, ): ComponentType> { return function CatalogRenderer(props: Omit) { return ; }; }