takumi-pdf 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,21 @@
1
+ <div align="center">
2
+ <img src="https://takumi.kane.tw/logo.svg" alt="Takumi" width="64" />
3
+
1
4
  # takumi-pdf
2
5
 
3
- Render JSX to paged PDF in WebAssembly. No Chromium or native binary.
6
+ **Render JSX to paged, selectable-text PDF. WebAssembly, no Chromium.**
7
+
8
+ Invoices, reports, and receipts from the Takumi renderer, with CSS layout and vector PDF output.
9
+
10
+ [Documentation](https://takumi.kane.tw/docs/) · [Playground](https://takumi.kane.tw/playground)
11
+
12
+ </div>
13
+
14
+ ## Why
15
+
16
+ Browser-based PDF generation brings the Chromium serverless tax: browser cold starts, browser memory, a large browser binary, and headless-browser work before a document can render. It is a capable screenshot pipeline, but it is still a browser.
17
+
18
+ `takumi-pdf` uses Takumi's own layout and PDF rendering primitives, compiled to WebAssembly. There is no browser process. Render JSX or a Takumi node tree with CSS and Tailwind classes, then receive vector PDF bytes with selectable, searchable text and embedded subset fonts.
4
19
 
5
20
  ## Install
6
21
 
@@ -13,17 +28,33 @@ bun add takumi-pdf
13
28
  ## Quick start
14
29
 
15
30
  ```tsx
16
- import { render } from "takumi-pdf";
17
31
  import { writeFile } from "node:fs/promises";
32
+ import { googleFonts } from "@takumi-rs/helpers";
33
+ import { render } from "takumi-pdf";
18
34
 
19
- const pdf = await render(<h1>Invoice #1042</h1>);
35
+ const pdf = await render(
36
+ <main tw="flex flex-col gap-4">
37
+ <h1 tw="text-2xl font-bold">Invoice INV-2026-001</h1>
38
+ <div tw="flex justify-between border-t border-gray-200 pt-2 font-bold">
39
+ <span>Total</span>
40
+ <span>$1,250.00</span>
41
+ </div>
42
+ </main>,
43
+ {
44
+ size: "a4",
45
+ fonts: await googleFonts(["Inter"]),
46
+ footer: (
47
+ <div tw="flex w-full justify-center text-[10px] text-gray-500">
48
+ Page <span className="pageNumber" /> of <span className="totalPages" />
49
+ </div>
50
+ ),
51
+ },
52
+ );
20
53
 
21
54
  await writeFile("invoice.pdf", pdf);
22
55
  ```
23
56
 
24
- `render()` returns `Uint8Array` PDF bytes. Output is paged A4 with a 48px margin by default; content flows onto as many pages as it needs. Text stays selectable and searchable, with fonts subset and embedded.
25
-
26
- See the [Takumi documentation](https://takumi.kane.tw/docs/) for the shared node and JSX model.
57
+ `render()` returns `Promise<Uint8Array>`. Paged output defaults to A4 with a uniform 48px margin; content flows across as many pages as it needs.
27
58
 
28
59
  ## Page setup
29
60
 
@@ -43,7 +74,7 @@ const pdf = await render(report, {
43
74
 
44
75
  ## Headers and footers
45
76
 
46
- Headers and footers repeat on every page. Elements with `pageNumber` or `totalPages` in their class list receive the counter as text, the same contract as Chromium print templates.
77
+ Headers and footers repeat on every page. Elements whose class list includes `pageNumber` or `totalPages` receive the counter as text.
47
78
 
48
79
  ```tsx
49
80
  const pdf = await render(report, {
@@ -94,15 +125,14 @@ const pdf = await render(receipt, { viewport: { width: 302 } });
94
125
 
95
126
  ## Fonts
96
127
 
97
- Pass a font URL or font bytes. Registered fonts are deduplicated across calls.
128
+ Pass a font URL, font bytes, or the `googleFonts` helper. Registered fonts are deduplicated across calls.
98
129
 
99
130
  ```tsx
131
+ import { googleFonts } from "@takumi-rs/helpers";
132
+
100
133
  const pdf = await render(doc, {
101
- fonts: [
102
- "https://example.com/Inter-Regular.woff2",
103
- { name: "Brand Sans", weight: 700, data: fontBytes },
104
- ],
105
- fontFamilies: ["Brand Sans", "sans-serif"],
134
+ fonts: [...(await googleFonts(["Inter"])), { name: "Brand Sans", weight: 700, data: fontBytes }],
135
+ fontFamilies: ["Brand Sans", "Inter", "sans-serif"],
106
136
  });
107
137
  ```
108
138
 
@@ -115,6 +145,7 @@ const renderer = new PdfRenderer();
115
145
  await renderer.registerFont("https://example.com/Inter-Regular.woff2");
116
146
 
117
147
  const pdf = await renderer.render(doc);
148
+ renderer.free();
118
149
  ```
119
150
 
120
151
  ## Pagination CSS
@@ -148,3 +179,7 @@ const pdf = await render(doc, {
148
179
  ```
149
180
 
150
181
  `@page` CSS rules are not supported. Set page geometry with `size`, `landscape`, and `margin`.
182
+
183
+ ## License
184
+
185
+ MIT or Apache-2.0
package/dist/export.d.cts CHANGED
@@ -104,6 +104,19 @@ type ViewportOptions = {
104
104
  header?: never;
105
105
  footer?: never;
106
106
  };
107
+ /** Document metadata written to the PDF's info dictionary. */
108
+ type PdfMetadata = {
109
+ /** The document title. */
110
+ title?: string;
111
+ /** The document description (the info dictionary's subject). */
112
+ description?: string;
113
+ /** The document authors. */
114
+ authors?: string[];
115
+ /** The document keywords. */
116
+ keywords?: string[];
117
+ /** The tool that created the source document. */
118
+ creator?: string;
119
+ };
107
120
  type RenderOptions = (PagedOptions | ViewportOptions) & {
108
121
  /** Fonts to register before rendering, deduped across calls. */
109
122
  fonts?: FontLoader$1[];
@@ -118,6 +131,10 @@ type RenderOptions = (PagedOptions | ViewportOptions) & {
118
131
  fontFamilies?: string[];
119
132
  /** Default BCP-47 language tag applied to the root. */
120
133
  lang?: string;
134
+ /** Document metadata; `lang` doubles as the metadata language. */
135
+ metadata?: PdfMetadata;
136
+ /** Generates a PDF outline (bookmarks) from `h1`–`h6` headings. */
137
+ outline?: boolean;
121
138
  };
122
139
  /** A PDF renderer holding registered fonts. Reuse one instance across renders. */
123
140
  declare class PdfRenderer {
@@ -133,4 +150,4 @@ declare class PdfRenderer {
133
150
  /** Renders with a lazily created shared {@link PdfRenderer}. */
134
151
  declare function render(node: NodeInput, options?: RenderOptions): Promise<Uint8Array>;
135
152
  //#endregion
136
- export { Dimensions, type FontLoader, type ImagesInput, NodeInput, PageMargin, PageSize, PdfRenderer, RenderOptions, ViewportInput, __wbg_init as default, initSync, render };
153
+ export { Dimensions, type FontLoader, type ImagesInput, NodeInput, PageMargin, PageSize, PdfMetadata, PdfRenderer, RenderOptions, ViewportInput, __wbg_init as default, initSync, render };
package/dist/export.d.mts CHANGED
@@ -104,6 +104,19 @@ type ViewportOptions = {
104
104
  header?: never;
105
105
  footer?: never;
106
106
  };
107
+ /** Document metadata written to the PDF's info dictionary. */
108
+ type PdfMetadata = {
109
+ /** The document title. */
110
+ title?: string;
111
+ /** The document description (the info dictionary's subject). */
112
+ description?: string;
113
+ /** The document authors. */
114
+ authors?: string[];
115
+ /** The document keywords. */
116
+ keywords?: string[];
117
+ /** The tool that created the source document. */
118
+ creator?: string;
119
+ };
107
120
  type RenderOptions = (PagedOptions | ViewportOptions) & {
108
121
  /** Fonts to register before rendering, deduped across calls. */
109
122
  fonts?: FontLoader$1[];
@@ -118,6 +131,10 @@ type RenderOptions = (PagedOptions | ViewportOptions) & {
118
131
  fontFamilies?: string[];
119
132
  /** Default BCP-47 language tag applied to the root. */
120
133
  lang?: string;
134
+ /** Document metadata; `lang` doubles as the metadata language. */
135
+ metadata?: PdfMetadata;
136
+ /** Generates a PDF outline (bookmarks) from `h1`–`h6` headings. */
137
+ outline?: boolean;
121
138
  };
122
139
  /** A PDF renderer holding registered fonts. Reuse one instance across renders. */
123
140
  declare class PdfRenderer {
@@ -133,4 +150,4 @@ declare class PdfRenderer {
133
150
  /** Renders with a lazily created shared {@link PdfRenderer}. */
134
151
  declare function render(node: NodeInput, options?: RenderOptions): Promise<Uint8Array>;
135
152
  //#endregion
136
- export { Dimensions, type FontLoader, type ImagesInput, NodeInput, PageMargin, PageSize, PdfRenderer, RenderOptions, ViewportInput, __wbg_init as default, initSync, render };
153
+ export { Dimensions, type FontLoader, type ImagesInput, NodeInput, PageMargin, PageSize, PdfMetadata, PdfRenderer, RenderOptions, ViewportInput, __wbg_init as default, initSync, render };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "takumi-pdf",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "HTML/JSX to paged, selectable-text PDF, powered by takumi. WebAssembly, no Chromium.",
5
5
  "keywords": [
6
6
  "css",
@@ -83,7 +83,7 @@
83
83
  "publish-lint": "attw --pack . && publint --strict ."
84
84
  },
85
85
  "dependencies": {
86
- "@takumi-rs/helpers": "2.5.6"
86
+ "@takumi-rs/helpers": "2.5.7"
87
87
  },
88
88
  "devDependencies": {
89
89
  "@types/bun": "^1.3.14",
Binary file