@pyreon/document 0.0.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/LICENSE +21 -0
- package/lib/analysis/index.js.html +5406 -0
- package/lib/chunk-ErZ26oRB.js +48 -0
- package/lib/confluence-Va8e7RxQ.js +192 -0
- package/lib/confluence-Va8e7RxQ.js.map +1 -0
- package/lib/csv-2c38ub-Y.js +32 -0
- package/lib/csv-2c38ub-Y.js.map +1 -0
- package/lib/discord-DAoUZqvE.js +134 -0
- package/lib/discord-DAoUZqvE.js.map +1 -0
- package/lib/dist-BsqdI2nY.js +20179 -0
- package/lib/dist-BsqdI2nY.js.map +1 -0
- package/lib/docx-CorFwEH9.js +450 -0
- package/lib/docx-CorFwEH9.js.map +1 -0
- package/lib/email-Bn_Brjdp.js +131 -0
- package/lib/email-Bn_Brjdp.js.map +1 -0
- package/lib/exceljs-BoIDUUaw.js +34377 -0
- package/lib/exceljs-BoIDUUaw.js.map +1 -0
- package/lib/google-chat-B6I017I1.js +125 -0
- package/lib/google-chat-B6I017I1.js.map +1 -0
- package/lib/html-De_iS_f0.js +151 -0
- package/lib/html-De_iS_f0.js.map +1 -0
- package/lib/index.js +619 -0
- package/lib/index.js.map +1 -0
- package/lib/markdown-BYC_3C9i.js +75 -0
- package/lib/markdown-BYC_3C9i.js.map +1 -0
- package/lib/notion-DHaQHO6P.js +187 -0
- package/lib/notion-DHaQHO6P.js.map +1 -0
- package/lib/pdf-CDPc5Itc.js +419 -0
- package/lib/pdf-CDPc5Itc.js.map +1 -0
- package/lib/pdfmake-DnmLxK4Q.js +55511 -0
- package/lib/pdfmake-DnmLxK4Q.js.map +1 -0
- package/lib/pptx-DKQU6bjq.js +252 -0
- package/lib/pptx-DKQU6bjq.js.map +1 -0
- package/lib/pptxgen.es-COcgXsyx.js +5697 -0
- package/lib/pptxgen.es-COcgXsyx.js.map +1 -0
- package/lib/slack-CJRJgkag.js +139 -0
- package/lib/slack-CJRJgkag.js.map +1 -0
- package/lib/svg-BM8biZmL.js +187 -0
- package/lib/svg-BM8biZmL.js.map +1 -0
- package/lib/teams-S99tonRG.js +176 -0
- package/lib/teams-S99tonRG.js.map +1 -0
- package/lib/telegram-CbEO_2PN.js +77 -0
- package/lib/telegram-CbEO_2PN.js.map +1 -0
- package/lib/text-B5U8ucRr.js +75 -0
- package/lib/text-B5U8ucRr.js.map +1 -0
- package/lib/types/index.d.ts +528 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/vfs_fonts-Df1kkZ4Y.js +19 -0
- package/lib/vfs_fonts-Df1kkZ4Y.js.map +1 -0
- package/lib/whatsapp-DJ2D1jGG.js +64 -0
- package/lib/whatsapp-DJ2D1jGG.js.map +1 -0
- package/lib/xlsx-D47x-gZ5.js +199 -0
- package/lib/xlsx-D47x-gZ5.js.map +1 -0
- package/package.json +62 -0
- package/src/builder.ts +266 -0
- package/src/download.ts +76 -0
- package/src/env.d.ts +17 -0
- package/src/index.ts +98 -0
- package/src/nodes.ts +315 -0
- package/src/render.ts +222 -0
- package/src/renderers/confluence.ts +231 -0
- package/src/renderers/csv.ts +67 -0
- package/src/renderers/discord.ts +192 -0
- package/src/renderers/docx.ts +612 -0
- package/src/renderers/email.ts +230 -0
- package/src/renderers/google-chat.ts +211 -0
- package/src/renderers/html.ts +225 -0
- package/src/renderers/markdown.ts +144 -0
- package/src/renderers/notion.ts +264 -0
- package/src/renderers/pdf.ts +427 -0
- package/src/renderers/pptx.ts +353 -0
- package/src/renderers/slack.ts +192 -0
- package/src/renderers/svg.ts +254 -0
- package/src/renderers/teams.ts +234 -0
- package/src/renderers/telegram.ts +137 -0
- package/src/renderers/text.ts +154 -0
- package/src/renderers/whatsapp.ts +121 -0
- package/src/renderers/xlsx.ts +342 -0
- package/src/tests/document.test.ts +2920 -0
- package/src/types.ts +291 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
//#region src/render.ts
|
|
2
|
+
const renderers = /* @__PURE__ */ new Map();
|
|
3
|
+
/**
|
|
4
|
+
* Register a custom renderer for a format.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* registerRenderer('thermal', {
|
|
9
|
+
* render(node, options) {
|
|
10
|
+
* // Walk nodes → ESC/POS commands
|
|
11
|
+
* return escPosBuffer
|
|
12
|
+
* },
|
|
13
|
+
* })
|
|
14
|
+
*
|
|
15
|
+
* await render(receipt, 'thermal')
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
function registerRenderer(format, renderer) {
|
|
19
|
+
renderers.set(format, renderer);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Remove a registered renderer.
|
|
23
|
+
*/
|
|
24
|
+
function unregisterRenderer(format) {
|
|
25
|
+
renderers.delete(format);
|
|
26
|
+
}
|
|
27
|
+
registerRenderer("html", () => import("./html-De_iS_f0.js").then((m) => m.htmlRenderer));
|
|
28
|
+
registerRenderer("email", () => import("./email-Bn_Brjdp.js").then((m) => m.emailRenderer));
|
|
29
|
+
registerRenderer("md", () => import("./markdown-BYC_3C9i.js").then((m) => m.markdownRenderer));
|
|
30
|
+
registerRenderer("text", () => import("./text-B5U8ucRr.js").then((m) => m.textRenderer));
|
|
31
|
+
registerRenderer("csv", () => import("./csv-2c38ub-Y.js").then((m) => m.csvRenderer));
|
|
32
|
+
registerRenderer("pdf", () => import("./pdf-CDPc5Itc.js").then((m) => m.pdfRenderer));
|
|
33
|
+
registerRenderer("docx", () => import("./docx-CorFwEH9.js").then((m) => m.docxRenderer));
|
|
34
|
+
registerRenderer("xlsx", () => import("./xlsx-D47x-gZ5.js").then((m) => m.xlsxRenderer));
|
|
35
|
+
registerRenderer("pptx", () => import("./pptx-DKQU6bjq.js").then((m) => m.pptxRenderer));
|
|
36
|
+
registerRenderer("slack", () => import("./slack-CJRJgkag.js").then((m) => m.slackRenderer));
|
|
37
|
+
registerRenderer("svg", () => import("./svg-BM8biZmL.js").then((m) => m.svgRenderer));
|
|
38
|
+
registerRenderer("teams", () => import("./teams-S99tonRG.js").then((m) => m.teamsRenderer));
|
|
39
|
+
registerRenderer("discord", () => import("./discord-DAoUZqvE.js").then((m) => m.discordRenderer));
|
|
40
|
+
registerRenderer("telegram", () => import("./telegram-CbEO_2PN.js").then((m) => m.telegramRenderer));
|
|
41
|
+
registerRenderer("notion", () => import("./notion-DHaQHO6P.js").then((m) => m.notionRenderer));
|
|
42
|
+
registerRenderer("confluence", () => import("./confluence-Va8e7RxQ.js").then((m) => m.confluenceRenderer));
|
|
43
|
+
registerRenderer("whatsapp", () => import("./whatsapp-DJ2D1jGG.js").then((m) => m.whatsappRenderer));
|
|
44
|
+
registerRenderer("google-chat", () => import("./google-chat-B6I017I1.js").then((m) => m.googleChatRenderer));
|
|
45
|
+
async function resolveRenderer(format) {
|
|
46
|
+
const entry = renderers.get(format);
|
|
47
|
+
if (!entry) throw new Error(`[@pyreon/document] No renderer registered for format '${format}'. Available: ${[...renderers.keys()].join(", ")}`);
|
|
48
|
+
if (typeof entry === "function") {
|
|
49
|
+
const renderer = await entry();
|
|
50
|
+
renderers.set(format, renderer);
|
|
51
|
+
return renderer;
|
|
52
|
+
}
|
|
53
|
+
return entry;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Render a document node tree to the specified format.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* const doc = <Document title="Report"><Page>...</Page></Document>
|
|
61
|
+
*
|
|
62
|
+
* const html = await render(doc, 'html') // → HTML string
|
|
63
|
+
* const pdf = await render(doc, 'pdf') // → PDF Uint8Array
|
|
64
|
+
* const docx = await render(doc, 'docx') // → DOCX Uint8Array
|
|
65
|
+
* const email = await render(doc, 'email') // → email-safe HTML string
|
|
66
|
+
* const md = await render(doc, 'md') // → Markdown string
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
async function render(node, format, options) {
|
|
70
|
+
return (await resolveRenderer(format)).render(node, options);
|
|
71
|
+
}
|
|
72
|
+
/** @internal For testing — reset renderer registry to defaults. */
|
|
73
|
+
function _resetRenderers() {
|
|
74
|
+
renderers.clear();
|
|
75
|
+
registerRenderer("html", () => import("./html-De_iS_f0.js").then((m) => m.htmlRenderer));
|
|
76
|
+
registerRenderer("email", () => import("./email-Bn_Brjdp.js").then((m) => m.emailRenderer));
|
|
77
|
+
registerRenderer("md", () => import("./markdown-BYC_3C9i.js").then((m) => m.markdownRenderer));
|
|
78
|
+
registerRenderer("text", () => import("./text-B5U8ucRr.js").then((m) => m.textRenderer));
|
|
79
|
+
registerRenderer("csv", () => import("./csv-2c38ub-Y.js").then((m) => m.csvRenderer));
|
|
80
|
+
registerRenderer("pdf", () => import("./pdf-CDPc5Itc.js").then((m) => m.pdfRenderer));
|
|
81
|
+
registerRenderer("docx", () => import("./docx-CorFwEH9.js").then((m) => m.docxRenderer));
|
|
82
|
+
registerRenderer("xlsx", () => import("./xlsx-D47x-gZ5.js").then((m) => m.xlsxRenderer));
|
|
83
|
+
registerRenderer("pptx", () => import("./pptx-DKQU6bjq.js").then((m) => m.pptxRenderer));
|
|
84
|
+
registerRenderer("slack", () => import("./slack-CJRJgkag.js").then((m) => m.slackRenderer));
|
|
85
|
+
registerRenderer("svg", () => import("./svg-BM8biZmL.js").then((m) => m.svgRenderer));
|
|
86
|
+
registerRenderer("teams", () => import("./teams-S99tonRG.js").then((m) => m.teamsRenderer));
|
|
87
|
+
registerRenderer("discord", () => import("./discord-DAoUZqvE.js").then((m) => m.discordRenderer));
|
|
88
|
+
registerRenderer("telegram", () => import("./telegram-CbEO_2PN.js").then((m) => m.telegramRenderer));
|
|
89
|
+
registerRenderer("notion", () => import("./notion-DHaQHO6P.js").then((m) => m.notionRenderer));
|
|
90
|
+
registerRenderer("confluence", () => import("./confluence-Va8e7RxQ.js").then((m) => m.confluenceRenderer));
|
|
91
|
+
registerRenderer("whatsapp", () => import("./whatsapp-DJ2D1jGG.js").then((m) => m.whatsappRenderer));
|
|
92
|
+
registerRenderer("google-chat", () => import("./google-chat-B6I017I1.js").then((m) => m.googleChatRenderer));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/download.ts
|
|
97
|
+
const FORMAT_MAP = {
|
|
98
|
+
html: "html",
|
|
99
|
+
htm: "html",
|
|
100
|
+
pdf: "pdf",
|
|
101
|
+
docx: "docx",
|
|
102
|
+
doc: "docx",
|
|
103
|
+
xlsx: "xlsx",
|
|
104
|
+
xls: "xlsx",
|
|
105
|
+
pptx: "pptx",
|
|
106
|
+
ppt: "pptx",
|
|
107
|
+
md: "md",
|
|
108
|
+
txt: "text",
|
|
109
|
+
csv: "csv",
|
|
110
|
+
svg: "svg"
|
|
111
|
+
};
|
|
112
|
+
const MIME_TYPES = {
|
|
113
|
+
html: "text/html",
|
|
114
|
+
pdf: "application/pdf",
|
|
115
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
116
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
117
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
118
|
+
email: "text/html",
|
|
119
|
+
md: "text/markdown",
|
|
120
|
+
text: "text/plain",
|
|
121
|
+
csv: "text/csv",
|
|
122
|
+
svg: "image/svg+xml"
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Download a document in the browser.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```tsx
|
|
129
|
+
* await download(doc, 'report.pdf')
|
|
130
|
+
* await download(doc, 'report.docx')
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
async function download(node, filename, options) {
|
|
134
|
+
const ext = filename.split(".").pop()?.toLowerCase();
|
|
135
|
+
if (!ext) throw new Error("[@pyreon/document] Filename must have an extension (e.g., report.pdf).");
|
|
136
|
+
const format = FORMAT_MAP[ext];
|
|
137
|
+
if (!format) throw new Error(`[@pyreon/document] Unknown file extension '.${ext}'. Supported: ${Object.keys(FORMAT_MAP).join(", ")}`);
|
|
138
|
+
const result = await render(node, format, options);
|
|
139
|
+
const blob = result instanceof Uint8Array ? new Blob([result]) : new Blob([result], { type: MIME_TYPES[format] ?? "application/octet-stream" });
|
|
140
|
+
const url = URL.createObjectURL(blob);
|
|
141
|
+
const a = document.createElement("a");
|
|
142
|
+
a.href = url;
|
|
143
|
+
a.download = filename;
|
|
144
|
+
a.click();
|
|
145
|
+
URL.revokeObjectURL(url);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/nodes.ts
|
|
150
|
+
function createNode(type, props, children) {
|
|
151
|
+
return {
|
|
152
|
+
type,
|
|
153
|
+
props,
|
|
154
|
+
children: normalizeChildren(children)
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function normalizeChildren(children) {
|
|
158
|
+
if (children == null || children === false) return [];
|
|
159
|
+
if (typeof children === "string") return [children];
|
|
160
|
+
if (typeof children === "number") return [String(children)];
|
|
161
|
+
if (Array.isArray(children)) return children.flatMap(normalizeChildren);
|
|
162
|
+
if (isDocNode(children)) return [children];
|
|
163
|
+
return [String(children)];
|
|
164
|
+
}
|
|
165
|
+
/** Type guard — checks if a value is a DocNode. */
|
|
166
|
+
function isDocNode(value) {
|
|
167
|
+
return typeof value === "object" && value !== null && "type" in value && "props" in value && "children" in value;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Root document container. Holds metadata and pages.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```tsx
|
|
174
|
+
* <Document title="Invoice #1234" author="Acme Corp">
|
|
175
|
+
* <Page>...</Page>
|
|
176
|
+
* </Document>
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
function Document(props) {
|
|
180
|
+
const { children, ...rest } = props;
|
|
181
|
+
return createNode("document", rest, children);
|
|
182
|
+
}
|
|
183
|
+
Document._documentType = "document";
|
|
184
|
+
/**
|
|
185
|
+
* Page container. Maps to a PDF page, DOCX section, or email block.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```tsx
|
|
189
|
+
* <Page size="A4" margin={40}>
|
|
190
|
+
* <Heading>Title</Heading>
|
|
191
|
+
* </Page>
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
function Page(props) {
|
|
195
|
+
const { children, ...rest } = props;
|
|
196
|
+
return createNode("page", rest, children);
|
|
197
|
+
}
|
|
198
|
+
Page._documentType = "page";
|
|
199
|
+
/**
|
|
200
|
+
* Layout section — groups content with optional direction, padding, background.
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```tsx
|
|
204
|
+
* <Section background="#f5f5f5" padding={20} direction="row" gap={12}>
|
|
205
|
+
* <Text>Left</Text>
|
|
206
|
+
* <Text>Right</Text>
|
|
207
|
+
* </Section>
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
function Section(props) {
|
|
211
|
+
const { children, ...rest } = props;
|
|
212
|
+
return createNode("section", rest, children);
|
|
213
|
+
}
|
|
214
|
+
Section._documentType = "section";
|
|
215
|
+
/**
|
|
216
|
+
* Horizontal layout container.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```tsx
|
|
220
|
+
* <Row gap={20}>
|
|
221
|
+
* <Column width="60%"><Text>Main</Text></Column>
|
|
222
|
+
* <Column width="40%"><Text>Side</Text></Column>
|
|
223
|
+
* </Row>
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
function Row(props) {
|
|
227
|
+
const { children, ...rest } = props;
|
|
228
|
+
return createNode("row", rest, children);
|
|
229
|
+
}
|
|
230
|
+
Row._documentType = "row";
|
|
231
|
+
/**
|
|
232
|
+
* Column within a Row.
|
|
233
|
+
*/
|
|
234
|
+
function Column(props) {
|
|
235
|
+
const { children, ...rest } = props;
|
|
236
|
+
return createNode("column", rest, children);
|
|
237
|
+
}
|
|
238
|
+
Column._documentType = "column";
|
|
239
|
+
/**
|
|
240
|
+
* Heading text (h1–h6).
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```tsx
|
|
244
|
+
* <Heading level={1}>Invoice #1234</Heading>
|
|
245
|
+
* <Heading level={2} color="#666">Details</Heading>
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
function Heading(props) {
|
|
249
|
+
const { children, ...rest } = props;
|
|
250
|
+
return createNode("heading", {
|
|
251
|
+
level: 1,
|
|
252
|
+
...rest
|
|
253
|
+
}, children);
|
|
254
|
+
}
|
|
255
|
+
Heading._documentType = "heading";
|
|
256
|
+
/**
|
|
257
|
+
* Text paragraph with optional formatting.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```tsx
|
|
261
|
+
* <Text bold size={14} color="#333">Hello World</Text>
|
|
262
|
+
* <Text italic align="right">Subtotal: $100</Text>
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
function Text(props) {
|
|
266
|
+
const { children, ...rest } = props;
|
|
267
|
+
return createNode("text", rest, children);
|
|
268
|
+
}
|
|
269
|
+
Text._documentType = "text";
|
|
270
|
+
/**
|
|
271
|
+
* Hyperlink.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```tsx
|
|
275
|
+
* <Link href="https://example.com">Visit site</Link>
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
function Link(props) {
|
|
279
|
+
const { children, ...rest } = props;
|
|
280
|
+
return createNode("link", rest, children);
|
|
281
|
+
}
|
|
282
|
+
Link._documentType = "link";
|
|
283
|
+
/**
|
|
284
|
+
* Image with optional sizing and caption.
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```tsx
|
|
288
|
+
* <Image src="/logo.png" width={120} alt="Company Logo" />
|
|
289
|
+
* <Image src={chartDataUrl} width={500} caption="Revenue Chart" />
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
function Image(props) {
|
|
293
|
+
return createNode("image", props, []);
|
|
294
|
+
}
|
|
295
|
+
Image._documentType = "image";
|
|
296
|
+
/**
|
|
297
|
+
* Data table with columns and rows.
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```tsx
|
|
301
|
+
* <Table
|
|
302
|
+
* columns={['Name', 'Price', 'Qty']}
|
|
303
|
+
* rows={[['Widget', '$10', '5'], ['Gadget', '$20', '3']]}
|
|
304
|
+
* striped
|
|
305
|
+
* headerStyle={{ background: '#1a1a2e', color: '#fff' }}
|
|
306
|
+
* />
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
function Table(props) {
|
|
310
|
+
return createNode("table", props, []);
|
|
311
|
+
}
|
|
312
|
+
Table._documentType = "table";
|
|
313
|
+
/**
|
|
314
|
+
* Ordered or unordered list.
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* ```tsx
|
|
318
|
+
* <List ordered>
|
|
319
|
+
* <ListItem>First item</ListItem>
|
|
320
|
+
* <ListItem>Second item</ListItem>
|
|
321
|
+
* </List>
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
function List(props) {
|
|
325
|
+
const { children, ...rest } = props;
|
|
326
|
+
return createNode("list", rest, children);
|
|
327
|
+
}
|
|
328
|
+
List._documentType = "list";
|
|
329
|
+
/**
|
|
330
|
+
* Single list item within a List.
|
|
331
|
+
*/
|
|
332
|
+
function ListItem(props) {
|
|
333
|
+
const { children } = props;
|
|
334
|
+
return createNode("list-item", {}, children);
|
|
335
|
+
}
|
|
336
|
+
ListItem._documentType = "list-item";
|
|
337
|
+
/**
|
|
338
|
+
* Code block with optional language hint.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```tsx
|
|
342
|
+
* <Code language="typescript">const x = 42</Code>
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
function Code(props) {
|
|
346
|
+
const { children, ...rest } = props;
|
|
347
|
+
return createNode("code", rest, children);
|
|
348
|
+
}
|
|
349
|
+
Code._documentType = "code";
|
|
350
|
+
/**
|
|
351
|
+
* Horizontal divider line.
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```tsx
|
|
355
|
+
* <Divider color="#ddd" thickness={2} />
|
|
356
|
+
* ```
|
|
357
|
+
*/
|
|
358
|
+
function Divider(props = {}) {
|
|
359
|
+
return createNode("divider", props, []);
|
|
360
|
+
}
|
|
361
|
+
Divider._documentType = "divider";
|
|
362
|
+
/**
|
|
363
|
+
* Page break — forces content after this point to the next page (PDF/DOCX)
|
|
364
|
+
* or inserts a visual separator (HTML/email).
|
|
365
|
+
*
|
|
366
|
+
* @example
|
|
367
|
+
* ```tsx
|
|
368
|
+
* <PageBreak />
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
function PageBreak() {
|
|
372
|
+
return createNode("page-break", {}, []);
|
|
373
|
+
}
|
|
374
|
+
PageBreak._documentType = "page-break";
|
|
375
|
+
/**
|
|
376
|
+
* Vertical spacer.
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```tsx
|
|
380
|
+
* <Spacer height={20} />
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
function Spacer(props) {
|
|
384
|
+
return createNode("spacer", props, []);
|
|
385
|
+
}
|
|
386
|
+
Spacer._documentType = "spacer";
|
|
387
|
+
/**
|
|
388
|
+
* CTA button — renders as a bulletproof button in email, styled link in PDF/DOCX.
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```tsx
|
|
392
|
+
* <Button href="https://acme.com/pay" background="#4f46e5" color="#fff">
|
|
393
|
+
* Pay Now
|
|
394
|
+
* </Button>
|
|
395
|
+
* ```
|
|
396
|
+
*/
|
|
397
|
+
function Button(props) {
|
|
398
|
+
const { children, ...rest } = props;
|
|
399
|
+
return createNode("button", rest, children);
|
|
400
|
+
}
|
|
401
|
+
Button._documentType = "button";
|
|
402
|
+
/**
|
|
403
|
+
* Block quote.
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* ```tsx
|
|
407
|
+
* <Quote borderColor="#4f46e5">This is a quote.</Quote>
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
function Quote(props) {
|
|
411
|
+
const { children, ...rest } = props;
|
|
412
|
+
return createNode("quote", rest, children);
|
|
413
|
+
}
|
|
414
|
+
Quote._documentType = "quote";
|
|
415
|
+
|
|
416
|
+
//#endregion
|
|
417
|
+
//#region src/builder.ts
|
|
418
|
+
/**
|
|
419
|
+
* Create a document using the builder pattern — no JSX needed.
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```ts
|
|
423
|
+
* const doc = createDocument({ title: 'Report' })
|
|
424
|
+
* .heading('Sales Report')
|
|
425
|
+
* .text('Q4 performance summary.')
|
|
426
|
+
* .table({ columns: ['Region', 'Revenue'], rows: [['US', '$1M']] })
|
|
427
|
+
*
|
|
428
|
+
* await doc.toPdf()
|
|
429
|
+
* await doc.download('report.pdf')
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
function createDocument(props = {}) {
|
|
433
|
+
const sections = [];
|
|
434
|
+
function getNode() {
|
|
435
|
+
return Document({
|
|
436
|
+
...props,
|
|
437
|
+
children: [Page({ children: sections })]
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
const builder = {
|
|
441
|
+
heading(text, p) {
|
|
442
|
+
sections.push(Heading({
|
|
443
|
+
...p,
|
|
444
|
+
children: text
|
|
445
|
+
}));
|
|
446
|
+
return builder;
|
|
447
|
+
},
|
|
448
|
+
text(text, p) {
|
|
449
|
+
sections.push(Text({
|
|
450
|
+
...p,
|
|
451
|
+
children: text
|
|
452
|
+
}));
|
|
453
|
+
return builder;
|
|
454
|
+
},
|
|
455
|
+
paragraph(text, p) {
|
|
456
|
+
return builder.text(text, p);
|
|
457
|
+
},
|
|
458
|
+
image(src, p) {
|
|
459
|
+
sections.push(Image({
|
|
460
|
+
src,
|
|
461
|
+
...p
|
|
462
|
+
}));
|
|
463
|
+
return builder;
|
|
464
|
+
},
|
|
465
|
+
table(p) {
|
|
466
|
+
sections.push(Table(p));
|
|
467
|
+
return builder;
|
|
468
|
+
},
|
|
469
|
+
list(items, p) {
|
|
470
|
+
sections.push(List({
|
|
471
|
+
...p,
|
|
472
|
+
children: items.map((item) => ListItem({ children: item }))
|
|
473
|
+
}));
|
|
474
|
+
return builder;
|
|
475
|
+
},
|
|
476
|
+
code(text, p) {
|
|
477
|
+
sections.push(Code({
|
|
478
|
+
...p,
|
|
479
|
+
children: text
|
|
480
|
+
}));
|
|
481
|
+
return builder;
|
|
482
|
+
},
|
|
483
|
+
divider(p) {
|
|
484
|
+
sections.push(Divider(p));
|
|
485
|
+
return builder;
|
|
486
|
+
},
|
|
487
|
+
spacer(height) {
|
|
488
|
+
sections.push(Spacer({ height }));
|
|
489
|
+
return builder;
|
|
490
|
+
},
|
|
491
|
+
quote(text, p) {
|
|
492
|
+
sections.push(Quote({
|
|
493
|
+
...p,
|
|
494
|
+
children: text
|
|
495
|
+
}));
|
|
496
|
+
return builder;
|
|
497
|
+
},
|
|
498
|
+
button(text, p) {
|
|
499
|
+
sections.push(Button({
|
|
500
|
+
...p,
|
|
501
|
+
children: text
|
|
502
|
+
}));
|
|
503
|
+
return builder;
|
|
504
|
+
},
|
|
505
|
+
link(text, p) {
|
|
506
|
+
sections.push(Link({
|
|
507
|
+
...p,
|
|
508
|
+
children: text
|
|
509
|
+
}));
|
|
510
|
+
return builder;
|
|
511
|
+
},
|
|
512
|
+
pageBreak() {
|
|
513
|
+
sections.push(PageBreak());
|
|
514
|
+
return builder;
|
|
515
|
+
},
|
|
516
|
+
chart(instance, p) {
|
|
517
|
+
const inst = instance;
|
|
518
|
+
if (inst?.getDataURL) {
|
|
519
|
+
const dataUrl = inst.getDataURL({
|
|
520
|
+
type: "png",
|
|
521
|
+
pixelRatio: 2
|
|
522
|
+
});
|
|
523
|
+
sections.push(Image({
|
|
524
|
+
src: dataUrl,
|
|
525
|
+
width: p?.width,
|
|
526
|
+
height: p?.height,
|
|
527
|
+
caption: p?.caption
|
|
528
|
+
}));
|
|
529
|
+
} else sections.push(Text({
|
|
530
|
+
children: "[Chart]",
|
|
531
|
+
italic: true,
|
|
532
|
+
color: "#999"
|
|
533
|
+
}));
|
|
534
|
+
return builder;
|
|
535
|
+
},
|
|
536
|
+
flow(instance, p) {
|
|
537
|
+
const inst = instance;
|
|
538
|
+
if (inst?.toSVG) {
|
|
539
|
+
const svg = inst.toSVG();
|
|
540
|
+
sections.push(Image({
|
|
541
|
+
src: `data:image/svg+xml,${encodeURIComponent(svg)}`,
|
|
542
|
+
width: p?.width,
|
|
543
|
+
height: p?.height,
|
|
544
|
+
caption: p?.caption
|
|
545
|
+
}));
|
|
546
|
+
} else sections.push(Text({
|
|
547
|
+
children: "[Flow Diagram]",
|
|
548
|
+
italic: true,
|
|
549
|
+
color: "#999"
|
|
550
|
+
}));
|
|
551
|
+
return builder;
|
|
552
|
+
},
|
|
553
|
+
build() {
|
|
554
|
+
return getNode();
|
|
555
|
+
},
|
|
556
|
+
async toHtml(options) {
|
|
557
|
+
return render(getNode(), "html", options);
|
|
558
|
+
},
|
|
559
|
+
async toPdf(options) {
|
|
560
|
+
return render(getNode(), "pdf", options);
|
|
561
|
+
},
|
|
562
|
+
async toDocx(options) {
|
|
563
|
+
return render(getNode(), "docx", options);
|
|
564
|
+
},
|
|
565
|
+
async toEmail(options) {
|
|
566
|
+
return render(getNode(), "email", options);
|
|
567
|
+
},
|
|
568
|
+
async toPptx(options) {
|
|
569
|
+
return render(getNode(), "pptx", options);
|
|
570
|
+
},
|
|
571
|
+
async toXlsx(options) {
|
|
572
|
+
return render(getNode(), "xlsx", options);
|
|
573
|
+
},
|
|
574
|
+
async toMarkdown(options) {
|
|
575
|
+
return render(getNode(), "md", options);
|
|
576
|
+
},
|
|
577
|
+
async toText(options) {
|
|
578
|
+
return render(getNode(), "text", options);
|
|
579
|
+
},
|
|
580
|
+
async toCsv(options) {
|
|
581
|
+
return render(getNode(), "csv", options);
|
|
582
|
+
},
|
|
583
|
+
async toSlack(options) {
|
|
584
|
+
return render(getNode(), "slack", options);
|
|
585
|
+
},
|
|
586
|
+
async toSvg(options) {
|
|
587
|
+
return render(getNode(), "svg", options);
|
|
588
|
+
},
|
|
589
|
+
async toTeams(options) {
|
|
590
|
+
return render(getNode(), "teams", options);
|
|
591
|
+
},
|
|
592
|
+
async toDiscord(options) {
|
|
593
|
+
return render(getNode(), "discord", options);
|
|
594
|
+
},
|
|
595
|
+
async toTelegram(options) {
|
|
596
|
+
return render(getNode(), "telegram", options);
|
|
597
|
+
},
|
|
598
|
+
async toNotion(options) {
|
|
599
|
+
return render(getNode(), "notion", options);
|
|
600
|
+
},
|
|
601
|
+
async toConfluence(options) {
|
|
602
|
+
return render(getNode(), "confluence", options);
|
|
603
|
+
},
|
|
604
|
+
async toWhatsApp(options) {
|
|
605
|
+
return render(getNode(), "whatsapp", options);
|
|
606
|
+
},
|
|
607
|
+
async toGoogleChat(options) {
|
|
608
|
+
return render(getNode(), "google-chat", options);
|
|
609
|
+
},
|
|
610
|
+
async download(filename, options) {
|
|
611
|
+
return download(getNode(), filename, options);
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
return builder;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
//#endregion
|
|
618
|
+
export { Button, Code, Column, Divider, Document, Heading, Image, Link, List, ListItem, Page, PageBreak, Quote, Row, Section, Spacer, Table, Text, _resetRenderers, createDocument, download, isDocNode, registerRenderer, render, unregisterRenderer };
|
|
619
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/render.ts","../src/download.ts","../src/nodes.ts","../src/builder.ts"],"sourcesContent":["import type {\n DocNode,\n DocumentRenderer,\n OutputFormat,\n RenderOptions,\n RenderResult,\n} from './types'\n\n// ─── Renderer Registry ──────────────────────────────────────────────────────\n\nconst renderers = new Map<\n string,\n DocumentRenderer | (() => Promise<DocumentRenderer>)\n>()\n\n/**\n * Register a custom renderer for a format.\n *\n * @example\n * ```ts\n * registerRenderer('thermal', {\n * render(node, options) {\n * // Walk nodes → ESC/POS commands\n * return escPosBuffer\n * },\n * })\n *\n * await render(receipt, 'thermal')\n * ```\n */\nexport function registerRenderer(\n format: string,\n renderer: DocumentRenderer | (() => Promise<DocumentRenderer>),\n): void {\n renderers.set(format, renderer)\n}\n\n/**\n * Remove a registered renderer.\n */\nexport function unregisterRenderer(format: string): void {\n renderers.delete(format)\n}\n\n// ─── Built-in Renderer Loaders ──────────────────────────────────────────────\n\n// Built-in renderers are registered lazily — only loaded when first used.\n\nregisterRenderer('html', () =>\n import('./renderers/html').then((m) => m.htmlRenderer),\n)\n\nregisterRenderer('email', () =>\n import('./renderers/email').then((m) => m.emailRenderer),\n)\n\nregisterRenderer('md', () =>\n import('./renderers/markdown').then((m) => m.markdownRenderer),\n)\n\nregisterRenderer('text', () =>\n import('./renderers/text').then((m) => m.textRenderer),\n)\n\nregisterRenderer('csv', () =>\n import('./renderers/csv').then((m) => m.csvRenderer),\n)\n\nregisterRenderer('pdf', () =>\n import('./renderers/pdf').then((m) => m.pdfRenderer),\n)\n\nregisterRenderer('docx', () =>\n import('./renderers/docx').then((m) => m.docxRenderer),\n)\n\nregisterRenderer('xlsx', () =>\n import('./renderers/xlsx').then((m) => m.xlsxRenderer),\n)\n\nregisterRenderer('pptx', () =>\n import('./renderers/pptx').then((m) => m.pptxRenderer),\n)\n\nregisterRenderer('slack', () =>\n import('./renderers/slack').then((m) => m.slackRenderer),\n)\n\nregisterRenderer('svg', () =>\n import('./renderers/svg').then((m) => m.svgRenderer),\n)\n\nregisterRenderer('teams', () =>\n import('./renderers/teams').then((m) => m.teamsRenderer),\n)\n\nregisterRenderer('discord', () =>\n import('./renderers/discord').then((m) => m.discordRenderer),\n)\n\nregisterRenderer('telegram', () =>\n import('./renderers/telegram').then((m) => m.telegramRenderer),\n)\n\nregisterRenderer('notion', () =>\n import('./renderers/notion').then((m) => m.notionRenderer),\n)\n\nregisterRenderer('confluence', () =>\n import('./renderers/confluence').then((m) => m.confluenceRenderer),\n)\n\nregisterRenderer('whatsapp', () =>\n import('./renderers/whatsapp').then((m) => m.whatsappRenderer),\n)\n\nregisterRenderer('google-chat', () =>\n import('./renderers/google-chat').then((m) => m.googleChatRenderer),\n)\n\n// ─── Render Function ────────────────────────────────────────────────────────\n\nasync function resolveRenderer(format: string): Promise<DocumentRenderer> {\n const entry = renderers.get(format)\n if (!entry) {\n throw new Error(\n `[@pyreon/document] No renderer registered for format '${format}'. Available: ${[...renderers.keys()].join(', ')}`,\n )\n }\n\n if (typeof entry === 'function') {\n const renderer = await entry()\n // Cache the resolved renderer so we don't re-import\n renderers.set(format, renderer)\n return renderer\n }\n\n return entry\n}\n\n/**\n * Render a document node tree to the specified format.\n *\n * @example\n * ```tsx\n * const doc = <Document title=\"Report\"><Page>...</Page></Document>\n *\n * const html = await render(doc, 'html') // → HTML string\n * const pdf = await render(doc, 'pdf') // → PDF Uint8Array\n * const docx = await render(doc, 'docx') // → DOCX Uint8Array\n * const email = await render(doc, 'email') // → email-safe HTML string\n * const md = await render(doc, 'md') // → Markdown string\n * ```\n */\nexport async function render(\n node: DocNode,\n format: OutputFormat | string,\n options?: RenderOptions,\n): Promise<RenderResult> {\n const renderer = await resolveRenderer(format)\n return renderer.render(node, options)\n}\n\n/** @internal For testing — reset renderer registry to defaults. */\nexport function _resetRenderers(): void {\n renderers.clear()\n // Re-register built-in lazy loaders\n registerRenderer('html', () =>\n import('./renderers/html').then((m) => m.htmlRenderer),\n )\n registerRenderer('email', () =>\n import('./renderers/email').then((m) => m.emailRenderer),\n )\n registerRenderer('md', () =>\n import('./renderers/markdown').then((m) => m.markdownRenderer),\n )\n registerRenderer('text', () =>\n import('./renderers/text').then((m) => m.textRenderer),\n )\n registerRenderer('csv', () =>\n import('./renderers/csv').then((m) => m.csvRenderer),\n )\n registerRenderer('pdf', () =>\n import('./renderers/pdf').then((m) => m.pdfRenderer),\n )\n registerRenderer('docx', () =>\n import('./renderers/docx').then((m) => m.docxRenderer),\n )\n registerRenderer('xlsx', () =>\n import('./renderers/xlsx').then((m) => m.xlsxRenderer),\n )\n registerRenderer('pptx', () =>\n import('./renderers/pptx').then((m) => m.pptxRenderer),\n )\n registerRenderer('slack', () =>\n import('./renderers/slack').then((m) => m.slackRenderer),\n )\n registerRenderer('svg', () =>\n import('./renderers/svg').then((m) => m.svgRenderer),\n )\n registerRenderer('teams', () =>\n import('./renderers/teams').then((m) => m.teamsRenderer),\n )\n registerRenderer('discord', () =>\n import('./renderers/discord').then((m) => m.discordRenderer),\n )\n registerRenderer('telegram', () =>\n import('./renderers/telegram').then((m) => m.telegramRenderer),\n )\n registerRenderer('notion', () =>\n import('./renderers/notion').then((m) => m.notionRenderer),\n )\n registerRenderer('confluence', () =>\n import('./renderers/confluence').then((m) => m.confluenceRenderer),\n )\n registerRenderer('whatsapp', () =>\n import('./renderers/whatsapp').then((m) => m.whatsappRenderer),\n )\n registerRenderer('google-chat', () =>\n import('./renderers/google-chat').then((m) => m.googleChatRenderer),\n )\n}\n","import { render } from './render'\nimport type { DocNode, RenderOptions } from './types'\n\nconst FORMAT_MAP: Record<string, string> = {\n html: 'html',\n htm: 'html',\n pdf: 'pdf',\n docx: 'docx',\n doc: 'docx',\n xlsx: 'xlsx',\n xls: 'xlsx',\n pptx: 'pptx',\n ppt: 'pptx',\n md: 'md',\n txt: 'text',\n csv: 'csv',\n svg: 'svg',\n}\n\nconst MIME_TYPES: Record<string, string> = {\n html: 'text/html',\n pdf: 'application/pdf',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n email: 'text/html',\n md: 'text/markdown',\n text: 'text/plain',\n csv: 'text/csv',\n svg: 'image/svg+xml',\n}\n\n/**\n * Download a document in the browser.\n *\n * @example\n * ```tsx\n * await download(doc, 'report.pdf')\n * await download(doc, 'report.docx')\n * ```\n */\nexport async function download(\n node: DocNode,\n filename: string,\n options?: RenderOptions,\n): Promise<void> {\n const ext = filename.split('.').pop()?.toLowerCase()\n if (!ext) {\n throw new Error(\n '[@pyreon/document] Filename must have an extension (e.g., report.pdf).',\n )\n }\n\n const format = FORMAT_MAP[ext]\n if (!format) {\n throw new Error(\n `[@pyreon/document] Unknown file extension '.${ext}'. Supported: ${Object.keys(FORMAT_MAP).join(', ')}`,\n )\n }\n\n const result = await render(node, format, options)\n\n const blob =\n result instanceof Uint8Array\n ? new Blob([result as BlobPart])\n : new Blob([result], {\n type: MIME_TYPES[format] ?? 'application/octet-stream',\n })\n\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n a.click()\n URL.revokeObjectURL(url)\n}\n","import type {\n ButtonProps,\n CodeProps,\n ColumnProps,\n DividerProps,\n DocChild,\n DocNode,\n DocumentProps,\n HeadingProps,\n ImageProps,\n LinkProps,\n ListItemProps,\n ListProps,\n NodeType,\n PageProps,\n QuoteProps,\n RowProps,\n SectionProps,\n SpacerProps,\n TableProps,\n TextProps,\n} from './types'\n\n// ─── Node Constructor ───────────────────────────────────────────────────────\n\nfunction createNode(type: NodeType, props: object, children: unknown): DocNode {\n return {\n type,\n props: props as Record<string, unknown>,\n children: normalizeChildren(children),\n }\n}\n\nfunction normalizeChildren(children: unknown): DocChild[] {\n if (children == null || children === false) return []\n if (typeof children === 'string') return [children]\n if (typeof children === 'number') return [String(children)]\n if (Array.isArray(children)) return children.flatMap(normalizeChildren)\n if (isDocNode(children)) return [children]\n return [String(children)]\n}\n\n/** Type guard — checks if a value is a DocNode. */\nexport function isDocNode(value: unknown): value is DocNode {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n 'props' in value &&\n 'children' in value\n )\n}\n\n// ─── Document Primitives ────────────────────────────────────────────────────\n\n/**\n * Root document container. Holds metadata and pages.\n *\n * @example\n * ```tsx\n * <Document title=\"Invoice #1234\" author=\"Acme Corp\">\n * <Page>...</Page>\n * </Document>\n * ```\n */\nexport function Document(props: DocumentProps): DocNode {\n const { children, ...rest } = props\n return createNode('document', rest, children)\n}\nDocument._documentType = 'document' as const\n\n/**\n * Page container. Maps to a PDF page, DOCX section, or email block.\n *\n * @example\n * ```tsx\n * <Page size=\"A4\" margin={40}>\n * <Heading>Title</Heading>\n * </Page>\n * ```\n */\nexport function Page(props: PageProps): DocNode {\n const { children, ...rest } = props\n return createNode('page', rest, children)\n}\nPage._documentType = 'page' as const\n\n/**\n * Layout section — groups content with optional direction, padding, background.\n *\n * @example\n * ```tsx\n * <Section background=\"#f5f5f5\" padding={20} direction=\"row\" gap={12}>\n * <Text>Left</Text>\n * <Text>Right</Text>\n * </Section>\n * ```\n */\nexport function Section(props: SectionProps): DocNode {\n const { children, ...rest } = props\n return createNode('section', rest, children)\n}\nSection._documentType = 'section' as const\n\n/**\n * Horizontal layout container.\n *\n * @example\n * ```tsx\n * <Row gap={20}>\n * <Column width=\"60%\"><Text>Main</Text></Column>\n * <Column width=\"40%\"><Text>Side</Text></Column>\n * </Row>\n * ```\n */\nexport function Row(props: RowProps): DocNode {\n const { children, ...rest } = props\n return createNode('row', rest, children)\n}\nRow._documentType = 'row' as const\n\n/**\n * Column within a Row.\n */\nexport function Column(props: ColumnProps): DocNode {\n const { children, ...rest } = props\n return createNode('column', rest, children)\n}\nColumn._documentType = 'column' as const\n\n/**\n * Heading text (h1–h6).\n *\n * @example\n * ```tsx\n * <Heading level={1}>Invoice #1234</Heading>\n * <Heading level={2} color=\"#666\">Details</Heading>\n * ```\n */\nexport function Heading(props: HeadingProps): DocNode {\n const { children, ...rest } = props\n return createNode('heading', { level: 1, ...rest }, children)\n}\nHeading._documentType = 'heading' as const\n\n/**\n * Text paragraph with optional formatting.\n *\n * @example\n * ```tsx\n * <Text bold size={14} color=\"#333\">Hello World</Text>\n * <Text italic align=\"right\">Subtotal: $100</Text>\n * ```\n */\nexport function Text(props: TextProps): DocNode {\n const { children, ...rest } = props\n return createNode('text', rest, children)\n}\nText._documentType = 'text' as const\n\n/**\n * Hyperlink.\n *\n * @example\n * ```tsx\n * <Link href=\"https://example.com\">Visit site</Link>\n * ```\n */\nexport function Link(props: LinkProps): DocNode {\n const { children, ...rest } = props\n return createNode('link', rest, children)\n}\nLink._documentType = 'link' as const\n\n/**\n * Image with optional sizing and caption.\n *\n * @example\n * ```tsx\n * <Image src=\"/logo.png\" width={120} alt=\"Company Logo\" />\n * <Image src={chartDataUrl} width={500} caption=\"Revenue Chart\" />\n * ```\n */\nexport function Image(props: ImageProps): DocNode {\n return createNode('image', props, [])\n}\nImage._documentType = 'image' as const\n\n/**\n * Data table with columns and rows.\n *\n * @example\n * ```tsx\n * <Table\n * columns={['Name', 'Price', 'Qty']}\n * rows={[['Widget', '$10', '5'], ['Gadget', '$20', '3']]}\n * striped\n * headerStyle={{ background: '#1a1a2e', color: '#fff' }}\n * />\n * ```\n */\nexport function Table(props: TableProps): DocNode {\n return createNode('table', props, [])\n}\nTable._documentType = 'table' as const\n\n/**\n * Ordered or unordered list.\n *\n * @example\n * ```tsx\n * <List ordered>\n * <ListItem>First item</ListItem>\n * <ListItem>Second item</ListItem>\n * </List>\n * ```\n */\nexport function List(props: ListProps): DocNode {\n const { children, ...rest } = props\n return createNode('list', rest, children)\n}\nList._documentType = 'list' as const\n\n/**\n * Single list item within a List.\n */\nexport function ListItem(props: ListItemProps): DocNode {\n const { children } = props\n return createNode('list-item', {}, children)\n}\nListItem._documentType = 'list-item' as const\n\n/**\n * Code block with optional language hint.\n *\n * @example\n * ```tsx\n * <Code language=\"typescript\">const x = 42</Code>\n * ```\n */\nexport function Code(props: CodeProps): DocNode {\n const { children, ...rest } = props\n return createNode('code', rest, children)\n}\nCode._documentType = 'code' as const\n\n/**\n * Horizontal divider line.\n *\n * @example\n * ```tsx\n * <Divider color=\"#ddd\" thickness={2} />\n * ```\n */\nexport function Divider(props: DividerProps = {}): DocNode {\n return createNode('divider', props, [])\n}\nDivider._documentType = 'divider' as const\n\n/**\n * Page break — forces content after this point to the next page (PDF/DOCX)\n * or inserts a visual separator (HTML/email).\n *\n * @example\n * ```tsx\n * <PageBreak />\n * ```\n */\nexport function PageBreak(): DocNode {\n return createNode('page-break', {}, [])\n}\nPageBreak._documentType = 'page-break' as const\n\n/**\n * Vertical spacer.\n *\n * @example\n * ```tsx\n * <Spacer height={20} />\n * ```\n */\nexport function Spacer(props: SpacerProps): DocNode {\n return createNode('spacer', props, [])\n}\nSpacer._documentType = 'spacer' as const\n\n/**\n * CTA button — renders as a bulletproof button in email, styled link in PDF/DOCX.\n *\n * @example\n * ```tsx\n * <Button href=\"https://acme.com/pay\" background=\"#4f46e5\" color=\"#fff\">\n * Pay Now\n * </Button>\n * ```\n */\nexport function Button(props: ButtonProps): DocNode {\n const { children, ...rest } = props\n return createNode('button', rest, children)\n}\nButton._documentType = 'button' as const\n\n/**\n * Block quote.\n *\n * @example\n * ```tsx\n * <Quote borderColor=\"#4f46e5\">This is a quote.</Quote>\n * ```\n */\nexport function Quote(props: QuoteProps): DocNode {\n const { children, ...rest } = props\n return createNode('quote', rest, children)\n}\nQuote._documentType = 'quote' as const\n","import { download } from './download'\nimport {\n Button,\n Code,\n Divider,\n Document,\n Heading,\n Image,\n Link,\n List,\n ListItem,\n Page,\n PageBreak,\n Quote,\n Spacer,\n Table,\n Text,\n} from './nodes'\nimport { render } from './render'\nimport type {\n ButtonProps,\n CodeProps,\n DividerProps,\n DocNode,\n DocumentBuilder,\n DocumentProps,\n HeadingProps,\n ImageProps,\n LinkProps,\n ListProps,\n QuoteProps,\n RenderOptions,\n TableProps,\n TextProps,\n} from './types'\n\n/**\n * Create a document using the builder pattern — no JSX needed.\n *\n * @example\n * ```ts\n * const doc = createDocument({ title: 'Report' })\n * .heading('Sales Report')\n * .text('Q4 performance summary.')\n * .table({ columns: ['Region', 'Revenue'], rows: [['US', '$1M']] })\n *\n * await doc.toPdf()\n * await doc.download('report.pdf')\n * ```\n */\nexport function createDocument(props: DocumentProps = {}): DocumentBuilder {\n const sections: DocNode[] = []\n\n function getNode(): DocNode {\n return Document({ ...props, children: [Page({ children: sections })] })\n }\n\n const builder: DocumentBuilder = {\n heading(text: string, p?: Omit<HeadingProps, 'children'>) {\n sections.push(Heading({ ...p, children: text }))\n return builder\n },\n\n text(text: string, p?: Omit<TextProps, 'children'>) {\n sections.push(Text({ ...p, children: text }))\n return builder\n },\n\n paragraph(text: string, p?: Omit<TextProps, 'children'>) {\n return builder.text(text, p)\n },\n\n image(src: string, p?: Omit<ImageProps, 'src'>) {\n sections.push(Image({ src, ...p }))\n return builder\n },\n\n table(p: TableProps) {\n sections.push(Table(p))\n return builder\n },\n\n list(items: string[], p?: Omit<ListProps, 'children'>) {\n sections.push(\n List({\n ...p,\n children: items.map((item) => ListItem({ children: item })),\n }),\n )\n return builder\n },\n\n code(text: string, p?: Omit<CodeProps, 'children'>) {\n sections.push(Code({ ...p, children: text }))\n return builder\n },\n\n divider(p?: DividerProps) {\n sections.push(Divider(p))\n return builder\n },\n\n spacer(height: number) {\n sections.push(Spacer({ height }))\n return builder\n },\n\n quote(text: string, p?: Omit<QuoteProps, 'children'>) {\n sections.push(Quote({ ...p, children: text }))\n return builder\n },\n\n button(text: string, p: Omit<ButtonProps, 'children'>) {\n sections.push(Button({ ...p, children: text }))\n return builder\n },\n\n link(text: string, p: Omit<LinkProps, 'children'>) {\n sections.push(Link({ ...p, children: text }))\n return builder\n },\n\n pageBreak() {\n sections.push(PageBreak())\n return builder\n },\n\n chart(\n instance: unknown,\n p?: { width?: number; height?: number; caption?: string },\n ) {\n // Try to get data URL from chart instance\n const inst = instance as { getDataURL?: (opts: unknown) => string }\n if (inst?.getDataURL) {\n const dataUrl = inst.getDataURL({ type: 'png', pixelRatio: 2 })\n sections.push(\n Image({\n src: dataUrl,\n width: p?.width,\n height: p?.height,\n caption: p?.caption,\n }),\n )\n } else {\n sections.push(\n Text({\n children: '[Chart]',\n italic: true,\n color: '#999',\n } as TextProps & { children: string }),\n )\n }\n return builder\n },\n\n flow(\n instance: unknown,\n p?: { width?: number; height?: number; caption?: string },\n ) {\n // Try to get SVG from flow instance\n const inst = instance as { toSVG?: () => string }\n if (inst?.toSVG) {\n const svg = inst.toSVG()\n sections.push(\n Image({\n src: `data:image/svg+xml,${encodeURIComponent(svg)}`,\n width: p?.width,\n height: p?.height,\n caption: p?.caption,\n }),\n )\n } else {\n sections.push(\n Text({\n children: '[Flow Diagram]',\n italic: true,\n color: '#999',\n } as TextProps & { children: string }),\n )\n }\n return builder\n },\n\n build() {\n return getNode()\n },\n\n async toHtml(options?: RenderOptions) {\n return render(getNode(), 'html', options) as Promise<string>\n },\n\n async toPdf(options?: RenderOptions) {\n return render(getNode(), 'pdf', options) as Promise<Uint8Array>\n },\n\n async toDocx(options?: RenderOptions) {\n return render(getNode(), 'docx', options) as Promise<Uint8Array>\n },\n\n async toEmail(options?: RenderOptions) {\n return render(getNode(), 'email', options) as Promise<string>\n },\n\n async toPptx(options?: RenderOptions) {\n return render(getNode(), 'pptx', options) as Promise<Uint8Array>\n },\n\n async toXlsx(options?: RenderOptions) {\n return render(getNode(), 'xlsx', options) as Promise<Uint8Array>\n },\n\n async toMarkdown(options?: RenderOptions) {\n return render(getNode(), 'md', options) as Promise<string>\n },\n\n async toText(options?: RenderOptions) {\n return render(getNode(), 'text', options) as Promise<string>\n },\n\n async toCsv(options?: RenderOptions) {\n return render(getNode(), 'csv', options) as Promise<string>\n },\n\n async toSlack(options?: RenderOptions) {\n return render(getNode(), 'slack', options) as Promise<string>\n },\n\n async toSvg(options?: RenderOptions) {\n return render(getNode(), 'svg', options) as Promise<string>\n },\n\n async toTeams(options?: RenderOptions) {\n return render(getNode(), 'teams', options) as Promise<string>\n },\n\n async toDiscord(options?: RenderOptions) {\n return render(getNode(), 'discord', options) as Promise<string>\n },\n\n async toTelegram(options?: RenderOptions) {\n return render(getNode(), 'telegram', options) as Promise<string>\n },\n\n async toNotion(options?: RenderOptions) {\n return render(getNode(), 'notion', options) as Promise<string>\n },\n\n async toConfluence(options?: RenderOptions) {\n return render(getNode(), 'confluence', options) as Promise<string>\n },\n\n async toWhatsApp(options?: RenderOptions) {\n return render(getNode(), 'whatsapp', options) as Promise<string>\n },\n\n async toGoogleChat(options?: RenderOptions) {\n return render(getNode(), 'google-chat', options) as Promise<string>\n },\n\n async download(filename: string, options?: RenderOptions) {\n return download(getNode(), filename, options)\n },\n }\n\n return builder\n}\n"],"mappings":"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"}
|