| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- import { pageMetadata } from "@/lib/page-metadata"
- export const metadata = pageMetadata("docs/changelog")
- # Changelog
- Notable changes and updates to json-render.
- ## v0.8.0
- February 2026
- ### New: `@json-render/react-pdf`
- PDF renderer for json-render, powered by [`@react-pdf/renderer`](https://react-pdf.org/). Define catalogs and registries the same way as `@json-render/react`, but output PDF documents instead of web UI.
- ```bash
- npm install @json-render/core @json-render/react-pdf
- ```
- ```typescript
- import { renderToBuffer } from "@json-render/react-pdf";
- import type { Spec } from "@json-render/core";
- const spec: Spec = {
- root: "doc",
- elements: {
- doc: { type: "Document", props: { title: "Invoice" }, children: ["page"] },
- page: {
- type: "Page",
- props: { size: "A4" },
- children: ["heading", "table"],
- },
- heading: {
- type: "Heading",
- props: { text: "Invoice #1234", level: "h1" },
- children: [],
- },
- table: {
- type: "Table",
- props: {
- columns: [
- { header: "Item", width: "60%" },
- { header: "Price", width: "40%", align: "right" },
- ],
- rows: [
- ["Widget A", "$10.00"],
- ["Widget B", "$25.00"],
- ],
- },
- children: [],
- },
- },
- };
- const buffer = await renderToBuffer(spec);
- ```
- Server-side rendering APIs:
- - `renderToBuffer(spec)` -- render to an in-memory PDF buffer
- - `renderToStream(spec)` -- render to a readable stream (pipe to HTTP response)
- - `renderToFile(spec, path)` -- render directly to a file
- 15 standard components covering document structure (Document, Page), layout (View, Row, Column), content (Heading, Text, Image, Link), data (Table, List), decorative (Divider, Spacer), and page-level (PageNumber).
- Supports custom catalogs with `defineRegistry`, server-safe imports via `@json-render/react-pdf/server`, and full context support (state, visibility, actions, validation, repeat scopes).
- ---
- ## v0.7.0
- February 2026
- ### New: `@json-render/shadcn`
- Pre-built [shadcn/ui](https://ui.shadcn.com/) component library for json-render. 36 components built on Radix UI + Tailwind CSS, ready to use with `defineCatalog` and `defineRegistry`.
- ```bash
- npm install @json-render/shadcn
- ```
- ```typescript
- import { defineCatalog } from "@json-render/core";
- import { schema } from "@json-render/react/schema";
- import { shadcnComponentDefinitions } from "@json-render/shadcn/catalog";
- import { defineRegistry } from "@json-render/react";
- import { shadcnComponents } from "@json-render/shadcn";
- const catalog = defineCatalog(schema, {
- components: {
- Card: shadcnComponentDefinitions.Card,
- Button: shadcnComponentDefinitions.Button,
- Input: shadcnComponentDefinitions.Input,
- },
- actions: {},
- });
- const { registry } = defineRegistry(catalog, {
- components: {
- Card: shadcnComponents.Card,
- Button: shadcnComponents.Button,
- Input: shadcnComponents.Input,
- },
- });
- ```
- Components include: layout (Card, Stack, Grid, Separator), navigation (Tabs, Accordion, Collapsible, Pagination), overlay (Dialog, Drawer, Tooltip, Popover, DropdownMenu), content (Heading, Text, Image, Avatar, Badge, Alert, Carousel, Table), feedback (Progress, Skeleton, Spinner), and input (Button, Link, Input, Textarea, Select, Checkbox, Radio, Switch, Slider, Toggle, ToggleGroup, ButtonGroup).
- See the [API reference](/docs/api/shadcn) for full details.
- ### New: Event Handles (`on()`)
- Components now receive an `on(event)` function in addition to `emit(event)`. The `on()` function returns an `EventHandle` with metadata:
- - `emit()` -- fire the event
- - `shouldPreventDefault` -- whether any action binding requested `preventDefault`
- - `bound` -- whether any handler is bound to this event
- ```tsx
- Link: ({ props, on }) => {
- const click = on("click");
- return (
- <a href={props.href} onClick={(e) => {
- if (click.shouldPreventDefault) e.preventDefault();
- click.emit();
- }}>{props.label}</a>
- );
- },
- ```
- ### New: `BaseComponentProps`
- Catalog-agnostic base type for component render functions. Use when building reusable component libraries (like `@json-render/shadcn`) that are not tied to a specific catalog.
- ```typescript
- import type { BaseComponentProps } from "@json-render/react";
- const Card = ({ props, children }: BaseComponentProps<{ title?: string }>) => (
- <div>{props.title}{children}</div>
- );
- ```
- ### New: Built-in Actions in Schema
- Schemas can now declare `builtInActions` -- actions that are always available at runtime and automatically injected into prompts. The React schema declares `setState`, `pushState`, and `removeState` as built-in, so they appear in prompts without needing to be listed in catalog `actions`.
- ### New: `preventDefault` on `ActionBinding`
- Action bindings now support a `preventDefault` boolean field, allowing the LLM to request that default browser behavior (e.g. navigation on links) be prevented.
- ### Improved: Stream Transform Text Block Splitting
- `createJsonRenderTransform()` now properly splits text blocks around spec data by emitting `text-end`/`text-start` pairs. This ensures the AI SDK creates separate text parts, preserving correct interleaving of prose and UI in `message.parts`.
- ### Improved: `defineRegistry` Actions Requirement
- `defineRegistry` now conditionally requires the `actions` field only when the catalog declares actions. Catalogs with no actions (e.g. `actions: {}`) no longer need to pass an empty actions object.
- ---
- ## v0.6.0
- February 2026
- ### New: Chat Mode (Inline GenUI)
- json-render now supports two generation modes: **Generate** (JSONL-only, the default) and **Chat** (text + JSONL inline). Chat mode lets the AI respond conversationally with embedded UI specs, ideal for chatbots and copilot experiences.
- ```typescript
- // Generate mode (default) — AI outputs only JSONL
- const prompt = catalog.prompt();
- // Chat mode — AI outputs text + JSONL inline
- const chatPrompt = catalog.prompt({ mode: "chat" });
- ```
- On the server, `pipeJsonRender()` separates text from JSONL patches in a mixed stream:
- ```typescript
- import { pipeJsonRender } from "@json-render/core";
- import { createUIMessageStream, createUIMessageStreamResponse } from "ai";
- const stream = createUIMessageStream({
- execute: async ({ writer }) => {
- writer.merge(pipeJsonRender(result.toUIMessageStream()));
- },
- });
- return createUIMessageStreamResponse({ stream });
- ```
- On the client, `useJsonRenderMessage` extracts the spec and text from message parts:
- ```tsx
- import { useJsonRenderMessage } from "@json-render/react";
- function ChatMessage({ message }) {
- const { spec, text, hasSpec } = useJsonRenderMessage(message.parts);
- return (
- <div>
- {text && <Markdown>{text}</Markdown>}
- {hasSpec && <Renderer spec={spec} registry={registry} />}
- </div>
- );
- }
- ```
- ### 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
- - `createJsonRenderTransform()` low-level TransformStream for custom pipelines
- - `createMixedStreamParser()` for parsing mixed text + JSONL streams
- ### 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 without custom `valuePath` props.
- ```json
- {
- "type": "Input",
- "props": { "label": "Email", "value": { "$bindState": "/form/email" } }
- }
- ```
- ```tsx
- import { useBoundProp } from "@json-render/react";
- Input: ({ props, bindings }) => {
- const [value, setValue] = useBoundProp<string>(props.value, bindings?.value);
- return <input value={value ?? ""} onChange={(e) => setValue(e.target.value)} />;
- }
- ```
- ### New: Expression-Based Props and Visibility
- All dynamic expressions now use structured `$state`, `$item`, and `$index` objects instead of string token rewriting. This is simpler, more explicit, and works for both props and visibility conditions.
- **Props:**
- ```json
- { "title": { "$state": "/user/name" } }
- { "label": { "$item": "title" } }
- { "position": { "$index": true } }
- ```
- **Visibility:**
- ```json
- { "$state": "/isAdmin" }
- { "$state": "/role", "eq": "admin" }
- [{ "$state": "/isAdmin" }, { "$state": "/feature" }]
- { "$or": [{ "$state": "/roleA" }, { "$state": "/roleB" }] }
- { "$item": "isActive" }
- { "$index": true, "gt": 0 }
- ```
- Comparison operators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `not`.
- ### 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`
- ### New: Chat Example
- Full-featured chat example (`examples/chat`) with AI agent, tool calls (crypto, GitHub, Hacker News, weather, search), theme toggle, and streaming inline UI generation.
- ### Improved: Renderer Performance
- - `ElementRenderer` is now `React.memo`'d for better performance with repeat lists
- - `emit` is always defined (never `undefined`)
- - Repeat scope passes the actual item object, eliminating string token rewriting
- ### Improved: Utilities
- - `applySpecPatch()` — typed wrapper for applying a single patch to a Spec
- - `nestedToFlat()` — convert nested tree specs to flat format
- - `resolveBindings()` / `resolveActionParam()` — resolve binding paths and action params
- ### Breaking Changes
- - `{ $path }` and `{ path }` replaced by `{ $state }`, `{ $item }`, `{ $index }` in props
- - Visibility: `{ path }` -> `{ $state }`, `{ and/or/not }` -> `{ $and/$or }` with `not` as operator flag
- - `DynamicValue`: `{ path: string }` -> `{ $state: string }`
- - `repeat.path` -> `repeat.statePath`
- - Action params: `path` -> `statePath` in setState action
- - `actionHandlers` -> `handlers` on `JSONUIProvider` / `ActionProvider`
- - `AuthState` and `{ auth }` visibility conditions removed (model auth as regular state)
- - Legacy catalog API removed: `createCatalog`, `generateCatalogPrompt`, `generateSystemPrompt`
- - React exports removed: `createRendererFromCatalog`, `rewriteRepeatTokens`
- - Codegen: `traverseTree` -> `traverseSpec`
- See the [Migration Guide](/docs/migration) for detailed upgrade instructions.
- ---
- ## v0.5.0
- February 2026
- ### New: @json-render/react-native
- Full React Native renderer with 25+ standard components, data binding, visibility, actions, and dynamic props. Build AI-generated native mobile UIs with the same catalog-driven approach as web.
- ```tsx
- import { defineCatalog } from "@json-render/core";
- import { schema } from "@json-render/react-native/schema";
- import {
- standardComponentDefinitions,
- standardActionDefinitions,
- } from "@json-render/react-native/catalog";
- import { defineRegistry, Renderer } from "@json-render/react-native";
- const catalog = defineCatalog(schema, {
- components: { ...standardComponentDefinitions },
- actions: standardActionDefinitions,
- });
- const { registry } = defineRegistry(catalog, { components: {} });
- <Renderer spec={spec} registry={registry} />
- ```
- Includes standard components for layout (Container, Row, Column, ScrollContainer, SafeArea, Pressable, Spacer, Divider), content (Heading, Paragraph, Label, Image, Avatar, Badge, Chip), input (Button, TextInput, Switch, Checkbox, Slider, SearchBar), feedback (Spinner, ProgressBar), and composite (Card, ListItem, Modal).
- ### New: Event System
- Components now use `emit` to fire named events instead of directly dispatching actions. The element's `on` field maps events to action bindings, decoupling component logic from action handling.
- ```tsx
- // Component emits a named event
- Button: ({ props, emit }) => (
- <button onClick={() => emit("press")}>{props.label}</button>
- ),
- // Element spec maps events to actions
- {
- "type": "Button",
- "props": { "label": "Submit" },
- "on": { "press": { "action": "submit", "params": { "formId": "main" } } }
- }
- ```
- ### New: Repeat/List Rendering
- Elements can now iterate over state arrays using the `repeat` field. Child elements use `{ "$item": "field" }` to read from the current item and `{ "$index": true }` for the current array index.
- ```json
- {
- "type": "Column",
- "repeat": { "statePath": "/posts", "key": "id" },
- "children": ["post-card"]
- }
- ```
- ```json
- {
- "type": "Card",
- "props": { "title": { "$item": "title" } }
- }
- ```
- ### New: User Prompt Builder
- Build structured user prompts with optional spec refinement and state context:
- ```typescript
- import { buildUserPrompt } from "@json-render/core";
- // Fresh generation
- buildUserPrompt({ prompt: "create a todo app" });
- // Refinement (patch-only mode)
- buildUserPrompt({ prompt: "add a toggle", currentSpec: spec });
- // With runtime state
- buildUserPrompt({ prompt: "show data", state: { todos: [] } });
- ```
- ### New: Spec Validation
- Validate spec structure and auto-fix common issues:
- ```typescript
- import { validateSpec, autoFixSpec } from "@json-render/core";
- const { valid, issues } = validateSpec(spec);
- const fixed = autoFixSpec(spec);
- ```
- ### Improved: State Management
- `DataProvider` has been renamed to `StateProvider` with a clearer API. State is now a first-class part of specs. Elements can bind to state via `$state` expressions, and the built-in `setState` action updates state directly.
- ### Improved: AI Prompts
- Schema prompts now include streaming best practices, repeat/list examples, and state patching guidance. Schemas can also define `defaultRules` that are always included in generated prompts.
- ### Improved: Documentation
- - All documentation pages migrated to MDX
- - AI-powered documentation chat
- - Dynamic Open Graph images for all docs pages
- - Improved playground
- ### Breaking Changes
- - `DataProvider` renamed to `StateProvider`
- - `useData` renamed to `useStateStore`, `useDataValue` to `useStateValue`, `useDataBinding` to `useStateBinding`
- - `onAction` renamed to `emit` in component context
- - `DataModel` type renamed to `StateModel`
- - `Action` type renamed to `ActionBinding` (old name still available but deprecated)
- ---
- ## v0.4.0
- February 2026
- ### New: Custom Schema System
- Create custom output formats with `defineSchema`. Each renderer now defines its own schema, enabling completely different spec formats for different use cases.
- ```typescript
- import { defineSchema } from "@json-render/core";
- const mySchema = defineSchema((s) => ({
- spec: s.object({
- pages: s.array(s.object({
- title: s.string(),
- blocks: s.array(s.ref("catalog.blocks")),
- })),
- }),
- catalog: s.object({
- blocks: s.map({ props: s.zod(), description: s.string() }),
- }),
- }), {
- promptTemplate: myPromptTemplate,
- });
- ```
- ### New: Component Slots
- Components can now define which slots they accept. Use `["default"]` for regular children, or named slots like `["header", "footer"]` for more complex layouts.
- ```typescript
- const catalog = defineCatalog(schema, {
- components: {
- Card: {
- props: z.object({ title: z.string() }),
- slots: ["default"], // accepts children
- description: "A card container",
- },
- Layout: {
- props: z.object({}),
- slots: ["header", "content", "footer"], // named slots
- description: "Page layout with header, content, footer",
- },
- },
- });
- ```
- ### New: AI Prompt Generation
- Catalogs now generate AI system prompts automatically with `catalog.prompt()`. The prompt includes all component definitions, props schemas, and action descriptions - ensuring the AI only generates valid specs.
- ```typescript
- import { defineCatalog } from "@json-render/core";
- import { schema } from "@json-render/react/schema";
- const catalog = defineCatalog(schema, {
- components: { /* ... */ },
- actions: { /* ... */ },
- });
- // Generate system prompt for AI
- const systemPrompt = catalog.prompt();
- // Use with any AI SDK
- const result = await streamText({
- model: "claude-haiku-4.5",
- system: systemPrompt,
- prompt: userMessage,
- });
- ```
- ### New: @json-render/remotion
- Generate AI-powered videos with Remotion. Define video catalogs, stream timeline specs, and render with the Remotion Player.
- ```tsx
- import { Player } from "@remotion/player";
- import { Renderer, schema, standardComponentDefinitions } from "@json-render/remotion";
- const catalog = defineCatalog(schema, {
- components: standardComponentDefinitions,
- transitions: standardTransitionDefinitions,
- });
- <Player
- component={Renderer}
- inputProps={{ spec }}
- durationInFrames={spec.composition.durationInFrames}
- fps={spec.composition.fps}
- compositionWidth={spec.composition.width}
- compositionHeight={spec.composition.height}
- />
- ```
- Includes 10 standard video components (TitleCard, TypingText, SplitScreen, etc.), 7 transition types, and the ClipWrapper utility for custom components.
- ### New: SpecStream
- SpecStream is json-render's streaming format for progressively building specs from JSONL patches. The new compiler API makes it easy to process streaming AI responses.
- ```typescript
- import { createSpecStreamCompiler } from "@json-render/core";
- const compiler = createSpecStreamCompiler<MySpec>();
- // Process streaming chunks
- const { result, newPatches } = compiler.push(chunk);
- setSpec(result); // Update UI with partial result
- ```
- ### Improved: Dashboard Example
- The dashboard example is now a full-featured accounting dashboard with:
- - Persistent SQLite database with Drizzle ORM
- - RESTful API for customers, invoices, expenses, accounts
- - Draggable widget reordering
- - AI-powered widget generation with streaming
- - Real data binding to database records
- ### Improved: Documentation
- - Interactive playground for testing specs
- - New guides: Custom Schema, Streaming, Code Export
- - Full API reference for all packages
- - Integration guides: A2UI, AG-UI, Adaptive Cards, OpenAPI
- ### Breaking Changes
- - `UITree` type renamed to `Spec`
- - Schema is now imported from renderer packages (`@json-render/react`) not core
- - `defineCatalog` now requires a schema as first argument
- ---
- ## v0.3.0
- January 2026
- Internal release with codegen foundations.
- - Added `@json-render/codegen` package (spec traversal and JSX serialization)
- - Configurable AI model via environment variables
- - Documentation improvements and bug fixes
- *Note: Only @json-render/core was published to npm for this release.*
- ---
- ## v0.2.0
- January 2026
- Initial public release.
- - Core catalog and spec types
- - React renderer with contexts for data, actions, visibility
- - AI prompt generation from catalogs
- - Basic streaming support
- - Dashboard example application
|