react-word-docx 1.0.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 +361 -0
- package/dist/DocxEngine.d.ts +118 -0
- package/dist/DocxEngine.d.ts.map +1 -0
- package/dist/DocxEngine.js +357 -0
- package/dist/DocxEngine.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
# react-word-docx
|
|
2
|
+
|
|
3
|
+
> Convert a simple JSON **Block Schema** into a fully-featured, native `.docx` file — entirely in the browser. No server, no canvas tricks, no HTML-to-Word hacks.
|
|
4
|
+
|
|
5
|
+
Built on top of the excellent [`docx`](https://github.com/dolanmiu/docx) library with a high-level JSON API that handles all the Word-specific quirks for you (half-point font math, real list numbering, heading hierarchy, table headers, and more).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Quick Start](#quick-start)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [API Reference](#api-reference)
|
|
14
|
+
- [Block Type Reference](#block-type-reference)
|
|
15
|
+
- [Styling Properties](#styling-properties)
|
|
16
|
+
- [Smart Layer — What DocxEngine Does Automatically](#smart-layer--what-docxengine-does-automatically)
|
|
17
|
+
- [Using in a React Component](#using-in-a-react-component)
|
|
18
|
+
- [Advanced: Getting the Raw Blob](#advanced-getting-the-raw-blob)
|
|
19
|
+
- [TypeScript Types](#typescript-types)
|
|
20
|
+
- [Compatibility](#compatibility)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { downloadDocx } from "react-word-docx";
|
|
28
|
+
|
|
29
|
+
const blocks = [
|
|
30
|
+
{ type: "h1", text: "My Report" },
|
|
31
|
+
{ type: "p", text: "Generated entirely in the browser." },
|
|
32
|
+
{
|
|
33
|
+
type: "table",
|
|
34
|
+
rows: [
|
|
35
|
+
["Name", "Score"],
|
|
36
|
+
["Alice", "98"],
|
|
37
|
+
["Bob", "87"],
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{ type: "ul", li: ["Fast", "Native", "No server required"] },
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// Triggers a browser download of "my-report.docx"
|
|
44
|
+
await downloadDocx(blocks, "my-report");
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install react-word-docx docx
|
|
53
|
+
# or
|
|
54
|
+
yarn add react-word-docx docx
|
|
55
|
+
# or
|
|
56
|
+
pnpm add react-word-docx docx
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
> **Note:** `docx` is a peer dependency. You must install it alongside this package.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## API Reference
|
|
64
|
+
|
|
65
|
+
### `downloadDocx(blocks, filename?)`
|
|
66
|
+
|
|
67
|
+
Converts the block array into a `.docx` file and triggers an instant browser download.
|
|
68
|
+
|
|
69
|
+
| Parameter | Type | Default | Description |
|
|
70
|
+
| ---------- | --------- | ------------ | ---------------------------------------------------------------- |
|
|
71
|
+
| `blocks` | `Block[]` | — | The array of content blocks to render. |
|
|
72
|
+
| `filename` | `string` | `"document"` | The file name. `.docx` is appended automatically if not present. |
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
await downloadDocx(blocks, "quarterly-report");
|
|
76
|
+
// → downloads "quarterly-report.docx"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### `blocksToBlob(blocks)`
|
|
82
|
+
|
|
83
|
+
Returns the raw `Blob` without triggering a download. Useful for server uploads, IndexedDB storage, or custom download handlers.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const blob = await blocksToBlob(blocks);
|
|
87
|
+
|
|
88
|
+
// Upload to a server
|
|
89
|
+
const formData = new FormData();
|
|
90
|
+
formData.append("file", blob, "report.docx");
|
|
91
|
+
await fetch("/api/upload", { method: "POST", body: formData });
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Block Type Reference
|
|
97
|
+
|
|
98
|
+
Every element in the `blocks` array is a **Block** object. The `type` property selects the element; all other properties are optional styling overrides.
|
|
99
|
+
|
|
100
|
+
| `type` | Purpose | Key Properties | Notes |
|
|
101
|
+
| ------------ | ----------------------- | ------------------------ | -------------------------------------------------- |
|
|
102
|
+
| `p` | Paragraph (default) | `text` | Used when `type` is omitted. |
|
|
103
|
+
| `h1` | Heading level 1 | `text` | Appears in Word's Navigation Pane. |
|
|
104
|
+
| `h2` | Heading level 2 | `text` | Appears in Word's Navigation Pane. |
|
|
105
|
+
| `h3` | Heading level 3 | `text` | Appears in Word's Navigation Pane. |
|
|
106
|
+
| `h4` | Heading level 4 | `text` | Appears in Word's Navigation Pane. |
|
|
107
|
+
| `h5` | Heading level 5 | `text` | Appears in Word's Navigation Pane. |
|
|
108
|
+
| `table` | Data table | `rows` | Row 0 is auto-formatted as a bold header row. |
|
|
109
|
+
| `ol` | Ordered / numbered list | `li` | True Word list — auto-increments and auto-indents. |
|
|
110
|
+
| `ul` | Unordered / bullet list | `li` | True Word list — bullet `•` with hanging indent. |
|
|
111
|
+
| `image` | Embedded image | `src`, `width`, `height` | URL or base64 data URI; fetched at render time. |
|
|
112
|
+
| `page-break` | Hard page break | _(none)_ | Inserts a `<w:br w:type="page"/>` break. |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Styling Properties
|
|
117
|
+
|
|
118
|
+
These properties are available on most block types (see the table above for exceptions).
|
|
119
|
+
|
|
120
|
+
| Property | Type | Default | Description |
|
|
121
|
+
| ----------- | -------------------------------------------- | --------- | --------------------------------------------------------------------------- |
|
|
122
|
+
| `text` | `string` | `""` | Text content for `p` and heading blocks. |
|
|
123
|
+
| `rows` | `string[][]` | `[]` | 2-D array of cell strings for `table` blocks. |
|
|
124
|
+
| `li` | `string[]` | `[]` | Array of list item strings for `ol` / `ul` blocks. |
|
|
125
|
+
| `align` | `"left" \| "center" \| "right" \| "justify"` | `"left"` | Text alignment. |
|
|
126
|
+
| `font` | `string` | `"Arial"` | Font family name (any font installed on the reader's machine). |
|
|
127
|
+
| `fontSize` | `number` | `12` | Font size **in typographic points**. DocxEngine multiplies by 2 internally. |
|
|
128
|
+
| `bold` | `boolean` | `false` | Bold text. |
|
|
129
|
+
| `italic` | `boolean` | `false` | Italic text. |
|
|
130
|
+
| `underline` | `boolean` | `false` | Single underline. |
|
|
131
|
+
| `color` | `string` | _(none)_ | Hex colour — `"#FF0000"` or `"FF0000"` (the `#` is stripped automatically). |
|
|
132
|
+
| `src` | `string` | — | Image source — absolute URL or `data:image/…;base64,…` URI. (`image` only) |
|
|
133
|
+
| `width` | `number` | `400` | Image render width in pixels. (`image` only) |
|
|
134
|
+
| `height` | `number` | `300` | Image render height in pixels. (`image` only) |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Smart Layer — What DocxEngine Does Automatically
|
|
139
|
+
|
|
140
|
+
DocxEngine is not just a thin wrapper. It applies a set of opinionated defaults so your output looks professional out of the box:
|
|
141
|
+
|
|
142
|
+
### 1 — Font Math (half-points)
|
|
143
|
+
|
|
144
|
+
Microsoft Word stores font sizes in **half-points**, not points. A 12 pt font is stored as `24`. DocxEngine handles this conversion automatically.
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
You write: fontSize: 14
|
|
148
|
+
Word gets: size: 28
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
You never have to think about this.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
### 2 — Heading Styles → Navigation Pane
|
|
156
|
+
|
|
157
|
+
`h1`–`h5` are mapped to Word's **built-in `Heading 1`–`Heading 5` styles**. This means:
|
|
158
|
+
|
|
159
|
+
- Word's **Navigation Pane** (`View → Navigation Pane`) works immediately.
|
|
160
|
+
- You can generate a **Table of Contents** (`References → Table of Contents`) without any extra work.
|
|
161
|
+
- The document outline structure is preserved when converting to PDF.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### 3 — Real Word Lists
|
|
166
|
+
|
|
167
|
+
`ol` and `ul` use Word's native **Numbering XML** (`numbering.xml`), not simulated indentation with spaces. This means:
|
|
168
|
+
|
|
169
|
+
- Numbers auto-increment correctly even when items are added or removed.
|
|
170
|
+
- Bullets survive copy-paste between Word documents without breaking.
|
|
171
|
+
- The indent is a proper hanging indent (`left: 0.5"`, `hanging: 0.25"`).
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### 4 — Table Header Row
|
|
176
|
+
|
|
177
|
+
For `table` blocks, row 0 is automatically promoted to a **header row**:
|
|
178
|
+
|
|
179
|
+
- Text is **bold**.
|
|
180
|
+
- Background is set to **`#F2F2F2`** (light gray).
|
|
181
|
+
- The `tableHeader` flag is set so Word repeats the row at the top of multi-page tables.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
### 5 — Default Paragraph Spacing
|
|
186
|
+
|
|
187
|
+
All paragraphs receive `spacing: { before: 120, after: 120 }` (120 twips = 6 pt). This prevents the "wall of text" look you get when every element is crammed together without breathing room. List items use tighter `60/60` spacing so they feel cohesive.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Using in a React Component
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
import React, { useState } from "react";
|
|
195
|
+
import { downloadDocx } from "react-word-docx";
|
|
196
|
+
import type { Block } from "react-word-docx";
|
|
197
|
+
|
|
198
|
+
const MY_BLOCKS: Block[] = [
|
|
199
|
+
{ type: "h1", text: "Invoice #1042" },
|
|
200
|
+
{ type: "p", text: "Issued: February 2026", italic: true },
|
|
201
|
+
{
|
|
202
|
+
type: "table",
|
|
203
|
+
rows: [
|
|
204
|
+
["Item", "Qty", "Unit Price", "Total"],
|
|
205
|
+
["Widget Pro", "3", "$29.99", "$89.97"],
|
|
206
|
+
["Support Plan", "1", "$199.00", "$199.00"],
|
|
207
|
+
],
|
|
208
|
+
},
|
|
209
|
+
{ type: "p", text: "Grand Total: $288.97", bold: true, align: "right" },
|
|
210
|
+
];
|
|
211
|
+
|
|
212
|
+
export function InvoiceButton() {
|
|
213
|
+
const [busy, setBusy] = useState(false);
|
|
214
|
+
|
|
215
|
+
async function generate() {
|
|
216
|
+
setBusy(true);
|
|
217
|
+
try {
|
|
218
|
+
await downloadDocx(MY_BLOCKS, "invoice-1042");
|
|
219
|
+
} finally {
|
|
220
|
+
setBusy(false);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<button onClick={generate} disabled={busy}>
|
|
226
|
+
{busy ? "Generating…" : "Download Invoice (.docx)"}
|
|
227
|
+
</button>
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Watermarks
|
|
235
|
+
|
|
236
|
+
Stamp an optional text or image watermark on **every page** by passing a `WatermarkOptions` object as the third argument to `downloadDocx` (or the second argument to `blocksToBlob`).
|
|
237
|
+
|
|
238
|
+
### Text watermark
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
await downloadDocx(blocks, "report", {
|
|
242
|
+
text: "DRAFT",
|
|
243
|
+
color: "#C0C0C0", // light gray — default
|
|
244
|
+
fontSize: 72, // points — default
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Image watermark
|
|
249
|
+
|
|
250
|
+
The image is fetched (URL) or decoded (base64 data URI) at generation time and floated **behind** the document content, centred on the page.
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
await downloadDocx(blocks, "report", {
|
|
254
|
+
image: "https://example.com/logo.png",
|
|
255
|
+
imageWidth: 300, // pixels — default
|
|
256
|
+
imageHeight: 200, // pixels — default
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Text + image together
|
|
261
|
+
|
|
262
|
+
Both options can be combined in a single call — they both appear in the document header on every page:
|
|
263
|
+
|
|
264
|
+
```tsx
|
|
265
|
+
await downloadDocx(blocks, "report", {
|
|
266
|
+
text: "CONFIDENTIAL",
|
|
267
|
+
color: "#FFB3B3",
|
|
268
|
+
fontSize: 54,
|
|
269
|
+
image: "https://example.com/stamp.png",
|
|
270
|
+
imageWidth: 200,
|
|
271
|
+
imageHeight: 133,
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### `WatermarkOptions` reference
|
|
276
|
+
|
|
277
|
+
| Property | Type | Default | Description |
|
|
278
|
+
|---------------|-------------|----------------------|----------------------------------------------------------------|
|
|
279
|
+
| `text` | `string` | — | Text stamped on every page (e.g. `"DRAFT"`). |
|
|
280
|
+
| `color` | `string` | `"#C0C0C0"` | Hex colour of the text watermark. |
|
|
281
|
+
| `fontSize` | `number` | `72` | Text watermark font size in typographic points. |
|
|
282
|
+
| `image` | `string` | — | URL or base64 data URI of an image watermark. |
|
|
283
|
+
| `imageWidth` | `number` | `300` | Image watermark width in pixels. |
|
|
284
|
+
| `imageHeight` | `number` | `200` | Image watermark height in pixels. |
|
|
285
|
+
| `imageType` | `ImageType` | auto-detected | Override the detected format (`"jpg"`, `"png"`, `"gif"`, `"bmp"`). |
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Advanced: Getting the Raw Blob
|
|
290
|
+
|
|
291
|
+
If you need the `Blob` for further processing instead of an automatic download:
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
import { blocksToBlob } from "react-word-docx";
|
|
295
|
+
|
|
296
|
+
// Upload directly to an S3-compatible endpoint
|
|
297
|
+
async function saveToCloud(blocks: Block[]) {
|
|
298
|
+
const blob = await blocksToBlob(blocks);
|
|
299
|
+
|
|
300
|
+
const { url } = await fetch("/api/presigned-url").then((r) => r.json());
|
|
301
|
+
await fetch(url, {
|
|
302
|
+
method: "PUT",
|
|
303
|
+
body: blob,
|
|
304
|
+
headers: {
|
|
305
|
+
"Content-Type":
|
|
306
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## TypeScript Types
|
|
315
|
+
|
|
316
|
+
Full type definitions are bundled with the package. Import them directly:
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
import type { Block, BlockType, AlignValue } from "react-word-docx";
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### `Block` (interface)
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
interface Block {
|
|
326
|
+
type?: BlockType; // "p" | "h1" | … | "page-break"
|
|
327
|
+
text?: string;
|
|
328
|
+
rows?: string[][];
|
|
329
|
+
li?: string[];
|
|
330
|
+
align?: AlignValue; // "left" | "center" | "right" | "justify"
|
|
331
|
+
font?: string;
|
|
332
|
+
fontSize?: number; // points — doubled internally for Word
|
|
333
|
+
bold?: boolean;
|
|
334
|
+
italic?: boolean;
|
|
335
|
+
underline?: boolean;
|
|
336
|
+
color?: string; // hex with or without "#"
|
|
337
|
+
src?: string; // image — URL or data URI
|
|
338
|
+
width?: number; // image pixels
|
|
339
|
+
height?: number; // image pixels
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Compatibility
|
|
346
|
+
|
|
347
|
+
| Environment | `downloadDocx` | `blocksToBlob` |
|
|
348
|
+
| ----------------- | :------------: | :------------: |
|
|
349
|
+
| Modern browsers | ✅ | ✅ |
|
|
350
|
+
| React 17 / 18 | ✅ | ✅ |
|
|
351
|
+
| Next.js (client) | ✅ | ✅ |
|
|
352
|
+
| Next.js (SSR/RSC) | ❌\* | ✅ |
|
|
353
|
+
| Node.js | ❌\* | ✅ |
|
|
354
|
+
|
|
355
|
+
> \* `downloadDocx` requires `document` and `URL.createObjectURL` — browser-only APIs. Call it inside a client component or `useEffect`. Use `blocksToBlob` on the server and stream the blob to the response.
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## License
|
|
360
|
+
|
|
361
|
+
MIT — use freely in commercial and open-source projects.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocxEngine.ts
|
|
3
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
* Converts a simple JSON "Block Schema" array into a fully-featured native
|
|
5
|
+
* .docx file and triggers a browser download — no server required.
|
|
6
|
+
*
|
|
7
|
+
* Dependencies: docx ^8.x
|
|
8
|
+
* Browser: Yes (uses URL.createObjectURL)
|
|
9
|
+
* Node / SSR: blocksToBlob() works; downloadDocx() requires a browser DOM.
|
|
10
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
*/
|
|
12
|
+
/** All recognised block element types. */
|
|
13
|
+
export type BlockType = "p" | "h1" | "h2" | "h3" | "h4" | "h5" | "table" | "ol" | "ul" | "image" | "page-break";
|
|
14
|
+
/** Text alignment options. */
|
|
15
|
+
export type AlignValue = "left" | "center" | "right" | "justify";
|
|
16
|
+
/**
|
|
17
|
+
* Image format types supported by docx v9's ImageRun (non-SVG raster formats).
|
|
18
|
+
* SVG requires a raster fallback image and is not supported by the simple `src` flow.
|
|
19
|
+
*/
|
|
20
|
+
export type ImageType = "jpg" | "png" | "gif" | "bmp";
|
|
21
|
+
/**
|
|
22
|
+
* A single content block fed to DocxEngine.
|
|
23
|
+
* All properties are optional — supply only what you need.
|
|
24
|
+
*/
|
|
25
|
+
export interface Block {
|
|
26
|
+
/**
|
|
27
|
+
* Element type.
|
|
28
|
+
* @default "p"
|
|
29
|
+
*/
|
|
30
|
+
type?: BlockType;
|
|
31
|
+
/** Text content — used by: p, h1, h2, h3, h4, h5. */
|
|
32
|
+
text?: string;
|
|
33
|
+
/**
|
|
34
|
+
* 2-D array of cell strings — used by: table.
|
|
35
|
+
* @example [["Name","Age"],["Alice","30"],["Bob","25"]]
|
|
36
|
+
*/
|
|
37
|
+
rows?: string[][];
|
|
38
|
+
/**
|
|
39
|
+
* Array of list item strings — used by: ol, ul.
|
|
40
|
+
* @example ["First item", "Second item"]
|
|
41
|
+
*/
|
|
42
|
+
li?: string[];
|
|
43
|
+
/** Horizontal text alignment. */
|
|
44
|
+
align?: AlignValue;
|
|
45
|
+
/**
|
|
46
|
+
* Font family name.
|
|
47
|
+
* @default "Arial"
|
|
48
|
+
*/
|
|
49
|
+
font?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Font size in typographic points (e.g. 12).
|
|
52
|
+
* DocxEngine automatically converts to Word's half-point unit (×2).
|
|
53
|
+
* @example 14 → 28 half-points inside the .docx
|
|
54
|
+
*/
|
|
55
|
+
fontSize?: number;
|
|
56
|
+
/** Bold text. */
|
|
57
|
+
bold?: boolean;
|
|
58
|
+
/** Italic text. */
|
|
59
|
+
italic?: boolean;
|
|
60
|
+
/** Single underline. */
|
|
61
|
+
underline?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Text colour as a hex string.
|
|
64
|
+
* The leading "#" is optional — both "#FF0000" and "FF0000" are accepted.
|
|
65
|
+
*/
|
|
66
|
+
color?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Image source — used by: image.
|
|
69
|
+
* Accepts an absolute URL or a base64 data URI.
|
|
70
|
+
* @example "https://example.com/logo.png"
|
|
71
|
+
* @example "data:image/png;base64,iVBOR..."
|
|
72
|
+
*/
|
|
73
|
+
src?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Rendered image width in pixels — used by: image.
|
|
76
|
+
* @default 400
|
|
77
|
+
*/
|
|
78
|
+
width?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Rendered image height in pixels — used by: image.
|
|
81
|
+
* @default 300
|
|
82
|
+
*/
|
|
83
|
+
height?: number;
|
|
84
|
+
/**
|
|
85
|
+
* Override the auto-detected image format — used by: image.
|
|
86
|
+
* DocxEngine detects the format from the URL or data URI; set this when
|
|
87
|
+
* auto-detection produces the wrong result.
|
|
88
|
+
* @default auto-detected from `src`
|
|
89
|
+
*/
|
|
90
|
+
imageType?: ImageType;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Convert an array of Block objects to a `.docx` Blob.
|
|
94
|
+
*
|
|
95
|
+
* Use this when you need the raw Blob — e.g. to upload to a server,
|
|
96
|
+
* store in IndexedDB, or pass to a custom download handler.
|
|
97
|
+
*
|
|
98
|
+
* @param blocks Array of Block descriptors.
|
|
99
|
+
* @returns A Blob of MIME type `application/vnd.openxmlformats-officedocument.wordprocessingml.document`.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* const blob = await blocksToBlob(blocks);
|
|
103
|
+
* await uploadToServer("/api/docs", blob);
|
|
104
|
+
*/
|
|
105
|
+
export declare function blocksToBlob(blocks: Block[]): Promise<Blob>;
|
|
106
|
+
/**
|
|
107
|
+
* Convert an array of Block objects into a `.docx` file and trigger a
|
|
108
|
+
* browser download — zero server round-trips.
|
|
109
|
+
*
|
|
110
|
+
* @param blocks Array of Block descriptors.
|
|
111
|
+
* @param filename Desired file name. `.docx` is appended automatically if omitted.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* await downloadDocx(myBlocks, "quarterly-report");
|
|
115
|
+
* // → downloads "quarterly-report.docx"
|
|
116
|
+
*/
|
|
117
|
+
export declare function downloadDocx(blocks: Block[], filename?: string): Promise<void>;
|
|
118
|
+
//# sourceMappingURL=DocxEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocxEngine.d.ts","sourceRoot":"","sources":["../src/DocxEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAuBH,0CAA0C;AAC1C,MAAM,MAAM,SAAS,GACjB,GAAG,GACH,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,OAAO,GACP,IAAI,GACJ,IAAI,GACJ,OAAO,GACP,YAAY,CAAC;AAEjB,8BAA8B;AAC9B,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjE;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAGtD;;;GAGG;AACH,MAAM,WAAW,KAAK;IACpB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;IAElB;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAEd,iCAAiC;IACjC,KAAK,CAAC,EAAE,UAAU,CAAC;IAEnB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,iBAAiB;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,mBAAmB;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,wBAAwB;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAoUD;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CASjE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,KAAK,EAAE,EACf,QAAQ,SAAa,GACpB,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DocxEngine.ts
|
|
4
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
* Converts a simple JSON "Block Schema" array into a fully-featured native
|
|
6
|
+
* .docx file and triggers a browser download — no server required.
|
|
7
|
+
*
|
|
8
|
+
* Dependencies: docx ^8.x
|
|
9
|
+
* Browser: Yes (uses URL.createObjectURL)
|
|
10
|
+
* Node / SSR: blocksToBlob() works; downloadDocx() requires a browser DOM.
|
|
11
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.blocksToBlob = blocksToBlob;
|
|
15
|
+
exports.downloadDocx = downloadDocx;
|
|
16
|
+
const docx_1 = require("docx");
|
|
17
|
+
// ─── Internal Constants ───────────────────────────────────────────────────────
|
|
18
|
+
const DEFAULT_FONT = "Arial";
|
|
19
|
+
/** 12 pt expressed in Word half-points. */
|
|
20
|
+
const DEFAULT_SIZE_HP = 24;
|
|
21
|
+
/** Paragraph spacing applied to every block (in twips, 1 pt = 20 twips). */
|
|
22
|
+
const PARA_SPACING = { before: 120, after: 120 };
|
|
23
|
+
/** Lighter spacing inside list items so they feel tighter than block gaps. */
|
|
24
|
+
const LIST_SPACING = { before: 60, after: 60 };
|
|
25
|
+
/** Minimal spacing inside table cells. */
|
|
26
|
+
const CELL_SPACING = { before: 80, after: 80 };
|
|
27
|
+
/** numbering.xml reference IDs — must be unique per document. */
|
|
28
|
+
const OL_REF = "docx-engine-ordered";
|
|
29
|
+
const UL_REF = "docx-engine-unordered";
|
|
30
|
+
// ─── Lookup Maps ──────────────────────────────────────────────────────────────
|
|
31
|
+
const ALIGNMENT_MAP = {
|
|
32
|
+
left: docx_1.AlignmentType.LEFT,
|
|
33
|
+
center: docx_1.AlignmentType.CENTER,
|
|
34
|
+
right: docx_1.AlignmentType.RIGHT,
|
|
35
|
+
justify: docx_1.AlignmentType.JUSTIFIED,
|
|
36
|
+
};
|
|
37
|
+
const HEADING_MAP = {
|
|
38
|
+
h1: docx_1.HeadingLevel.HEADING_1,
|
|
39
|
+
h2: docx_1.HeadingLevel.HEADING_2,
|
|
40
|
+
h3: docx_1.HeadingLevel.HEADING_3,
|
|
41
|
+
h4: docx_1.HeadingLevel.HEADING_4,
|
|
42
|
+
h5: docx_1.HeadingLevel.HEADING_5,
|
|
43
|
+
};
|
|
44
|
+
// ─── Numbering Configuration ──────────────────────────────────────────────────
|
|
45
|
+
// Injected once per document. Produces proper Word list numbering so that
|
|
46
|
+
// items auto-indent, auto-increment, and survive copy-paste into other docs.
|
|
47
|
+
const NUMBERING_CONFIG = {
|
|
48
|
+
config: [
|
|
49
|
+
{
|
|
50
|
+
reference: OL_REF,
|
|
51
|
+
levels: [
|
|
52
|
+
{
|
|
53
|
+
level: 0,
|
|
54
|
+
format: docx_1.LevelFormat.DECIMAL,
|
|
55
|
+
text: "%1.",
|
|
56
|
+
alignment: docx_1.AlignmentType.LEFT,
|
|
57
|
+
style: {
|
|
58
|
+
paragraph: {
|
|
59
|
+
indent: {
|
|
60
|
+
left: (0, docx_1.convertInchesToTwip)(0.5),
|
|
61
|
+
hanging: (0, docx_1.convertInchesToTwip)(0.25),
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
reference: UL_REF,
|
|
70
|
+
levels: [
|
|
71
|
+
{
|
|
72
|
+
level: 0,
|
|
73
|
+
format: docx_1.LevelFormat.BULLET,
|
|
74
|
+
text: "\u2022", // •
|
|
75
|
+
alignment: docx_1.AlignmentType.LEFT,
|
|
76
|
+
style: {
|
|
77
|
+
paragraph: {
|
|
78
|
+
indent: {
|
|
79
|
+
left: (0, docx_1.convertInchesToTwip)(0.5),
|
|
80
|
+
hanging: (0, docx_1.convertInchesToTwip)(0.25),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
// ─── Utility Helpers ──────────────────────────────────────────────────────────
|
|
90
|
+
/**
|
|
91
|
+
* Strip an optional leading "#" from a hex colour string and upper-case it.
|
|
92
|
+
* Returns undefined if the input is falsy, preserving optional semantics.
|
|
93
|
+
*/
|
|
94
|
+
function normalizeColor(color) {
|
|
95
|
+
if (!color)
|
|
96
|
+
return undefined;
|
|
97
|
+
const raw = color.startsWith("#") ? color.slice(1) : color;
|
|
98
|
+
return raw.toUpperCase();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Resolve the half-point font size to pass to TextRun.
|
|
102
|
+
* Returns undefined for headings without an explicit override so that Word's
|
|
103
|
+
* built-in heading style governs the size (keeps Navigation Pane hierarchy).
|
|
104
|
+
*/
|
|
105
|
+
function resolveSize(block, isHeading) {
|
|
106
|
+
if (block.fontSize !== undefined)
|
|
107
|
+
return block.fontSize * 2;
|
|
108
|
+
return isHeading ? undefined : DEFAULT_SIZE_HP;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Build a styled TextRun from a block's formatting properties.
|
|
112
|
+
* Shared by list items and reusable wherever a single run suffices.
|
|
113
|
+
*/
|
|
114
|
+
function makeTextRun(text, block, bold) {
|
|
115
|
+
var _a;
|
|
116
|
+
return new docx_1.TextRun({
|
|
117
|
+
text,
|
|
118
|
+
font: (_a = block.font) !== null && _a !== void 0 ? _a : DEFAULT_FONT,
|
|
119
|
+
size: block.fontSize ? block.fontSize * 2 : DEFAULT_SIZE_HP,
|
|
120
|
+
bold: bold !== null && bold !== void 0 ? bold : block.bold,
|
|
121
|
+
italics: block.italic,
|
|
122
|
+
underline: block.underline ? { type: docx_1.UnderlineType.SINGLE } : undefined,
|
|
123
|
+
color: normalizeColor(block.color),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// ─── Block Builders ───────────────────────────────────────────────────────────
|
|
127
|
+
/** Build a Paragraph node for "p" and "h1"–"h5" blocks. */
|
|
128
|
+
function buildParagraph(block) {
|
|
129
|
+
var _a, _b, _c, _d;
|
|
130
|
+
const type = (_a = block.type) !== null && _a !== void 0 ? _a : "p";
|
|
131
|
+
const isHeading = type !== "p" && type in HEADING_MAP;
|
|
132
|
+
return new docx_1.Paragraph({
|
|
133
|
+
heading: isHeading ? HEADING_MAP[type] : undefined,
|
|
134
|
+
alignment: block.align ? ALIGNMENT_MAP[block.align] : docx_1.AlignmentType.LEFT,
|
|
135
|
+
spacing: PARA_SPACING,
|
|
136
|
+
children: [
|
|
137
|
+
new docx_1.TextRun({
|
|
138
|
+
text: (_b = block.text) !== null && _b !== void 0 ? _b : "",
|
|
139
|
+
font: (_c = block.font) !== null && _c !== void 0 ? _c : DEFAULT_FONT,
|
|
140
|
+
size: resolveSize(block, isHeading),
|
|
141
|
+
// For headings: let Word's style govern boldness unless the caller
|
|
142
|
+
// explicitly sets bold. For "p" blocks default to non-bold.
|
|
143
|
+
bold: (_d = block.bold) !== null && _d !== void 0 ? _d : (isHeading ? undefined : false),
|
|
144
|
+
italics: block.italic,
|
|
145
|
+
underline: block.underline ? { type: docx_1.UnderlineType.SINGLE } : undefined,
|
|
146
|
+
color: normalizeColor(block.color),
|
|
147
|
+
}),
|
|
148
|
+
],
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/** Build one Paragraph per list item with the correct numbering reference. */
|
|
152
|
+
function buildListItems(block, listType) {
|
|
153
|
+
var _a;
|
|
154
|
+
const ref = listType === "ol" ? OL_REF : UL_REF;
|
|
155
|
+
return ((_a = block.li) !== null && _a !== void 0 ? _a : []).map((item) => new docx_1.Paragraph({
|
|
156
|
+
numbering: { reference: ref, level: 0 },
|
|
157
|
+
spacing: LIST_SPACING,
|
|
158
|
+
children: [makeTextRun(item, block)],
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Build a full-width Table.
|
|
163
|
+
* The first row is automatically styled as a header:
|
|
164
|
+
* • Bold text
|
|
165
|
+
* • Light gray background (#F2F2F2)
|
|
166
|
+
* • tableHeader flag set so Word repeats it on multi-page tables
|
|
167
|
+
*/
|
|
168
|
+
function buildTable(block) {
|
|
169
|
+
var _a;
|
|
170
|
+
const rows = (_a = block.rows) !== null && _a !== void 0 ? _a : [];
|
|
171
|
+
return new docx_1.Table({
|
|
172
|
+
width: { size: 100, type: docx_1.WidthType.PERCENTAGE },
|
|
173
|
+
rows: rows.map((row, rowIndex) => {
|
|
174
|
+
const isHeader = rowIndex === 0;
|
|
175
|
+
return new docx_1.TableRow({
|
|
176
|
+
tableHeader: isHeader,
|
|
177
|
+
children: row.map((cellText) => new docx_1.TableCell({
|
|
178
|
+
shading: isHeader
|
|
179
|
+
? {
|
|
180
|
+
fill: "F2F2F2",
|
|
181
|
+
type: docx_1.ShadingType.CLEAR,
|
|
182
|
+
color: "auto",
|
|
183
|
+
}
|
|
184
|
+
: undefined,
|
|
185
|
+
children: [
|
|
186
|
+
new docx_1.Paragraph({
|
|
187
|
+
spacing: CELL_SPACING,
|
|
188
|
+
children: [makeTextRun(cellText, block, isHeader ? true : block.bold)],
|
|
189
|
+
}),
|
|
190
|
+
],
|
|
191
|
+
})),
|
|
192
|
+
});
|
|
193
|
+
}),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Infer the image format from a URL path or data URI MIME type.
|
|
198
|
+
* docx v9 requires an explicit `type` discriminator on every ImageRun.
|
|
199
|
+
* Falls back to "png" — the safest raster format for Word's renderer.
|
|
200
|
+
*/
|
|
201
|
+
function detectImageType(src) {
|
|
202
|
+
const lower = src.toLowerCase();
|
|
203
|
+
if (lower.includes("image/jpeg") || /\.jpe?g(\?|$|#)/.test(lower))
|
|
204
|
+
return "jpg";
|
|
205
|
+
if (lower.includes("image/gif") || /\.gif(\?|$|#)/.test(lower))
|
|
206
|
+
return "gif";
|
|
207
|
+
if (lower.includes("image/bmp") || /\.bmp(\?|$|#)/.test(lower))
|
|
208
|
+
return "bmp";
|
|
209
|
+
if (lower.includes("image/png") || /\.png(\?|$|#)/.test(lower))
|
|
210
|
+
return "png";
|
|
211
|
+
return "png"; // safe default
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Fetch or decode an image block and wrap it in a Paragraph > ImageRun.
|
|
215
|
+
*
|
|
216
|
+
* Supports:
|
|
217
|
+
* - Absolute URLs (fetched via the browser's fetch API)
|
|
218
|
+
* - base64 data URIs (decoded to raw base64 without the header)
|
|
219
|
+
*
|
|
220
|
+
* If the image cannot be loaded a warning is logged and an empty Paragraph
|
|
221
|
+
* is returned so the rest of the document renders without throwing.
|
|
222
|
+
*/
|
|
223
|
+
async function buildImage(block) {
|
|
224
|
+
var _a, _b, _c;
|
|
225
|
+
if (!block.src) {
|
|
226
|
+
console.warn("[DocxEngine] Image block is missing a `src` property — skipping.");
|
|
227
|
+
return new docx_1.Paragraph({ children: [] });
|
|
228
|
+
}
|
|
229
|
+
// docx v9 requires an explicit type discriminator on ImageRun.
|
|
230
|
+
const type = (_a = block.imageType) !== null && _a !== void 0 ? _a : detectImageType(block.src);
|
|
231
|
+
let data;
|
|
232
|
+
if (block.src.startsWith("data:")) {
|
|
233
|
+
// ── base64 data URI ───────────────────────────────────────────────────────
|
|
234
|
+
const commaIdx = block.src.indexOf(",");
|
|
235
|
+
if (commaIdx === -1) {
|
|
236
|
+
console.warn("[DocxEngine] Malformed data URI in image block — skipping.");
|
|
237
|
+
return new docx_1.Paragraph({ children: [] });
|
|
238
|
+
}
|
|
239
|
+
// docx's ImageRun accepts raw base64 (no "data:…;base64," prefix).
|
|
240
|
+
data = block.src.slice(commaIdx + 1);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
// ── Remote URL ────────────────────────────────────────────────────────────
|
|
244
|
+
try {
|
|
245
|
+
const response = await fetch(block.src);
|
|
246
|
+
if (!response.ok) {
|
|
247
|
+
throw new Error(`HTTP ${response.status} ${response.statusText}`);
|
|
248
|
+
}
|
|
249
|
+
data = await response.arrayBuffer();
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
console.warn("[DocxEngine] Failed to fetch image:", err, "— skipping.");
|
|
253
|
+
return new docx_1.Paragraph({ children: [] });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return new docx_1.Paragraph({
|
|
257
|
+
alignment: block.align ? ALIGNMENT_MAP[block.align] : docx_1.AlignmentType.LEFT,
|
|
258
|
+
spacing: PARA_SPACING,
|
|
259
|
+
children: [
|
|
260
|
+
new docx_1.ImageRun({
|
|
261
|
+
type,
|
|
262
|
+
data,
|
|
263
|
+
transformation: {
|
|
264
|
+
width: (_b = block.width) !== null && _b !== void 0 ? _b : 400,
|
|
265
|
+
height: (_c = block.height) !== null && _c !== void 0 ? _c : 300,
|
|
266
|
+
},
|
|
267
|
+
}),
|
|
268
|
+
],
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
/** Insert a hard page break as a zero-content Paragraph. */
|
|
272
|
+
function buildPageBreak() {
|
|
273
|
+
return new docx_1.Paragraph({ children: [new docx_1.PageBreak()] });
|
|
274
|
+
}
|
|
275
|
+
// ─── Document Assembly ────────────────────────────────────────────────────────
|
|
276
|
+
/**
|
|
277
|
+
* Walk the blocks array and dispatch each block to its builder.
|
|
278
|
+
* Returns a flat array of docx child nodes ready to place in a Section.
|
|
279
|
+
*/
|
|
280
|
+
async function assembleChildren(blocks) {
|
|
281
|
+
var _a;
|
|
282
|
+
const children = [];
|
|
283
|
+
for (const block of blocks) {
|
|
284
|
+
const type = (_a = block.type) !== null && _a !== void 0 ? _a : "p";
|
|
285
|
+
switch (type) {
|
|
286
|
+
case "page-break":
|
|
287
|
+
children.push(buildPageBreak());
|
|
288
|
+
break;
|
|
289
|
+
case "table":
|
|
290
|
+
children.push(buildTable(block));
|
|
291
|
+
break;
|
|
292
|
+
case "ol":
|
|
293
|
+
case "ul":
|
|
294
|
+
children.push(...buildListItems(block, type));
|
|
295
|
+
break;
|
|
296
|
+
case "image":
|
|
297
|
+
children.push(await buildImage(block));
|
|
298
|
+
break;
|
|
299
|
+
// "p" | "h1" | "h2" | "h3" | "h4" | "h5"
|
|
300
|
+
default:
|
|
301
|
+
children.push(buildParagraph(block));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return children;
|
|
305
|
+
}
|
|
306
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
307
|
+
/**
|
|
308
|
+
* Convert an array of Block objects to a `.docx` Blob.
|
|
309
|
+
*
|
|
310
|
+
* Use this when you need the raw Blob — e.g. to upload to a server,
|
|
311
|
+
* store in IndexedDB, or pass to a custom download handler.
|
|
312
|
+
*
|
|
313
|
+
* @param blocks Array of Block descriptors.
|
|
314
|
+
* @returns A Blob of MIME type `application/vnd.openxmlformats-officedocument.wordprocessingml.document`.
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* const blob = await blocksToBlob(blocks);
|
|
318
|
+
* await uploadToServer("/api/docs", blob);
|
|
319
|
+
*/
|
|
320
|
+
async function blocksToBlob(blocks) {
|
|
321
|
+
const children = await assembleChildren(blocks);
|
|
322
|
+
const doc = new docx_1.Document({
|
|
323
|
+
numbering: NUMBERING_CONFIG,
|
|
324
|
+
sections: [{ children }],
|
|
325
|
+
});
|
|
326
|
+
return docx_1.Packer.toBlob(doc);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Convert an array of Block objects into a `.docx` file and trigger a
|
|
330
|
+
* browser download — zero server round-trips.
|
|
331
|
+
*
|
|
332
|
+
* @param blocks Array of Block descriptors.
|
|
333
|
+
* @param filename Desired file name. `.docx` is appended automatically if omitted.
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* await downloadDocx(myBlocks, "quarterly-report");
|
|
337
|
+
* // → downloads "quarterly-report.docx"
|
|
338
|
+
*/
|
|
339
|
+
async function downloadDocx(blocks, filename = "document") {
|
|
340
|
+
const blob = await blocksToBlob(blocks);
|
|
341
|
+
const name = filename.endsWith(".docx") ? filename : `${filename}.docx`;
|
|
342
|
+
const url = URL.createObjectURL(blob);
|
|
343
|
+
try {
|
|
344
|
+
const anchor = document.createElement("a");
|
|
345
|
+
anchor.href = url;
|
|
346
|
+
anchor.download = name;
|
|
347
|
+
anchor.style.display = "none";
|
|
348
|
+
document.body.appendChild(anchor);
|
|
349
|
+
anchor.click();
|
|
350
|
+
document.body.removeChild(anchor);
|
|
351
|
+
}
|
|
352
|
+
finally {
|
|
353
|
+
// Always release the object URL to prevent memory leaks.
|
|
354
|
+
URL.revokeObjectURL(url);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=DocxEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocxEngine.js","sourceRoot":"","sources":["../src/DocxEngine.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.downloadDocx = exports.blocksToBlob = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* react-word-docx
|
|
6
|
+
* Public surface — re-export everything a consumer needs.
|
|
7
|
+
*/
|
|
8
|
+
var DocxEngine_1 = require("./DocxEngine");
|
|
9
|
+
Object.defineProperty(exports, "blocksToBlob", { enumerable: true, get: function () { return DocxEngine_1.blocksToBlob; } });
|
|
10
|
+
Object.defineProperty(exports, "downloadDocx", { enumerable: true, get: function () { return DocxEngine_1.downloadDocx; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,2CAA0D;AAAjD,0GAAA,YAAY,OAAA;AAAE,0GAAA,YAAY,OAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-word-docx",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Convert a simple JSON Block Schema into a native .docx file from any React / browser app.",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"types": "./src/index.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "vite",
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"watch": "tsc --watch",
|
|
15
|
+
"type-check": "tsc --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"react": ">=17.0.0",
|
|
19
|
+
"react-dom": ">=17.0.0"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"docx": "^9.5.3"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/react": "^18.3.0",
|
|
26
|
+
"@types/react-dom": "^18.3.0",
|
|
27
|
+
"@vitejs/plugin-react": "^5.1.4",
|
|
28
|
+
"react": "^18.3.0",
|
|
29
|
+
"react-dom": "^18.3.0",
|
|
30
|
+
"typescript": "^5.4.0",
|
|
31
|
+
"vite": "^7.3.1"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"docx",
|
|
35
|
+
"word",
|
|
36
|
+
"react",
|
|
37
|
+
"typescript",
|
|
38
|
+
"document",
|
|
39
|
+
"export"
|
|
40
|
+
],
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/JayBeeLearn/react-word-docx"
|
|
45
|
+
}
|
|
46
|
+
}
|