mirror of
https://github.com/vercel-labs/json-render.git
synced 2026-10-03 04:18:15 +08:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fcc670a21 |
@@ -22,7 +22,7 @@ json-render is a **Generative UI** framework: AI generates interfaces from natur
|
||||
- **Predictable** - JSON output matches your schema, every time
|
||||
- **Fast** - Stream and render progressively as the model responds
|
||||
- **Cross-Platform** - React (web) and React Native (mobile) from the same catalog
|
||||
- **Batteries Included** - 30+ pre-built shadcn/ui components ready to use
|
||||
- **Batteries Included** - 36 pre-built shadcn/ui components ready to use
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -108,7 +108,7 @@ function Dashboard({ spec }) {
|
||||
|---------|-------------|
|
||||
| `@json-render/core` | Schemas, catalogs, AI prompts, dynamic props, SpecStream utilities |
|
||||
| `@json-render/react` | React renderer, contexts, hooks |
|
||||
| `@json-render/shadcn` | 30+ pre-built shadcn/ui components (Radix UI + Tailwind CSS) |
|
||||
| `@json-render/shadcn` | 36 pre-built shadcn/ui components (Radix UI + Tailwind CSS) |
|
||||
| `@json-render/react-native` | React Native renderer with standard mobile components |
|
||||
| `@json-render/remotion` | Remotion video renderer, timeline schema |
|
||||
|
||||
@@ -150,7 +150,7 @@ import { schema, defineRegistry, Renderer } from "@json-render/react";
|
||||
import { shadcnComponentDefinitions } from "@json-render/shadcn/catalog";
|
||||
import { shadcnComponents } from "@json-render/shadcn";
|
||||
|
||||
// Pick components from the 30+ standard definitions
|
||||
// Pick components from the 36 standard definitions
|
||||
const catalog = defineCatalog(schema, {
|
||||
components: {
|
||||
Card: shadcnComponentDefinitions.Card,
|
||||
|
||||
@@ -157,6 +157,14 @@ const spec = compileSpecStream<MySpec>(jsonlString);
|
||||
| `defineSchema(builder, options?)` | Create a schema with spec/catalog structure |
|
||||
| `SchemaBuilder` | Builder with `s.object()`, `s.array()`, `s.map()`, etc. |
|
||||
|
||||
Schema options:
|
||||
|
||||
| Option | Purpose |
|
||||
|--------|---------|
|
||||
| `promptTemplate` | Custom AI prompt generator |
|
||||
| `defaultRules` | Default rules injected before custom rules in prompts |
|
||||
| `builtInActions` | Actions always available at runtime, auto-injected into prompts (e.g. `setState`) |
|
||||
|
||||
### Catalog
|
||||
|
||||
| Export | Purpose |
|
||||
@@ -196,12 +204,30 @@ const spec = compileSpecStream<MySpec>(jsonlString);
|
||||
| `autoFixSpec(spec)` | Auto-fix common spec issues (returns corrected copy) |
|
||||
| `formatSpecIssues(issues)` | Format validation issues as readable strings |
|
||||
|
||||
### Actions
|
||||
|
||||
| Export | Purpose |
|
||||
|--------|---------|
|
||||
| `ActionBinding` | Action binding with `action`, `params`, `confirm`, `preventDefault`, etc. |
|
||||
| `BuiltInAction` | Built-in action definition with `name` and `description` |
|
||||
|
||||
### Chat Mode (Mixed Streams)
|
||||
|
||||
| Export | Purpose |
|
||||
|--------|---------|
|
||||
| `createJsonRenderTransform()` | TransformStream that separates text from JSONL patches in a mixed stream |
|
||||
| `pipeJsonRender()` | Server-side helper to pipe a mixed stream through the transform |
|
||||
| `SPEC_DATA_PART` / `SPEC_DATA_PART_TYPE` | Constants for filtering spec data parts |
|
||||
|
||||
The transform splits text blocks around spec data by emitting `text-end`/`text-start` pairs, ensuring the AI SDK creates separate text parts and preserving correct interleaving of prose and UI in `message.parts`.
|
||||
|
||||
### Types
|
||||
|
||||
| Export | Purpose |
|
||||
|--------|---------|
|
||||
| `Spec` | Base spec type |
|
||||
| `Catalog` | Catalog type |
|
||||
| `BuiltInAction` | Built-in action type (`name` + `description`) |
|
||||
| `VisibilityCondition` | Visibility condition type (used by `$cond`) |
|
||||
| `VisibilityContext` | Context for evaluating visibility and prop expressions |
|
||||
| `SpecStreamLine` | Single patch operation |
|
||||
|
||||
@@ -51,6 +51,8 @@ export const catalog = defineCatalog(schema, {
|
||||
|
||||
### 2. Define Component Implementations
|
||||
|
||||
`defineRegistry` conditionally requires the `actions` field only when the catalog declares actions. Catalogs with `actions: {}` can omit it entirely.
|
||||
|
||||
```tsx
|
||||
import { defineRegistry, useBoundProp } from "@json-render/react";
|
||||
import { catalog } from "./catalog";
|
||||
@@ -297,7 +299,7 @@ See [@json-render/core](../core/README.md) for full expression syntax.
|
||||
|
||||
## Built-in Actions
|
||||
|
||||
The `setState`, `pushState`, and `removeState` actions are handled automatically by `ActionProvider`. They update the state model, which triggers re-evaluation of visibility conditions and dynamic prop expressions:
|
||||
The `setState`, `pushState`, and `removeState` actions are built into the React schema and handled automatically by `ActionProvider`. They are injected into AI prompts without needing to be declared in your catalog's `actions`. They update the state model, which triggers re-evaluation of visibility conditions and dynamic prop expressions:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -321,14 +323,52 @@ When using `defineRegistry`, components receive these props:
|
||||
interface ComponentContext<P> {
|
||||
props: P; // Typed props from the catalog (expressions resolved)
|
||||
children?: React.ReactNode; // Rendered children
|
||||
emit?: (event: string) => void; // Emit a named event
|
||||
emit: (event: string) => void; // Emit a named event (always defined)
|
||||
on: (event: string) => EventHandle; // Get event handle with metadata
|
||||
loading?: boolean; // Whether the parent is loading
|
||||
bindings?: Record<string, string>; // State paths for $bindState/$bindItem expressions (e.g. bindings.value)
|
||||
}
|
||||
|
||||
interface EventHandle {
|
||||
emit: () => void; // Fire the event
|
||||
shouldPreventDefault: boolean; // Whether any binding requested preventDefault
|
||||
bound: boolean; // Whether any handler is bound
|
||||
}
|
||||
```
|
||||
|
||||
Use `emit("press")` for simple event firing. Use `on("click")` when you need to check metadata like `shouldPreventDefault` or `bound`:
|
||||
|
||||
```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>
|
||||
);
|
||||
},
|
||||
```
|
||||
|
||||
Use `bindings?.value`, `bindings?.checked`, etc. with `useBoundProp()` for two-way bound form components.
|
||||
|
||||
### `BaseComponentProps`
|
||||
|
||||
For building reusable component libraries that are not tied to a specific catalog (e.g. `@json-render/shadcn`), use the catalog-agnostic `BaseComponentProps` type:
|
||||
|
||||
```typescript
|
||||
import type { BaseComponentProps } from "@json-render/react";
|
||||
|
||||
const Card = ({ props, children }: BaseComponentProps<{ title?: string }>) => (
|
||||
<div>{props.title}{children}</div>
|
||||
);
|
||||
```
|
||||
|
||||
## Generate AI Prompts
|
||||
|
||||
```typescript
|
||||
@@ -374,3 +414,28 @@ function App() {
|
||||
return <Renderer spec={spec} registry={registry} />;
|
||||
}
|
||||
```
|
||||
|
||||
## Key Exports
|
||||
|
||||
| Export | Purpose |
|
||||
|--------|---------|
|
||||
| `defineRegistry` | Create a type-safe component registry from a catalog |
|
||||
| `Renderer` | Render a spec using a registry |
|
||||
| `schema` | Element tree schema (includes built-in actions: `setState`, `pushState`, `removeState`) |
|
||||
| `useStateStore` | Access state context |
|
||||
| `useStateValue` | Get single value from state |
|
||||
| `useBoundProp` | Two-way binding for `$bindState`/`$bindItem` expressions |
|
||||
| `useActions` | Access actions context |
|
||||
| `useAction` | Get a single action dispatch function |
|
||||
| `useUIStream` | Stream specs from an API endpoint |
|
||||
|
||||
### Types
|
||||
|
||||
| Export | Purpose |
|
||||
|--------|---------|
|
||||
| `ComponentContext` | Typed component render function context (catalog-aware) |
|
||||
| `BaseComponentProps` | Catalog-agnostic base type for reusable component libraries |
|
||||
| `EventHandle` | Event handle with `emit()`, `shouldPreventDefault`, `bound` |
|
||||
| `ComponentFn` | Component render function type |
|
||||
| `SetState` | State setter type |
|
||||
| `StateModel` | State model type |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# @json-render/shadcn
|
||||
|
||||
Pre-built [shadcn/ui](https://ui.shadcn.com/) components for json-render. Drop-in catalog definitions and React implementations for 30+ components built on Radix UI + Tailwind CSS.
|
||||
Pre-built [shadcn/ui](https://ui.shadcn.com/) components for json-render. Drop-in catalog definitions and React implementations for 36 components built on Radix UI + Tailwind CSS.
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
@@ -157,6 +157,20 @@ visibility.always // true
|
||||
visibility.never // false
|
||||
```
|
||||
|
||||
## Built-in Actions in Schema
|
||||
|
||||
Schemas can declare `builtInActions` -- actions that are always available at runtime and auto-injected into prompts:
|
||||
|
||||
```typescript
|
||||
const schema = defineSchema(builder, {
|
||||
builtInActions: [
|
||||
{ name: "setState", description: "Update a value in the state model" },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
These appear in prompts as `[built-in]` and don't require handlers in `defineRegistry`.
|
||||
|
||||
## Key Exports
|
||||
|
||||
| Export | Purpose |
|
||||
@@ -169,5 +183,8 @@ visibility.never // false
|
||||
| `validateSpec` | Validate spec structure |
|
||||
| `autoFixSpec` | Auto-fix common spec issues |
|
||||
| `createSpecStreamCompiler` | Stream JSONL patches into spec |
|
||||
| `createJsonRenderTransform` | TransformStream separating text from JSONL in mixed streams |
|
||||
| `parseSpecStreamLine` | Parse single JSONL line |
|
||||
| `applySpecStreamPatch` | Apply patch to object |
|
||||
| `BuiltInAction` | Type for built-in action definitions (`name` + `description`) |
|
||||
| `ActionBinding` | Action binding type (includes `preventDefault` field) |
|
||||
|
||||
@@ -118,13 +118,24 @@ Components receive already-resolved props. For two-way bound props, use the `use
|
||||
|
||||
## Event System
|
||||
|
||||
Components use `emit` to fire named events. The element's `on` field maps events to action bindings:
|
||||
Components use `emit` to fire named events, or `on()` to get an event handle with metadata. The element's `on` field maps events to action bindings:
|
||||
|
||||
```tsx
|
||||
// Component emits a named event
|
||||
// Simple event firing
|
||||
Button: ({ props, emit }) => (
|
||||
<button onClick={() => emit("press")}>{props.label}</button>
|
||||
),
|
||||
|
||||
// Event handle with metadata (e.g. preventDefault)
|
||||
Link: ({ props, on }) => {
|
||||
const click = on("click");
|
||||
return (
|
||||
<a href={props.href} onClick={(e) => {
|
||||
if (click.shouldPreventDefault) e.preventDefault();
|
||||
click.emit();
|
||||
}}>{props.label}</a>
|
||||
);
|
||||
},
|
||||
```
|
||||
|
||||
```json
|
||||
@@ -135,12 +146,16 @@ Button: ({ props, emit }) => (
|
||||
}
|
||||
```
|
||||
|
||||
The `EventHandle` returned by `on()` has: `emit()`, `shouldPreventDefault` (boolean), and `bound` (boolean).
|
||||
|
||||
## Built-in Actions
|
||||
|
||||
The `setState` action is handled automatically by `ActionProvider` and updates the state model directly, which re-evaluates visibility conditions and dynamic prop expressions:
|
||||
The `setState`, `pushState`, and `removeState` actions are built into the React schema and handled automatically by `ActionProvider`. They are injected into AI prompts without needing to be declared in catalog `actions`:
|
||||
|
||||
```json
|
||||
{ "action": "setState", "actionParams": { "statePath": "/activeTab", "value": "home" } }
|
||||
{ "action": "setState", "params": { "statePath": "/activeTab", "value": "home" } }
|
||||
{ "action": "pushState", "params": { "statePath": "/items", "value": { "text": "New" } } }
|
||||
{ "action": "removeState", "params": { "statePath": "/items", "index": 0 } }
|
||||
```
|
||||
|
||||
Note: `statePath` in action params (e.g. `setState.statePath`) targets the mutation path. Two-way binding in component props uses `{ "$bindState": "/path" }` on the value prop, not `statePath`.
|
||||
@@ -168,16 +183,35 @@ Input: ({ element, bindings }) => {
|
||||
|
||||
`useBoundProp(propValue, bindingPath)` returns `[value, setValue]`. The `value` is the resolved prop; `setValue` writes back to the bound state path (no-op if not bound).
|
||||
|
||||
## BaseComponentProps
|
||||
|
||||
For building reusable component libraries not tied to a specific catalog (e.g. `@json-render/shadcn`):
|
||||
|
||||
```typescript
|
||||
import type { BaseComponentProps } from "@json-render/react";
|
||||
|
||||
const Card = ({ props, children }: BaseComponentProps<{ title?: string }>) => (
|
||||
<div>{props.title}{children}</div>
|
||||
);
|
||||
```
|
||||
|
||||
## defineRegistry
|
||||
|
||||
`defineRegistry` conditionally requires the `actions` field only when the catalog declares actions. Catalogs with `actions: {}` can omit it.
|
||||
|
||||
## Key Exports
|
||||
|
||||
| Export | Purpose |
|
||||
|--------|---------|
|
||||
| `defineRegistry` | Create a type-safe component registry from a catalog |
|
||||
| `Renderer` | Render a spec using a registry |
|
||||
| `schema` | Element tree schema |
|
||||
| `schema` | Element tree schema (includes built-in state actions) |
|
||||
| `useStateStore` | Access state context |
|
||||
| `useStateValue` | Get single value from state |
|
||||
| `useBoundProp` | Two-way binding for `$bindState`/`$bindItem` expressions |
|
||||
| `useActions` | Access actions context |
|
||||
| `useAction` | Get a single action dispatch function |
|
||||
| `useUIStream` | Stream specs from an API endpoint |
|
||||
| `BaseComponentProps` | Catalog-agnostic base type for reusable component libraries |
|
||||
| `EventHandle` | Event handle type (`emit`, `shouldPreventDefault`, `bound`) |
|
||||
| `ComponentContext` | Typed component context (catalog-aware) |
|
||||
|
||||
@@ -5,7 +5,7 @@ description: Pre-built shadcn/ui components for json-render. Use when working wi
|
||||
|
||||
# @json-render/shadcn
|
||||
|
||||
Pre-built shadcn/ui component definitions and implementations for json-render. Provides 30+ components built on Radix UI + Tailwind CSS.
|
||||
Pre-built shadcn/ui component definitions and implementations for json-render. Provides 36 components built on Radix UI + Tailwind CSS.
|
||||
|
||||
## Two Entry Points
|
||||
|
||||
|
||||
Reference in New Issue
Block a user