docx-kit 0.1.0 → 0.3.0
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 +13 -15
- package/dist/browser.d.ts +65 -44
- package/dist/browser.js +73 -30
- package/dist/node.d.ts +58 -53
- package/dist/node.js +78 -16
- package/package.json +68 -48
- package/dist/compileDocument-BvuU28Yj.js +0 -750
- package/dist/errors-c9CC63Ti.js +0 -63
- package/dist/fs-DF8ug9Wi.js +0 -43
- package/dist/image-6yS25Ggr.js +0 -76
- package/dist/index.d.ts +0 -1032
- package/dist/index.js +0 -683
- package/dist/pack-0Jsv03Sk.js +0 -79
package/dist/index.js
DELETED
|
@@ -1,683 +0,0 @@
|
|
|
1
|
-
import { n as ERROR_CODES, t as DocxKitError } from "./errors-c9CC63Ti.js";
|
|
2
|
-
import { n as dataUrlToUint8Array, t as createImageRun } from "./image-6yS25Ggr.js";
|
|
3
|
-
import { Paragraph } from "docx";
|
|
4
|
-
//#region src/types/style.ts
|
|
5
|
-
/**
|
|
6
|
-
* Define a type-safe stylesheet.
|
|
7
|
-
*
|
|
8
|
-
* `fontSize` defaults to pt when passed as a bare number.
|
|
9
|
-
*
|
|
10
|
-
* @param styles - — The stylesheet object
|
|
11
|
-
* @returns The same stylesheet with `const` type inference
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```ts
|
|
15
|
-
* const styles = defineStyles({
|
|
16
|
-
* title: { fontSize: 28, fontWeight: 'bold' },
|
|
17
|
-
* body: { fontSize: 12, lineHeight: 1.5 },
|
|
18
|
-
* })
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
function defineStyles(styles) {
|
|
22
|
-
return styles;
|
|
23
|
-
}
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/types/plugin.ts
|
|
26
|
-
/**
|
|
27
|
-
* Define a type-safe plugin with full inference.
|
|
28
|
-
*
|
|
29
|
-
* @param plugin - — The plugin definition object
|
|
30
|
-
* @returns The same plugin with `const` type inference
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* ```ts
|
|
34
|
-
* const myPlugin = definePlugin<'badge', { text: string }>({
|
|
35
|
-
* name: 'badge',
|
|
36
|
-
* render: async (opts, ctx) => {
|
|
37
|
-
* // ... render logic
|
|
38
|
-
* return new Paragraph({ text: opts.text })
|
|
39
|
-
* },
|
|
40
|
-
* })
|
|
41
|
-
* ```
|
|
42
|
-
*/
|
|
43
|
-
function definePlugin(plugin) {
|
|
44
|
-
return plugin;
|
|
45
|
-
}
|
|
46
|
-
//#endregion
|
|
47
|
-
//#region src/builder/DocxBuilder.ts
|
|
48
|
-
/**
|
|
49
|
-
* Fluent document builder.
|
|
50
|
-
*
|
|
51
|
-
* Use `createDocx()` to instantiate, then chain `.h1()`, `.p()`, `.table()`,
|
|
52
|
-
* etc. to build content. Call `.save()`, `.toBlob()`, `.toBuffer()`, or
|
|
53
|
-
* `.toBase64()` to export the document.
|
|
54
|
-
*
|
|
55
|
-
* @template TStyles — Inferred stylesheet type from `config.styles`
|
|
56
|
-
* @template TPlugins — Accumulated plugin registry (built via `.use()`)
|
|
57
|
-
*/
|
|
58
|
-
var DocxBuilder = class {
|
|
59
|
-
config;
|
|
60
|
-
nodes = [];
|
|
61
|
-
pendingSetups = [];
|
|
62
|
-
pluginMap = /* @__PURE__ */ new Map();
|
|
63
|
-
constructor(config = {}) {
|
|
64
|
-
this.config = config;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Add a raw DSL node to the document.
|
|
68
|
-
*
|
|
69
|
-
* @param node - — Any block-level node
|
|
70
|
-
* @returns The builder (for chaining)
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* ```ts
|
|
74
|
-
* doc.add({ type: 'heading', level: 2, text: 'Section' })
|
|
75
|
-
* doc.add({ type: 'pageBreak' })
|
|
76
|
-
* ```
|
|
77
|
-
*/
|
|
78
|
-
add(node) {
|
|
79
|
-
this.nodes.push(node);
|
|
80
|
-
return this;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Add a level-1 heading.
|
|
84
|
-
*
|
|
85
|
-
* @param text - — Heading text
|
|
86
|
-
* @param options - — Optional style overrides (className, id, style)
|
|
87
|
-
* @returns The builder (for chaining)
|
|
88
|
-
*
|
|
89
|
-
* @example
|
|
90
|
-
* ```ts
|
|
91
|
-
* doc.h1('Introduction', { className: 'title' })
|
|
92
|
-
* ```
|
|
93
|
-
*/
|
|
94
|
-
h1(text, options = {}) {
|
|
95
|
-
return this.add({
|
|
96
|
-
level: 1,
|
|
97
|
-
text,
|
|
98
|
-
type: "heading",
|
|
99
|
-
...options
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Add a level-2 heading.
|
|
104
|
-
*
|
|
105
|
-
* @param text - — Heading text
|
|
106
|
-
* @param options - — Optional style overrides
|
|
107
|
-
* @returns The builder (for chaining)
|
|
108
|
-
*/
|
|
109
|
-
h2(text, options = {}) {
|
|
110
|
-
return this.add({
|
|
111
|
-
level: 2,
|
|
112
|
-
text,
|
|
113
|
-
type: "heading",
|
|
114
|
-
...options
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Add a level-3 heading.
|
|
119
|
-
*
|
|
120
|
-
* @param text - — Heading text
|
|
121
|
-
* @param options - — Optional style overrides
|
|
122
|
-
* @returns The builder (for chaining)
|
|
123
|
-
*/
|
|
124
|
-
h3(text, options = {}) {
|
|
125
|
-
return this.add({
|
|
126
|
-
level: 3,
|
|
127
|
-
text,
|
|
128
|
-
type: "heading",
|
|
129
|
-
...options
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Add a level-4 heading.
|
|
134
|
-
*
|
|
135
|
-
* @param text - — Heading text
|
|
136
|
-
* @param options - — Optional style overrides
|
|
137
|
-
* @returns The builder (for chaining)
|
|
138
|
-
*/
|
|
139
|
-
h4(text, options = {}) {
|
|
140
|
-
return this.add({
|
|
141
|
-
level: 4,
|
|
142
|
-
text,
|
|
143
|
-
type: "heading",
|
|
144
|
-
...options
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Add a level-5 heading.
|
|
149
|
-
*
|
|
150
|
-
* @param text - — Heading text
|
|
151
|
-
* @param options - — Optional style overrides
|
|
152
|
-
* @returns The builder (for chaining)
|
|
153
|
-
*/
|
|
154
|
-
h5(text, options = {}) {
|
|
155
|
-
return this.add({
|
|
156
|
-
level: 5,
|
|
157
|
-
text,
|
|
158
|
-
type: "heading",
|
|
159
|
-
...options
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Add a level-6 heading.
|
|
164
|
-
*
|
|
165
|
-
* @param text - — Heading text
|
|
166
|
-
* @param options - — Optional style overrides
|
|
167
|
-
* @returns The builder (for chaining)
|
|
168
|
-
*/
|
|
169
|
-
h6(text, options = {}) {
|
|
170
|
-
return this.add({
|
|
171
|
-
level: 6,
|
|
172
|
-
text,
|
|
173
|
-
type: "heading",
|
|
174
|
-
...options
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Add an image node.
|
|
179
|
-
*
|
|
180
|
-
* @param options - — Image node options (data, width, height, etc.)
|
|
181
|
-
* @returns The builder (for chaining)
|
|
182
|
-
*
|
|
183
|
-
* @example
|
|
184
|
-
* ```ts
|
|
185
|
-
* doc.image({ data: imageBytes, width: 400, height: 300 })
|
|
186
|
-
* ```
|
|
187
|
-
*/
|
|
188
|
-
image(options) {
|
|
189
|
-
return this.add({
|
|
190
|
-
type: "image",
|
|
191
|
-
...options
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Add a paragraph.
|
|
196
|
-
*
|
|
197
|
-
* @param text - — Paragraph text content
|
|
198
|
-
* @param options - — Optional style overrides (className, id, style)
|
|
199
|
-
* @returns The builder (for chaining)
|
|
200
|
-
*
|
|
201
|
-
* @example
|
|
202
|
-
* ```ts
|
|
203
|
-
* doc.p('Hello world', { className: 'body', style: { textAlign: 'center' } })
|
|
204
|
-
* ```
|
|
205
|
-
*/
|
|
206
|
-
p(text, options = {}) {
|
|
207
|
-
return this.add({
|
|
208
|
-
text,
|
|
209
|
-
type: "paragraph",
|
|
210
|
-
...options
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Add a forced page break.
|
|
215
|
-
*
|
|
216
|
-
* @returns The builder (for chaining)
|
|
217
|
-
*
|
|
218
|
-
* @example
|
|
219
|
-
* ```ts
|
|
220
|
-
* doc.h1('Chapter 1').pageBreak().h1('Chapter 2')
|
|
221
|
-
* ```
|
|
222
|
-
*/
|
|
223
|
-
pageBreak() {
|
|
224
|
-
return this.add({ type: "pageBreak" });
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Invoke a registered plugin.
|
|
228
|
-
*
|
|
229
|
-
* @param name - — Plugin name (must match a previously registered plugin)
|
|
230
|
-
* @param options - — Plugin-specific options
|
|
231
|
-
* @param style - — Optional inline style for the plugin's container
|
|
232
|
-
* @returns The builder (for chaining)
|
|
233
|
-
*
|
|
234
|
-
* @example
|
|
235
|
-
* ```ts
|
|
236
|
-
* doc.use(qrcodePlugin()).plugin('qrcode', { text: 'https://example.com' })
|
|
237
|
-
* ```
|
|
238
|
-
*/
|
|
239
|
-
plugin(name, options, style) {
|
|
240
|
-
return this.add({
|
|
241
|
-
name,
|
|
242
|
-
options,
|
|
243
|
-
style,
|
|
244
|
-
type: "plugin"
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Save the document to a file (Node.js only).
|
|
249
|
-
*
|
|
250
|
-
* **⚠️ Not available in browser environments.**
|
|
251
|
-
* Use {@link toBlob} and trigger a download instead.
|
|
252
|
-
*
|
|
253
|
-
* @param filename - — Output file path (e.g. `"report.docx"`)
|
|
254
|
-
*
|
|
255
|
-
* @example
|
|
256
|
-
* ```ts
|
|
257
|
-
* await doc.save('output.docx')
|
|
258
|
-
* ```
|
|
259
|
-
*/
|
|
260
|
-
async save(filename) {
|
|
261
|
-
const { saveDocument } = await import("./fs-DF8ug9Wi.js").then((n) => n.t);
|
|
262
|
-
return saveDocument(await this.toDocument(), filename);
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Add a table.
|
|
266
|
-
*
|
|
267
|
-
* @param options - — Table node options (columns, data, style, etc.)
|
|
268
|
-
* @returns The builder (for chaining)
|
|
269
|
-
*
|
|
270
|
-
* @example
|
|
271
|
-
* ```ts
|
|
272
|
-
* doc.table({
|
|
273
|
-
* columns: [
|
|
274
|
-
* { key: 'name', title: 'Name' },
|
|
275
|
-
* { key: 'value', title: 'Value', align: 'right' },
|
|
276
|
-
* ],
|
|
277
|
-
* data: [{ name: 'Revenue', value: '$1.2M' }],
|
|
278
|
-
* headerCellStyle: { fontWeight: 'bold' },
|
|
279
|
-
* })
|
|
280
|
-
* ```
|
|
281
|
-
*/
|
|
282
|
-
table(options) {
|
|
283
|
-
return this.add({
|
|
284
|
-
type: "table",
|
|
285
|
-
...options
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Export the document as a base64-encoded string.
|
|
290
|
-
*
|
|
291
|
-
* @returns Base64-encoded .docx data
|
|
292
|
-
*
|
|
293
|
-
* @example
|
|
294
|
-
* ```ts
|
|
295
|
-
* const b64 = await doc.toBase64()
|
|
296
|
-
* // Send b64 over HTTP or store in a database
|
|
297
|
-
* ```
|
|
298
|
-
*/
|
|
299
|
-
async toBase64() {
|
|
300
|
-
const { packToBase64String } = await import("./pack-0Jsv03Sk.js");
|
|
301
|
-
return packToBase64String(await this.toDocument());
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Export the document as a `Blob` (browser-friendly).
|
|
305
|
-
*
|
|
306
|
-
* @returns A `Blob` containing the .docx binary
|
|
307
|
-
*
|
|
308
|
-
* @example
|
|
309
|
-
* ```ts
|
|
310
|
-
* const blob = await doc.toBlob()
|
|
311
|
-
* const url = URL.createObjectURL(blob)
|
|
312
|
-
* ```
|
|
313
|
-
*/
|
|
314
|
-
async toBlob() {
|
|
315
|
-
const { packToBlob } = await import("./pack-0Jsv03Sk.js");
|
|
316
|
-
return packToBlob(await this.toDocument());
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Export the document as a `Uint8Array` (alias for {@link toUint8Array}).
|
|
320
|
-
*
|
|
321
|
-
* **Note:** Despite the name, this returns a standard `Uint8Array`,
|
|
322
|
-
* not a Node.js `Buffer`. Prefer using {@link toUint8Array} for clarity.
|
|
323
|
-
*
|
|
324
|
-
* @returns Raw .docx bytes
|
|
325
|
-
*
|
|
326
|
-
* @example
|
|
327
|
-
* ```ts
|
|
328
|
-
* const bytes = await doc.toBuffer()
|
|
329
|
-
* fs.writeFileSync('output.docx', bytes)
|
|
330
|
-
* ```
|
|
331
|
-
*/
|
|
332
|
-
async toBuffer() {
|
|
333
|
-
return this.toUint8Array();
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Compile and return the internal `docx` {@link Document} instance.
|
|
337
|
-
*
|
|
338
|
-
* Useful if you need to further manipulate the document with the
|
|
339
|
-
* raw `docx` library before packaging.
|
|
340
|
-
*
|
|
341
|
-
* @returns A `docx` `Document` object
|
|
342
|
-
*/
|
|
343
|
-
async toDocument() {
|
|
344
|
-
await Promise.all(this.pendingSetups);
|
|
345
|
-
this.pendingSetups.length = 0;
|
|
346
|
-
const { compileDocument } = await import("./compileDocument-BvuU28Yj.js");
|
|
347
|
-
return compileDocument({
|
|
348
|
-
config: this.config,
|
|
349
|
-
nodes: this.nodes,
|
|
350
|
-
plugins: this.pluginMap
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* Serialize the builder state to a JSON-friendly object.
|
|
355
|
-
*
|
|
356
|
-
* Useful for debugging, serialization, or AI-driven document generation.
|
|
357
|
-
*
|
|
358
|
-
* @returns The config + content node array as a plain object
|
|
359
|
-
*/
|
|
360
|
-
toJSON() {
|
|
361
|
-
return {
|
|
362
|
-
...this.config,
|
|
363
|
-
content: this.nodes
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Export the document as a `Uint8Array` (browser & Node.js).
|
|
368
|
-
*
|
|
369
|
-
* This is the preferred cross-platform export method.
|
|
370
|
-
*
|
|
371
|
-
* @returns Raw .docx bytes
|
|
372
|
-
*
|
|
373
|
-
* @example
|
|
374
|
-
* ```ts
|
|
375
|
-
* const bytes = await doc.toUint8Array()
|
|
376
|
-
* // In Node.js: import { writeFileSync } from 'node:fs'
|
|
377
|
-
* // In browser: trigger a download
|
|
378
|
-
* ```
|
|
379
|
-
*/
|
|
380
|
-
async toUint8Array() {
|
|
381
|
-
const { packToBuffer } = await import("./pack-0Jsv03Sk.js");
|
|
382
|
-
return packToBuffer(await this.toDocument());
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* Register a plugin.
|
|
386
|
-
*
|
|
387
|
-
* The plugin's name and options type are accumulated into the builder's
|
|
388
|
-
* type-level plugin registry, enabling type-safe `.plugin()` calls.
|
|
389
|
-
*
|
|
390
|
-
* @param plugin - — The plugin definition returned by `definePlugin()`
|
|
391
|
-
* @returns The builder with the plugin type merged into `TPlugins`
|
|
392
|
-
*
|
|
393
|
-
* @example
|
|
394
|
-
* ```ts
|
|
395
|
-
* const doc = createDocx()
|
|
396
|
-
* .use(qrcodePlugin())
|
|
397
|
-
* .plugin('qrcode', { text: 'https://example.com' })
|
|
398
|
-
* ```
|
|
399
|
-
*/
|
|
400
|
-
use(plugin) {
|
|
401
|
-
this.pluginMap.set(plugin.name, plugin);
|
|
402
|
-
if (plugin.setup) this.pendingSetups.push(Promise.resolve(plugin.setup()));
|
|
403
|
-
return this;
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
//#endregion
|
|
407
|
-
//#region src/plugins/qrcode/index.ts
|
|
408
|
-
/**
|
|
409
|
-
* QR Code plugin — embeds a QR code image in the document.
|
|
410
|
-
*
|
|
411
|
-
* Uses the `qrcode` package (peer dependency) to generate
|
|
412
|
-
* a QR code PNG and renders it as an inline `ImageRun`.
|
|
413
|
-
*
|
|
414
|
-
* @module plugins/qrcode
|
|
415
|
-
*
|
|
416
|
-
* @example
|
|
417
|
-
* ```ts
|
|
418
|
-
* const doc = createDocx()
|
|
419
|
-
* .use(qrcodePlugin())
|
|
420
|
-
* .h1('Scan Me')
|
|
421
|
-
* .plugin('qrcode', { text: 'https://example.com', caption: 'Visit us' })
|
|
422
|
-
* .save('qrcode.docx')
|
|
423
|
-
* ```
|
|
424
|
-
*/
|
|
425
|
-
/**
|
|
426
|
-
* Create a QRCode plugin instance.
|
|
427
|
-
*
|
|
428
|
-
* The plugin dynamically imports the `qrcode` package at render time,
|
|
429
|
-
* keeping it an optional peer dependency of docx-kit core.
|
|
430
|
-
*
|
|
431
|
-
* @returns A configured DocxPlugin for `'qrcode'`
|
|
432
|
-
*
|
|
433
|
-
* @example
|
|
434
|
-
* ```ts
|
|
435
|
-
* import { createDocx, qrcodePlugin } from 'docx-kit'
|
|
436
|
-
*
|
|
437
|
-
* const doc = createDocx()
|
|
438
|
-
* .use(qrcodePlugin())
|
|
439
|
-
* .plugin('qrcode', {
|
|
440
|
-
* text: 'https://example.com',
|
|
441
|
-
* size: 256,
|
|
442
|
-
* errorCorrectionLevel: 'H',
|
|
443
|
-
* caption: 'Scan to visit',
|
|
444
|
-
* })
|
|
445
|
-
* ```
|
|
446
|
-
*/
|
|
447
|
-
function qrcodePlugin() {
|
|
448
|
-
return definePlugin({
|
|
449
|
-
name: "qrcode",
|
|
450
|
-
async render(options) {
|
|
451
|
-
const QRCode = (await import("qrcode")).default ?? await import("qrcode");
|
|
452
|
-
const size = options.size ?? 128;
|
|
453
|
-
const paragraphs = [new Paragraph({ children: [createImageRun({
|
|
454
|
-
data: await dataUrlToUint8Array(await QRCode.toDataURL(options.text, {
|
|
455
|
-
errorCorrectionLevel: options.errorCorrectionLevel ?? "M",
|
|
456
|
-
margin: options.margin ?? 1,
|
|
457
|
-
width: size
|
|
458
|
-
})),
|
|
459
|
-
height: size,
|
|
460
|
-
type: "png",
|
|
461
|
-
width: size
|
|
462
|
-
})] })];
|
|
463
|
-
if (options.caption) paragraphs.push(new Paragraph({ text: options.caption }));
|
|
464
|
-
return paragraphs;
|
|
465
|
-
}
|
|
466
|
-
});
|
|
467
|
-
}
|
|
468
|
-
//#endregion
|
|
469
|
-
//#region src/plugins/echarts/index.ts
|
|
470
|
-
/**
|
|
471
|
-
* ECharts plugin — embeds interactive ECharts charts as static images.
|
|
472
|
-
*
|
|
473
|
-
* Renders charts in the browser via the DOM. For Node.js rendering,
|
|
474
|
-
* a custom canvas/SVG implementation is needed (not built-in).
|
|
475
|
-
*
|
|
476
|
-
* @module plugins/echarts
|
|
477
|
-
*
|
|
478
|
-
* @example
|
|
479
|
-
* ```ts
|
|
480
|
-
* const doc = createDocx()
|
|
481
|
-
* .use(echartsPlugin())
|
|
482
|
-
* .h1('Sales Chart')
|
|
483
|
-
* .plugin('echarts', {
|
|
484
|
-
* option: {
|
|
485
|
-
* title: { text: 'Monthly Sales' },
|
|
486
|
-
* xAxis: { data: ['Jan', 'Feb', 'Mar'] },
|
|
487
|
-
* yAxis: {},
|
|
488
|
-
* series: [{ type: 'bar', data: [120, 200, 150] }],
|
|
489
|
-
* },
|
|
490
|
-
* width: 640,
|
|
491
|
-
* height: 360,
|
|
492
|
-
* caption: 'Figure 1: Monthly sales data',
|
|
493
|
-
* })
|
|
494
|
-
* .save('chart.docx')
|
|
495
|
-
* ```
|
|
496
|
-
*/
|
|
497
|
-
/**
|
|
498
|
-
* Create an ECharts plugin instance.
|
|
499
|
-
*
|
|
500
|
-
* The plugin renders charts using the browser DOM. In Node.js
|
|
501
|
-
* environments, it throws an error prompting the user to provide
|
|
502
|
-
* a server-side canvas implementation.
|
|
503
|
-
*
|
|
504
|
-
* @returns A configured DocxPlugin for `'echarts'`
|
|
505
|
-
*
|
|
506
|
-
* @example
|
|
507
|
-
* ```ts
|
|
508
|
-
* import { createDocx, echartsPlugin } from 'docx-kit'
|
|
509
|
-
*
|
|
510
|
-
* const doc = createDocx()
|
|
511
|
-
* .use(echartsPlugin())
|
|
512
|
-
* .plugin('echarts', {
|
|
513
|
-
* option: {
|
|
514
|
-
* title: { text: 'Revenue' },
|
|
515
|
-
* xAxis: { type: 'category', data: ['Q1', 'Q2', 'Q3', 'Q4'] },
|
|
516
|
-
* yAxis: { type: 'value' },
|
|
517
|
-
* series: [{ data: [820, 932, 901, 1347], type: 'line' }],
|
|
518
|
-
* },
|
|
519
|
-
* caption: 'Quarterly revenue trend',
|
|
520
|
-
* })
|
|
521
|
-
* ```
|
|
522
|
-
*/
|
|
523
|
-
function echartsPlugin() {
|
|
524
|
-
return definePlugin({
|
|
525
|
-
name: "echarts",
|
|
526
|
-
async render(options) {
|
|
527
|
-
const width = options.width ?? 640;
|
|
528
|
-
const height = options.height ?? 360;
|
|
529
|
-
const imageType = options.imageType ?? "png";
|
|
530
|
-
const renderer = options.renderer ?? "canvas";
|
|
531
|
-
const image = await renderEChartsToImage(options.option, {
|
|
532
|
-
height,
|
|
533
|
-
imageType,
|
|
534
|
-
renderer,
|
|
535
|
-
width
|
|
536
|
-
});
|
|
537
|
-
const paragraphs = [new Paragraph({ children: [createImageRun({
|
|
538
|
-
data: image.data,
|
|
539
|
-
height,
|
|
540
|
-
type: image.type,
|
|
541
|
-
width
|
|
542
|
-
})] })];
|
|
543
|
-
if (options.caption) paragraphs.push(new Paragraph({ text: options.caption }));
|
|
544
|
-
return paragraphs;
|
|
545
|
-
}
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* Render an ECharts option to an image.
|
|
550
|
-
*
|
|
551
|
-
* Automatically selects browser or Node.js rendering based on
|
|
552
|
-
* whether the `window` global is available.
|
|
553
|
-
*
|
|
554
|
-
* @param option - — Full ECharts option object
|
|
555
|
-
* @param config - — Render dimensions and format
|
|
556
|
-
* @returns Rendered image data and type
|
|
557
|
-
*/
|
|
558
|
-
async function renderEChartsToImage(option, config) {
|
|
559
|
-
if (typeof window !== "undefined") return renderInBrowser(option, config);
|
|
560
|
-
return renderInNode(option, config);
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Browser-side ECharts rendering.
|
|
564
|
-
*
|
|
565
|
-
* Creates a hidden DOM container, renders the chart, and extracts
|
|
566
|
-
* the image as a base64 data-URL.
|
|
567
|
-
*/
|
|
568
|
-
async function renderInBrowser(option, config) {
|
|
569
|
-
const echarts = await import("echarts");
|
|
570
|
-
const container = document.createElement("div");
|
|
571
|
-
container.style.cssText = `width:${config.width}px;height:${config.height}px;position:fixed;left:-99999px;`;
|
|
572
|
-
document.body.append(container);
|
|
573
|
-
const chart = echarts.init(container, void 0, {
|
|
574
|
-
height: config.height,
|
|
575
|
-
renderer: config.renderer,
|
|
576
|
-
width: config.width
|
|
577
|
-
});
|
|
578
|
-
chart.setOption(option);
|
|
579
|
-
const dataUrl = chart.getDataURL({
|
|
580
|
-
backgroundColor: "#ffffff",
|
|
581
|
-
pixelRatio: 2,
|
|
582
|
-
type: config.imageType === "svg" ? "svg" : "png"
|
|
583
|
-
});
|
|
584
|
-
chart.dispose();
|
|
585
|
-
container.remove();
|
|
586
|
-
return {
|
|
587
|
-
data: await dataUrlToUint8Array(dataUrl),
|
|
588
|
-
type: config.imageType
|
|
589
|
-
};
|
|
590
|
-
}
|
|
591
|
-
/**
|
|
592
|
-
* Node.js-side ECharts rendering (not built-in).
|
|
593
|
-
*
|
|
594
|
-
* Requires a server-side canvas or SVG DOM implementation
|
|
595
|
-
* (e.g. `node-canvas` + `echarts`). Throws an error prompting
|
|
596
|
-
* the user to provide a custom render function when used
|
|
597
|
-
* outside the browser.
|
|
598
|
-
*/
|
|
599
|
-
async function renderInNode(_option, _config) {
|
|
600
|
-
throw new DocxKitError(ERROR_CODES.PLUGIN_RENDER_FAILED, "ECharts Node renderer is not built-in. Use a server-side canvas implementation (e.g. node-canvas + echarts) and provide a custom render function. See https://github.com/ntnyq/docx-kit for alternatives.");
|
|
601
|
-
}
|
|
602
|
-
//#endregion
|
|
603
|
-
//#region src/builder/createDocx.ts
|
|
604
|
-
/**
|
|
605
|
-
* Factory functions for creating `DocxBuilder` instances.
|
|
606
|
-
*
|
|
607
|
-
* Two entry points are provided:
|
|
608
|
-
* - `createDocx()` — Fluent builder API with chaining
|
|
609
|
-
* - `renderDocx()` — JSON-schema driven (AI-friendly / serializable)
|
|
610
|
-
*
|
|
611
|
-
* @module builder/createDocx
|
|
612
|
-
*/
|
|
613
|
-
/**
|
|
614
|
-
* Create a new DocxBuilder with optional configuration.
|
|
615
|
-
*
|
|
616
|
-
* This is the primary entry point for the fluent builder API.
|
|
617
|
-
* Chain `.h1()`, `.p()`, `.table()`, etc. and call `.save()`
|
|
618
|
-
* or `.toBlob()` to export.
|
|
619
|
-
*
|
|
620
|
-
* @param config - — Document configuration (page, styles, metadata, theme, defaults)
|
|
621
|
-
* @returns A new `DocxBuilder` instance
|
|
622
|
-
*
|
|
623
|
-
* @example
|
|
624
|
-
* ```ts
|
|
625
|
-
* const styles = defineStyles({
|
|
626
|
-
* title: { fontSize: 28, fontWeight: 'bold' },
|
|
627
|
-
* body: { fontSize: 12, lineHeight: 1.5 },
|
|
628
|
-
* })
|
|
629
|
-
*
|
|
630
|
-
* const doc = createDocx({
|
|
631
|
-
* styles,
|
|
632
|
-
* page: { size: 'A4', margin: '20mm' },
|
|
633
|
-
* metadata: { title: 'Report', creator: 'docx-kit' },
|
|
634
|
-
* })
|
|
635
|
-
*
|
|
636
|
-
* await doc
|
|
637
|
-
* .h1('Annual Report', { className: 'title' })
|
|
638
|
-
* .p('Lorem ipsum...', { className: 'body' })
|
|
639
|
-
* .save('report.docx')
|
|
640
|
-
* ```
|
|
641
|
-
*/
|
|
642
|
-
function createDocx(config = {}) {
|
|
643
|
-
return new DocxBuilder(config);
|
|
644
|
-
}
|
|
645
|
-
/**
|
|
646
|
-
* Render a document from a JSON schema (AI-friendly / serializable DSL).
|
|
647
|
-
*
|
|
648
|
-
* Unlike `createDocx()`, this accepts a single JSON-serializable object
|
|
649
|
-
* with `content` (node array), optional `styles`, and optional `page` config.
|
|
650
|
-
* Ideal for AI-driven document generation or API integrations.
|
|
651
|
-
*
|
|
652
|
-
* @param schema - — The `DocxSchema` object
|
|
653
|
-
* @returns A `DocxBuilder` instance (ready to export)
|
|
654
|
-
*
|
|
655
|
-
* @example
|
|
656
|
-
* ```ts
|
|
657
|
-
* const blob = await renderDocx({
|
|
658
|
-
* page: { size: 'A4', margin: '20mm' },
|
|
659
|
-
* styles: {
|
|
660
|
-
* h1: { fontSize: 24, fontWeight: 'bold' },
|
|
661
|
-
* p: { fontSize: 12 },
|
|
662
|
-
* },
|
|
663
|
-
* content: [
|
|
664
|
-
* { type: 'heading', level: 1, text: 'Report', className: 'h1' },
|
|
665
|
-
* { type: 'paragraph', text: 'This is a report generated via JSON DSL.', className: 'p' },
|
|
666
|
-
* { type: 'pageBreak' },
|
|
667
|
-
* {
|
|
668
|
-
* type: 'table',
|
|
669
|
-
* columns: [{ key: 'name', title: 'Name' }, { key: 'value', title: 'Value' }],
|
|
670
|
-
* data: [{ name: 'Revenue', value: '$1.2M' }],
|
|
671
|
-
* },
|
|
672
|
-
* ],
|
|
673
|
-
* }).toBlob()
|
|
674
|
-
* ```
|
|
675
|
-
*/
|
|
676
|
-
function renderDocx(schema) {
|
|
677
|
-
const { content, ...config } = schema;
|
|
678
|
-
const builder = new DocxBuilder(config);
|
|
679
|
-
for (const node of content) builder.add(node);
|
|
680
|
-
return builder;
|
|
681
|
-
}
|
|
682
|
-
//#endregion
|
|
683
|
-
export { DocxBuilder, DocxKitError, ERROR_CODES, createDocx, dataUrlToUint8Array, definePlugin, defineStyles, echartsPlugin, qrcodePlugin, renderDocx };
|