Compare commits

...
Author SHA1 Message Date
Chris Tate c7a7bfb9ba add docs 2026-02-20 02:30:06 -06:00
github-actions[bot] 0a404302ef chore: version packages (#126)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-20 02:17:13 -06:00
Chris Tate 09376db2f6 v0.8.0 changeset (#125) 2026-02-20 02:15:51 -06:00
20 changed files with 610 additions and 11 deletions
+1
View File
@@ -6,6 +6,7 @@
[ [
"@json-render/core", "@json-render/core",
"@json-render/react", "@json-render/react",
"@json-render/react-pdf",
"@json-render/shadcn", "@json-render/shadcn",
"@json-render/react-native", "@json-render/react-native",
"@json-render/remotion", "@json-render/remotion",
@@ -0,0 +1,422 @@
export const metadata = { title: "@json-render/react-pdf API" }
# @json-render/react-pdf
PDF document renderer. Turn JSON specs into PDFs using `@react-pdf/renderer`.
## Install
```bash
npm install @json-render/core @json-render/react-pdf
```
See the [React PDF example](https://github.com/vercel-labs/json-render/tree/main/examples/react-pdf) for a full working example.
## schema
The PDF element schema for document specs. Use with `defineCatalog` from core.
```typescript
import { defineCatalog } from '@json-render/core';
import { schema, standardComponentDefinitions } from '@json-render/react-pdf';
const catalog = defineCatalog(schema, {
components: standardComponentDefinitions,
});
```
## Render Functions
Server-side functions for producing PDF output. All accept a spec and optional `RenderOptions`.
```typescript
import { renderToBuffer, renderToStream, renderToFile } from '@json-render/react-pdf';
const buffer = await renderToBuffer(spec);
const stream = await renderToStream(spec);
stream.pipe(res);
await renderToFile(spec, './output.pdf');
```
### RenderOptions
```typescript
interface RenderOptions {
registry?: ComponentRegistry;
includeStandard?: boolean; // default: true
state?: Record<string, unknown>;
}
```
<table>
<thead>
<tr>
<th>Option</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>registry</code></td>
<td>Custom component map (merged with standard components)</td>
</tr>
<tr>
<td><code>includeStandard</code></td>
<td>Include built-in standard components (default: <code>true</code>)</td>
</tr>
<tr>
<td><code>state</code></td>
<td>Initial state for <code>$state</code> / <code>$cond</code> dynamic prop resolution</td>
</tr>
</tbody>
</table>
## defineRegistry
Create a type-safe component registry from a catalog. Components receive `{ props, children, emit, bindings, loading }`.
```tsx
import { defineRegistry } from '@json-render/react-pdf';
import { View, Text } from '@react-pdf/renderer';
const { registry } = defineRegistry(catalog, {
components: {
Badge: ({ props }) => (
<View style={{ backgroundColor: props.color ?? '#e5e7eb', padding: 4, borderRadius: 4 }}>
<Text style={{ fontSize: 10 }}>{props.label}</Text>
</View>
),
},
});
const buffer = await renderToBuffer(spec, { registry });
```
## createRenderer
Create a standalone renderer component wired to state, actions, and validation.
```typescript
import { createRenderer } from '@json-render/react-pdf';
const PDFRenderer = createRenderer(catalog, components);
```
```typescript
interface CreateRendererProps {
spec: Spec | null;
state?: Record<string, unknown>;
onAction?: (actionName: string, params?: Record<string, unknown>) => void;
onStateChange?: (path: string, value: unknown) => void;
loading?: boolean;
fallback?: ComponentRenderer;
}
```
## Renderer
The main component that renders a spec to `@react-pdf/renderer` elements.
```typescript
interface RendererProps {
spec: Spec | null;
registry?: ComponentRegistry;
includeStandard?: boolean; // default: true
loading?: boolean;
fallback?: ComponentRenderer;
}
```
## Standard Components
### Document Structure
#### Document
Top-level PDF wrapper. Must be the root element. Children must be `Page` components.
```typescript
{
title: string | null;
author: string | null;
subject: string | null;
}
```
#### Page
A page in the document with configurable size, orientation, and margins.
```typescript
{
size: "A4" | "A3" | "A5" | "LETTER" | "LEGAL" | "TABLOID" | null;
orientation: "portrait" | "landscape" | null;
marginTop: number | null;
marginBottom: number | null;
marginLeft: number | null;
marginRight: number | null;
backgroundColor: string | null;
}
```
### Layout
#### View
Generic container with padding, margin, background, border, and flex alignment.
```typescript
{
padding: number | null;
paddingTop: number | null;
paddingBottom: number | null;
paddingLeft: number | null;
paddingRight: number | null;
margin: number | null;
backgroundColor: string | null;
borderWidth: number | null;
borderColor: string | null;
borderRadius: number | null;
flex: number | null;
alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
}
```
#### Row
Horizontal flex layout with optional wrapping.
```typescript
{
gap: number | null;
alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
padding: number | null;
flex: number | null;
wrap: boolean | null;
}
```
#### Column
Vertical flex layout.
```typescript
{
gap: number | null;
alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
padding: number | null;
flex: number | null;
}
```
### Content
#### Heading
h1-h4 heading text with configurable color and alignment.
```typescript
{
text: string;
level: "h1" | "h2" | "h3" | "h4" | null;
color: string | null;
align: "left" | "center" | "right" | null;
}
```
#### Text
Body text with full styling control.
```typescript
{
text: string;
fontSize: number | null;
color: string | null;
align: "left" | "center" | "right" | null;
fontWeight: "normal" | "bold" | null;
fontStyle: "normal" | "italic" | null;
lineHeight: number | null;
}
```
#### Image
Image from a URL with optional dimensions and fit.
```typescript
{
src: string;
width: number | null;
height: number | null;
objectFit: "contain" | "cover" | "fill" | "none" | null;
}
```
#### Link
Hyperlink with visible text.
```typescript
{
text: string;
href: string;
fontSize: number | null;
color: string | null;
}
```
### Data
#### Table
Data table with typed columns and string rows. Supports header styling and striped rows.
```typescript
{
columns: { header: string; width?: string; align?: "left" | "center" | "right" }[];
rows: string[][];
headerBackgroundColor: string | null;
headerTextColor: string | null;
borderColor: string | null;
fontSize: number | null;
striped: boolean | null;
}
```
#### List
Ordered or unordered list.
```typescript
{
items: string[];
ordered: boolean | null;
fontSize: number | null;
color: string | null;
spacing: number | null;
}
```
### Decorative
#### Divider
Horizontal line separator.
```typescript
{
color: string | null;
thickness: number | null;
marginTop: number | null;
marginBottom: number | null;
}
```
#### Spacer
Empty vertical space.
```typescript
{
height: number | null;
}
```
### Page-Level
#### PageNumber
Renders current page number and total pages. Format uses `{pageNumber}` and `{totalPages}` placeholders.
```typescript
{
format: string | null; // default: "{pageNumber} / {totalPages}"
fontSize: number | null;
color: string | null;
align: "left" | "center" | "right" | null;
}
```
## Server-Safe Import
Import schema and catalog definitions without pulling in React or `@react-pdf/renderer`:
```typescript
import { schema, standardComponentDefinitions } from '@json-render/react-pdf/server';
```
## Sub-path Exports
<table>
<thead>
<tr>
<th>Export</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>@json-render/react-pdf</code></td>
<td>Full package: schema, renderer, components, render functions</td>
</tr>
<tr>
<td><code>@json-render/react-pdf/server</code></td>
<td>Schema and catalog definitions only (no React)</td>
</tr>
<tr>
<td><code>@json-render/react-pdf/catalog</code></td>
<td>Standard component definitions and types</td>
</tr>
<tr>
<td><code>@json-render/react-pdf/render</code></td>
<td>Server-side render functions only</td>
</tr>
</tbody>
</table>
## Types
<table>
<thead>
<tr>
<th>Export</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>ReactPdfSchema</code></td>
<td>Schema type for PDF specs</td>
</tr>
<tr>
<td><code>ReactPdfSpec</code></td>
<td>Spec type for PDF documents</td>
</tr>
<tr>
<td><code>RenderOptions</code></td>
<td>Options for render functions</td>
</tr>
<tr>
<td><code>ComponentContext</code></td>
<td>Typed component render function context</td>
</tr>
<tr>
<td><code>ComponentFn</code></td>
<td>Component render function type</td>
</tr>
<tr>
<td><code>StandardComponentDefinitions</code></td>
<td>Type of the standard component definitions object</td>
</tr>
<tr>
<td><code>StandardComponentProps&lt;K&gt;</code></td>
<td>Inferred props type for a standard component by name</td>
</tr>
</tbody>
</table>
@@ -4,6 +4,68 @@ export const metadata = { title: "Changelog" }
Notable changes and updates to json-render. 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 ## v0.7.0
February 2026 February 2026
+15 -4
View File
@@ -154,23 +154,34 @@ button {
margin-bottom: 0.5em; margin-bottom: 0.5em;
} }
/* MDX table styles — fallback for GFM-generated tables */ /* MDX table styles — applies to both GFM pipe tables and raw HTML tables */
.mdx-table th, .mdx-table th,
.mdx-table td { .mdx-table td,
article table th,
article table td {
border: 1px solid var(--border); border: 1px solid var(--border);
padding: 0.75rem 1rem; padding: 0.75rem 1rem;
text-align: left; text-align: left;
} }
.mdx-table th { .mdx-table th,
article table th {
font-weight: 600; font-weight: 600;
background-color: var(--muted); background-color: var(--muted);
} }
.mdx-table td { .mdx-table td,
article table td {
color: var(--muted-foreground); color: var(--muted-foreground);
} }
article table {
width: 100%;
font-size: 0.875rem;
border-collapse: collapse;
margin: 1.5rem 0;
}
/* Shiki dual theme support */ /* Shiki dual theme support */
.shiki, .shiki,
.shiki span { .shiki span {
+6
View File
@@ -57,6 +57,11 @@ export const docsNavigation: NavSection[] = [
href: "https://github.com/vercel-labs/json-render/tree/main/examples/react-native", href: "https://github.com/vercel-labs/json-render/tree/main/examples/react-native",
external: true, external: true,
}, },
{
title: "React PDF",
href: "https://github.com/vercel-labs/json-render/tree/main/examples/react-pdf",
external: true,
},
{ {
title: "Remotion", title: "Remotion",
href: "https://github.com/vercel-labs/json-render/tree/main/examples/remotion", href: "https://github.com/vercel-labs/json-render/tree/main/examples/remotion",
@@ -86,6 +91,7 @@ export const docsNavigation: NavSection[] = [
items: [ items: [
{ title: "@json-render/core", href: "/docs/api/core" }, { title: "@json-render/core", href: "/docs/api/core" },
{ title: "@json-render/react", href: "/docs/api/react" }, { title: "@json-render/react", href: "/docs/api/react" },
{ title: "@json-render/react-pdf", href: "/docs/api/react-pdf" },
{ title: "@json-render/shadcn", href: "/docs/api/shadcn" }, { title: "@json-render/shadcn", href: "/docs/api/shadcn" },
{ title: "@json-render/react-native", href: "/docs/api/react-native" }, { title: "@json-render/react-native", href: "/docs/api/react-native" },
{ title: "@json-render/remotion", href: "/docs/api/remotion" }, { title: "@json-render/remotion", href: "/docs/api/remotion" },
+1
View File
@@ -38,6 +38,7 @@ export const PAGE_TITLES: Record<string, string> = {
// API references // API references
"docs/api/core": "@json-render/core API", "docs/api/core": "@json-render/core API",
"docs/api/react": "@json-render/react API", "docs/api/react": "@json-render/react API",
"docs/api/react-pdf": "@json-render/react-pdf API",
"docs/api/react-native": "@json-render/react-native API", "docs/api/react-native": "@json-render/react-native API",
"docs/api/codegen": "@json-render/codegen API", "docs/api/codegen": "@json-render/codegen API",
"docs/api/remotion": "@json-render/remotion API", "docs/api/remotion": "@json-render/remotion API",
+7
View File
@@ -1,5 +1,12 @@
# @json-render/codegen # @json-render/codegen
## 0.8.0
### Patch Changes
- Updated dependencies [09376db]
- @json-render/core@0.8.0
## 0.7.0 ## 0.7.0
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@json-render/codegen", "name": "@json-render/codegen",
"version": "0.7.0", "version": "0.8.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "Utilities for generating code from json-render UI trees", "description": "Utilities for generating code from json-render UI trees",
"keywords": [ "keywords": [
+27
View File
@@ -1,5 +1,32 @@
# @json-render/core # @json-render/core
## 0.8.0
### Minor Changes
- 09376db: New `@json-render/react-pdf` package for generating PDF documents from JSON specs.
### New: `@json-render/react-pdf`
PDF renderer for json-render, powered by `@react-pdf/renderer`. Define catalogs and registries the same way as `@json-render/react`, but output PDF documents instead of web UI.
- `renderToBuffer(spec)` — render a spec 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 on disk
- `defineRegistry` / `createRenderer` — same API as `@json-render/react` for custom components
- `standardComponentDefinitions` — Zod-based catalog definitions (server-safe via `@json-render/react-pdf/catalog`)
- `standardComponents` — React PDF implementations for all standard components
- Server-safe import via `@json-render/react-pdf/server`
Standard components:
- **Document structure**: Document, Page
- **Layout**: View, Row, Column
- **Content**: Heading, Text, Image, Link
- **Data**: Table, List
- **Decorative**: Divider, Spacer
- **Page-level**: PageNumber
Includes full context support: state management, visibility conditions, actions, validation, and repeat scopes — matching the capabilities of `@json-render/react`.
## 0.7.0 ## 0.7.0
### Minor Changes ### Minor Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@json-render/core", "name": "@json-render/core",
"version": "0.7.0", "version": "0.8.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "JSON becomes real things. Define your catalog, register your components, let AI generate.", "description": "JSON becomes real things. Define your catalog, register your components, let AI generate.",
"keywords": [ "keywords": [
+7
View File
@@ -1,5 +1,12 @@
# @json-render/react-native # @json-render/react-native
## 0.8.0
### Patch Changes
- Updated dependencies [09376db]
- @json-render/core@0.8.0
## 0.7.0 ## 0.7.0
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@json-render/react-native", "name": "@json-render/react-native",
"version": "0.7.0", "version": "0.8.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "React Native renderer for @json-render/core. JSON becomes React Native components.", "description": "React Native renderer for @json-render/core. JSON becomes React Native components.",
"keywords": [ "keywords": [
+33
View File
@@ -0,0 +1,33 @@
# @json-render/react-pdf
## 0.8.0
### Minor Changes
- 09376db: New `@json-render/react-pdf` package for generating PDF documents from JSON specs.
### New: `@json-render/react-pdf`
PDF renderer for json-render, powered by `@react-pdf/renderer`. Define catalogs and registries the same way as `@json-render/react`, but output PDF documents instead of web UI.
- `renderToBuffer(spec)` — render a spec 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 on disk
- `defineRegistry` / `createRenderer` — same API as `@json-render/react` for custom components
- `standardComponentDefinitions` — Zod-based catalog definitions (server-safe via `@json-render/react-pdf/catalog`)
- `standardComponents` — React PDF implementations for all standard components
- Server-safe import via `@json-render/react-pdf/server`
Standard components:
- **Document structure**: Document, Page
- **Layout**: View, Row, Column
- **Content**: Heading, Text, Image, Link
- **Data**: Table, List
- **Decorative**: Divider, Spacer
- **Page-level**: PageNumber
Includes full context support: state management, visibility conditions, actions, validation, and repeat scopes — matching the capabilities of `@json-render/react`.
### Patch Changes
- Updated dependencies [09376db]
- @json-render/core@0.8.0
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@json-render/react-pdf", "name": "@json-render/react-pdf",
"version": "0.7.0", "version": "0.8.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "React PDF renderer for @json-render/core. JSON becomes PDF documents.", "description": "React PDF renderer for @json-render/core. JSON becomes PDF documents.",
"keywords": [ "keywords": [
+7
View File
@@ -1,5 +1,12 @@
# @json-render/react # @json-render/react
## 0.8.0
### Patch Changes
- Updated dependencies [09376db]
- @json-render/core@0.8.0
## 0.7.0 ## 0.7.0
### Minor Changes ### Minor Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@json-render/react", "name": "@json-render/react",
"version": "0.7.0", "version": "0.8.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "React renderer for @json-render/core. JSON becomes React components.", "description": "React renderer for @json-render/core. JSON becomes React components.",
"keywords": [ "keywords": [
+7
View File
@@ -1,5 +1,12 @@
# @json-render/remotion # @json-render/remotion
## 0.8.0
### Patch Changes
- Updated dependencies [09376db]
- @json-render/core@0.8.0
## 0.7.0 ## 0.7.0
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@json-render/remotion", "name": "@json-render/remotion",
"version": "0.7.0", "version": "0.8.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "Remotion renderer for @json-render/core. JSON becomes video compositions.", "description": "Remotion renderer for @json-render/core. JSON becomes video compositions.",
"keywords": [ "keywords": [
+8
View File
@@ -1,5 +1,13 @@
# @json-render/shadcn # @json-render/shadcn
## 0.8.0
### Patch Changes
- Updated dependencies [09376db]
- @json-render/core@0.8.0
- @json-render/react@0.8.0
## 0.7.0 ## 0.7.0
### Minor Changes ### Minor Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@json-render/shadcn", "name": "@json-render/shadcn",
"version": "0.7.0", "version": "0.8.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "shadcn/ui component library for @json-render/core. JSON becomes beautiful Tailwind-styled React components.", "description": "shadcn/ui component library for @json-render/core. JSON becomes beautiful Tailwind-styled React components.",
"keywords": [ "keywords": [