export const metadata = { title: "@json-render/react API" } # @json-render/react React components, providers, and hooks. ## Providers ### StateProvider ```tsx {children} ``` ### ActionProvider ```tsx }> {children} type ActionHandler = (params: Record) => void | Promise; ``` ### VisibilityProvider ```tsx {children} ``` `VisibilityProvider` reads state from the parent `StateProvider` automatically. Conditions in specs use the `VisibilityCondition` format with `$state` paths (e.g. `{ "$state": "/path" }`, `{ "$state": "/path", "eq": value }`). See [visibility](/docs/visibility) for the full syntax. ### ValidationProvider ```tsx }> {children} type ValidationFunction = (value: unknown, args?: object) => boolean | Promise; ``` ## defineRegistry Create a type-safe component registry from a catalog. Components receive `props`, `children`, `emit`, and `loading` with catalog-inferred types. ```tsx import { defineRegistry } from '@json-render/react'; const { registry } = defineRegistry(catalog, { components: { Card: ({ props, children }) =>
{props.title}{children}
, Button: ({ props, emit }) => ( ), }, }); // Pass to ``` ## Components ### Renderer ```tsx type Registry = Record>; ``` ### Component Props (via defineRegistry) ```tsx interface ComponentContext

{ props: P; // Typed props from catalog children?: React.ReactNode; // Rendered children (for slot components) emit: (event: string) => void; // Emit a named event loading?: boolean; bindings?: Record; // State paths from $bindState/$bindItem expressions } ``` ## Hooks ### useUIStream ```typescript const { spec, // Spec | null - current UI state isStreaming, // boolean - true while streaming error, // Error | null send, // (prompt: string, context?: Record) => Promise clear, // () => void - reset spec and error } = useUIStream({ api: string, // API endpoint URL onComplete?: (spec: Spec) => void, // Called when streaming completes onError?: (error: Error) => void, // Called when an error occurs }); ``` ### useStateStore ```typescript const { state, // StateModel (Record) get, // (path: string) => unknown set, // (path: string, value: unknown) => void update, // (updates: Record) => void } = useStateStore(); ``` ### useStateValue ```typescript const value = useStateValue(path: string); ``` ### useStateBinding (deprecated) > **Deprecated.** Use `useBoundProp` with `$bindState` expressions instead. ```typescript const [value, setValue] = useStateBinding(path: string); ``` ### useActions ```typescript const { execute } = useActions(); // execute(binding: ActionBinding) => Promise ``` ### useAction ```typescript const { execute, isLoading } = useAction(binding: ActionBinding); // execute() => Promise ``` ### useIsVisible ```typescript const isVisible = useIsVisible(condition?: VisibilityCondition); ``` ### useFieldValidation ```typescript const { state, // FieldValidationState validate, // () => ValidationResult touch, // () => void clear, // () => void errors, // string[] isValid, // boolean } = useFieldValidation(path: string, config?: ValidationConfig); ``` `ValidationConfig` is `{ checks?: ValidationCheck[], validateOn?: 'change' | 'blur' | 'submit' }`. ### useBoundProp Two-way binding helper for `$bindState` / `$bindItem` expressions. Returns `[value, setValue]` where `setValue` writes back to the bound state path. ```typescript const [value, setValue] = useBoundProp( propValue: T | undefined, // The already-resolved prop value bindingPath: string | undefined // From bindings?.value ); ``` Use inside registry components: ```tsx const Input: ComponentRenderer = ({ props, bindings }) => { const [value, setValue] = useBoundProp(props.value, bindings?.value); return setValue(e.target.value)} />; }; ``` ### Chat Hooks Two hooks are available for chat + GenUI, depending on your setup: - **`useChatUI`** -- Self-contained chat hook with its own message state, fetch logic, and mixed stream parsing. Use when you want a standalone chat experience without the Vercel AI SDK. - **`useJsonRenderMessage`** -- Extracts spec + text from an AI SDK `UIMessage.parts` array. Use with the Vercel AI SDK's `useChat` for full AI SDK integration. ### useChatUI Hook for chat + GenUI experiences. Manages a multi-turn conversation where each assistant message can contain both text and a json-render UI spec. ```typescript const { messages, // ChatMessage[] - all messages in the conversation isStreaming, // boolean - true while streaming error, // Error | null send, // (text: string) => Promise clear, // () => void - reset conversation } = useChatUI({ api: string, // API endpoint onComplete?: (message: ChatMessage) => void, // Called when streaming completes onError?: (error: Error) => void, // Called on error }); interface ChatMessage { id: string; role: "user" | "assistant"; text: string; spec: Spec | null; } ``` ### useJsonRenderMessage Extract a spec and text content from an AI SDK message's `parts` array. Designed for integration with Vercel AI SDK's `useChat`. ```typescript const { spec, text, hasSpec } = useJsonRenderMessage(parts: DataPart[]); // spec: Spec | null - compiled from JSONL patches in data parts // text: string - concatenated text parts // hasSpec: boolean - true when spec is non-null ``` ### buildSpecFromParts / getTextFromParts Standalone utilities for extracting spec and text from AI SDK message parts (non-hook versions): ```typescript import { buildSpecFromParts, getTextFromParts } from '@json-render/react'; const spec = buildSpecFromParts(message.parts); // Spec | null const text = getTextFromParts(message.parts); // string ```