|
|
@@ -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<K></code></td>
|
|
|
+ <td>Inferred props type for a standard component by name</td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+</table>
|