Compare commits

..
Author SHA1 Message Date
github-actions[bot] e7103ce519 chore: version packages (#113)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-15 09:06:46 -06:00
Chris Tate 43ad534482 v0.6.1 changeset (#112) 2026-02-15 09:04:39 -06:00
Chris Tate ea97aff3e0 fix max update depth on homepage demo (#111)
When form inputs lack `$bindState` bindings (like in the homepage contact form simulation), `useFieldValidation` was called with `bindings?.value ?? ""` as the path. All three inputs registered at the same `""` path but with different validation configs. Each `registerField` call overwrote the previous one, triggering a re-render where the other inputs would see a mismatched config and re-register -- creating an infinite loop.

- Fix infinite re-render loop caused by multiple unbound form inputs (Input, Textarea, Select) all registering field validation at path `""` with different `checks` configs, causing them to overwrite each other endlessly
- Stabilize context values in ActionProvider, ValidationProvider, and useUIStream by using refs for state/callbacks, preventing unnecessary re-render cascades on every state update
2026-02-15 08:56:08 -06:00
github-actions[bot] 9af3f999e0 chore: version packages (#109)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-13 18:03:21 -06:00
Chris Tate 06b8745da7 v0.6.0 (#108) 2026-02-13 18:00:57 -06:00
15 changed files with 453 additions and 98 deletions
-75
View File
@@ -1,75 +0,0 @@
---
"@json-render/core": minor
"@json-render/react": minor
"@json-render/react-native": minor
"@json-render/codegen": minor
"@json-render/remotion": minor
---
Chat mode (inline GenUI), AI SDK integration, two-way binding, and expression-based visibility/props.
### New: Chat Mode (Inline GenUI)
Two generation modes: **Generate** (JSONL-only, the default) and **Chat** (text + JSONL inline). Chat mode lets AI respond conversationally with embedded UI specs — ideal for chatbots and copilot experiences.
- `catalog.prompt({ mode: "chat" })` generates a chat-aware system prompt
- `pipeJsonRender()` server-side transform separates text from JSONL patches in a mixed stream
- `createJsonRenderTransform()` low-level TransformStream for custom pipelines
### New: AI SDK Integration
First-class Vercel AI SDK support with typed data parts and stream utilities.
- `SpecDataPart` type for `data-spec` stream parts (patch, flat, nested payloads)
- `SPEC_DATA_PART` / `SPEC_DATA_PART_TYPE` constants for type-safe part filtering
- `createMixedStreamParser()` for parsing mixed text + JSONL streams
### New: React Chat Hooks
- `useChatUI()` — full chat hook with message history, streaming, and spec extraction
- `useJsonRenderMessage()` — extract spec + text from a message's parts array
- `buildSpecFromParts()` / `getTextFromParts()` — utilities for working with AI SDK message parts
- `useBoundProp()` — two-way binding hook for `$bindState` / `$bindItem` expressions
### New: Two-Way Binding
Props can now use `$bindState` and `$bindItem` expressions for two-way data binding. The renderer resolves bindings and passes a `bindings` map to components, enabling write-back to state.
### New: Expression-Based Props and Visibility
Replaced string token rewriting with structured expression objects:
- Props: `{ $state: "/path" }`, `{ $item: "field" }`, `{ $index: true }`
- Visibility: `{ $state: "/path", eq: "value" }`, `{ $item: "active" }`, `{ $index: true, gt: 0 }`
- Logic: `{ $and: [...] }`, `{ $or: [...] }`, and implicit AND via arrays
- Comparison operators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `not`
### New: Utilities
- `applySpecPatch()` — typed convenience wrapper for applying a single patch to a Spec
- `nestedToFlat()` — convert nested tree specs to flat `{ root, elements }` format
- `resolveBindings()` / `resolveActionParam()` — resolve binding paths and action params
### New: Chat Example
Full-featured chat example (`examples/chat`) with AI agent, tool calls (crypto, GitHub, Hacker News, weather, search), theme toggle, and streaming UI generation.
### Improved: Renderer
- `ElementRenderer` is now `React.memo`'d for better performance in repeat lists
- `emit` is always defined (never `undefined`) — no more optional chaining needed
- Action params are resolved through `resolveActionParam` supporting `$item`, `$index`, `$state`
- Repeat scope now passes the actual item object instead of requiring token rewriting
### Breaking Changes
- **Expressions renamed**: `{ $path }` / `{ path }` replaced by `{ $state }`, `{ $item }`, `{ $index }`
- **Visibility conditions**: `{ path }` → `{ $state }`, `{ and/or/not }` → `{ $and/$or }` with `not` as operator flag
- **DynamicValue**: `{ path: string }` → `{ $state: string }`
- **Repeat field**: `repeat.path` → `repeat.statePath`
- **Action params**: `path` → `statePath` in setState action params
- **Provider props**: `actionHandlers` → `handlers` on `JSONUIProvider`/`ActionProvider`
- **Auth removed**: `AuthState` type and `{ auth }` visibility conditions removed — model auth as regular state
- **Legacy catalog removed**: `createCatalog`, `generateCatalogPrompt`, `generateSystemPrompt`, `ComponentDefinition`, `CatalogConfig`, `SystemPromptOptions` removed
- **React exports removed**: `createRendererFromCatalog`, `rewriteRepeatTokens`
- **Codegen**: `traverseTree` → `traverseSpec`, `SpecVisitor` → `TreeVisitor`
+12 -9
View File
@@ -781,9 +781,10 @@ export const { registry, executeAction } = defineRegistry(playgroundCatalog, {
const setValue = isBound ? setBoundValue : setLocalValue;
const hasValidation = !!(bindings?.value && props.checks?.length);
const { errors, validate } = useFieldValidation(bindings?.value ?? "", {
checks: props.checks ?? [],
});
const { errors, validate } = useFieldValidation(
bindings?.value ?? "",
hasValidation ? { checks: props.checks ?? [] } : undefined,
);
return (
<div className="space-y-2">
@@ -822,9 +823,10 @@ export const { registry, executeAction } = defineRegistry(playgroundCatalog, {
const setValue = isBound ? setBoundValue : setLocalValue;
const hasValidation = !!(bindings?.value && props.checks?.length);
const { errors, validate } = useFieldValidation(bindings?.value ?? "", {
checks: props.checks ?? [],
});
const { errors, validate } = useFieldValidation(
bindings?.value ?? "",
hasValidation ? { checks: props.checks ?? [] } : undefined,
);
return (
<div className="space-y-2">
@@ -864,9 +866,10 @@ export const { registry, executeAction } = defineRegistry(playgroundCatalog, {
);
const hasValidation = !!(bindings?.value && props.checks?.length);
const { errors, validate } = useFieldValidation(bindings?.value ?? "", {
checks: props.checks ?? [],
});
const { errors, validate } = useFieldValidation(
bindings?.value ?? "",
hasValidation ? { checks: props.checks ?? [] } : undefined,
);
return (
<div className="space-y-2">
+83
View File
@@ -1,5 +1,88 @@
# @json-render/codegen
## 0.6.1
### Patch Changes
- @json-render/core@0.6.1
## 0.6.1
### Patch Changes
- Updated dependencies [ea97aff]
- @json-render/core@0.6.1
## 0.6.0
### Minor Changes
- 06b8745: Chat mode (inline GenUI), AI SDK integration, two-way binding, and expression-based visibility/props.
### New: Chat Mode (Inline GenUI)
Two generation modes: **Generate** (JSONL-only, the default) and **Chat** (text + JSONL inline). Chat mode lets AI respond conversationally with embedded UI specs — ideal for chatbots and copilot experiences.
- `catalog.prompt({ mode: "chat" })` generates a chat-aware system prompt
- `pipeJsonRender()` server-side transform separates text from JSONL patches in a mixed stream
- `createJsonRenderTransform()` low-level TransformStream for custom pipelines
### New: AI SDK Integration
First-class Vercel AI SDK support with typed data parts and stream utilities.
- `SpecDataPart` type for `data-spec` stream parts (patch, flat, nested payloads)
- `SPEC_DATA_PART` / `SPEC_DATA_PART_TYPE` constants for type-safe part filtering
- `createMixedStreamParser()` for parsing mixed text + JSONL streams
### New: React Chat Hooks
- `useChatUI()` — full chat hook with message history, streaming, and spec extraction
- `useJsonRenderMessage()` — extract spec + text from a message's parts array
- `buildSpecFromParts()` / `getTextFromParts()` — utilities for working with AI SDK message parts
- `useBoundProp()` — two-way binding hook for `$bindState` / `$bindItem` expressions
### New: Two-Way Binding
Props can now use `$bindState` and `$bindItem` expressions for two-way data binding. The renderer resolves bindings and passes a `bindings` map to components, enabling write-back to state.
### New: Expression-Based Props and Visibility
Replaced string token rewriting with structured expression objects:
- Props: `{ $state: "/path" }`, `{ $item: "field" }`, `{ $index: true }`
- Visibility: `{ $state: "/path", eq: "value" }`, `{ $item: "active" }`, `{ $index: true, gt: 0 }`
- Logic: `{ $and: [...] }`, `{ $or: [...] }`, and implicit AND via arrays
- Comparison operators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `not`
### New: Utilities
- `applySpecPatch()` — typed convenience wrapper for applying a single patch to a Spec
- `nestedToFlat()` — convert nested tree specs to flat `{ root, elements }` format
- `resolveBindings()` / `resolveActionParam()` — resolve binding paths and action params
### New: Chat Example
Full-featured chat example (`examples/chat`) with AI agent, tool calls (crypto, GitHub, Hacker News, weather, search), theme toggle, and streaming UI generation.
### Improved: Renderer
- `ElementRenderer` is now `React.memo`'d for better performance in repeat lists
- `emit` is always defined (never `undefined`) — no more optional chaining needed
- Action params are resolved through `resolveActionParam` supporting `$item`, `$index`, `$state`
- Repeat scope now passes the actual item object instead of requiring token rewriting
### Breaking Changes
- **Expressions renamed**: `{ $path }` / `{ path }` replaced by `{ $state }`, `{ $item }`, `{ $index }`
- **Visibility conditions**: `{ path }` → `{ $state }`, `{ and/or/not }` → `{ $and/$or }` with `not` as operator flag
- **DynamicValue**: `{ path: string }` → `{ $state: string }`
- **Repeat field**: `repeat.path` → `repeat.statePath`
- **Action params**: `path` → `statePath` in setState action params
- **Provider props**: `actionHandlers` → `handlers` on `JSONUIProvider`/`ActionProvider`
- **Auth removed**: `AuthState` type and `{ auth }` visibility conditions removed — model auth as regular state
- **Legacy catalog removed**: `createCatalog`, `generateCatalogPrompt`, `generateSystemPrompt`, `ComponentDefinition`, `CatalogConfig`, `SystemPromptOptions` removed
- **React exports removed**: `createRendererFromCatalog`, `rewriteRepeatTokens`
- **Codegen**: `traverseTree` → `traverseSpec`, `SpecVisitor` → `TreeVisitor`
### Patch Changes
- Updated dependencies [06b8745]
- @json-render/core@0.6.0
## 0.5.2
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@json-render/codegen",
"version": "0.5.2",
"version": "0.6.1",
"license": "Apache-2.0",
"description": "Utilities for generating code from json-render UI trees",
"keywords": [
+73
View File
@@ -1,5 +1,78 @@
# @json-render/core
## 0.6.1
## 0.6.1
### Patch Changes
- ea97aff: Fix infinite re-render loop caused by multiple unbound form inputs (Input, Textarea, Select) all registering field validation at the same empty path with different `checks` configs, causing them to overwrite each other endlessly. Stabilize context values in ActionProvider, ValidationProvider, and useUIStream by using refs for state/callbacks, preventing unnecessary re-render cascades on every state update.
## 0.6.0
### Minor Changes
- 06b8745: Chat mode (inline GenUI), AI SDK integration, two-way binding, and expression-based visibility/props.
### New: Chat Mode (Inline GenUI)
Two generation modes: **Generate** (JSONL-only, the default) and **Chat** (text + JSONL inline). Chat mode lets AI respond conversationally with embedded UI specs — ideal for chatbots and copilot experiences.
- `catalog.prompt({ mode: "chat" })` generates a chat-aware system prompt
- `pipeJsonRender()` server-side transform separates text from JSONL patches in a mixed stream
- `createJsonRenderTransform()` low-level TransformStream for custom pipelines
### New: AI SDK Integration
First-class Vercel AI SDK support with typed data parts and stream utilities.
- `SpecDataPart` type for `data-spec` stream parts (patch, flat, nested payloads)
- `SPEC_DATA_PART` / `SPEC_DATA_PART_TYPE` constants for type-safe part filtering
- `createMixedStreamParser()` for parsing mixed text + JSONL streams
### New: React Chat Hooks
- `useChatUI()` — full chat hook with message history, streaming, and spec extraction
- `useJsonRenderMessage()` — extract spec + text from a message's parts array
- `buildSpecFromParts()` / `getTextFromParts()` — utilities for working with AI SDK message parts
- `useBoundProp()` — two-way binding hook for `$bindState` / `$bindItem` expressions
### New: Two-Way Binding
Props can now use `$bindState` and `$bindItem` expressions for two-way data binding. The renderer resolves bindings and passes a `bindings` map to components, enabling write-back to state.
### New: Expression-Based Props and Visibility
Replaced string token rewriting with structured expression objects:
- Props: `{ $state: "/path" }`, `{ $item: "field" }`, `{ $index: true }`
- Visibility: `{ $state: "/path", eq: "value" }`, `{ $item: "active" }`, `{ $index: true, gt: 0 }`
- Logic: `{ $and: [...] }`, `{ $or: [...] }`, and implicit AND via arrays
- Comparison operators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `not`
### New: Utilities
- `applySpecPatch()` — typed convenience wrapper for applying a single patch to a Spec
- `nestedToFlat()` — convert nested tree specs to flat `{ root, elements }` format
- `resolveBindings()` / `resolveActionParam()` — resolve binding paths and action params
### New: Chat Example
Full-featured chat example (`examples/chat`) with AI agent, tool calls (crypto, GitHub, Hacker News, weather, search), theme toggle, and streaming UI generation.
### Improved: Renderer
- `ElementRenderer` is now `React.memo`'d for better performance in repeat lists
- `emit` is always defined (never `undefined`) — no more optional chaining needed
- Action params are resolved through `resolveActionParam` supporting `$item`, `$index`, `$state`
- Repeat scope now passes the actual item object instead of requiring token rewriting
### Breaking Changes
- **Expressions renamed**: `{ $path }` / `{ path }` replaced by `{ $state }`, `{ $item }`, `{ $index }`
- **Visibility conditions**: `{ path }` → `{ $state }`, `{ and/or/not }` → `{ $and/$or }` with `not` as operator flag
- **DynamicValue**: `{ path: string }` → `{ $state: string }`
- **Repeat field**: `repeat.path` → `repeat.statePath`
- **Action params**: `path` → `statePath` in setState action params
- **Provider props**: `actionHandlers` → `handlers` on `JSONUIProvider`/`ActionProvider`
- **Auth removed**: `AuthState` type and `{ auth }` visibility conditions removed — model auth as regular state
- **Legacy catalog removed**: `createCatalog`, `generateCatalogPrompt`, `generateSystemPrompt`, `ComponentDefinition`, `CatalogConfig`, `SystemPromptOptions` removed
- **React exports removed**: `createRendererFromCatalog`, `rewriteRepeatTokens`
- **Codegen**: `traverseTree` → `traverseSpec`, `SpecVisitor` → `TreeVisitor`
## 0.5.2
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@json-render/core",
"version": "0.5.2",
"version": "0.6.1",
"license": "Apache-2.0",
"description": "JSON becomes real things. Define your catalog, register your components, let AI generate.",
"keywords": [
+83
View File
@@ -1,5 +1,88 @@
# @json-render/react-native
## 0.6.1
### Patch Changes
- @json-render/core@0.6.1
## 0.6.1
### Patch Changes
- Updated dependencies [ea97aff]
- @json-render/core@0.6.1
## 0.6.0
### Minor Changes
- 06b8745: Chat mode (inline GenUI), AI SDK integration, two-way binding, and expression-based visibility/props.
### New: Chat Mode (Inline GenUI)
Two generation modes: **Generate** (JSONL-only, the default) and **Chat** (text + JSONL inline). Chat mode lets AI respond conversationally with embedded UI specs — ideal for chatbots and copilot experiences.
- `catalog.prompt({ mode: "chat" })` generates a chat-aware system prompt
- `pipeJsonRender()` server-side transform separates text from JSONL patches in a mixed stream
- `createJsonRenderTransform()` low-level TransformStream for custom pipelines
### New: AI SDK Integration
First-class Vercel AI SDK support with typed data parts and stream utilities.
- `SpecDataPart` type for `data-spec` stream parts (patch, flat, nested payloads)
- `SPEC_DATA_PART` / `SPEC_DATA_PART_TYPE` constants for type-safe part filtering
- `createMixedStreamParser()` for parsing mixed text + JSONL streams
### New: React Chat Hooks
- `useChatUI()` — full chat hook with message history, streaming, and spec extraction
- `useJsonRenderMessage()` — extract spec + text from a message's parts array
- `buildSpecFromParts()` / `getTextFromParts()` — utilities for working with AI SDK message parts
- `useBoundProp()` — two-way binding hook for `$bindState` / `$bindItem` expressions
### New: Two-Way Binding
Props can now use `$bindState` and `$bindItem` expressions for two-way data binding. The renderer resolves bindings and passes a `bindings` map to components, enabling write-back to state.
### New: Expression-Based Props and Visibility
Replaced string token rewriting with structured expression objects:
- Props: `{ $state: "/path" }`, `{ $item: "field" }`, `{ $index: true }`
- Visibility: `{ $state: "/path", eq: "value" }`, `{ $item: "active" }`, `{ $index: true, gt: 0 }`
- Logic: `{ $and: [...] }`, `{ $or: [...] }`, and implicit AND via arrays
- Comparison operators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `not`
### New: Utilities
- `applySpecPatch()` — typed convenience wrapper for applying a single patch to a Spec
- `nestedToFlat()` — convert nested tree specs to flat `{ root, elements }` format
- `resolveBindings()` / `resolveActionParam()` — resolve binding paths and action params
### New: Chat Example
Full-featured chat example (`examples/chat`) with AI agent, tool calls (crypto, GitHub, Hacker News, weather, search), theme toggle, and streaming UI generation.
### Improved: Renderer
- `ElementRenderer` is now `React.memo`'d for better performance in repeat lists
- `emit` is always defined (never `undefined`) — no more optional chaining needed
- Action params are resolved through `resolveActionParam` supporting `$item`, `$index`, `$state`
- Repeat scope now passes the actual item object instead of requiring token rewriting
### Breaking Changes
- **Expressions renamed**: `{ $path }` / `{ path }` replaced by `{ $state }`, `{ $item }`, `{ $index }`
- **Visibility conditions**: `{ path }` → `{ $state }`, `{ and/or/not }` → `{ $and/$or }` with `not` as operator flag
- **DynamicValue**: `{ path: string }` → `{ $state: string }`
- **Repeat field**: `repeat.path` → `repeat.statePath`
- **Action params**: `path` → `statePath` in setState action params
- **Provider props**: `actionHandlers` → `handlers` on `JSONUIProvider`/`ActionProvider`
- **Auth removed**: `AuthState` type and `{ auth }` visibility conditions removed — model auth as regular state
- **Legacy catalog removed**: `createCatalog`, `generateCatalogPrompt`, `generateSystemPrompt`, `ComponentDefinition`, `CatalogConfig`, `SystemPromptOptions` removed
- **React exports removed**: `createRendererFromCatalog`, `rewriteRepeatTokens`
- **Codegen**: `traverseTree` → `traverseSpec`, `SpecVisitor` → `TreeVisitor`
### Patch Changes
- Updated dependencies [06b8745]
- @json-render/core@0.6.0
## 0.5.2
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@json-render/react-native",
"version": "0.5.2",
"version": "0.6.1",
"license": "Apache-2.0",
"description": "React Native renderer for @json-render/core. JSON becomes React Native components.",
"keywords": [
+85
View File
@@ -1,5 +1,90 @@
# @json-render/react
## 0.6.1
### Patch Changes
- 43ad534: Fix infinite re-render loop caused by multiple unbound form inputs (Input, Textarea, Select) all registering field validation at the same empty path with different `checks` configs, causing them to overwrite each other endlessly. Stabilize context values in ActionProvider, ValidationProvider, and useUIStream by using refs for state/callbacks, preventing unnecessary re-render cascades on every state update.
- @json-render/core@0.6.1
## 0.6.1
### Patch Changes
- ea97aff: Fix infinite re-render loop caused by multiple unbound form inputs (Input, Textarea, Select) all registering field validation at the same empty path with different `checks` configs, causing them to overwrite each other endlessly. Stabilize context values in ActionProvider, ValidationProvider, and useUIStream by using refs for state/callbacks, preventing unnecessary re-render cascades on every state update.
- Updated dependencies [ea97aff]
- @json-render/core@0.6.1
## 0.6.0
### Minor Changes
- 06b8745: Chat mode (inline GenUI), AI SDK integration, two-way binding, and expression-based visibility/props.
### New: Chat Mode (Inline GenUI)
Two generation modes: **Generate** (JSONL-only, the default) and **Chat** (text + JSONL inline). Chat mode lets AI respond conversationally with embedded UI specs — ideal for chatbots and copilot experiences.
- `catalog.prompt({ mode: "chat" })` generates a chat-aware system prompt
- `pipeJsonRender()` server-side transform separates text from JSONL patches in a mixed stream
- `createJsonRenderTransform()` low-level TransformStream for custom pipelines
### New: AI SDK Integration
First-class Vercel AI SDK support with typed data parts and stream utilities.
- `SpecDataPart` type for `data-spec` stream parts (patch, flat, nested payloads)
- `SPEC_DATA_PART` / `SPEC_DATA_PART_TYPE` constants for type-safe part filtering
- `createMixedStreamParser()` for parsing mixed text + JSONL streams
### New: React Chat Hooks
- `useChatUI()` — full chat hook with message history, streaming, and spec extraction
- `useJsonRenderMessage()` — extract spec + text from a message's parts array
- `buildSpecFromParts()` / `getTextFromParts()` — utilities for working with AI SDK message parts
- `useBoundProp()` — two-way binding hook for `$bindState` / `$bindItem` expressions
### New: Two-Way Binding
Props can now use `$bindState` and `$bindItem` expressions for two-way data binding. The renderer resolves bindings and passes a `bindings` map to components, enabling write-back to state.
### New: Expression-Based Props and Visibility
Replaced string token rewriting with structured expression objects:
- Props: `{ $state: "/path" }`, `{ $item: "field" }`, `{ $index: true }`
- Visibility: `{ $state: "/path", eq: "value" }`, `{ $item: "active" }`, `{ $index: true, gt: 0 }`
- Logic: `{ $and: [...] }`, `{ $or: [...] }`, and implicit AND via arrays
- Comparison operators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `not`
### New: Utilities
- `applySpecPatch()` — typed convenience wrapper for applying a single patch to a Spec
- `nestedToFlat()` — convert nested tree specs to flat `{ root, elements }` format
- `resolveBindings()` / `resolveActionParam()` — resolve binding paths and action params
### New: Chat Example
Full-featured chat example (`examples/chat`) with AI agent, tool calls (crypto, GitHub, Hacker News, weather, search), theme toggle, and streaming UI generation.
### Improved: Renderer
- `ElementRenderer` is now `React.memo`'d for better performance in repeat lists
- `emit` is always defined (never `undefined`) — no more optional chaining needed
- Action params are resolved through `resolveActionParam` supporting `$item`, `$index`, `$state`
- Repeat scope now passes the actual item object instead of requiring token rewriting
### Breaking Changes
- **Expressions renamed**: `{ $path }` / `{ path }` replaced by `{ $state }`, `{ $item }`, `{ $index }`
- **Visibility conditions**: `{ path }` → `{ $state }`, `{ and/or/not }` → `{ $and/$or }` with `not` as operator flag
- **DynamicValue**: `{ path: string }` → `{ $state: string }`
- **Repeat field**: `repeat.path` → `repeat.statePath`
- **Action params**: `path` → `statePath` in setState action params
- **Provider props**: `actionHandlers` → `handlers` on `JSONUIProvider`/`ActionProvider`
- **Auth removed**: `AuthState` type and `{ auth }` visibility conditions removed — model auth as regular state
- **Legacy catalog removed**: `createCatalog`, `generateCatalogPrompt`, `generateSystemPrompt`, `ComponentDefinition`, `CatalogConfig`, `SystemPromptOptions` removed
- **React exports removed**: `createRendererFromCatalog`, `rewriteRepeatTokens`
- **Codegen**: `traverseTree` → `traverseSpec`, `SpecVisitor` → `TreeVisitor`
### Patch Changes
- Updated dependencies [06b8745]
- @json-render/core@0.6.0
## 0.5.2
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@json-render/react",
"version": "0.5.2",
"version": "0.6.1",
"license": "Apache-2.0",
"description": "React renderer for @json-render/core. JSON becomes React components.",
"keywords": [
+8 -2
View File
@@ -6,6 +6,7 @@ import React, {
useState,
useCallback,
useMemo,
useRef,
type ReactNode,
} from "react";
import {
@@ -137,6 +138,11 @@ export function ActionProvider({
children,
}: ActionProviderProps) {
const { state, get, set } = useStateStore();
// Keep a ref to the latest state so `execute` doesn't change on every
// state update — preventing the entire action context from churning.
const stateRef = useRef(state);
stateRef.current = state;
const [handlers, setHandlers] =
useState<Record<string, ActionHandler>>(initialHandlers);
const [loadingActions, setLoadingActions] = useState<Set<string>>(new Set());
@@ -152,7 +158,7 @@ export function ActionProvider({
const execute = useCallback(
async (binding: ActionBinding) => {
const resolved = resolveAction(binding, state);
const resolved = resolveAction(binding, stateRef.current);
// Built-in: setState updates the StateProvider state directly
if (resolved.action === "setState" && resolved.params) {
@@ -299,7 +305,7 @@ export function ActionProvider({
});
}
},
[state, handlers, get, set, navigate],
[handlers, get, set, navigate],
);
const confirm = useCallback(() => {
+11 -4
View File
@@ -6,6 +6,7 @@ import React, {
useState,
useCallback,
useMemo,
useRef,
type ReactNode,
} from "react";
import {
@@ -130,6 +131,11 @@ export function ValidationProvider({
children,
}: ValidationProviderProps) {
const { state } = useStateStore();
// Keep a ref to the latest state so `validate` doesn't change on every
// state update — preventing the entire validation context from churning.
const stateRef = useRef(state);
stateRef.current = state;
const [fieldStates, setFieldStates] = useState<
Record<string, FieldValidationState>
>({});
@@ -155,8 +161,9 @@ export function ValidationProvider({
const validate = useCallback(
(path: string, config: ValidationConfig): ValidationResult => {
// Walk the nested state object using JSON Pointer segments
const currentState = stateRef.current;
const segments = path.split("/").filter(Boolean);
let value: unknown = state;
let value: unknown = currentState;
for (const seg of segments) {
if (value != null && typeof value === "object") {
value = (value as Record<string, unknown>)[seg];
@@ -167,7 +174,7 @@ export function ValidationProvider({
}
const result = runValidation(config, {
value,
stateModel: state,
stateModel: currentState,
customFunctions,
});
@@ -182,7 +189,7 @@ export function ValidationProvider({
return result;
},
[state, customFunctions],
[customFunctions],
);
const touch = useCallback((path: string) => {
@@ -280,7 +287,7 @@ export function useFieldValidation(
// Register field on mount
React.useEffect(() => {
if (config) {
if (path && config) {
registerField(path, config);
}
}, [path, config, registerField]);
+10 -3
View File
@@ -250,6 +250,13 @@ export function useUIStream({
const [rawLines, setRawLines] = useState<string[]>([]);
const abortControllerRef = useRef<AbortController | null>(null);
// Keep refs to callbacks so `send` doesn't recreate when consumers
// pass inline arrow functions.
const onCompleteRef = useRef(onComplete);
onCompleteRef.current = onComplete;
const onErrorRef = useRef(onError);
onErrorRef.current = onError;
const clear = useCallback(() => {
setSpec(null);
setError(null);
@@ -350,19 +357,19 @@ export function useUIStream({
}
}
onComplete?.(currentSpec);
onCompleteRef.current?.(currentSpec);
} catch (err) {
if ((err as Error).name === "AbortError") {
return;
}
const error = err instanceof Error ? err : new Error(String(err));
setError(error);
onError?.(error);
onErrorRef.current?.(error);
} finally {
setIsStreaming(false);
}
},
[api, onComplete, onError],
[api],
);
// Cleanup on unmount
+83
View File
@@ -1,5 +1,88 @@
# @json-render/remotion
## 0.6.1
### Patch Changes
- @json-render/core@0.6.1
## 0.6.1
### Patch Changes
- Updated dependencies [ea97aff]
- @json-render/core@0.6.1
## 0.6.0
### Minor Changes
- 06b8745: Chat mode (inline GenUI), AI SDK integration, two-way binding, and expression-based visibility/props.
### New: Chat Mode (Inline GenUI)
Two generation modes: **Generate** (JSONL-only, the default) and **Chat** (text + JSONL inline). Chat mode lets AI respond conversationally with embedded UI specs — ideal for chatbots and copilot experiences.
- `catalog.prompt({ mode: "chat" })` generates a chat-aware system prompt
- `pipeJsonRender()` server-side transform separates text from JSONL patches in a mixed stream
- `createJsonRenderTransform()` low-level TransformStream for custom pipelines
### New: AI SDK Integration
First-class Vercel AI SDK support with typed data parts and stream utilities.
- `SpecDataPart` type for `data-spec` stream parts (patch, flat, nested payloads)
- `SPEC_DATA_PART` / `SPEC_DATA_PART_TYPE` constants for type-safe part filtering
- `createMixedStreamParser()` for parsing mixed text + JSONL streams
### New: React Chat Hooks
- `useChatUI()` — full chat hook with message history, streaming, and spec extraction
- `useJsonRenderMessage()` — extract spec + text from a message's parts array
- `buildSpecFromParts()` / `getTextFromParts()` — utilities for working with AI SDK message parts
- `useBoundProp()` — two-way binding hook for `$bindState` / `$bindItem` expressions
### New: Two-Way Binding
Props can now use `$bindState` and `$bindItem` expressions for two-way data binding. The renderer resolves bindings and passes a `bindings` map to components, enabling write-back to state.
### New: Expression-Based Props and Visibility
Replaced string token rewriting with structured expression objects:
- Props: `{ $state: "/path" }`, `{ $item: "field" }`, `{ $index: true }`
- Visibility: `{ $state: "/path", eq: "value" }`, `{ $item: "active" }`, `{ $index: true, gt: 0 }`
- Logic: `{ $and: [...] }`, `{ $or: [...] }`, and implicit AND via arrays
- Comparison operators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `not`
### New: Utilities
- `applySpecPatch()` — typed convenience wrapper for applying a single patch to a Spec
- `nestedToFlat()` — convert nested tree specs to flat `{ root, elements }` format
- `resolveBindings()` / `resolveActionParam()` — resolve binding paths and action params
### New: Chat Example
Full-featured chat example (`examples/chat`) with AI agent, tool calls (crypto, GitHub, Hacker News, weather, search), theme toggle, and streaming UI generation.
### Improved: Renderer
- `ElementRenderer` is now `React.memo`'d for better performance in repeat lists
- `emit` is always defined (never `undefined`) — no more optional chaining needed
- Action params are resolved through `resolveActionParam` supporting `$item`, `$index`, `$state`
- Repeat scope now passes the actual item object instead of requiring token rewriting
### Breaking Changes
- **Expressions renamed**: `{ $path }` / `{ path }` replaced by `{ $state }`, `{ $item }`, `{ $index }`
- **Visibility conditions**: `{ path }` → `{ $state }`, `{ and/or/not }` → `{ $and/$or }` with `not` as operator flag
- **DynamicValue**: `{ path: string }` → `{ $state: string }`
- **Repeat field**: `repeat.path` → `repeat.statePath`
- **Action params**: `path` → `statePath` in setState action params
- **Provider props**: `actionHandlers` → `handlers` on `JSONUIProvider`/`ActionProvider`
- **Auth removed**: `AuthState` type and `{ auth }` visibility conditions removed — model auth as regular state
- **Legacy catalog removed**: `createCatalog`, `generateCatalogPrompt`, `generateSystemPrompt`, `ComponentDefinition`, `CatalogConfig`, `SystemPromptOptions` removed
- **React exports removed**: `createRendererFromCatalog`, `rewriteRepeatTokens`
- **Codegen**: `traverseTree` → `traverseSpec`, `SpecVisitor` → `TreeVisitor`
### Patch Changes
- Updated dependencies [06b8745]
- @json-render/core@0.6.0
## 0.5.2
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@json-render/remotion",
"version": "0.5.2",
"version": "0.6.1",
"license": "Apache-2.0",
"description": "Remotion renderer for @json-render/core. JSON becomes video compositions.",
"keywords": [