weasyprint-tsx 0.1.0 → 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.pdf +0 -0
- package/bun.lock +22 -4
- package/package.json +7 -2
- package/packages/build/package.json +1 -1
- package/packages/build/src/build.ts +9 -9
- package/packages/build/src/config.ts +2 -2
- package/packages/build/src/orchestrator.ts +8 -6
- package/packages/build/src/server.ts +4 -5
- package/packages/ui/package.json +5 -2
- package/packages/ui/src/BlockBox.tsx +6 -3
- package/packages/ui/src/CodeBlock.module.css +4 -0
- package/packages/ui/src/CodeBlock.tsx +20 -2
- package/packages/ui/src/Stack.module.css +9 -0
- package/packages/ui/src/Stack.tsx +24 -0
- package/packages/ui/src/Title.module.css +40 -32
- package/packages/ui/src/index.ts +1 -0
- package/src/index.css +7 -2
- package/src/index.tsx +271 -128
- package/testUI/index.css +1 -0
- package/testUI/index.tsx +20 -0
- package/weasyprint-tsx.config.ts +8 -0
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.
|
|
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
|
|
30
|
+
"version": "0.1.0",
|
|
28
31
|
"bin": {
|
|
29
|
-
"create-weasyprint-tsx": "
|
|
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
|
|
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.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"
|
|
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
|
-
import
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
await Bun.write(BUILD_PATH, html);
|
|
52
|
+
let html = "<!DOCTYPE html>" + renderToStaticMarkup(h(Document, {}));
|
|
55
53
|
|
|
56
54
|
if (dev) {
|
|
57
|
-
|
|
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
|
-
|
|
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[] {
|
|
@@ -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
|
|
|
@@ -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
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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(){});},
|
|
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
|
-
|
|
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
|
-
|
package/packages/ui/package.json
CHANGED
|
@@ -16,8 +16,8 @@ interface BlockProps extends ComponentProps<"div"> {
|
|
|
16
16
|
align?: "middle" | "top" | "bottom";
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export function Block(
|
|
20
|
-
return
|
|
19
|
+
export function Block({ children }: BlockProps) {
|
|
20
|
+
return children;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export function BlockBox({
|
|
@@ -40,7 +40,10 @@ export function BlockBox({
|
|
|
40
40
|
const child = blockList.map(
|
|
41
41
|
({ props: { style, ratio = 1, className, centered, align, ...props } }) => (
|
|
42
42
|
<div
|
|
43
|
-
style={mergeStyle(style, {
|
|
43
|
+
style={mergeStyle(style, {
|
|
44
|
+
"--ratio": ratio,
|
|
45
|
+
"--block-box-align": align,
|
|
46
|
+
})}
|
|
44
47
|
className={joinClasses(
|
|
45
48
|
className,
|
|
46
49
|
styles.block,
|
|
@@ -1,16 +1,34 @@
|
|
|
1
1
|
import hljs from "highlight.js";
|
|
2
2
|
import "highlight.js/styles/atom-one-dark.css";
|
|
3
3
|
import { ComponentProps } from "preact";
|
|
4
|
+
import styles from "./CodeBlock.module.css";
|
|
5
|
+
import { joinClasses, mergeStyle } from "./utils";
|
|
4
6
|
|
|
5
7
|
interface CodeBlockProps extends Omit<ComponentProps<"code">, "children"> {
|
|
6
8
|
language: string;
|
|
7
9
|
code: string;
|
|
10
|
+
bgColor?: string;
|
|
11
|
+
color?: string;
|
|
12
|
+
|
|
8
13
|
}
|
|
9
14
|
|
|
10
|
-
export function CodeBlock({
|
|
15
|
+
export function CodeBlock({
|
|
16
|
+
code,
|
|
17
|
+
language,
|
|
18
|
+
bgColor,
|
|
19
|
+
color,
|
|
20
|
+
style,
|
|
21
|
+
className,
|
|
22
|
+
...props
|
|
23
|
+
}: CodeBlockProps) {
|
|
11
24
|
const codeBlock = hljs.highlight(code, { language: language });
|
|
25
|
+
const css = mergeStyle(style, {
|
|
26
|
+
"--codeblock-bg": bgColor,
|
|
27
|
+
"--color-color" : color,
|
|
28
|
+
breakInside: "avoid",
|
|
29
|
+
});
|
|
12
30
|
return (
|
|
13
|
-
<pre style={{
|
|
31
|
+
<pre style={css} className={joinClasses(className, styles.pre)}>
|
|
14
32
|
<code {...props} dangerouslySetInnerHTML={{ __html: codeBlock.value }} />
|
|
15
33
|
</pre>
|
|
16
34
|
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComponentProps } from "preact";
|
|
2
|
+
import styles from "./Stack.module.css";
|
|
3
|
+
import { joinClasses, mergeStyle } from "./utils";
|
|
4
|
+
|
|
5
|
+
interface StackProps extends ComponentProps<"div"> {
|
|
6
|
+
gap?: number | string;
|
|
7
|
+
align?: "left" | "right";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function Stack({ gap, align, className, style, ...props }: StackProps) {
|
|
11
|
+
const css = mergeStyle(style, {
|
|
12
|
+
"--stack-gap": gap,
|
|
13
|
+
"--stack-ml": align === "left" ? undefined : "auto",
|
|
14
|
+
"--stack-mr": align === "right" ? undefined : "auto",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
style={css}
|
|
20
|
+
className={joinClasses(className, styles.stack)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -1,28 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
.
|
|
3
|
-
.
|
|
4
|
-
.
|
|
5
|
-
.
|
|
6
|
-
.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
float: left;
|
|
10
|
-
clear: left;
|
|
11
|
-
}
|
|
12
|
-
&[data-marker]::before {
|
|
13
|
-
content: attr(data-marker);
|
|
14
|
-
}
|
|
1
|
+
.h1::before,
|
|
2
|
+
.h2::before,
|
|
3
|
+
.h3::before,
|
|
4
|
+
.h4::before,
|
|
5
|
+
.h5::before,
|
|
6
|
+
.h6::before {
|
|
7
|
+
float: left;
|
|
8
|
+
clear: left;
|
|
15
9
|
}
|
|
16
10
|
|
|
11
|
+
.h1[data-marker]::before,
|
|
12
|
+
.h2[data-marker]::before,
|
|
13
|
+
.h3[data-marker]::before,
|
|
14
|
+
.h4[data-marker]::before,
|
|
15
|
+
.h5[data-marker]::before,
|
|
16
|
+
.h6[data-marker]::before {
|
|
17
|
+
content: attr(data-marker);
|
|
18
|
+
}
|
|
17
19
|
|
|
18
20
|
.h1 {
|
|
19
21
|
color: var(--h1-color, inherit);
|
|
20
22
|
font-size: var(--h1-fontsize, inherit);
|
|
21
23
|
counter-reset: count-h2 count-h3 count-h4 count-h5 count-h6;
|
|
22
24
|
counter-increment: count-h1;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
:where(.h1)::before {
|
|
28
|
+
content: counter(count-h1, upper-roman) ". ";
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
.h2 {
|
|
@@ -30,9 +33,10 @@
|
|
|
30
33
|
font-size: var(--h2-fontsize, inherit);
|
|
31
34
|
counter-reset: count-h3 count-h4 count-h5 count-h6;
|
|
32
35
|
counter-increment: count-h2;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
:where(.h2)::before {
|
|
39
|
+
content: counter(count-h2, decimal) ". ";
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
.h3 {
|
|
@@ -40,9 +44,10 @@
|
|
|
40
44
|
font-size: var(--h3-fontsize, inherit);
|
|
41
45
|
counter-reset: count-h4 count-h5 count-h6;
|
|
42
46
|
counter-increment: count-h3;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
:where(.h3)::before {
|
|
50
|
+
content: counter(count-h3, upper-alpha) ". ";
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
.h4 {
|
|
@@ -50,9 +55,10 @@
|
|
|
50
55
|
font-size: var(--h4-fontsize, inherit);
|
|
51
56
|
counter-reset: count-h5 count-h6;
|
|
52
57
|
counter-increment: count-h4;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:where(.h4)::before {
|
|
61
|
+
content: counter(count-h4, decimal) ". ";
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
.h5 {
|
|
@@ -60,16 +66,18 @@
|
|
|
60
66
|
font-size: var(--h5-fontsize, inherit);
|
|
61
67
|
counter-reset: count-h6;
|
|
62
68
|
counter-increment: count-h5;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
:where(.h5)::before {
|
|
72
|
+
content: counter(count-h5, lower-alpha) ". ";
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
.h6 {
|
|
69
76
|
color: var(--h6-color, inherit);
|
|
70
77
|
font-size: var(--h6-fontsize, inherit);
|
|
71
78
|
counter-increment: count-h6;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
:where(.h6)::before {
|
|
82
|
+
content: counter(count-h6, lower-roman) ". ";
|
|
75
83
|
}
|
package/packages/ui/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { DotLine } from "./DotLine";
|
|
|
4
4
|
export { Equation } from "./Equation";
|
|
5
5
|
export { LI, OL, UL } from "./List";
|
|
6
6
|
export { Page, PageBreak } from "./Page";
|
|
7
|
+
export { Stack } from "./Stack";
|
|
7
8
|
export { Entry, Table } from "./Table";
|
|
8
9
|
export { H1, H2, H3, H4, H5, H6, ResetCounter, Title } from "./Titles";
|
|
9
10
|
|
package/src/index.css
CHANGED
|
@@ -19,16 +19,21 @@ body {
|
|
|
19
19
|
font-size: 10pt;
|
|
20
20
|
line-height: 1.75;
|
|
21
21
|
font-family: system-ui, sans-serif;
|
|
22
|
+
font-family: "Public Sans Variable", sans-serif;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
h1,
|
|
25
|
+
h1,
|
|
26
|
+
h2,
|
|
27
|
+
h3 {
|
|
25
28
|
line-height: 1.2;
|
|
26
29
|
}
|
|
27
30
|
|
|
31
|
+
|
|
32
|
+
|
|
28
33
|
code {
|
|
29
34
|
font-family: ui-monospace, monospace;
|
|
30
35
|
font-size: 0.88em;
|
|
31
|
-
background: #
|
|
36
|
+
background: #4490dd;
|
|
32
37
|
padding: 0.1em 0.3em;
|
|
33
38
|
border-radius: 3px;
|
|
34
39
|
}
|
package/src/index.tsx
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
H1, H2, H3,
|
|
3
|
-
Page, PageBreak,
|
|
4
|
-
UL, OL, LI,
|
|
5
|
-
Table, Entry,
|
|
6
|
-
BlockBox, Block,
|
|
7
2
|
CodeBlock,
|
|
8
3
|
DotLine,
|
|
4
|
+
Entry,
|
|
5
|
+
H1,
|
|
6
|
+
H2,
|
|
7
|
+
H3,
|
|
8
|
+
LI,
|
|
9
|
+
OL,
|
|
10
|
+
PageBreak,
|
|
11
|
+
Stack,
|
|
12
|
+
Table,
|
|
13
|
+
UL,
|
|
9
14
|
} from "@weasyprint-tsx/ui";
|
|
10
15
|
import "./index.css";
|
|
11
16
|
|
|
@@ -56,148 +61,286 @@ export default function Document() {
|
|
|
56
61
|
<link rel="stylesheet" href="index.css" />
|
|
57
62
|
</head>
|
|
58
63
|
<body>
|
|
59
|
-
|
|
60
64
|
{/* ── Cover ── */}
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
<BlockBox gap="1cm">
|
|
72
|
-
<Block ratio={1}>
|
|
73
|
-
<H3 color="#1e40af">Requirements</H3>
|
|
74
|
-
<UL>
|
|
75
|
-
<LI>Bun ≥ 1.0</LI>
|
|
76
|
-
<LI>WeasyPrint (pip install weasyprint)</LI>
|
|
77
|
-
</UL>
|
|
78
|
-
</Block>
|
|
79
|
-
<Block ratio={1}>
|
|
80
|
-
<H3 color="#1e40af">Quick start</H3>
|
|
81
|
-
<OL>
|
|
82
|
-
<LI>bunx create-weasyprint-tsx my-doc</LI>
|
|
83
|
-
<LI>cd my-doc && bun install</LI>
|
|
84
|
-
<LI>bun run dev</LI>
|
|
85
|
-
</OL>
|
|
86
|
-
</Block>
|
|
87
|
-
</BlockBox>
|
|
88
|
-
</Page>
|
|
65
|
+
<div style={{ marginBottom: "1.5cm" }}>
|
|
66
|
+
<H1 fontSize="28pt" color="#1e40af">
|
|
67
|
+
weasyprint-tsx
|
|
68
|
+
</H1>
|
|
69
|
+
<p style={{ fontSize: "13pt", color: "#475569", marginTop: "0.3cm" }}>
|
|
70
|
+
Write PDFs in TSX — Bun bundles your Preact components into HTML,
|
|
71
|
+
WeasyPrint renders them as PDF.
|
|
72
|
+
</p>
|
|
73
|
+
<DotLine width="100%" color="#cbd5e1" />
|
|
74
|
+
</div>
|
|
89
75
|
|
|
76
|
+
<Stack gap="1cm">
|
|
77
|
+
<div className="w-1/2">
|
|
78
|
+
<H3 color="#1e40af">Requirements</H3>
|
|
79
|
+
<UL>
|
|
80
|
+
<LI>Bun ≥ 1.0</LI>
|
|
81
|
+
<LI>WeasyPrint (pip install weasyprint)</LI>
|
|
82
|
+
</UL>
|
|
83
|
+
</div>
|
|
84
|
+
<div className="w-1/2">
|
|
85
|
+
<H3 color="#1e40af">
|
|
86
|
+
Quick start
|
|
87
|
+
</H3>
|
|
88
|
+
<OL>
|
|
89
|
+
<LI>bunx create-weasyprint-tsx my-doc</LI>
|
|
90
|
+
<LI>cd my-doc && bun install</LI>
|
|
91
|
+
<LI>bun run dev</LI>
|
|
92
|
+
</OL>
|
|
93
|
+
</div>
|
|
94
|
+
</Stack>
|
|
90
95
|
<PageBreak />
|
|
91
96
|
|
|
92
97
|
{/* ── Getting Started ── */}
|
|
93
|
-
<
|
|
94
|
-
<H2 color="#1e40af">Getting Started</H2>
|
|
98
|
+
<H2 color="#1e40af">Getting Started</H2>
|
|
95
99
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
<p>
|
|
101
|
+
The <code>create-weasyprint-tsx</code> scaffolder generates a
|
|
102
|
+
ready-to-use project. After installation, two scripts are available:
|
|
103
|
+
</p>
|
|
100
104
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
<Table
|
|
106
|
+
orientation="col"
|
|
107
|
+
headerBg="#1e40af"
|
|
108
|
+
headerFontSize="9pt"
|
|
109
|
+
cellFontSize="9pt"
|
|
110
|
+
borderColor="#e2e8f0"
|
|
111
|
+
>
|
|
112
|
+
<Entry content={["Script", "Effect"]} />
|
|
113
|
+
<Entry
|
|
114
|
+
content={[
|
|
115
|
+
"bun run dev",
|
|
116
|
+
"Watch src/, rebuild on change, serve preview at localhost:3000",
|
|
117
|
+
]}
|
|
118
|
+
/>
|
|
119
|
+
<Entry content={["bun run build", "Build once, write output.pdf"]} />
|
|
120
|
+
</Table>
|
|
106
121
|
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
<H3>Project structure</H3>
|
|
123
|
+
<CodeBlock
|
|
124
|
+
language="plaintext"
|
|
125
|
+
code={`my-doc/
|
|
109
126
|
├── src/
|
|
110
127
|
│ ├── index.tsx # Document root — export a default Preact component
|
|
111
128
|
│ └── index.css # Styles — must start with @import "tailwindcss"
|
|
112
129
|
├── weasyprint-tsx.config.ts
|
|
113
|
-
└── package.json`}
|
|
114
|
-
|
|
115
|
-
<H3>Entry point</H3>
|
|
116
|
-
<p>
|
|
117
|
-
<code>src/index.tsx</code> must export a default component that renders a
|
|
118
|
-
complete HTML document. WeasyPrint receives the full HTML string.
|
|
119
|
-
</p>
|
|
120
|
-
<CodeBlock language="tsx" code={indexCode} />
|
|
121
|
-
</Page>
|
|
130
|
+
└── package.json`}
|
|
131
|
+
/>
|
|
122
132
|
|
|
123
|
-
<
|
|
133
|
+
<H3>Entry point</H3>
|
|
134
|
+
<p>
|
|
135
|
+
<code>src/index.tsx</code> must export a default component that
|
|
136
|
+
renders a complete HTML document. WeasyPrint receives the full HTML
|
|
137
|
+
string.
|
|
138
|
+
</p>
|
|
139
|
+
<CodeBlock language="tsx" code={indexCode} />
|
|
124
140
|
|
|
125
141
|
{/* ── Configuration ── */}
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
<CodeBlock language="typescript" code={configCode} />
|
|
133
|
-
|
|
134
|
-
<H3>All config fields</H3>
|
|
135
|
-
|
|
136
|
-
<Table orientation="col" headerBg="#334155" headerFontSize="8.5pt" cellFontSize="8.5pt" borderColor="#e2e8f0">
|
|
137
|
-
<Entry content={["Field", "Default", "Description"]} />
|
|
138
|
-
<Entry content={["io.input", "src/index.tsx", "TSX entry point"]} />
|
|
139
|
-
<Entry content={["io.output", "output.pdf", "Output PDF path"]} />
|
|
140
|
-
<Entry content={["io.buildDir", ".build", "Intermediate HTML directory"]} />
|
|
141
|
-
<Entry content={["io.media_type", "print", "CSS media type"]} />
|
|
142
|
-
<Entry content={["weasyprint.path", "weasyprint", "Path to WeasyPrint binary"]} />
|
|
143
|
-
<Entry content={["weasyprint.dpi", "—", "Output resolution"]} />
|
|
144
|
-
<Entry content={["weasyprint.optimize_images", "—", "Compress images in output"]} />
|
|
145
|
-
<Entry content={["weasyprint.pdf_forms", "—", "Enable PDF form fields"]} />
|
|
146
|
-
<Entry content={["weasyprint.pdf_variant", "—", "pdf/a-1b, pdf/ua-1, …"]} />
|
|
147
|
-
<Entry content={["weasyprint.full_fonts", "—", "Embed full font files"]} />
|
|
148
|
-
<Entry content={["weasyprint.cache", "—", "Font/image cache folder"]} />
|
|
149
|
-
<Entry content={["dev.port", "3000", "Dev server port"]} />
|
|
150
|
-
<Entry content={["dev.watch", "src", "Directory to watch"]} />
|
|
151
|
-
<Entry content={["pdf.stylesheets", "[]", "Extra CSS files via --stylesheet"]} />
|
|
152
|
-
</Table>
|
|
153
|
-
</Page>
|
|
142
|
+
<H2 color="#1e40af">Configuration</H2>
|
|
143
|
+
<p>
|
|
144
|
+
Create <code>weasyprint-tsx.config.ts</code> at the project root to
|
|
145
|
+
override any default:
|
|
146
|
+
</p>
|
|
147
|
+
<CodeBlock language="typescript" code={configCode} />
|
|
154
148
|
|
|
155
|
-
<
|
|
149
|
+
<H3>All config fields</H3>
|
|
150
|
+
|
|
151
|
+
<Table
|
|
152
|
+
orientation="col"
|
|
153
|
+
headerBg="#334155"
|
|
154
|
+
headerFontSize="8.5pt"
|
|
155
|
+
cellFontSize="8.5pt"
|
|
156
|
+
borderColor="#e2e8f0"
|
|
157
|
+
>
|
|
158
|
+
<Entry content={["Field", "Default", "Description"]} />
|
|
159
|
+
<Entry content={["io.input", "src/index.tsx", "TSX entry point"]} />
|
|
160
|
+
<Entry content={["io.output", "output.pdf", "Output PDF path"]} />
|
|
161
|
+
<Entry
|
|
162
|
+
content={["io.buildDir", ".build", "Intermediate HTML directory"]}
|
|
163
|
+
/>
|
|
164
|
+
<Entry content={["io.media_type", "print", "CSS media type"]} />
|
|
165
|
+
<Entry
|
|
166
|
+
content={[
|
|
167
|
+
"weasyprint.path",
|
|
168
|
+
"weasyprint",
|
|
169
|
+
"Path to WeasyPrint binary",
|
|
170
|
+
]}
|
|
171
|
+
/>
|
|
172
|
+
<Entry content={["weasyprint.dpi", "—", "Output resolution"]} />
|
|
173
|
+
<Entry
|
|
174
|
+
content={[
|
|
175
|
+
"weasyprint.optimize_images",
|
|
176
|
+
"—",
|
|
177
|
+
"Compress images in output",
|
|
178
|
+
]}
|
|
179
|
+
/>
|
|
180
|
+
<Entry
|
|
181
|
+
content={["weasyprint.pdf_forms", "—", "Enable PDF form fields"]}
|
|
182
|
+
/>
|
|
183
|
+
<Entry
|
|
184
|
+
content={["weasyprint.pdf_variant", "—", "pdf/a-1b, pdf/ua-1, …"]}
|
|
185
|
+
/>
|
|
186
|
+
<Entry
|
|
187
|
+
content={["weasyprint.full_fonts", "—", "Embed full font files"]}
|
|
188
|
+
/>
|
|
189
|
+
<Entry
|
|
190
|
+
content={["weasyprint.cache", "—", "Font/image cache folder"]}
|
|
191
|
+
/>
|
|
192
|
+
<Entry content={["dev.port", "3000", "Dev server port"]} />
|
|
193
|
+
<Entry content={["dev.watch", "src", "Directory to watch"]} />
|
|
194
|
+
<Entry
|
|
195
|
+
content={[
|
|
196
|
+
"pdf.stylesheets",
|
|
197
|
+
"[]",
|
|
198
|
+
"Extra CSS files via --stylesheet",
|
|
199
|
+
]}
|
|
200
|
+
/>
|
|
201
|
+
</Table>
|
|
156
202
|
|
|
157
203
|
{/* ── UI Components ── */}
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
<
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
</
|
|
204
|
+
<H2 color="#1e40af">UI Components</H2>
|
|
205
|
+
<p>
|
|
206
|
+
<code>@weasyprint-tsx/ui</code> provides print-optimized Preact
|
|
207
|
+
components. Import everything from the package root:
|
|
208
|
+
</p>
|
|
209
|
+
<CodeBlock
|
|
210
|
+
language="ts"
|
|
211
|
+
code={`import { H1, H2, Page, PageBreak, UL, OL, LI, Table, Entry, BlockBox, Block, DotLine, CodeBlock, Equation } from "@weasyprint-tsx/ui";`}
|
|
212
|
+
/>
|
|
213
|
+
|
|
214
|
+
<H3>Page & Layout</H3>
|
|
215
|
+
<Table
|
|
216
|
+
orientation="row"
|
|
217
|
+
headerBg="#f1f5f9"
|
|
218
|
+
borderColor="#e2e8f0"
|
|
219
|
+
headerFontSize="8.5pt"
|
|
220
|
+
cellFontSize="8.5pt"
|
|
221
|
+
>
|
|
222
|
+
<Entry
|
|
223
|
+
content={[
|
|
224
|
+
"Page",
|
|
225
|
+
"Wraps a page section (<section>). Accepts page?: string for named page rules.",
|
|
226
|
+
]}
|
|
227
|
+
/>
|
|
228
|
+
<Entry
|
|
229
|
+
content={["PageBreak", "Inserts a CSS page break. No props."]}
|
|
230
|
+
/>
|
|
231
|
+
<Entry
|
|
232
|
+
content={[
|
|
233
|
+
"BlockBox",
|
|
234
|
+
"Multi-column flex container. Props: gap, basis, centered, align.",
|
|
235
|
+
]}
|
|
236
|
+
/>
|
|
237
|
+
<Entry
|
|
238
|
+
content={[
|
|
239
|
+
"Block",
|
|
240
|
+
"Column inside BlockBox. Props: ratio, centered, align.",
|
|
241
|
+
]}
|
|
242
|
+
/>
|
|
243
|
+
</Table>
|
|
244
|
+
|
|
245
|
+
<H3>Headings</H3>
|
|
246
|
+
<Table
|
|
247
|
+
orientation="row"
|
|
248
|
+
headerBg="#f1f5f9"
|
|
249
|
+
borderColor="#e2e8f0"
|
|
250
|
+
headerFontSize="8.5pt"
|
|
251
|
+
cellFontSize="8.5pt"
|
|
252
|
+
>
|
|
253
|
+
<Entry
|
|
254
|
+
content={[
|
|
255
|
+
"H1 – H6",
|
|
256
|
+
"Render h1–h6. Props: marker (data-marker for CSS counters), color, fontSize.",
|
|
257
|
+
]}
|
|
258
|
+
/>
|
|
259
|
+
<Entry
|
|
260
|
+
content={[
|
|
261
|
+
"ResetCounter",
|
|
262
|
+
"Hidden div that resets CSS counters. Use at the top of numbered sections.",
|
|
263
|
+
]}
|
|
264
|
+
/>
|
|
265
|
+
</Table>
|
|
266
|
+
|
|
267
|
+
<H3>Lists</H3>
|
|
268
|
+
<Table
|
|
269
|
+
orientation="row"
|
|
270
|
+
headerBg="#f1f5f9"
|
|
271
|
+
borderColor="#e2e8f0"
|
|
272
|
+
headerFontSize="8.5pt"
|
|
273
|
+
cellFontSize="8.5pt"
|
|
274
|
+
>
|
|
275
|
+
<Entry
|
|
276
|
+
content={[
|
|
277
|
+
"UL",
|
|
278
|
+
"Unordered list. Props: marker (bullet char), gap, pre.",
|
|
279
|
+
]}
|
|
280
|
+
/>
|
|
281
|
+
<Entry
|
|
282
|
+
content={[
|
|
283
|
+
"OL",
|
|
284
|
+
"Ordered list. Props: start, counterType (decimal/lower-alpha/upper-roman/…), markerPre, markerPost, gap, pre.",
|
|
285
|
+
]}
|
|
286
|
+
/>
|
|
287
|
+
<Entry
|
|
288
|
+
content={[
|
|
289
|
+
"LI",
|
|
290
|
+
"List item. Props: marker (override bullet), count (override counter).",
|
|
291
|
+
]}
|
|
292
|
+
/>
|
|
293
|
+
</Table>
|
|
294
|
+
|
|
295
|
+
<H3>Table</H3>
|
|
296
|
+
<Table
|
|
297
|
+
orientation="row"
|
|
298
|
+
headerBg="#f1f5f9"
|
|
299
|
+
borderColor="#e2e8f0"
|
|
300
|
+
headerFontSize="8.5pt"
|
|
301
|
+
cellFontSize="8.5pt"
|
|
302
|
+
>
|
|
303
|
+
<Entry
|
|
304
|
+
content={[
|
|
305
|
+
"Table",
|
|
306
|
+
`orientation "col" (default): first Entry is the header row. orientation "row": first cell of each Entry is the row header. Also: headerBg, cellBg, borderWidth, borderColor, headerFontSize, cellFontSize.`,
|
|
307
|
+
]}
|
|
308
|
+
/>
|
|
309
|
+
<Entry
|
|
310
|
+
content={[
|
|
311
|
+
"Entry",
|
|
312
|
+
"Data row/column. content: ComponentChild[] holds cell values. Accepts per-entry overrides: headerBg, cellBg.",
|
|
313
|
+
]}
|
|
314
|
+
/>
|
|
315
|
+
</Table>
|
|
200
316
|
|
|
317
|
+
<H3>Inline elements</H3>
|
|
318
|
+
<Table
|
|
319
|
+
orientation="row"
|
|
320
|
+
headerBg="#f1f5f9"
|
|
321
|
+
borderColor="#e2e8f0"
|
|
322
|
+
headerFontSize="8.5pt"
|
|
323
|
+
cellFontSize="8.5pt"
|
|
324
|
+
>
|
|
325
|
+
<Entry
|
|
326
|
+
content={[
|
|
327
|
+
"DotLine",
|
|
328
|
+
"Repeating dot fill line. Props: num, width, inline, color, lineHeight.",
|
|
329
|
+
]}
|
|
330
|
+
/>
|
|
331
|
+
<Entry
|
|
332
|
+
content={[
|
|
333
|
+
"CodeBlock",
|
|
334
|
+
"Syntax-highlighted code (highlight.js). Props: language, code.",
|
|
335
|
+
]}
|
|
336
|
+
/>
|
|
337
|
+
<Entry
|
|
338
|
+
content={[
|
|
339
|
+
"Equation",
|
|
340
|
+
"LaTeX via KaTeX. Props: tex, displayMode, aligned, chemical.",
|
|
341
|
+
]}
|
|
342
|
+
/>
|
|
343
|
+
</Table>
|
|
201
344
|
</body>
|
|
202
345
|
</html>
|
|
203
346
|
);
|
package/testUI/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "tailwindcss";
|
package/testUI/index.tsx
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Stack } from "@weasyprint-tsx/ui";
|
|
2
|
+
import "./index.css";
|
|
3
|
+
|
|
4
|
+
export default function Document() {
|
|
5
|
+
return (
|
|
6
|
+
<html>
|
|
7
|
+
<head>
|
|
8
|
+
<meta charset="UTF-8" />
|
|
9
|
+
<title>weasyprint-tsx</title>
|
|
10
|
+
<link rel="stylesheet" href="index.css" />
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<Stack gap={"1cm"} className="border-2 border-solid h-125 py-5">
|
|
14
|
+
<div className="bg-green-800 size-50"></div>
|
|
15
|
+
<div className="bg-blue-800 size-50"></div>
|
|
16
|
+
</Stack>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
19
|
+
);
|
|
20
|
+
}
|
package/weasyprint-tsx.config.ts
CHANGED