@docen/export-docx 0.0.12 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,271 +1,271 @@
1
- # @docen/export-docx
2
-
3
- ![npm version](https://img.shields.io/npm/v/@docen/export-docx)
4
- ![npm downloads](https://img.shields.io/npm/dw/@docen/export-docx)
5
- ![npm license](https://img.shields.io/npm/l/@docen/export-docx)
6
-
7
- > Export TipTap/ProseMirror editor content to Microsoft Word DOCX format.
8
-
9
- ## Features
10
-
11
- - 📝 **Rich Text Support** - Full support for headings, paragraphs, and blockquotes with proper formatting
12
- - 🖼️ **Image Handling** - Automatic image sizing, positioning, and metadata extraction
13
- - 📊 **Table Support** - Complete table structure with headers, cells, colspan, and rowspan
14
- - ✅ **Lists & Tasks** - Bullet lists, numbered lists with custom start numbers, and task lists with checkboxes
15
- - 🎨 **Text Formatting** - Bold, italic, underline, strikethrough, subscript, and superscript
16
- - 🎯 **Text Styles** - Comprehensive style support including colors, backgrounds, fonts, sizes, and line heights
17
- - 🔗 **Links** - Hyperlink support with href preservation
18
- - 💻 **Code Blocks** - Syntax highlighted code blocks with language attribute support
19
- - 📁 **Collapsible Content** - Details/summary sections for expandable content
20
- - 😀 **Emoji Support** - Native emoji rendering in documents
21
- - 🧮 **Mathematical Content** - LaTeX-style formula support
22
- - ⚙️ **Configurable Options** - Customizable export options for documents, tables, styles, and horizontal rules
23
-
24
- ## Installation
25
-
26
- ```bash
27
- # Install with npm
28
- $ npm install @docen/export-docx
29
-
30
- # Install with yarn
31
- $ yarn add @docen/export-docx
32
-
33
- # Install with pnpm
34
- $ pnpm add @docen/export-docx
35
- ```
36
-
37
- ## Quick Start
38
-
39
- ```typescript
40
- import { generateDOCX } from "@docen/export-docx";
41
- import { writeFileSync } from "node:fs";
42
-
43
- // Your TipTap/ProseMirror editor content
44
- const content = {
45
- type: "doc",
46
- content: [
47
- {
48
- type: "paragraph",
49
- content: [
50
- {
51
- type: "text",
52
- marks: [{ type: "bold" }, { type: "italic" }],
53
- text: "Hello, world!",
54
- },
55
- ],
56
- },
57
- ],
58
- };
59
-
60
- // Convert to DOCX and save to file
61
- const docx = await generateDOCX(content, { outputType: "nodebuffer" });
62
- writeFileSync("document.docx", docx);
63
- ```
64
-
65
- ## API Reference
66
-
67
- ### `generateDOCX(content, options)`
68
-
69
- Converts TipTap/ProseMirror content to DOCX format.
70
-
71
- **Parameters:**
72
-
73
- - `content: JSONContent` - TipTap/ProseMirror editor content
74
- - `options: DocxExportOptions` - Export configuration options
75
-
76
- **Returns:** `Promise<OutputByType[T]>` - DOCX file data with type matching the specified outputType
77
-
78
- **Available Output Types:**
79
-
80
- - `"base64"` - Base64 encoded string
81
- - `"string"` - Text string
82
- - `"text"` - Plain text
83
- - `"binarystring"` - Binary string
84
- - `"array"` - Array of numbers
85
- - `"uint8array"` - Uint8Array
86
- - `"arraybuffer"` - ArrayBuffer
87
- - `"blob"` - Blob object
88
- - `"nodebuffer"` - Node.js Buffer
89
-
90
- **Configuration Options:**
91
-
92
- - `title` - Document title
93
- - `creator` - Document author
94
- - `description` - Document description
95
- - `outputType` - Output format (required)
96
- - `table` - Table styling defaults (alignment, spacing, borders)
97
- - `image` - Image handling options
98
- - `styles` - Document default styles (font, line height, spacing)
99
- - `horizontalRule` - Horizontal rule style
100
-
101
- ## Supported Content Types
102
-
103
- ### Text Formatting
104
-
105
- - **Bold**, _Italic_, <u>Underline</u>, ~~Strikethrough~~
106
- - ^Superscript^ and ~Subscript~
107
- - Text colors and background colors
108
- - Font families and sizes
109
- - Line heights
110
-
111
- ### Block Elements
112
-
113
- - **Headings** (H1-H6) with level attribute
114
- - **Paragraphs** with text alignment (left, right, center, justify)
115
- - **Blockquotes** (Note: Exported as indented paragraphs with left border due to DOCX format)
116
- - **Horizontal Rules** (Exported as page breaks by default)
117
- - **Code Blocks** with language support
118
-
119
- ### Lists
120
-
121
- - **Bullet Lists** - Standard unordered lists
122
- - **Numbered Lists** - Ordered lists with custom start number
123
- - **Task Lists** - Checkbox lists with checked/unchecked states
124
-
125
- ### Tables
126
-
127
- - Complete table structure with rows and cells
128
- - **Table Headers** with colspan/rowspan support
129
- - **Table Cells** with colspan/rowspan support
130
- - Cell alignment and formatting options
131
-
132
- ### Media & Embeds
133
-
134
- - **Images** with automatic sizing and positioning
135
- - **Links** (hyperlinks) with href attribute
136
- - **Emoji** rendering
137
- - **Mathematics** formulas (LaTeX-style)
138
- - **Details/Summary** collapsible sections
139
-
140
- ## Examples
141
-
142
- ### Document with Tables and Colspan/Rowspan
143
-
144
- ```typescript
145
- const content = {
146
- type: "doc",
147
- content: [
148
- {
149
- type: "table",
150
- content: [
151
- {
152
- type: "tableRow",
153
- content: [
154
- {
155
- type: "tableHeader",
156
- attrs: { colspan: 2, rowspan: 1 },
157
- content: [
158
- {
159
- type: "paragraph",
160
- content: [{ type: "text", text: "Spanning Header" }],
161
- },
162
- ],
163
- },
164
- {
165
- type: "tableCell",
166
- content: [
167
- {
168
- type: "paragraph",
169
- content: [{ type: "text", text: "Regular Cell" }],
170
- },
171
- ],
172
- },
173
- ],
174
- },
175
- ],
176
- },
177
- ],
178
- };
179
- ```
180
-
181
- ### Document with Text Styles
182
-
183
- ```typescript
184
- const content = {
185
- type: "doc",
186
- content: [
187
- {
188
- type: "paragraph",
189
- content: [
190
- {
191
- type: "text",
192
- marks: [
193
- {
194
- type: "textStyle",
195
- attrs: {
196
- color: "#FF0000",
197
- fontSize: "18px",
198
- fontFamily: "Arial",
199
- backgroundColor: "#FFFF00",
200
- },
201
- },
202
- ],
203
- text: "Red, 18px, Arial text on yellow background",
204
- },
205
- ],
206
- },
207
- ],
208
- };
209
- ```
210
-
211
- ### Document with Lists
212
-
213
- ```typescript
214
- const content = {
215
- type: "doc",
216
- content: [
217
- {
218
- type: "bulletList",
219
- content: [
220
- {
221
- type: "listItem",
222
- content: [
223
- {
224
- type: "paragraph",
225
- content: [{ type: "text", text: "First item" }],
226
- },
227
- ],
228
- },
229
- {
230
- type: "listItem",
231
- content: [
232
- {
233
- type: "paragraph",
234
- content: [{ type: "text", text: "Second item" }],
235
- },
236
- ],
237
- },
238
- ],
239
- },
240
- ],
241
- };
242
- ```
243
-
244
- ## Known Limitations
245
-
246
- ### Blockquote Structure
247
-
248
- DOCX does not have a semantic blockquote structure. Blockquotes are exported as:
249
-
250
- - Indented paragraphs (720 twips / 0.5 inch left indentation)
251
- - Left border (single line)
252
-
253
- This is a DOCX format limitation, not a bug.
254
-
255
- ### Code Marks
256
-
257
- The `code` mark is exported as monospace font (Consolas). When re-importing, it will be recognized as `textStyle` with `fontFamily: "Consolas"`, not as a `code` mark.
258
-
259
- This is intentional - we do not detect code marks from fonts during import to avoid false positives.
260
-
261
- ### Color Name Conversion
262
-
263
- Color names (like `"red"`, `"green"`, `"blue"`) are automatically converted to hex values (`"#FF0000"`, `"#008000"`, `"#0000FF"`) for DOCX compatibility.
264
-
265
- ## Contributing
266
-
267
- Contributions are welcome! Please read our [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) and submit pull requests to the [main repository](https://github.com/DemoMacro/docen).
268
-
269
- ## License
270
-
271
- - [MIT](LICENSE) &copy; [Demo Macro](https://imst.xyz/)
1
+ # @docen/export-docx
2
+
3
+ ![npm version](https://img.shields.io/npm/v/@docen/export-docx)
4
+ ![npm downloads](https://img.shields.io/npm/dw/@docen/export-docx)
5
+ ![npm license](https://img.shields.io/npm/l/@docen/export-docx)
6
+
7
+ > Export TipTap/ProseMirror editor content to Microsoft Word DOCX format.
8
+
9
+ ## Features
10
+
11
+ - 📝 **Rich Text Support** - Full support for headings, paragraphs, and blockquotes with proper formatting
12
+ - 🖼️ **Image Handling** - Automatic image sizing, positioning, and metadata extraction
13
+ - 📊 **Table Support** - Complete table structure with headers, cells, colspan, and rowspan
14
+ - ✅ **Lists & Tasks** - Bullet lists, numbered lists with custom start numbers, and task lists with checkboxes
15
+ - 🎨 **Text Formatting** - Bold, italic, underline, strikethrough, subscript, and superscript
16
+ - 🎯 **Text Styles** - Comprehensive style support including colors, backgrounds, fonts, sizes, and line heights
17
+ - 🔗 **Links** - Hyperlink support with href preservation
18
+ - 💻 **Code Blocks** - Syntax highlighted code blocks with language attribute support
19
+ - 📁 **Collapsible Content** - Details/summary sections for expandable content
20
+ - 😀 **Emoji Support** - Native emoji rendering in documents
21
+ - 🧮 **Mathematical Content** - LaTeX-style formula support
22
+ - ⚙️ **Configurable Options** - Customizable export options for documents, tables, styles, and horizontal rules
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ # Install with npm
28
+ $ npm install @docen/export-docx
29
+
30
+ # Install with yarn
31
+ $ yarn add @docen/export-docx
32
+
33
+ # Install with pnpm
34
+ $ pnpm add @docen/export-docx
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```typescript
40
+ import { generateDOCX } from "@docen/export-docx";
41
+ import { writeFileSync } from "node:fs";
42
+
43
+ // Your TipTap/ProseMirror editor content
44
+ const content = {
45
+ type: "doc",
46
+ content: [
47
+ {
48
+ type: "paragraph",
49
+ content: [
50
+ {
51
+ type: "text",
52
+ marks: [{ type: "bold" }, { type: "italic" }],
53
+ text: "Hello, world!",
54
+ },
55
+ ],
56
+ },
57
+ ],
58
+ };
59
+
60
+ // Convert to DOCX and save to file
61
+ const docx = await generateDOCX(content, { outputType: "nodebuffer" });
62
+ writeFileSync("document.docx", docx);
63
+ ```
64
+
65
+ ## API Reference
66
+
67
+ ### `generateDOCX(content, options)`
68
+
69
+ Converts TipTap/ProseMirror content to DOCX format.
70
+
71
+ **Parameters:**
72
+
73
+ - `content: JSONContent` - TipTap/ProseMirror editor content
74
+ - `options: DocxExportOptions` - Export configuration options
75
+
76
+ **Returns:** `Promise<OutputByType[T]>` - DOCX file data with type matching the specified outputType
77
+
78
+ **Available Output Types:**
79
+
80
+ - `"base64"` - Base64 encoded string
81
+ - `"string"` - Text string
82
+ - `"text"` - Plain text
83
+ - `"binarystring"` - Binary string
84
+ - `"array"` - Array of numbers
85
+ - `"uint8array"` - Uint8Array
86
+ - `"arraybuffer"` - ArrayBuffer
87
+ - `"blob"` - Blob object
88
+ - `"nodebuffer"` - Node.js Buffer
89
+
90
+ **Configuration Options:**
91
+
92
+ - `title` - Document title
93
+ - `creator` - Document author
94
+ - `description` - Document description
95
+ - `outputType` - Output format (required)
96
+ - `table` - Table styling defaults (alignment, spacing, borders)
97
+ - `image` - Image handling options
98
+ - `styles` - Document default styles (font, line height, spacing)
99
+ - `horizontalRule` - Horizontal rule style
100
+
101
+ ## Supported Content Types
102
+
103
+ ### Text Formatting
104
+
105
+ - **Bold**, _Italic_, <u>Underline</u>, ~~Strikethrough~~
106
+ - ^Superscript^ and ~Subscript~
107
+ - Text colors and background colors
108
+ - Font families and sizes
109
+ - Line heights
110
+
111
+ ### Block Elements
112
+
113
+ - **Headings** (H1-H6) with level attribute
114
+ - **Paragraphs** with text alignment (left, right, center, justify)
115
+ - **Blockquotes** (Note: Exported as indented paragraphs with left border due to DOCX format)
116
+ - **Horizontal Rules** (Exported as page breaks by default)
117
+ - **Code Blocks** with language support
118
+
119
+ ### Lists
120
+
121
+ - **Bullet Lists** - Standard unordered lists
122
+ - **Numbered Lists** - Ordered lists with custom start number
123
+ - **Task Lists** - Checkbox lists with checked/unchecked states
124
+
125
+ ### Tables
126
+
127
+ - Complete table structure with rows and cells
128
+ - **Table Headers** with colspan/rowspan support
129
+ - **Table Cells** with colspan/rowspan support
130
+ - Cell alignment and formatting options
131
+
132
+ ### Media & Embeds
133
+
134
+ - **Images** with automatic sizing and positioning
135
+ - **Links** (hyperlinks) with href attribute
136
+ - **Emoji** rendering
137
+ - **Mathematics** formulas (LaTeX-style)
138
+ - **Details/Summary** collapsible sections
139
+
140
+ ## Examples
141
+
142
+ ### Document with Tables and Colspan/Rowspan
143
+
144
+ ```typescript
145
+ const content = {
146
+ type: "doc",
147
+ content: [
148
+ {
149
+ type: "table",
150
+ content: [
151
+ {
152
+ type: "tableRow",
153
+ content: [
154
+ {
155
+ type: "tableHeader",
156
+ attrs: { colspan: 2, rowspan: 1 },
157
+ content: [
158
+ {
159
+ type: "paragraph",
160
+ content: [{ type: "text", text: "Spanning Header" }],
161
+ },
162
+ ],
163
+ },
164
+ {
165
+ type: "tableCell",
166
+ content: [
167
+ {
168
+ type: "paragraph",
169
+ content: [{ type: "text", text: "Regular Cell" }],
170
+ },
171
+ ],
172
+ },
173
+ ],
174
+ },
175
+ ],
176
+ },
177
+ ],
178
+ };
179
+ ```
180
+
181
+ ### Document with Text Styles
182
+
183
+ ```typescript
184
+ const content = {
185
+ type: "doc",
186
+ content: [
187
+ {
188
+ type: "paragraph",
189
+ content: [
190
+ {
191
+ type: "text",
192
+ marks: [
193
+ {
194
+ type: "textStyle",
195
+ attrs: {
196
+ color: "#FF0000",
197
+ fontSize: "18px",
198
+ fontFamily: "Arial",
199
+ backgroundColor: "#FFFF00",
200
+ },
201
+ },
202
+ ],
203
+ text: "Red, 18px, Arial text on yellow background",
204
+ },
205
+ ],
206
+ },
207
+ ],
208
+ };
209
+ ```
210
+
211
+ ### Document with Lists
212
+
213
+ ```typescript
214
+ const content = {
215
+ type: "doc",
216
+ content: [
217
+ {
218
+ type: "bulletList",
219
+ content: [
220
+ {
221
+ type: "listItem",
222
+ content: [
223
+ {
224
+ type: "paragraph",
225
+ content: [{ type: "text", text: "First item" }],
226
+ },
227
+ ],
228
+ },
229
+ {
230
+ type: "listItem",
231
+ content: [
232
+ {
233
+ type: "paragraph",
234
+ content: [{ type: "text", text: "Second item" }],
235
+ },
236
+ ],
237
+ },
238
+ ],
239
+ },
240
+ ],
241
+ };
242
+ ```
243
+
244
+ ## Known Limitations
245
+
246
+ ### Blockquote Structure
247
+
248
+ DOCX does not have a semantic blockquote structure. Blockquotes are exported as:
249
+
250
+ - Indented paragraphs (720 twips / 0.5 inch left indentation)
251
+ - Left border (single line)
252
+
253
+ This is a DOCX format limitation, not a bug.
254
+
255
+ ### Code Marks
256
+
257
+ The `code` mark is exported as monospace font (Consolas). When re-importing, it will be recognized as `textStyle` with `fontFamily: "Consolas"`, not as a `code` mark.
258
+
259
+ This is intentional - we do not detect code marks from fonts during import to avoid false positives.
260
+
261
+ ### Color Name Conversion
262
+
263
+ Color names (like `"red"`, `"green"`, `"blue"`) are automatically converted to hex values (`"#FF0000"`, `"#008000"`, `"#0000FF"`) for DOCX compatibility.
264
+
265
+ ## Contributing
266
+
267
+ Contributions are welcome! Please read our [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) and submit pull requests to the [main repository](https://github.com/DemoMacro/docen).
268
+
269
+ ## License
270
+
271
+ - [MIT](LICENSE) &copy; [Demo Macro](https://imst.xyz/)
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { ExternalHyperlink, FileChild, IFloating, IHorizontalPositionOptions, IImageOptions, IParagraphOptions, IParagraphStyleOptions, IPropertiesOptions, ISectionOptions, ITableCellOptions, ITableOfContentsOptions, ITableOptions, ITableRowOptions, IVerticalPositionOptions, ImageRun, OutputByType, OutputType, PositiveUniversalMeasure as PositiveUniversalMeasure$1, Table, TableCell, TableRow, TextRun } from "docx";
1
+ import { ExternalHyperlink, FileChild, IImageOptions, IParagraphOptions, IParagraphStyleOptions, IPropertiesOptions, ISectionOptions, ITableCellOptions, ITableOfContentsOptions, ITableOptions, ITableRowOptions, ImageRun, OutputByType, OutputType, PositiveUniversalMeasure as PositiveUniversalMeasure$1, Table, TableCell, TableRow, TextRun } from "docx";
2
2
  import { ImageMeta } from "image-meta";
3
3
 
4
4
  //#region ../../node_modules/.pnpm/orderedmap@2.1.1/node_modules/orderedmap/dist/index.d.ts
@@ -2166,7 +2166,7 @@ can be lifted. Will not go across
2166
2166
  [isolating](https://prosemirror.net/docs/ref/#model.NodeSpec.isolating) parent nodes.
2167
2167
  */
2168
2168
  //#endregion
2169
- //#region ../../node_modules/.pnpm/prosemirror-view@1.41.6/node_modules/prosemirror-view/dist/index.d.ts
2169
+ //#region ../../node_modules/.pnpm/prosemirror-view@1.41.7/node_modules/prosemirror-view/dist/index.d.ts
2170
2170
  type DOMNode = InstanceType<typeof window.Node>;
2171
2171
  type WidgetConstructor = ((view: EditorView, getPos: () => number | undefined) => DOMNode) | DOMNode;
2172
2172
  /**
@@ -3672,7 +3672,7 @@ point into textblock nodes. It can be empty (a regular cursor
3672
3672
  position).
3673
3673
  */
3674
3674
  //#endregion
3675
- //#region ../../node_modules/.pnpm/@tiptap+core@3.20.1_@tiptap+pm@3.20.1/node_modules/@tiptap/core/dist/index.d.ts
3675
+ //#region ../../node_modules/.pnpm/@tiptap+core@3.20.4_@tiptap+pm@3.20.4/node_modules/@tiptap/core/dist/index.d.ts
3676
3676
  type StringKeyOf<T> = Extract<keyof T, string>;
3677
3677
  type CallbackType<T extends Record<string, any>, EventName extends StringKeyOf<T>> = T[EventName] extends any[] ? T[EventName] : [T[EventName]];
3678
3678
  type CallbackFunction<T extends Record<string, any>, EventName extends StringKeyOf<T>> = (...props: CallbackType<T, EventName>) => any;
@@ -4436,6 +4436,27 @@ interface ExtendableConfig<Options = any, Storage = any, Config extends Extensio
4436
4436
  * Defines if this markdown element should indent it's child elements
4437
4437
  */
4438
4438
  indentsContent?: boolean;
4439
+ /**
4440
+ * Lets a mark tell the Markdown serializer which inline HTML tags it can
4441
+ * safely use when plain markdown delimiters would become ambiguous.
4442
+ *
4443
+ * This is mainly useful for overlapping marks. For example, bold followed
4444
+ * by bold+italic followed by italic cannot always be written back with only
4445
+ * `*` and `**` in a way that still parses correctly. In that case, the
4446
+ * serializer can close the overlapping section with markdown and reopen the
4447
+ * remaining tail with HTML instead.
4448
+ *
4449
+ * Example:
4450
+ * - desired formatting: `**123` + `*456*` + `789 italic`
4451
+ * - serialized result: `**123*456***<em>789</em>`
4452
+ *
4453
+ * If your extension defines custom mark names, set `htmlReopen` on that
4454
+ * extension so the serializer can reuse its HTML form for overlap cases.
4455
+ */
4456
+ htmlReopen?: {
4457
+ open: string;
4458
+ close: string;
4459
+ };
4439
4460
  };
4440
4461
  /**
4441
4462
  * This function extends the schema of the node.
@@ -5279,7 +5300,8 @@ type MarkdownToken = {
5279
5300
  */
5280
5301
  type MarkdownParseHelpers = {
5281
5302
  /** Parse an array of inline tokens into text nodes with marks */parseInline: (tokens: MarkdownToken[]) => JSONContent[]; /** Parse an array of block-level tokens */
5282
- parseChildren: (tokens: MarkdownToken[]) => JSONContent[]; /** Create a text node with optional marks */
5303
+ parseChildren: (tokens: MarkdownToken[]) => JSONContent[]; /** Parse block-level tokens while preserving implicit empty paragraphs from blank lines */
5304
+ parseBlockChildren?: (tokens: MarkdownToken[]) => JSONContent[]; /** Create a text node with optional marks */
5283
5305
  createTextNode: (text: string, marks?: Array<{
5284
5306
  type: string;
5285
5307
  attrs?: any;
@@ -5312,6 +5334,7 @@ type RenderContext = {
5312
5334
  level: number;
5313
5335
  meta?: Record<string, any>;
5314
5336
  parentType?: string | null;
5337
+ previousNode?: JSONContent | null;
5315
5338
  };
5316
5339
  /** Extension contract for markdown parsing/serialization. */
5317
5340
  /**
@@ -5345,7 +5368,8 @@ type MarkdownRendererHelpers = {
5345
5368
  * @param separator An optional separator string (legacy) or RenderContext
5346
5369
  * @returns The rendered markdown string
5347
5370
  */
5348
- renderChildren: (nodes: JSONContent | JSONContent[], separator?: string) => string;
5371
+ renderChildren: (nodes: JSONContent | JSONContent[], separator?: string) => string; /** Render a single child node with its sibling index preserved */
5372
+ renderChild?: (node: JSONContent, index: number) => string;
5349
5373
  /**
5350
5374
  * Render a text token to a markdown string
5351
5375
  * @param prefix The prefix to add before the content
@@ -6763,12 +6787,225 @@ declare function convertDocument(node: JSONContent, params: {
6763
6787
  declare function convertNode(node: JSONContent, options: DocxExportOptions, effectiveContentWidth: number): Promise<FileChild | FileChild[] | null>;
6764
6788
  //#endregion
6765
6789
  //#region ../extensions/dist/types.d.mts
6790
+ //#region ../../node_modules/.pnpm/docx@9.6.1/node_modules/docx/dist/index.d.ts
6791
+ declare const CompoundLine: {
6792
+ readonly SINGLE: "sng";
6793
+ readonly DOUBLE: "dbl";
6794
+ readonly THICK_THIN: "thickThin";
6795
+ readonly THIN_THICK: "thinThick";
6796
+ readonly TRI: "tri";
6797
+ };
6798
+ declare type CoreImageOptions = {
6799
+ readonly transformation: IMediaTransformation;
6800
+ readonly floating?: IFloating;
6801
+ readonly altText?: DocPropertiesOptions;
6802
+ readonly outline?: OutlineOptions;
6803
+ readonly solidFill?: SolidFillOptions;
6804
+ };
6805
+ declare type DocPropertiesOptions = {
6806
+ readonly name: string;
6807
+ readonly description?: string;
6808
+ readonly title?: string;
6809
+ readonly id?: string;
6810
+ };
6811
+ declare const HorizontalPositionAlign: {
6812
+ readonly CENTER: "center";
6813
+ readonly INSIDE: "inside";
6814
+ readonly LEFT: "left";
6815
+ readonly OUTSIDE: "outside";
6816
+ readonly RIGHT: "right";
6817
+ };
6818
+ declare const HorizontalPositionRelativeFrom: {
6819
+ readonly CHARACTER: "character";
6820
+ readonly COLUMN: "column";
6821
+ readonly INSIDE_MARGIN: "insideMargin";
6822
+ readonly LEFT_MARGIN: "leftMargin";
6823
+ readonly MARGIN: "margin";
6824
+ readonly OUTSIDE_MARGIN: "outsideMargin";
6825
+ readonly PAGE: "page";
6826
+ readonly RIGHT_MARGIN: "rightMargin";
6827
+ };
6828
+ declare type IDistance = {
6829
+ readonly distT?: number;
6830
+ readonly distB?: number;
6831
+ readonly distL?: number;
6832
+ readonly distR?: number;
6833
+ };
6834
+ declare type IFloating = {
6835
+ readonly horizontalPosition: IHorizontalPositionOptions;
6836
+ readonly verticalPosition: IVerticalPositionOptions;
6837
+ readonly allowOverlap?: boolean;
6838
+ readonly lockAnchor?: boolean;
6839
+ readonly behindDocument?: boolean;
6840
+ readonly layoutInCell?: boolean;
6841
+ readonly margins?: IMargins;
6842
+ readonly wrap?: ITextWrapping;
6843
+ readonly zIndex?: number;
6844
+ };
6845
+ declare type IHorizontalPositionOptions = {
6846
+ readonly relative?: (typeof HorizontalPositionRelativeFrom)[keyof typeof HorizontalPositionRelativeFrom];
6847
+ readonly align?: (typeof HorizontalPositionAlign)[keyof typeof HorizontalPositionAlign];
6848
+ readonly offset?: number;
6849
+ };
6850
+ declare type IImageOptions$1 = (RegularImageOptions | SvgMediaOptions) & CoreImageOptions;
6851
+ declare type IMargins = {
6852
+ readonly left?: number;
6853
+ readonly bottom?: number;
6854
+ readonly top?: number;
6855
+ readonly right?: number;
6856
+ };
6857
+ declare type IMediaTransformation = {
6858
+ readonly offset?: {
6859
+ readonly top?: number;
6860
+ readonly left?: number;
6861
+ };
6862
+ readonly width: number;
6863
+ readonly height: number;
6864
+ readonly flip?: {
6865
+ readonly vertical?: boolean;
6866
+ readonly horizontal?: boolean;
6867
+ };
6868
+ readonly rotation?: number;
6869
+ };
6870
+ declare type ITextWrapping = {
6871
+ readonly type: (typeof TextWrappingType)[keyof typeof TextWrappingType];
6872
+ readonly side?: (typeof TextWrappingSide)[keyof typeof TextWrappingSide];
6873
+ readonly margins?: IDistance;
6874
+ };
6875
+ declare type IVerticalPositionOptions = {
6876
+ readonly relative?: (typeof VerticalPositionRelativeFrom)[keyof typeof VerticalPositionRelativeFrom];
6877
+ readonly align?: (typeof VerticalPositionAlign)[keyof typeof VerticalPositionAlign];
6878
+ readonly offset?: number;
6879
+ };
6880
+ declare const LineCap: {
6881
+ readonly ROUND: "rnd";
6882
+ readonly SQUARE: "sq";
6883
+ readonly FLAT: "flat";
6884
+ };
6885
+ declare type OutlineAttributes = {
6886
+ readonly width?: number;
6887
+ readonly cap?: keyof typeof LineCap;
6888
+ readonly compoundLine?: keyof typeof CompoundLine;
6889
+ readonly align?: keyof typeof PenAlignment;
6890
+ };
6891
+ declare type OutlineFillProperties = OutlineNoFill | OutlineSolidFill;
6892
+ declare type OutlineNoFill = {
6893
+ readonly type: "noFill";
6894
+ };
6895
+ declare type OutlineOptions = OutlineAttributes & OutlineFillProperties;
6896
+ declare type OutlineRgbSolidFill = {
6897
+ readonly type: "solidFill";
6898
+ readonly solidFillType: "rgb";
6899
+ readonly value: string;
6900
+ };
6901
+ declare type OutlineSchemeSolidFill = {
6902
+ readonly type: "solidFill";
6903
+ readonly solidFillType: "scheme";
6904
+ readonly value: (typeof SchemeColor)[keyof typeof SchemeColor];
6905
+ };
6906
+ declare type OutlineSolidFill = OutlineRgbSolidFill | OutlineSchemeSolidFill;
6907
+ declare const PenAlignment: {
6908
+ readonly CENTER: "ctr";
6909
+ readonly INSET: "in";
6910
+ };
6911
+ declare type RegularImageOptions = {
6912
+ readonly type: "jpg" | "png" | "gif" | "bmp";
6913
+ readonly data: Buffer | string | Uint8Array | ArrayBuffer;
6914
+ };
6915
+ declare type RgbColorOptions = {
6916
+ readonly type: "rgb";
6917
+ readonly value: string;
6918
+ };
6919
+ declare const SchemeColor: {
6920
+ readonly BG1: "bg1";
6921
+ readonly TX1: "tx1";
6922
+ readonly BG2: "bg2";
6923
+ readonly TX2: "tx2";
6924
+ readonly ACCENT1: "accent1";
6925
+ readonly ACCENT2: "accent2";
6926
+ readonly ACCENT3: "accent3";
6927
+ readonly ACCENT4: "accent4";
6928
+ readonly ACCENT5: "accent5";
6929
+ readonly ACCENT6: "accent6";
6930
+ readonly HLINK: "hlink";
6931
+ readonly FOLHLINK: "folHlink";
6932
+ readonly DK1: "dk1";
6933
+ readonly LT1: "lt1";
6934
+ readonly DK2: "dk2";
6935
+ readonly LT2: "lt2";
6936
+ readonly PHCLR: "phClr";
6937
+ };
6938
+ declare type SchemeColorOptions = {
6939
+ readonly type: "scheme";
6940
+ readonly value: (typeof SchemeColor)[keyof typeof SchemeColor];
6941
+ };
6942
+ declare type SolidFillOptions = RgbColorOptions | SchemeColorOptions;
6943
+ declare type SvgMediaOptions = {
6944
+ readonly type: "svg";
6945
+ readonly data: Buffer | string | Uint8Array | ArrayBuffer;
6946
+ readonly fallback: RegularImageOptions;
6947
+ };
6948
+ declare const TextWrappingSide: {
6949
+ readonly BOTH_SIDES: "bothSides";
6950
+ readonly LEFT: "left";
6951
+ readonly RIGHT: "right";
6952
+ readonly LARGEST: "largest";
6953
+ };
6954
+ declare const TextWrappingType: {
6955
+ readonly NONE: 0;
6956
+ readonly SQUARE: 1;
6957
+ readonly TIGHT: 2;
6958
+ readonly TOP_AND_BOTTOM: 3;
6959
+ };
6960
+ declare const VerticalPositionAlign: {
6961
+ readonly BOTTOM: "bottom";
6962
+ readonly CENTER: "center";
6963
+ readonly INSIDE: "inside";
6964
+ readonly OUTSIDE: "outside";
6965
+ readonly TOP: "top";
6966
+ };
6967
+ declare const VerticalPositionRelativeFrom: {
6968
+ readonly BOTTOM_MARGIN: "bottomMargin";
6969
+ readonly INSIDE_MARGIN: "insideMargin";
6970
+ readonly LINE: "line";
6971
+ readonly MARGIN: "margin";
6972
+ readonly OUTSIDE_MARGIN: "outsideMargin";
6973
+ readonly PAGE: "page";
6974
+ readonly PARAGRAPH: "paragraph";
6975
+ readonly TOP_MARGIN: "topMargin";
6976
+ }; //#endregion
6766
6977
  //#region src/types.d.ts
6978
+ /**
6979
+ * Border definition (compatible with docx.js BorderOptions)
6980
+ * Used by paragraphs, table cells, and blockquotes
6981
+ */
6982
+ interface Border {
6983
+ /** Border color (hex without #, e.g., "FF0000" or "auto") */
6984
+ color?: string;
6985
+ /** Border size (eighth-points, 1/8 pt) */
6986
+ size?: number;
6987
+ /** Border style */
6988
+ style?: "single" | "dashed" | "dotted" | "double" | "dotDash" | "dotDotDash" | "none";
6989
+ /** Space between border and content (points) */
6990
+ space?: number;
6991
+ }
6992
+ /**
6993
+ * Shading definition (compatible with docx.js ShadingOptions)
6994
+ * Used for paragraph and table cell background colors
6995
+ */
6996
+ interface Shading {
6997
+ /** Fill color (hex without #, e.g., "FF0000") */
6998
+ fill?: string;
6999
+ /** Pattern color (hex without #) */
7000
+ color?: string;
7001
+ /** Shading pattern type (e.g., "clear", "percent-10") */
7002
+ type?: string;
7003
+ }
6767
7004
  type ImageFloatingOptions = {
6768
7005
  horizontalPosition: IHorizontalPositionOptions;
6769
7006
  verticalPosition: IVerticalPositionOptions;
6770
7007
  } & Partial<Omit<IFloating, "horizontalPosition" | "verticalPosition">>;
6771
- type ImageOutlineOptions = IImageOptions["outline"];
7008
+ type ImageOutlineOptions = IImageOptions$1["outline"];
6772
7009
  interface TextNode {
6773
7010
  type: "text";
6774
7011
  text: string;
@@ -6806,6 +7043,11 @@ interface ParagraphNode extends JSONContent {
6806
7043
  indentFirstLine?: string;
6807
7044
  spacingBefore?: string;
6808
7045
  spacingAfter?: string;
7046
+ shading?: Shading;
7047
+ borderTop?: Border;
7048
+ borderBottom?: Border;
7049
+ borderLeft?: Border;
7050
+ borderRight?: Border;
6809
7051
  };
6810
7052
  content?: Array<TextNode | HardBreakNode | ImageNode>;
6811
7053
  }
@@ -6819,6 +7061,11 @@ interface HeadingNode extends JSONContent {
6819
7061
  spacingBefore?: string;
6820
7062
  spacingAfter?: string;
6821
7063
  textAlign?: "left" | "right" | "center" | "justify";
7064
+ shading?: Shading;
7065
+ borderTop?: Border;
7066
+ borderBottom?: Border;
7067
+ borderLeft?: Border;
7068
+ borderRight?: Border;
6822
7069
  };
6823
7070
  content?: Array<TextNode | HardBreakNode>;
6824
7071
  }
@@ -6864,11 +7111,6 @@ interface TaskItemNode extends JSONContent {
6864
7111
  };
6865
7112
  content?: Array<ParagraphNode>;
6866
7113
  }
6867
- interface TableCellBorder {
6868
- color?: string;
6869
- width?: number;
6870
- style?: "solid" | "dashed" | "dotted" | "double" | "none";
6871
- }
6872
7114
  interface TableNode extends JSONContent {
6873
7115
  type: "table";
6874
7116
  attrs?: {
@@ -6894,10 +7136,10 @@ interface TableCellNode extends JSONContent {
6894
7136
  colwidth?: number[] | null;
6895
7137
  backgroundColor?: string | null;
6896
7138
  verticalAlign?: "top" | "middle" | "bottom" | null;
6897
- borderTop?: TableCellBorder | null;
6898
- borderBottom?: TableCellBorder | null;
6899
- borderLeft?: TableCellBorder | null;
6900
- borderRight?: TableCellBorder | null;
7139
+ borderTop?: Border;
7140
+ borderBottom?: Border;
7141
+ borderLeft?: Border;
7142
+ borderRight?: Border;
6901
7143
  };
6902
7144
  content?: Array<ParagraphNode>;
6903
7145
  }
@@ -6909,10 +7151,10 @@ interface TableHeaderNode extends JSONContent {
6909
7151
  colwidth?: number[] | null;
6910
7152
  backgroundColor?: string | null;
6911
7153
  verticalAlign?: "top" | "middle" | "bottom" | null;
6912
- borderTop?: TableCellBorder | null;
6913
- borderBottom?: TableCellBorder | null;
6914
- borderLeft?: TableCellBorder | null;
6915
- borderRight?: TableCellBorder | null;
7154
+ borderTop?: Border;
7155
+ borderBottom?: Border;
7156
+ borderLeft?: Border;
7157
+ borderRight?: Border;
6916
7158
  };
6917
7159
  content?: Array<ParagraphNode>;
6918
7160
  }
@@ -7632,26 +7874,30 @@ declare function createStringValidator<T extends string>(validValues: readonly T
7632
7874
  * Calculate effective content width from document options
7633
7875
  */
7634
7876
  declare function calculateEffectiveContentWidth(options?: DocxExportOptions): number;
7635
- //#endregion
7636
- //#region src/utils/paragraph.d.ts
7637
7877
  /**
7638
- * Apply paragraph style attributes to options
7878
+ * Convert Border to docx.js format
7639
7879
  */
7640
- declare const applyParagraphStyleAttributes: <T extends Record<string, unknown>>(options: T, attrs?: ParagraphNode["attrs"]) => T;
7641
- //#endregion
7642
- //#region src/utils/table.d.ts
7880
+ declare function convertBorder(border?: Border): {
7881
+ color?: string;
7882
+ size?: number;
7883
+ style?: string;
7884
+ space?: number;
7885
+ } | undefined;
7643
7886
  /**
7644
- * Convert TipTap border to DOCX border format
7645
- *
7646
- * @param border - TipTap table cell border definition
7647
- * @returns DOCX border options or undefined if no border
7887
+ * Convert Shading to docx.js format
7648
7888
  */
7649
- declare function convertBorder(border: TableCellBorder | null | undefined): {
7889
+ declare function convertShading(shading?: Shading): {
7890
+ fill?: string;
7650
7891
  color?: string;
7651
- size?: number;
7652
- style: "single" | "dashed" | "dotted" | "double" | "none";
7892
+ val?: string;
7653
7893
  } | undefined;
7654
7894
  //#endregion
7895
+ //#region src/utils/paragraph.d.ts
7896
+ /**
7897
+ * Apply paragraph style attributes to options
7898
+ */
7899
+ declare const applyParagraphStyleAttributes: <T extends Record<string, unknown>>(options: T, attrs?: ParagraphNode["attrs"]) => T;
7900
+ //#endregion
7655
7901
  //#region src/converters/image.d.ts
7656
7902
  /**
7657
7903
  * Convert TipTap image node to DOCX ImageRun
@@ -7825,4 +8071,4 @@ declare function convertDetailsSummary(node: DetailsSummaryNode, params: {
7825
8071
  /** Export options for details styling */options?: DocxExportOptions["details"];
7826
8072
  }): IParagraphOptions;
7827
8073
  //#endregion
7828
- export { BlockNode, BlockquoteNode, BulletListNode, CHECKBOX_SYMBOLS, COLOR_NAME_TO_HEX, CodeBlockNode, DEFAULT_CODE_FONT, DOCX_DPI, DOCX_STYLE_NAMES, DetailsContentNode, DetailsNode, DetailsSummaryNode, DocumentNode, DocxExportOptions, DocxImageExportHandler, EMUS_PER_INCH, HALF_POINTS_PER_PIXEL, HardBreakNode, HeadingNode, HorizontalRuleNode, ImageFloatingOptions, ImageNode, ImageOutlineOptions, type JSONContent, ListItemNode, ListOptions, Mark, OrderedListNode, PAGE_DIMENSIONS, PIXELS_PER_HALF_POINT, ParagraphNode, PositiveUniversalMeasure, TEXT_ALIGN_MAP, TWIPS_PER_INCH, TableCellBorder, TableCellNode, TableHeaderNode, TableNode, TableRowNode, TaskItemNode, TaskListNode, TextContent, TextNode, applyParagraphStyleAttributes, applyTableMargins, calculateEffectiveContentWidth, convertBlockquote, convertBorder, convertBulletList, convertCodeBlock, convertColorToHex, convertCssLengthToPixels, convertDetailsSummary, convertDocument, convertEmuStringToPixels, convertEmuToPixels, convertHardBreak, convertHeading, convertHorizontalRule, convertImage, convertList, convertListItem, convertMeasureToInches, convertMeasureToPixels, convertNode, convertOrderedList, convertParagraph, convertPixelsToEmu, convertPixelsToTwip, convertTable, convertTableCell, convertTableHeader, convertTableRow, convertTaskItem, convertTaskList, convertText, convertTextNodes, convertToDocxImageType, convertTwipToCssString, convertTwipToPixels, createFloatingOptions, createStringValidator, findChild, findDeepChild, findDeepChildren, generateDOCX, getImageDataAndMeta, getImageHeight, getImageTypeFromSrc, getImageWidth, normalizeHexColor, parseTwipAttr };
8074
+ export { BlockNode, BlockquoteNode, Border, BulletListNode, CHECKBOX_SYMBOLS, COLOR_NAME_TO_HEX, CodeBlockNode, DEFAULT_CODE_FONT, DOCX_DPI, DOCX_STYLE_NAMES, DetailsContentNode, DetailsNode, DetailsSummaryNode, DocumentNode, DocxExportOptions, DocxImageExportHandler, EMUS_PER_INCH, HALF_POINTS_PER_PIXEL, HardBreakNode, HeadingNode, HorizontalRuleNode, ImageFloatingOptions, ImageNode, ImageOutlineOptions, type JSONContent, ListItemNode, ListOptions, Mark, OrderedListNode, PAGE_DIMENSIONS, PIXELS_PER_HALF_POINT, ParagraphNode, PositiveUniversalMeasure, Shading, TEXT_ALIGN_MAP, TWIPS_PER_INCH, TableCellNode, TableHeaderNode, TableNode, TableRowNode, TaskItemNode, TaskListNode, TextContent, TextNode, applyParagraphStyleAttributes, applyTableMargins, calculateEffectiveContentWidth, convertBlockquote, convertBorder, convertBulletList, convertCodeBlock, convertColorToHex, convertCssLengthToPixels, convertDetailsSummary, convertDocument, convertEmuStringToPixels, convertEmuToPixels, convertHardBreak, convertHeading, convertHorizontalRule, convertImage, convertList, convertListItem, convertMeasureToInches, convertMeasureToPixels, convertNode, convertOrderedList, convertParagraph, convertPixelsToEmu, convertPixelsToTwip, convertShading, convertTable, convertTableCell, convertTableHeader, convertTableRow, convertTaskItem, convertTaskList, convertText, convertTextNodes, convertToDocxImageType, convertTwipToCssString, convertTwipToPixels, createFloatingOptions, createStringValidator, findChild, findDeepChild, findDeepChildren, generateDOCX, getImageDataAndMeta, getImageHeight, getImageTypeFromSrc, getImageWidth, normalizeHexColor, parseTwipAttr };
package/dist/index.mjs CHANGED
@@ -438,6 +438,29 @@ function calculateEffectiveContentWidth(options) {
438
438
  const effectiveWidth = pageWidth - marginLeft - marginRight;
439
439
  return Math.max(convertTwipToPixels(effectiveWidth), 96);
440
440
  }
441
+ /**
442
+ * Convert Border to docx.js format
443
+ */
444
+ function convertBorder(border) {
445
+ if (!border) return void 0;
446
+ const docxBorder = {};
447
+ if (border.color) docxBorder.color = border.color.replace("#", "");
448
+ if (border.size !== void 0) docxBorder.size = border.size;
449
+ if (border.style) docxBorder.style = border.style;
450
+ if (border.space !== void 0) docxBorder.space = border.space;
451
+ return Object.keys(docxBorder).length > 0 ? docxBorder : void 0;
452
+ }
453
+ /**
454
+ * Convert Shading to docx.js format
455
+ */
456
+ function convertShading(shading) {
457
+ if (!shading || !shading.fill) return void 0;
458
+ const docxShading = {};
459
+ if (shading.fill) docxShading.fill = shading.fill.replace("#", "");
460
+ if (shading.color) docxShading.color = shading.color.replace("#", "");
461
+ docxShading.val = shading.type || "clear";
462
+ return docxShading;
463
+ }
441
464
  //#endregion
442
465
  //#region src/utils/image.ts
443
466
  const DEFAULT_MAX_IMAGE_WIDTH_PIXELS = 6.5 * 96;
@@ -600,52 +623,27 @@ async function getImageDataAndMeta(url) {
600
623
  */
601
624
  const applyParagraphStyleAttributes = (options, attrs) => {
602
625
  if (!attrs) return options;
603
- let result = { ...options };
604
- if (attrs.indentLeft || attrs.indentRight || attrs.indentFirstLine) result = {
605
- ...result,
606
- indent: {
607
- ...attrs.indentLeft && { left: convertPixelsToTwip(convertCssLengthToPixels(attrs.indentLeft)) },
608
- ...attrs.indentRight && { right: convertPixelsToTwip(convertCssLengthToPixels(attrs.indentRight)) },
609
- ...attrs.indentFirstLine && { firstLine: convertPixelsToTwip(convertCssLengthToPixels(attrs.indentFirstLine)) }
610
- }
626
+ const result = { ...options };
627
+ if (attrs.indentLeft || attrs.indentRight || attrs.indentFirstLine) result.indent = {
628
+ ...attrs.indentLeft && { left: convertPixelsToTwip(convertCssLengthToPixels(attrs.indentLeft)) },
629
+ ...attrs.indentRight && { right: convertPixelsToTwip(convertCssLengthToPixels(attrs.indentRight)) },
630
+ ...attrs.indentFirstLine && { firstLine: convertPixelsToTwip(convertCssLengthToPixels(attrs.indentFirstLine)) }
611
631
  };
612
- if (attrs.spacingBefore || attrs.spacingAfter) result = {
613
- ...result,
614
- spacing: {
615
- ...attrs.spacingBefore && { before: convertPixelsToTwip(convertCssLengthToPixels(attrs.spacingBefore)) },
616
- ...attrs.spacingAfter && { after: convertPixelsToTwip(convertCssLengthToPixels(attrs.spacingAfter)) }
617
- }
632
+ if (attrs.spacingBefore || attrs.spacingAfter) result.spacing = {
633
+ ...attrs.spacingBefore && { before: convertPixelsToTwip(convertCssLengthToPixels(attrs.spacingBefore)) },
634
+ ...attrs.spacingAfter && { after: convertPixelsToTwip(convertCssLengthToPixels(attrs.spacingAfter)) }
618
635
  };
619
- if (attrs.textAlign) result = {
620
- ...result,
621
- alignment: TEXT_ALIGN_MAP.tiptapToDocx[attrs.textAlign]
636
+ if (attrs.textAlign) result.alignment = TEXT_ALIGN_MAP.tiptapToDocx[attrs.textAlign];
637
+ if (attrs.shading) result.shading = convertShading(attrs.shading);
638
+ if (attrs.borderTop || attrs.borderBottom || attrs.borderLeft || attrs.borderRight) result.border = {
639
+ ...attrs.borderTop && { top: convertBorder(attrs.borderTop) },
640
+ ...attrs.borderBottom && { bottom: convertBorder(attrs.borderBottom) },
641
+ ...attrs.borderLeft && { left: convertBorder(attrs.borderLeft) },
642
+ ...attrs.borderRight && { right: convertBorder(attrs.borderRight) }
622
643
  };
623
644
  return result;
624
645
  };
625
646
  //#endregion
626
- //#region src/utils/table.ts
627
- /**
628
- * Convert TipTap border to DOCX border format
629
- *
630
- * @param border - TipTap table cell border definition
631
- * @returns DOCX border options or undefined if no border
632
- */
633
- function convertBorder(border) {
634
- if (!border) return void 0;
635
- const docxStyle = border.style ? {
636
- solid: "single",
637
- dashed: "dashed",
638
- dotted: "dotted",
639
- double: "double",
640
- none: "none"
641
- }[border.style] || "single" : "single";
642
- return {
643
- color: border.color?.replace("#", "") || "auto",
644
- size: border.width ? border.width * 6 : 4,
645
- style: docxStyle
646
- };
647
- }
648
- //#endregion
649
647
  //#region src/converters/text.ts
650
648
  /**
651
649
  * Convert TipTap text node to DOCX TextRun or ExternalHyperlink
@@ -933,13 +931,16 @@ async function convertTableCell(node, params) {
933
931
  }
934
932
  if (node.attrs?.backgroundColor) cellOptions.shading = { fill: node.attrs.backgroundColor.replace("#", "") };
935
933
  if (node.attrs?.verticalAlign) cellOptions.verticalAlign = node.attrs.verticalAlign === "middle" ? "center" : node.attrs.verticalAlign;
936
- const borders = {
937
- top: convertBorder(node.attrs?.borderTop),
938
- bottom: convertBorder(node.attrs?.borderBottom),
939
- left: convertBorder(node.attrs?.borderLeft),
940
- right: convertBorder(node.attrs?.borderRight)
941
- };
942
- if (borders.top || borders.bottom || borders.left || borders.right) cellOptions.borders = borders;
934
+ const borders = {};
935
+ const top = convertBorder(node.attrs?.borderTop);
936
+ if (top) borders.top = top;
937
+ const bottom = convertBorder(node.attrs?.borderBottom);
938
+ if (bottom) borders.bottom = bottom;
939
+ const left = convertBorder(node.attrs?.borderLeft);
940
+ if (left) borders.left = left;
941
+ const right = convertBorder(node.attrs?.borderRight);
942
+ if (right) borders.right = right;
943
+ if (Object.keys(borders).length > 0) cellOptions.borders = borders;
943
944
  return new TableCell(cellOptions);
944
945
  }
945
946
  //#endregion
@@ -973,13 +974,16 @@ async function convertTableHeader(node, params) {
973
974
  }
974
975
  if (node.attrs?.backgroundColor) headerCellOptions.shading = { fill: node.attrs.backgroundColor.replace("#", "") };
975
976
  if (node.attrs?.verticalAlign) headerCellOptions.verticalAlign = node.attrs.verticalAlign === "middle" ? "center" : node.attrs.verticalAlign;
976
- const borders = {
977
- top: convertBorder(node.attrs?.borderTop),
978
- bottom: convertBorder(node.attrs?.borderBottom),
979
- left: convertBorder(node.attrs?.borderLeft),
980
- right: convertBorder(node.attrs?.borderRight)
981
- };
982
- if (borders.top || borders.bottom || borders.left || borders.right) headerCellOptions.borders = borders;
977
+ const borders = {};
978
+ const top = convertBorder(node.attrs?.borderTop);
979
+ if (top) borders.top = top;
980
+ const bottom = convertBorder(node.attrs?.borderBottom);
981
+ if (bottom) borders.bottom = bottom;
982
+ const left = convertBorder(node.attrs?.borderLeft);
983
+ if (left) borders.left = left;
984
+ const right = convertBorder(node.attrs?.borderRight);
985
+ if (right) borders.right = right;
986
+ if (Object.keys(borders).length > 0) headerCellOptions.borders = borders;
983
987
  return new TableCell(headerCellOptions);
984
988
  }
985
989
  //#endregion
@@ -1264,11 +1268,13 @@ async function generateDOCX(docJson, options) {
1264
1268
  * Convert document content to DOCX elements
1265
1269
  */
1266
1270
  async function convertDocument(node, params) {
1267
- const elements = [];
1268
- if (!node || !Array.isArray(node.content)) return elements;
1271
+ if (!node || !Array.isArray(node.content)) return [];
1269
1272
  const effectiveContentWidth = calculateEffectiveContentWidth(params.options);
1270
- for (const childNode of node.content) {
1271
- const element = await convertNode(childNode, params.options, effectiveContentWidth);
1273
+ const convertedElements = await Promise.all(node.content.map((childNode) => convertNode(childNode, params.options, effectiveContentWidth)));
1274
+ const elements = [];
1275
+ for (let i = 0; i < convertedElements.length; i++) {
1276
+ const element = convertedElements[i];
1277
+ const childNode = node.content[i];
1272
1278
  if (Array.isArray(element)) elements.push(...element);
1273
1279
  else if (element) {
1274
1280
  elements.push(element);
@@ -1292,6 +1298,7 @@ async function convertNode(node, options, effectiveContentWidth) {
1292
1298
  if (Array.isArray(dataResult)) {
1293
1299
  const styleId = getStyleIdByNodeType(node.type, options);
1294
1300
  return dataResult.map((paragraphOptions) => {
1301
+ if (!styleId) return new Paragraph(paragraphOptions);
1295
1302
  return new Paragraph(applyStyleReference(paragraphOptions, styleId));
1296
1303
  });
1297
1304
  }
@@ -1299,6 +1306,7 @@ async function convertNode(node, options, effectiveContentWidth) {
1299
1306
  if (!styleId && node.type === "paragraph" && node.content) {
1300
1307
  if (node.content.length > 0 && node.content.every((child) => child.type === "image")) styleId = options.image?.style?.id;
1301
1308
  }
1309
+ if (!styleId) return createDOCXObject(dataResult);
1302
1310
  return createDOCXObject(applyStyleReference(dataResult, styleId));
1303
1311
  }
1304
1312
  /**
@@ -1443,4 +1451,4 @@ function createDOCXObject(options) {
1443
1451
  return new Paragraph(options);
1444
1452
  }
1445
1453
  //#endregion
1446
- export { CHECKBOX_SYMBOLS, COLOR_NAME_TO_HEX, DEFAULT_CODE_FONT, DOCX_DPI, DOCX_STYLE_NAMES, EMUS_PER_INCH, HALF_POINTS_PER_PIXEL, PAGE_DIMENSIONS, PIXELS_PER_HALF_POINT, TEXT_ALIGN_MAP, TWIPS_PER_INCH, applyParagraphStyleAttributes, applyTableMargins, calculateEffectiveContentWidth, convertBlockquote, convertBorder, convertBulletList, convertCodeBlock, convertColorToHex, convertCssLengthToPixels, convertDetailsSummary, convertDocument, convertEmuStringToPixels, convertEmuToPixels, convertHardBreak, convertHeading, convertHorizontalRule, convertImage, convertList, convertListItem, convertMeasureToInches, convertMeasureToPixels, convertNode, convertOrderedList, convertParagraph, convertPixelsToEmu, convertPixelsToTwip, convertTable, convertTableCell, convertTableHeader, convertTableRow, convertTaskItem, convertTaskList, convertText, convertTextNodes, convertToDocxImageType, convertTwipToCssString, convertTwipToPixels, createFloatingOptions, createStringValidator, findChild, findDeepChild, findDeepChildren, generateDOCX, getImageDataAndMeta, getImageHeight, getImageTypeFromSrc, getImageWidth, normalizeHexColor, parseTwipAttr };
1454
+ export { CHECKBOX_SYMBOLS, COLOR_NAME_TO_HEX, DEFAULT_CODE_FONT, DOCX_DPI, DOCX_STYLE_NAMES, EMUS_PER_INCH, HALF_POINTS_PER_PIXEL, PAGE_DIMENSIONS, PIXELS_PER_HALF_POINT, TEXT_ALIGN_MAP, TWIPS_PER_INCH, applyParagraphStyleAttributes, applyTableMargins, calculateEffectiveContentWidth, convertBlockquote, convertBorder, convertBulletList, convertCodeBlock, convertColorToHex, convertCssLengthToPixels, convertDetailsSummary, convertDocument, convertEmuStringToPixels, convertEmuToPixels, convertHardBreak, convertHeading, convertHorizontalRule, convertImage, convertList, convertListItem, convertMeasureToInches, convertMeasureToPixels, convertNode, convertOrderedList, convertParagraph, convertPixelsToEmu, convertPixelsToTwip, convertShading, convertTable, convertTableCell, convertTableHeader, convertTableRow, convertTaskItem, convertTaskList, convertText, convertTextNodes, convertToDocxImageType, convertTwipToCssString, convertTwipToPixels, createFloatingOptions, createStringValidator, findChild, findDeepChild, findDeepChildren, generateDOCX, getImageDataAndMeta, getImageHeight, getImageTypeFromSrc, getImageWidth, normalizeHexColor, parseTwipAttr };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docen/export-docx",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "description": "A powerful TipTap/ProseMirror extension that converts editor content to Microsoft Word DOCX format",
5
5
  "keywords": [
6
6
  "converter",
@@ -54,9 +54,9 @@
54
54
  "ofetch": "1.5.1"
55
55
  },
56
56
  "devDependencies": {
57
- "@tiptap/core": "3.20.1",
58
- "@docen/utils": "0.0.12",
59
- "@docen/extensions": "0.0.12"
57
+ "@tiptap/core": "3.20.4",
58
+ "@docen/extensions": "0.0.14",
59
+ "@docen/utils": "0.0.14"
60
60
  },
61
61
  "scripts": {
62
62
  "dev": "basis build --stub",