page.mdx 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. import { pageMetadata } from "@/lib/page-metadata"
  2. export const metadata = pageMetadata("docs/api/react-pdf")
  3. # @json-render/react-pdf
  4. PDF document renderer. Turn JSON specs into PDFs using `@react-pdf/renderer`.
  5. ## Install
  6. ```bash
  7. npm install @json-render/core @json-render/react-pdf
  8. ```
  9. See the [React PDF example](https://github.com/vercel-labs/json-render/tree/main/examples/react-pdf) for a full working example.
  10. ## schema
  11. The PDF element schema for document specs. Use with `defineCatalog` from core.
  12. ```typescript
  13. import { defineCatalog } from '@json-render/core';
  14. import { schema, standardComponentDefinitions } from '@json-render/react-pdf';
  15. const catalog = defineCatalog(schema, {
  16. components: standardComponentDefinitions,
  17. });
  18. ```
  19. ## Render Functions
  20. Server-side functions for producing PDF output. All accept a spec and optional `RenderOptions`.
  21. ```typescript
  22. import { renderToBuffer, renderToStream, renderToFile } from '@json-render/react-pdf';
  23. const buffer = await renderToBuffer(spec);
  24. const stream = await renderToStream(spec);
  25. stream.pipe(res);
  26. await renderToFile(spec, './output.pdf');
  27. ```
  28. ### RenderOptions
  29. ```typescript
  30. interface RenderOptions {
  31. registry?: ComponentRegistry;
  32. includeStandard?: boolean; // default: true
  33. state?: Record<string, unknown>;
  34. }
  35. ```
  36. <table>
  37. <thead>
  38. <tr>
  39. <th>Option</th>
  40. <th>Description</th>
  41. </tr>
  42. </thead>
  43. <tbody>
  44. <tr>
  45. <td><code>registry</code></td>
  46. <td>Custom component map (merged with standard components)</td>
  47. </tr>
  48. <tr>
  49. <td><code>includeStandard</code></td>
  50. <td>Include built-in standard components (default: <code>true</code>)</td>
  51. </tr>
  52. <tr>
  53. <td><code>state</code></td>
  54. <td>Initial state for <code>$state</code> / <code>$cond</code> dynamic prop resolution</td>
  55. </tr>
  56. </tbody>
  57. </table>
  58. ## defineRegistry
  59. Create a type-safe component registry from a catalog. Components receive `{ props, children, emit, bindings, loading }`.
  60. ```tsx
  61. import { defineRegistry } from '@json-render/react-pdf';
  62. import { View, Text } from '@react-pdf/renderer';
  63. const { registry } = defineRegistry(catalog, {
  64. components: {
  65. Badge: ({ props }) => (
  66. <View style={{ backgroundColor: props.color ?? '#e5e7eb', padding: 4, borderRadius: 4 }}>
  67. <Text style={{ fontSize: 10 }}>{props.label}</Text>
  68. </View>
  69. ),
  70. },
  71. });
  72. const buffer = await renderToBuffer(spec, { registry });
  73. ```
  74. ## createRenderer
  75. Create a standalone renderer component wired to state, actions, and validation.
  76. ```typescript
  77. import { createRenderer } from '@json-render/react-pdf';
  78. const PDFRenderer = createRenderer(catalog, components);
  79. ```
  80. ```typescript
  81. interface CreateRendererProps {
  82. spec: Spec | null;
  83. store?: StateStore;
  84. state?: Record<string, unknown>;
  85. onAction?: (actionName: string, params?: Record<string, unknown>) => void;
  86. onStateChange?: (changes: Array<{ path: string; value: unknown }>) => void;
  87. loading?: boolean;
  88. fallback?: ComponentRenderer;
  89. }
  90. ```
  91. When `store` is provided, `state` and `onStateChange` are ignored (controlled mode).
  92. ## Renderer
  93. The main component that renders a spec to `@react-pdf/renderer` elements.
  94. ```typescript
  95. interface RendererProps {
  96. spec: Spec | null;
  97. registry?: ComponentRegistry;
  98. includeStandard?: boolean; // default: true
  99. loading?: boolean;
  100. fallback?: ComponentRenderer;
  101. }
  102. ```
  103. ## Standard Components
  104. ### Document Structure
  105. #### Document
  106. Top-level PDF wrapper. Must be the root element. Children must be `Page` components.
  107. ```typescript
  108. {
  109. title: string | null;
  110. author: string | null;
  111. subject: string | null;
  112. }
  113. ```
  114. #### Page
  115. A page in the document with configurable size, orientation, and margins.
  116. ```typescript
  117. {
  118. size: "A4" | "A3" | "A5" | "LETTER" | "LEGAL" | "TABLOID" | null;
  119. orientation: "portrait" | "landscape" | null;
  120. marginTop: number | null;
  121. marginBottom: number | null;
  122. marginLeft: number | null;
  123. marginRight: number | null;
  124. backgroundColor: string | null;
  125. }
  126. ```
  127. ### Layout
  128. #### View
  129. Generic container with padding, margin, background, border, and flex alignment.
  130. ```typescript
  131. {
  132. padding: number | null;
  133. paddingTop: number | null;
  134. paddingBottom: number | null;
  135. paddingLeft: number | null;
  136. paddingRight: number | null;
  137. margin: number | null;
  138. backgroundColor: string | null;
  139. borderWidth: number | null;
  140. borderColor: string | null;
  141. borderRadius: number | null;
  142. flex: number | null;
  143. alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
  144. justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
  145. }
  146. ```
  147. #### Row
  148. Horizontal flex layout with optional wrapping.
  149. ```typescript
  150. {
  151. gap: number | null;
  152. alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
  153. justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
  154. padding: number | null;
  155. flex: number | null;
  156. wrap: boolean | null;
  157. }
  158. ```
  159. #### Column
  160. Vertical flex layout.
  161. ```typescript
  162. {
  163. gap: number | null;
  164. alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
  165. justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
  166. padding: number | null;
  167. flex: number | null;
  168. }
  169. ```
  170. ### Content
  171. #### Heading
  172. h1-h4 heading text with configurable color and alignment.
  173. ```typescript
  174. {
  175. text: string;
  176. level: "h1" | "h2" | "h3" | "h4" | null;
  177. color: string | null;
  178. align: "left" | "center" | "right" | null;
  179. }
  180. ```
  181. #### Text
  182. Body text with full styling control.
  183. ```typescript
  184. {
  185. text: string;
  186. fontSize: number | null;
  187. color: string | null;
  188. align: "left" | "center" | "right" | null;
  189. fontWeight: "normal" | "bold" | null;
  190. fontStyle: "normal" | "italic" | null;
  191. lineHeight: number | null;
  192. }
  193. ```
  194. #### Image
  195. Image from a URL with optional dimensions and fit.
  196. ```typescript
  197. {
  198. src: string;
  199. width: number | null;
  200. height: number | null;
  201. objectFit: "contain" | "cover" | "fill" | "none" | null;
  202. }
  203. ```
  204. #### Link
  205. Hyperlink with visible text.
  206. ```typescript
  207. {
  208. text: string;
  209. href: string;
  210. fontSize: number | null;
  211. color: string | null;
  212. }
  213. ```
  214. ### Data
  215. #### Table
  216. Data table with typed columns and string rows. Supports header styling and striped rows.
  217. ```typescript
  218. {
  219. columns: { header: string; width?: string; align?: "left" | "center" | "right" }[];
  220. rows: string[][];
  221. headerBackgroundColor: string | null;
  222. headerTextColor: string | null;
  223. borderColor: string | null;
  224. fontSize: number | null;
  225. striped: boolean | null;
  226. }
  227. ```
  228. #### List
  229. Ordered or unordered list.
  230. ```typescript
  231. {
  232. items: string[];
  233. ordered: boolean | null;
  234. fontSize: number | null;
  235. color: string | null;
  236. spacing: number | null;
  237. }
  238. ```
  239. ### Decorative
  240. #### Divider
  241. Horizontal line separator.
  242. ```typescript
  243. {
  244. color: string | null;
  245. thickness: number | null;
  246. marginTop: number | null;
  247. marginBottom: number | null;
  248. }
  249. ```
  250. #### Spacer
  251. Empty vertical space.
  252. ```typescript
  253. {
  254. height: number | null;
  255. }
  256. ```
  257. ### Page-Level
  258. #### PageNumber
  259. Renders current page number and total pages. Format uses `{pageNumber}` and `{totalPages}` placeholders.
  260. ```typescript
  261. {
  262. format: string | null; // default: "{pageNumber} / {totalPages}"
  263. fontSize: number | null;
  264. color: string | null;
  265. align: "left" | "center" | "right" | null;
  266. }
  267. ```
  268. ## External Store (Controlled Mode)
  269. Pass a `StateStore` to `StateProvider`, `JSONUIProvider`, or `createRenderer` for full control over state:
  270. ```tsx
  271. import { createStateStore, type StateStore } from "@json-render/react-pdf";
  272. const store = createStateStore({ invoice: { total: 100 } });
  273. store.set("/invoice/total", 200);
  274. ```
  275. When `store` is provided, `initialState` / `state` and `onStateChange` are ignored.
  276. ## Server-Safe Import
  277. Import schema and catalog definitions without pulling in React or `@react-pdf/renderer`:
  278. ```typescript
  279. import { schema, standardComponentDefinitions } from '@json-render/react-pdf/server';
  280. ```
  281. ## Sub-path Exports
  282. <table>
  283. <thead>
  284. <tr>
  285. <th>Export</th>
  286. <th>Description</th>
  287. </tr>
  288. </thead>
  289. <tbody>
  290. <tr>
  291. <td><code>@json-render/react-pdf</code></td>
  292. <td>Full package: schema, renderer, components, render functions</td>
  293. </tr>
  294. <tr>
  295. <td><code>@json-render/react-pdf/server</code></td>
  296. <td>Schema and catalog definitions only (no React)</td>
  297. </tr>
  298. <tr>
  299. <td><code>@json-render/react-pdf/catalog</code></td>
  300. <td>Standard component definitions and types</td>
  301. </tr>
  302. <tr>
  303. <td><code>@json-render/react-pdf/render</code></td>
  304. <td>Server-side render functions only</td>
  305. </tr>
  306. </tbody>
  307. </table>
  308. ## Types
  309. <table>
  310. <thead>
  311. <tr>
  312. <th>Export</th>
  313. <th>Description</th>
  314. </tr>
  315. </thead>
  316. <tbody>
  317. <tr>
  318. <td><code>ReactPdfSchema</code></td>
  319. <td>Schema type for PDF specs</td>
  320. </tr>
  321. <tr>
  322. <td><code>ReactPdfSpec</code></td>
  323. <td>Spec type for PDF documents</td>
  324. </tr>
  325. <tr>
  326. <td><code>RenderOptions</code></td>
  327. <td>Options for render functions</td>
  328. </tr>
  329. <tr>
  330. <td><code>ComponentContext</code></td>
  331. <td>Typed component render function context</td>
  332. </tr>
  333. <tr>
  334. <td><code>ComponentFn</code></td>
  335. <td>Component render function type</td>
  336. </tr>
  337. <tr>
  338. <td><code>StandardComponentDefinitions</code></td>
  339. <td>Type of the standard component definitions object</td>
  340. </tr>
  341. <tr>
  342. <td><code>StandardComponentProps&lt;K&gt;</code></td>
  343. <td>Inferred props type for a standard component by name</td>
  344. </tr>
  345. </tbody>
  346. </table>