Skip to content

Commit 801708a

Browse files
authored
react-native and other things (#81)
* react native * fixes * pop/push * fixes * rename data -> state * remove . tsbuildinfo * fixes * fixes * user prompt * fixes * $id * combine catalog.ts * better actions * repeat * fix docs * fixes * fixes * fixes * better stream * catalog * fixes * fixes * fixes * dialog * sonner * accordion * catalog on homepage * fixes * more catalog * fixes * fixes * refactor * mv * 404 * fixes * nested * fixes * fixes * fixes * fixes * mobile playground * mdx * fix mdx * fixes * streamdown * fixes * use haiku * fixes * great * fixes * fix ... * fixes * fixes * fix build * fix lint * fix lint * fix lint * fix tests
1 parent e9ea9c7 commit 801708a

File tree

175 files changed

+23991
-8003
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

175 files changed

+23991
-8003
lines changed

.changeset/config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
[
77
"@json-render/core",
88
"@json-render/react",
9+
"@json-render/react-native",
910
"@json-render/remotion",
1011
"@json-render/codegen"
1112
]

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,15 @@ coverage
2121
# Vercel
2222
.vercel
2323

24+
# Expo
25+
.expo/
26+
2427
# Build Outputs
2528
.next/
2629
out/
2730
build
2831
dist
32+
*.tsbuildinfo
2933

3034

3135
# Debug

README.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ function Dashboard({ spec }) {
100100

101101
| Package | Description |
102102
|---------|-------------|
103-
| `@json-render/core` | Schemas, catalogs, AI prompts, SpecStream utilities |
103+
| `@json-render/core` | Schemas, catalogs, AI prompts, dynamic props, SpecStream utilities |
104104
| `@json-render/react` | React renderer, contexts, hooks |
105+
| `@json-render/react-native` | React Native renderer with standard mobile components |
105106
| `@json-render/remotion` | Remotion video renderer, timeline schema |
106107

107108
## Renderers
@@ -197,18 +198,39 @@ const systemPrompt = catalog.prompt();
197198
}
198199
```
199200

200-
### Data Binding
201+
### Dynamic Props
202+
203+
Any prop value can be data-driven using expressions:
201204

202205
```json
203206
{
204-
"type": "Metric",
207+
"type": "Icon",
205208
"props": {
206-
"label": "Revenue",
207-
"value": "{{data.revenue}}"
209+
"name": { "$cond": { "eq": [{ "path": "/activeTab" }, "home"] }, "$then": "home", "$else": "home-outline" },
210+
"color": { "$cond": { "eq": [{ "path": "/activeTab" }, "home"] }, "$then": "#007AFF", "$else": "#8E8E93" }
208211
}
209212
}
210213
```
211214

215+
Two expression forms:
216+
217+
- **`{ "$path": "/state/key" }`** -- reads a value from the data model
218+
- **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** -- evaluates a condition (same syntax as visibility conditions) and picks a branch
219+
220+
### Actions
221+
222+
Components can trigger actions, including the built-in `setState` action:
223+
224+
```json
225+
{
226+
"type": "Pressable",
227+
"props": { "action": "setState", "actionParams": { "path": "/activeTab", "value": "home" } },
228+
"children": ["home-icon"]
229+
}
230+
```
231+
232+
The `setState` action updates the data model directly, which re-evaluates visibility conditions and dynamic prop expressions.
233+
212234
---
213235

214236
## Demo
Lines changed: 58 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,25 @@
1-
import Link from "next/link";
2-
import { Code } from "@/components/code";
1+
export const metadata = { title: "A2UI Integration" }
32

4-
export const metadata = {
5-
title: "A2UI Integration | json-render",
6-
};
3+
# A2UI Integration
4+
5+
Use `@json-render/core` to support [A2UI](https://a2ui.org) natively.
6+
7+
<div className="rounded-lg border border-amber-500/50 bg-amber-500/10 p-4 mb-8">
8+
<p className="text-sm text-amber-700 dark:text-amber-300">
9+
<strong>Concept:</strong> This page demonstrates how json-render can support A2UI. The examples are illustrative and may require adaptation for production use.
10+
</p>
11+
</div>
12+
13+
## Native A2UI Support
14+
15+
`@json-render/core` is schema-agnostic. Define a catalog that matches A2UI's format and build a renderer that understands it - no conversion layer needed.
16+
17+
## Example A2UI Message
718

8-
export default function A2UIPage() {
9-
return (
10-
<article>
11-
<h1 className="text-3xl font-bold mb-4">A2UI Integration</h1>
12-
<p className="text-muted-foreground mb-8">
13-
Use <code className="text-foreground">@json-render/core</code> to
14-
support{" "}
15-
<a
16-
href="https://a2ui.org"
17-
target="_blank"
18-
rel="noopener noreferrer"
19-
className="text-foreground hover:underline"
20-
>
21-
A2UI
22-
</a>{" "}
23-
natively.
24-
</p>
25-
26-
<div className="rounded-lg border border-amber-500/50 bg-amber-500/10 p-4 mb-8">
27-
<p className="text-sm text-amber-700 dark:text-amber-300">
28-
<strong>Concept:</strong> This page demonstrates how json-render can
29-
support A2UI. The examples are illustrative and may require adaptation
30-
for production use.
31-
</p>
32-
</div>
33-
34-
<h2 className="text-xl font-semibold mt-12 mb-4">Native A2UI Support</h2>
35-
<p className="text-sm text-muted-foreground mb-4">
36-
<code className="text-foreground">@json-render/core</code> is
37-
schema-agnostic. Define a catalog that matches A2UI&apos;s format and
38-
build a renderer that understands it - no conversion layer needed.
39-
</p>
40-
41-
<h2 className="text-xl font-semibold mt-12 mb-4">Example A2UI Message</h2>
42-
<p className="text-sm text-muted-foreground mb-4">
43-
A2UI uses an adjacency list model - a flat list of components with ID
44-
references. This makes it easy to patch individual components:
45-
</p>
46-
<Code lang="json">{`{
19+
A2UI uses an adjacency list model - a flat list of components with ID references. This makes it easy to patch individual components:
20+
21+
```json
22+
{
4723
"surfaceUpdate": {
4824
"surfaceId": "main",
4925
"components": [
@@ -83,12 +59,13 @@ export default function A2UIPage() {
8359
}
8460
]
8561
}
86-
}`}</Code>
62+
}
63+
```
64+
65+
## Define the A2UI Catalog
8766

88-
<h2 className="text-xl font-semibold mt-12 mb-4">
89-
Define the A2UI Catalog
90-
</h2>
91-
<Code lang="typescript">{`import { createCatalog } from '@json-render/core';
67+
```typescript
68+
import { createCatalog } from '@json-render/core';
9269
import { z } from 'zod';
9370

9471
// A2UI BoundValue schema
@@ -151,15 +128,15 @@ export const a2uiCatalog = createCatalog({
151128
},
152129
// Add more A2UI standard components...
153130
},
154-
});`}</Code>
131+
});
132+
```
133+
134+
## Define the A2UI Schema
155135

156-
<h2 className="text-xl font-semibold mt-12 mb-4">
157-
Define the A2UI Schema
158-
</h2>
159-
<p className="text-sm text-muted-foreground mb-4">
160-
Define the schema for A2UI message types:
161-
</p>
162-
<Code lang="typescript">{`import { z } from 'zod';
136+
Define the schema for A2UI message types:
137+
138+
```typescript
139+
import { z } from 'zod';
163140

164141
// Component instance in the adjacency list
165142
const A2UIComponent = z.object({
@@ -173,8 +150,8 @@ const SurfaceUpdate = z.object({
173150
components: z.array(A2UIComponent),
174151
});
175152

176-
// Data model update message
177-
const DataModelUpdate = z.object({
153+
// State model update message
154+
const StateModelUpdate = z.object({
178155
surfaceId: z.string().optional(),
179156
path: z.string().optional(),
180157
contents: z.array(z.object({
@@ -196,18 +173,18 @@ const BeginRendering = z.object({
196173
// Complete A2UI message schema
197174
export const A2UIMessage = z.object({
198175
surfaceUpdate: SurfaceUpdate.optional(),
199-
dataModelUpdate: DataModelUpdate.optional(),
176+
dataModelUpdate: StateModelUpdate.optional(),
200177
beginRendering: BeginRendering.optional(),
201178
deleteSurface: z.object({ surfaceId: z.string() }).optional(),
202-
});`}</Code>
179+
});
180+
```
181+
182+
## Build an A2UI Renderer
183+
184+
Create a renderer that processes the A2UI adjacency list format:
203185

204-
<h2 className="text-xl font-semibold mt-12 mb-4">
205-
Build an A2UI Renderer
206-
</h2>
207-
<p className="text-sm text-muted-foreground mb-4">
208-
Create a renderer that processes the A2UI adjacency list format:
209-
</p>
210-
<Code lang="tsx">{`import { a2uiCatalog } from './catalog';
186+
```tsx
187+
import { a2uiCatalog } from './catalog';
211188

212189
// Component registry
213190
const components = {
@@ -239,7 +216,7 @@ export function renderA2UI(
239216
if (!bound) return undefined;
240217
if (bound.literalString) return bound.literalString;
241218
if (bound.path) {
242-
const parts = bound.path.replace(/^\\//, '').split('/');
219+
const parts = bound.path.replace(/^\//, '').split('/');
243220
let value = dataModel;
244221
for (const p of parts) value = value?.[p];
245222
return value;
@@ -272,10 +249,13 @@ export function renderA2UI(
272249
}
273250

274251
return render(rootId);
275-
}`}</Code>
252+
}
253+
```
254+
255+
## Usage
276256

277-
<h2 className="text-xl font-semibold mt-12 mb-4">Usage</h2>
278-
<Code lang="tsx">{`const [components] = useState(() => new Map());
257+
```tsx
258+
const [components] = useState(() => new Map());
279259
const [dataModel, setDataModel] = useState({});
280260
const [rootId, setRootId] = useState<string | null>(null);
281261

@@ -295,19 +275,9 @@ function handleMessage(msg: any) {
295275
}
296276

297277
// Render
298-
{rootId && renderA2UI(components, dataModel, rootId, handleAction)}`}</Code>
299-
300-
<h2 className="text-xl font-semibold mt-12 mb-4">Next</h2>
301-
<p className="text-sm text-muted-foreground">
302-
Learn about{" "}
303-
<Link
304-
href="/docs/adaptive-cards"
305-
className="text-foreground hover:underline"
306-
>
307-
Adaptive Cards integration
308-
</Link>{" "}
309-
for another UI protocol.
310-
</p>
311-
</article>
312-
);
313-
}
278+
{rootId && renderA2UI(components, dataModel, rootId, handleAction)}
279+
```
280+
281+
## Next
282+
283+
Learn about [Adaptive Cards integration](/docs/adaptive-cards) for another UI protocol.

0 commit comments

Comments
 (0)