weasyprint-tsx 0.0.1 → 0.1.1

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 +1,99 @@
1
-
1
+ # weasyprint-tsx
2
+
3
+ Write PDFs in TSX. Uses [Bun](https://bun.sh) to bundle your Preact components into HTML, then [WeasyPrint](https://weasyprint.org) to render them as PDF.
4
+
5
+ ## Requirements
6
+
7
+ - [Bun](https://bun.sh) ≥ 1.0
8
+ - [WeasyPrint](https://weasyprint.org) — `pip install weasyprint`
9
+
10
+ ## Quick start
11
+
12
+ ```bash
13
+ bunx create-weasyprint-tsx my-doc
14
+ cd my-doc
15
+ bun install
16
+ bun run dev
17
+ ```
18
+
19
+ Open `http://localhost:3000` to preview the document live. The PDF is written to `output.pdf` on every save.
20
+
21
+ ## Scripts
22
+
23
+ | Script | Effect |
24
+ |--------|--------|
25
+ | `bun run dev` | Watch `src/`, rebuild HTML + PDF on change, serve preview at port 3000 |
26
+ | `bun run build` | Build once and write `output.pdf` |
27
+
28
+ ## Project structure
29
+
30
+ ```
31
+ my-doc/
32
+ ├── src/
33
+ │ ├── index.tsx # Document root — must export a default Preact component
34
+ │ └── index.css # Styles — must begin with @import "tailwindcss"
35
+ ├── weasyprint-tsx.config.ts
36
+ └── package.json
37
+ ```
38
+
39
+ `src/index.tsx` must export a default component that renders a **complete HTML document** (`<html>`, `<head>`, `<body>`). WeasyPrint receives the full HTML string.
40
+
41
+ ## Configuration
42
+
43
+ Create or edit `weasyprint-tsx.config.ts` at the project root:
44
+
45
+ ```ts
46
+ import type { Config } from "@weasyprint-tsx/build";
47
+
48
+ const config: Config = {
49
+ io: { output: "report.pdf" },
50
+ weasyprint: { path: "weasyprint", optimize_images: true },
51
+ };
52
+
53
+ export default config;
54
+ ```
55
+
56
+ ### `io`
57
+
58
+ | Field | Default | Description |
59
+ |-------|---------|-------------|
60
+ | `input` | `"src/index.tsx"` | Entry point |
61
+ | `output` | `"output.pdf"` | Output PDF path |
62
+ | `buildDir` | `".build"` | Intermediate HTML directory |
63
+ | `media_type` | `"print"` | CSS media type passed to WeasyPrint |
64
+
65
+ ### `weasyprint`
66
+
67
+ | Field | Default | Description |
68
+ |-------|---------|-------------|
69
+ | `path` | `"weasyprint"` | Path to the WeasyPrint binary |
70
+ | `verbose` | `false` | Print WeasyPrint stdout |
71
+ | `dpi` | — | Output resolution |
72
+ | `optimize_images` | — | Compress images in output |
73
+ | `pdf_forms` | — | Enable PDF form fields |
74
+ | `pdf_variant` | — | `"pdf/a-1b"`, `"pdf/a-2b"`, `"pdf/a-3b"`, `"pdf/a-4b"`, `"pdf/ua-1"` |
75
+ | `cache` | — | WeasyPrint font/image cache folder |
76
+ | `full_fonts` | — | Embed full font files (not just subsets) |
77
+ | `srgb` | — | Force sRGB color profile |
78
+ | `jpeg_quality` | — | JPEG compression quality (0–95) |
79
+
80
+ ### `dev`
81
+
82
+ | Field | Default | Description |
83
+ |-------|---------|-------------|
84
+ | `port` | `3000` | Dev server port |
85
+ | `watch` | `"src"` | Directory to watch for changes |
86
+
87
+ ### `pdf`
88
+
89
+ | Field | Default | Description |
90
+ |-------|---------|-------------|
91
+ | `stylesheets` | `[]` | Additional CSS files passed to WeasyPrint via `--stylesheet` |
92
+
93
+ ## UI components
94
+
95
+ `@weasyprint-tsx/ui` provides print-optimized Preact components. See [`packages/ui/README.md`](packages/ui/README.md) for the full API.
96
+
97
+ ```tsx
98
+ import { H1, H2, Page, UL, LI, Table, Entry } from "@weasyprint-tsx/ui";
99
+ ```
package/ReadMe.pdf CHANGED
Binary file
package/bun.lock CHANGED
@@ -4,10 +4,13 @@
4
4
  "workspaces": {
5
5
  "": {
6
6
  "name": "@weasyprint-tsx/build",
7
+ "dependencies": {
8
+ "@fontsource-variable/public-sans": "^5.2.7",
9
+ },
7
10
  },
8
11
  "packages/build": {
9
12
  "name": "@weasyprint-tsx/build",
10
- "version": "0.0.1",
13
+ "version": "0.1.1",
11
14
  "bin": {
12
15
  "weasyprint-tsx": "./src/cli.ts",
13
16
  },
@@ -24,14 +27,21 @@
24
27
  },
25
28
  "packages/create": {
26
29
  "name": "@weasyprint-tsx/create",
27
- "version": "0.0.1",
30
+ "version": "0.1.0",
28
31
  "bin": {
29
- "create-weasyprint-tsx": "src/cli.ts",
32
+ "create-weasyprint-tsx": "cli.js",
33
+ },
34
+ "dependencies": {
35
+ "highlight.js": "11.11.1",
30
36
  },
31
37
  },
32
38
  "packages/ui": {
33
39
  "name": "@weasyprint-tsx/ui",
34
- "version": "0.0.1",
40
+ "version": "0.1.0",
41
+ "dependencies": {
42
+ "highlight.js": "^11.11.1",
43
+ "katex": "^0.16.47",
44
+ },
35
45
  },
36
46
  },
37
47
  "packages": {
@@ -45,6 +55,8 @@
45
55
 
46
56
  "@csstools/utilities": ["@csstools/utilities@3.0.0", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-etDqA/4jYvOGBM6yfKCOsEXfH96BKztZdgGmGqKi2xHnDe0ILIBraRspwgYatJH9JsCZ5HCGoCst8w18EKOAdg=="],
47
57
 
58
+ "@fontsource-variable/public-sans": ["@fontsource-variable/public-sans@5.2.7", "", {}, "sha512-4mvade2J3slKkvwRkS+p8T3szet/0vhWoSnuUJTVU81Uo2pRpSZY/Y8bSLRqpSwzIPxjVmRJ53oq6JKP/l/PSg=="],
59
+
48
60
  "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
49
61
 
50
62
  "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
@@ -95,14 +107,20 @@
95
107
 
96
108
  "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
97
109
 
110
+ "commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="],
111
+
98
112
  "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
99
113
 
100
114
  "enhanced-resolve": ["enhanced-resolve@5.24.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-SkE2t82KlkkxQRVMVLAGKxLfORGQfrkx5dkj+vlgXRVNEdPc4eZcR+J/Fvj8C+yKSFH5L0q3NFlyufOVQnCcYQ=="],
101
115
 
102
116
  "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
103
117
 
118
+ "highlight.js": ["highlight.js@11.11.1", "", {}, "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w=="],
119
+
104
120
  "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
105
121
 
122
+ "katex": ["katex@0.16.47", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg=="],
123
+
106
124
  "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
107
125
 
108
126
  "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "weasyprint-tsx",
3
- "version": "0.0.1",
3
+ "version": "0.1.1",
4
+ "bin": {
5
+ "create-weasyprint-tsx": "bun packages/create/cli.ts",
6
+ "build-weasyprint-tsx": "bun packages/build/src/cli.ts"
7
+ },
4
8
  "scripts": {
5
9
  "dev": "bun packages/build/src/cli.ts --watch",
6
- "init" : "bun packages/create/cli.ts"
10
+ "init": "bun packages/create/cli.ts",
11
+ "build": "bun packages/build/src/cli.ts"
7
12
  },
8
13
  "workspaces": [
9
14
  "packages/*"
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@weasyprint-tsx/build",
3
- "version": "0.0.1",
3
+ "version": "0.1.1",
4
+ "main": "./src/index.ts",
5
+ "exports": { ".": "./src/index.ts" },
6
+ "types": "./src/index.ts",
4
7
  "bin": {
5
8
  "weasyprint-tsx": "./src/cli.ts"
6
9
  },
7
- "workspaces": [
8
- "packages/*"
9
- ],
10
10
  "devDependencies": {
11
11
  "bun-types": "latest"
12
12
  },
@@ -1,12 +1,12 @@
1
- import { join } from "path";
2
- import { DConfig } from "./config";
1
+ import tailwindcss from "@tailwindcss/postcss";
3
2
  import { BunPlugin } from "bun";
3
+ import { join } from "path";
4
4
  import postcss from "postcss";
5
5
  import customProperties from "postcss-custom-properties";
6
- import tailwindcss from "@tailwindcss/postcss";
7
- import { injectDevScript } from "./server";
8
6
  import { h } from "preact";
9
7
  import { renderToStaticMarkup } from "preact-render-to-string";
8
+ import { DConfig } from "./config";
9
+ import { DEV_SCRIPT } from "./server";
10
10
 
11
11
  const tailwindPlugin: BunPlugin = {
12
12
  name: "tailwind-postcss",
@@ -49,17 +49,17 @@ export async function buildHTML(cfg: DConfig, dev: boolean = false) {
49
49
  join(BUILD_DIR, `index.js?t=${performance.now()}`)
50
50
  );
51
51
 
52
- const html = "<!DOCTYPE html>" + renderToStaticMarkup(h(Document, {}));
53
-
54
- await Bun.write(BUILD_PATH, html);
52
+ let html = "<!DOCTYPE html>" + renderToStaticMarkup(h(Document, {}));
55
53
 
56
54
  if (dev) {
57
- injectDevScript(BUILD_PATH);
55
+ html = html.replace("</html>", `${DEV_SCRIPT}</html>`);
58
56
  }
57
+ await Bun.write(BUILD_PATH, html);
59
58
  process.stdout.write(
60
59
  `Bun HTML build -- ${(performance.now() - t0).toFixed(2)}ms\n`,
61
60
  );
62
- return Bun.hash(html);
61
+ const css = await Bun.file(join(BUILD_DIR, "index.css")).text();
62
+ return Bun.hash(html + css);
63
63
  }
64
64
 
65
65
  function buildArgs(cfg: DConfig): string[] {
@@ -89,7 +89,7 @@ export async function buildPDF(cfg: DConfig): Promise<void> {
89
89
  const t0 = performance.now();
90
90
  const proc = Bun.spawn(args, {
91
91
  cwd: process.cwd(),
92
- stderr: "inherit",
92
+ stderr: cfg.weasyprint.verbose ? "inherit" : "ignore",
93
93
  stdout: cfg.weasyprint.verbose ? "inherit" : "ignore",
94
94
  });
95
95
  const code = await proc.exited;
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env bun
1
2
  import { devMode, buildOnce } from "./orchestrator";
2
3
 
3
4
 
@@ -24,7 +24,7 @@ export interface Config {
24
24
  };
25
25
  dev?: {
26
26
  port?: number;
27
- watch?: string;
27
+ watch?: string[];
28
28
  };
29
29
  }
30
30
 
@@ -44,7 +44,7 @@ const defaultConfig = {
44
44
  },
45
45
  dev: {
46
46
  port: 3000,
47
- watch: "src",
47
+ watch: ["src"],
48
48
  },
49
49
  } satisfies Config;
50
50
 
@@ -80,11 +80,12 @@ export async function loadConfig(): Promise<DConfig> {
80
80
  const configPath = resolve(process.cwd(), "weasyprint-tsx.config.ts");
81
81
  let config = defaultConfig;
82
82
  try {
83
- const {default : userConfig} = await import(`${configPath}`);
83
+ const { default: userConfig } = await import(`${configPath}`);
84
84
  config = mergeDeep(config, userConfig) as unknown as DConfig;
85
- console.log(config , userConfig)
86
85
  } catch (e) {
87
- process.stdout.write(`No config file at ${configPath} found, using default.`);
86
+ process.stdout.write(
87
+ `No config file at ${configPath} found, using default.`,
88
+ );
88
89
  }
89
90
  return config;
90
91
  }
@@ -0,0 +1 @@
1
+ export type { Config, DConfig } from "./config";
@@ -1,8 +1,8 @@
1
1
  import { watch } from "fs";
2
+ import { join } from "path";
2
3
  import { buildHTML, buildPDF } from "./build";
3
4
  import { loadConfig } from "./config";
4
5
  import { bumpPing, startServer } from "./server";
5
- import { join } from "path";
6
6
 
7
7
  export async function buildOnce(output?: string) {
8
8
  const cfg = await loadConfig();
@@ -22,7 +22,7 @@ export async function buildOnce(output?: string) {
22
22
 
23
23
  export async function devMode(output?: string) {
24
24
  const cfg = await loadConfig();
25
- const WATCH_DIR = join(process.cwd(), cfg.dev.watch);
25
+ const WATCH_DIRS = cfg.dev.watch.map((p) => join(process.cwd(), p));
26
26
 
27
27
  if (output) cfg.io.output = cfg.io.output ?? output;
28
28
  process.stdout.write(`Dev: http://localhost:${cfg.dev.port}`);
@@ -52,10 +52,12 @@ export async function devMode(output?: string) {
52
52
 
53
53
  startServer(cfg.dev.port, cfg.io.buildDir);
54
54
 
55
- watch(WATCH_DIR, {}, async (ev, f) => {
56
- process.stdout.write(`${ev} : file changed ${f}`);
57
- await rebuild();
58
- });
55
+ WATCH_DIRS.forEach((dir) =>
56
+ watch(dir, { recursive: true }, async (_, f) => {
57
+ process.stdout.write(`file changed ${f}`);
58
+ await rebuild();
59
+ }),
60
+ );
59
61
 
60
62
  await Bun.sleep(Infinity);
61
63
  }
@@ -1,6 +1,6 @@
1
1
  import { join } from "path";
2
2
 
3
- const DEV_SCRIPT = `<script>var _t=null;setInterval(function(){fetch('/__dev_ping').then(function(r){return r.text();}).then(function(s){if(_t!==null&&s!==_t)location.reload();_t=s;}).catch(function(){});},300);</script>`;
3
+ export const DEV_SCRIPT = `<script>var _t=null;setInterval(function(){fetch('/__dev_ping').then(function(r){return r.text();}).then(function(s){if(_t!==null&&s!==_t)location.reload();_t=s;}).catch(function(){});},1000);</script>`;
4
4
 
5
5
  let pingCounter = 0;
6
6
 
@@ -19,8 +19,9 @@ export function startServer(port: number, buildDir: string): void {
19
19
  headers: { "Cache-Control": "no-store" },
20
20
  });
21
21
  }
22
-
23
- const file = Bun.file(join(process.cwd(), buildDir , "index.html"));
22
+ const pathname = url.pathname === "/" ? "/index.html" : url.pathname;
23
+ if (pathname == "/favicon.ico") return new Response(null);
24
+ const file = Bun.file(join(process.cwd(), buildDir, pathname));
24
25
  return new Response(file);
25
26
  },
26
27
  });
@@ -29,8 +30,6 @@ export function startServer(port: number, buildDir: string): void {
29
30
  export async function injectDevScript(htmlPath: string): Promise<void> {
30
31
  let html = await Bun.file(htmlPath).text();
31
32
  if (!html.includes("/__dev_ping")) {
32
- html = html.replace("</html>", `${DEV_SCRIPT}</html>`);
33
33
  await Bun.write(htmlPath, html);
34
34
  }
35
35
  }
36
-
@@ -1,11 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { cpSync, existsSync, readFileSync, writeFileSync } from "fs";
4
- import { join } from "path";
4
+ import { join,dirname } from "path";
5
+ import { fileURLToPath } from "url";
5
6
 
6
7
  const name = process.argv[2] ?? "my-doc";
7
8
  const dest = join(process.cwd(), name);
8
- const templateDir = join(import.meta.dir, "template");
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+
13
+ const templateDir = join(__dirname, "template");
9
14
 
10
15
  if (existsSync(dest)) {
11
16
  process.stderr.write(`Error: directory '${name}' already exists\n`);
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@weasyprint-tsx/create",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "bin": {
5
- "create-weasyprint-tsx": "src/cli.ts"
5
+ "create-weasyprint-tsx": "cli.js"
6
6
  },
7
- "workspaces": [
8
- "packages/*"
7
+ "files": [
8
+ "cli.js",
9
+ "template"
9
10
  ]
10
11
  }
@@ -0,0 +1,119 @@
1
+ # weasyprint-tsx Project — LLM Context
2
+
3
+ This is a **weasyprint-tsx** document project. The output is a PDF file generated from Preact/TSX source.
4
+
5
+ ## Pipeline
6
+
7
+ ```
8
+ src/index.tsx → Bun.build() → .build/index.html → WeasyPrint → output.pdf
9
+ ```
10
+
11
+ - **Bun** bundles the TSX entry point (and its imports) into a static HTML file
12
+ - **WeasyPrint** converts that HTML into a PDF using CSS print rules
13
+ - The dev server (`port 3000`) serves the HTML with live reload injected
14
+
15
+ ## Commands
16
+
17
+ ```bash
18
+ bun run dev # watch src/, rebuild on change, serve preview at localhost:3000
19
+ bun run build # build once, write output.pdf
20
+ ```
21
+
22
+ ## Entry point (`src/index.tsx`)
23
+
24
+ Must export a **default Preact component** that returns a **complete HTML document**:
25
+
26
+ ```tsx
27
+ import { H1, Page } from "@weasyprint-tsx/ui";
28
+ import "./index.css";
29
+
30
+ export default function Document() {
31
+ return (
32
+ <html>
33
+ <head>
34
+ <meta charset="UTF-8" />
35
+ <title>My Document</title>
36
+ <link rel="stylesheet" href="index.css" />
37
+ </head>
38
+ <body>
39
+ <Page>
40
+ <H1>My Document</H1>
41
+ </Page>
42
+ </body>
43
+ </html>
44
+ );
45
+ }
46
+ ```
47
+
48
+ The component must render `<html>`, `<head>`, and `<body>` — WeasyPrint receives the full HTML string.
49
+
50
+ ## Stylesheet (`src/index.css`)
51
+
52
+ Must start with `@import "tailwindcss"`. Page size and margins are set via `@page`:
53
+
54
+ ```css
55
+ @import "tailwindcss";
56
+
57
+ @page {
58
+ size: A4;
59
+ margin: 2cm 1.5cm;
60
+ }
61
+ ```
62
+
63
+ CSS `@page` rules control paper size, margins, and page headers/footers. Do **not** use `html { width: 21cm }` — let WeasyPrint handle page geometry via `@page`.
64
+
65
+ ## Configuration (`weasyprint-tsx.config.ts`)
66
+
67
+ ```ts
68
+ import type { Config } from "@weasyprint-tsx/build";
69
+
70
+ const config: Config = {
71
+ io: {
72
+ output: "output.pdf", // output path
73
+ input: "src/index.tsx", // entry point
74
+ },
75
+ weasyprint: {
76
+ path: "weasyprint", // path to weasyprint binary
77
+ },
78
+ };
79
+
80
+ export default config;
81
+ ```
82
+
83
+ ## UI Components (`@weasyprint-tsx/ui`)
84
+
85
+ All components are Preact components (not React). Import from `@weasyprint-tsx/ui`:
86
+
87
+ ```ts
88
+ import {
89
+ // Layout
90
+ Page, PageBreak,
91
+ BlockBox, Block,
92
+ // Headings
93
+ H1, H2, H3, H4, H5, H6, Title, ResetCounter,
94
+ // Lists
95
+ UL, OL, LI,
96
+ // Table
97
+ Table, Entry,
98
+ // Inline
99
+ DotLine, CodeBlock, Equation,
100
+ } from "@weasyprint-tsx/ui";
101
+ ```
102
+
103
+ See the full API: https://github.com/weasyprint-tsx/weasyprint-tsx/blob/main/packages/ui/README.md
104
+
105
+ ## CSS References
106
+
107
+ - **WeasyPrint CSS support**: https://doc.courtbouillon.org/weasyprint/stable/first_steps.html
108
+ - **Tailwind CSS v4 docs**: https://tailwindcss.com/docs
109
+
110
+ ## Constraints for LLMs
111
+
112
+ - **No `position: fixed` or `position: sticky`** — these do not work in print media
113
+ - **No `vh` / `vw` units** — viewport units are meaningless in print context
114
+ - **No `@media screen`** — the document is rendered in print media; use `@media print` or no media query
115
+ - **Page geometry** belongs in `@page` rules, not on `html` or `body`
116
+ - **All layout** should use CSS that WeasyPrint supports. Flexbox and CSS Grid have partial support — prefer block layout or the `BlockBox`/`Block` components for multi-column content
117
+ - **Components are Preact**, not React — use `class` not `className` for raw HTML elements (Preact accepts both, but prefer `class`)
118
+ - **Images** must be embedded as base64 data URIs or served by the dev server; external URLs may not resolve during build
119
+ - **Fonts** must be declared in CSS with `@font-face` or imported via Tailwind; Google Fonts CDN links work at build time
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "name": "my-doc",
3
- "private": true,
4
3
  "scripts": {
5
4
  "build": "weasyprint-tsx",
6
5
  "dev": "weasyprint-tsx --watch",
@@ -1,17 +1,5 @@
1
1
  import type { Config } from "@weasyprint-tsx/build";
2
2
 
3
- const config: Config = {
4
- io: {
5
- engine: "weasyprint",
6
- output: "output.pdf",
7
- },
8
- weasyprint: {
9
- pdf_forms: true,
10
- },
11
- watchdog: {
12
- path: "./src",
13
- debounce: 500,
14
- },
15
- };
3
+ const config: Config = {};
16
4
 
17
5
  export default config;