@blocknote/xl-docx-exporter 0.48.0 → 0.49.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/dist/blocknote-xl-docx-exporter.cjs +1 -1
- package/dist/blocknote-xl-docx-exporter.cjs.map +1 -1
- package/dist/blocknote-xl-docx-exporter.js +3 -3
- package/dist/blocknote-xl-docx-exporter.js.map +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +7 -7
- package/src/docx/__snapshots__/basic/document.xml +2 -2
- package/src/docx/__snapshots__/basic/styles.xml +175 -0
- package/src/docx/__snapshots__/noLocale/styles.xml +1159 -0
- package/src/docx/__snapshots__/withCustomOptions/document.xml.rels +1 -0
- package/src/docx/__snapshots__/withLocale/styles.xml +1160 -0
- package/src/docx/__snapshots__/withMultiColumn/styles.xml +175 -0
- package/src/docx/docxExporter.test.ts +47 -0
- package/src/docx/docxExporter.ts +17 -12
- package/types/src/docx/docxExporter.d.ts +4 -4
|
@@ -1,5 +1,180 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
2
2
|
<w:styles xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16du="http://schemas.microsoft.com/office/word/2023/wordml/word16du" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh w16du">
|
|
3
|
+
<w:docDefaults>
|
|
4
|
+
<w:rPrDefault/>
|
|
5
|
+
<w:pPrDefault/>
|
|
6
|
+
</w:docDefaults>
|
|
7
|
+
<w:style w:type="paragraph" w:styleId="Title">
|
|
8
|
+
<w:name w:val="Title"/>
|
|
9
|
+
<w:basedOn w:val="Normal"/>
|
|
10
|
+
<w:next w:val="Normal"/>
|
|
11
|
+
<w:qFormat/>
|
|
12
|
+
<w:rPr>
|
|
13
|
+
<w:sz w:val="56"/>
|
|
14
|
+
<w:szCs w:val="56"/>
|
|
15
|
+
</w:rPr>
|
|
16
|
+
</w:style>
|
|
17
|
+
<w:style w:type="paragraph" w:styleId="Heading1">
|
|
18
|
+
<w:name w:val="Heading 1"/>
|
|
19
|
+
<w:basedOn w:val="Normal"/>
|
|
20
|
+
<w:next w:val="Normal"/>
|
|
21
|
+
<w:qFormat/>
|
|
22
|
+
<w:rPr>
|
|
23
|
+
<w:color w:val="2E74B5"/>
|
|
24
|
+
<w:sz w:val="32"/>
|
|
25
|
+
<w:szCs w:val="32"/>
|
|
26
|
+
</w:rPr>
|
|
27
|
+
</w:style>
|
|
28
|
+
<w:style w:type="paragraph" w:styleId="Heading2">
|
|
29
|
+
<w:name w:val="Heading 2"/>
|
|
30
|
+
<w:basedOn w:val="Normal"/>
|
|
31
|
+
<w:next w:val="Normal"/>
|
|
32
|
+
<w:qFormat/>
|
|
33
|
+
<w:rPr>
|
|
34
|
+
<w:color w:val="2E74B5"/>
|
|
35
|
+
<w:sz w:val="26"/>
|
|
36
|
+
<w:szCs w:val="26"/>
|
|
37
|
+
</w:rPr>
|
|
38
|
+
</w:style>
|
|
39
|
+
<w:style w:type="paragraph" w:styleId="Heading3">
|
|
40
|
+
<w:name w:val="Heading 3"/>
|
|
41
|
+
<w:basedOn w:val="Normal"/>
|
|
42
|
+
<w:next w:val="Normal"/>
|
|
43
|
+
<w:qFormat/>
|
|
44
|
+
<w:rPr>
|
|
45
|
+
<w:color w:val="1F4D78"/>
|
|
46
|
+
<w:sz w:val="24"/>
|
|
47
|
+
<w:szCs w:val="24"/>
|
|
48
|
+
</w:rPr>
|
|
49
|
+
</w:style>
|
|
50
|
+
<w:style w:type="paragraph" w:styleId="Heading4">
|
|
51
|
+
<w:name w:val="Heading 4"/>
|
|
52
|
+
<w:basedOn w:val="Normal"/>
|
|
53
|
+
<w:next w:val="Normal"/>
|
|
54
|
+
<w:qFormat/>
|
|
55
|
+
<w:rPr>
|
|
56
|
+
<w:i/>
|
|
57
|
+
<w:iCs/>
|
|
58
|
+
<w:color w:val="2E74B5"/>
|
|
59
|
+
</w:rPr>
|
|
60
|
+
</w:style>
|
|
61
|
+
<w:style w:type="paragraph" w:styleId="Heading5">
|
|
62
|
+
<w:name w:val="Heading 5"/>
|
|
63
|
+
<w:basedOn w:val="Normal"/>
|
|
64
|
+
<w:next w:val="Normal"/>
|
|
65
|
+
<w:qFormat/>
|
|
66
|
+
<w:rPr>
|
|
67
|
+
<w:color w:val="2E74B5"/>
|
|
68
|
+
</w:rPr>
|
|
69
|
+
</w:style>
|
|
70
|
+
<w:style w:type="paragraph" w:styleId="Heading6">
|
|
71
|
+
<w:name w:val="Heading 6"/>
|
|
72
|
+
<w:basedOn w:val="Normal"/>
|
|
73
|
+
<w:next w:val="Normal"/>
|
|
74
|
+
<w:qFormat/>
|
|
75
|
+
<w:rPr>
|
|
76
|
+
<w:color w:val="1F4D78"/>
|
|
77
|
+
</w:rPr>
|
|
78
|
+
</w:style>
|
|
79
|
+
<w:style w:type="paragraph" w:styleId="Strong">
|
|
80
|
+
<w:name w:val="Strong"/>
|
|
81
|
+
<w:basedOn w:val="Normal"/>
|
|
82
|
+
<w:next w:val="Normal"/>
|
|
83
|
+
<w:qFormat/>
|
|
84
|
+
<w:rPr>
|
|
85
|
+
<w:b/>
|
|
86
|
+
<w:bCs/>
|
|
87
|
+
</w:rPr>
|
|
88
|
+
</w:style>
|
|
89
|
+
<w:style w:type="paragraph" w:styleId="ListParagraph">
|
|
90
|
+
<w:name w:val="List Paragraph"/>
|
|
91
|
+
<w:basedOn w:val="Normal"/>
|
|
92
|
+
<w:qFormat/>
|
|
93
|
+
</w:style>
|
|
94
|
+
<w:style w:type="character" w:styleId="Hyperlink">
|
|
95
|
+
<w:name w:val="Hyperlink"/>
|
|
96
|
+
<w:basedOn w:val="DefaultParagraphFont"/>
|
|
97
|
+
<w:uiPriority w:val="99"/>
|
|
98
|
+
<w:unhideWhenUsed/>
|
|
99
|
+
<w:rPr>
|
|
100
|
+
<w:color w:val="0563C1"/>
|
|
101
|
+
<w:u w:val="single"/>
|
|
102
|
+
</w:rPr>
|
|
103
|
+
</w:style>
|
|
104
|
+
<w:style w:type="character" w:styleId="FootnoteReference">
|
|
105
|
+
<w:name w:val="footnote reference"/>
|
|
106
|
+
<w:basedOn w:val="DefaultParagraphFont"/>
|
|
107
|
+
<w:uiPriority w:val="99"/>
|
|
108
|
+
<w:semiHidden/>
|
|
109
|
+
<w:unhideWhenUsed/>
|
|
110
|
+
<w:rPr>
|
|
111
|
+
<w:vertAlign w:val="superscript"/>
|
|
112
|
+
</w:rPr>
|
|
113
|
+
</w:style>
|
|
114
|
+
<w:style w:type="paragraph" w:styleId="FootnoteText">
|
|
115
|
+
<w:name w:val="footnote text"/>
|
|
116
|
+
<w:basedOn w:val="Normal"/>
|
|
117
|
+
<w:link w:val="FootnoteTextChar"/>
|
|
118
|
+
<w:uiPriority w:val="99"/>
|
|
119
|
+
<w:semiHidden/>
|
|
120
|
+
<w:unhideWhenUsed/>
|
|
121
|
+
<w:pPr>
|
|
122
|
+
<w:spacing w:after="0" w:line="240" w:lineRule="auto"/>
|
|
123
|
+
</w:pPr>
|
|
124
|
+
<w:rPr>
|
|
125
|
+
<w:sz w:val="20"/>
|
|
126
|
+
<w:szCs w:val="20"/>
|
|
127
|
+
</w:rPr>
|
|
128
|
+
</w:style>
|
|
129
|
+
<w:style w:type="character" w:styleId="FootnoteTextChar">
|
|
130
|
+
<w:name w:val="Footnote Text Char"/>
|
|
131
|
+
<w:basedOn w:val="DefaultParagraphFont"/>
|
|
132
|
+
<w:link w:val="FootnoteText"/>
|
|
133
|
+
<w:uiPriority w:val="99"/>
|
|
134
|
+
<w:semiHidden/>
|
|
135
|
+
<w:unhideWhenUsed/>
|
|
136
|
+
<w:rPr>
|
|
137
|
+
<w:sz w:val="20"/>
|
|
138
|
+
<w:szCs w:val="20"/>
|
|
139
|
+
</w:rPr>
|
|
140
|
+
</w:style>
|
|
141
|
+
<w:style w:type="character" w:styleId="EndnoteReference">
|
|
142
|
+
<w:name w:val="endnote reference"/>
|
|
143
|
+
<w:basedOn w:val="DefaultParagraphFont"/>
|
|
144
|
+
<w:uiPriority w:val="99"/>
|
|
145
|
+
<w:semiHidden/>
|
|
146
|
+
<w:unhideWhenUsed/>
|
|
147
|
+
<w:rPr>
|
|
148
|
+
<w:vertAlign w:val="superscript"/>
|
|
149
|
+
</w:rPr>
|
|
150
|
+
</w:style>
|
|
151
|
+
<w:style w:type="paragraph" w:styleId="EndnoteText">
|
|
152
|
+
<w:name w:val="endnote text"/>
|
|
153
|
+
<w:basedOn w:val="Normal"/>
|
|
154
|
+
<w:link w:val="EndnoteTextChar"/>
|
|
155
|
+
<w:uiPriority w:val="99"/>
|
|
156
|
+
<w:semiHidden/>
|
|
157
|
+
<w:unhideWhenUsed/>
|
|
158
|
+
<w:pPr>
|
|
159
|
+
<w:spacing w:after="0" w:line="240" w:lineRule="auto"/>
|
|
160
|
+
</w:pPr>
|
|
161
|
+
<w:rPr>
|
|
162
|
+
<w:sz w:val="20"/>
|
|
163
|
+
<w:szCs w:val="20"/>
|
|
164
|
+
</w:rPr>
|
|
165
|
+
</w:style>
|
|
166
|
+
<w:style w:type="character" w:styleId="EndnoteTextChar">
|
|
167
|
+
<w:name w:val="Endnote Text Char"/>
|
|
168
|
+
<w:basedOn w:val="DefaultParagraphFont"/>
|
|
169
|
+
<w:link w:val="EndnoteText"/>
|
|
170
|
+
<w:uiPriority w:val="99"/>
|
|
171
|
+
<w:semiHidden/>
|
|
172
|
+
<w:unhideWhenUsed/>
|
|
173
|
+
<w:rPr>
|
|
174
|
+
<w:sz w:val="20"/>
|
|
175
|
+
<w:szCs w:val="20"/>
|
|
176
|
+
</w:rPr>
|
|
177
|
+
</w:style>
|
|
3
178
|
<w:docDefaults>
|
|
4
179
|
<w:rPrDefault>
|
|
5
180
|
<w:rPr>
|
|
@@ -217,6 +217,53 @@ describe("exporter", () => {
|
|
|
217
217
|
).toMatchFileSnapshot("__snapshots__/withMultiColumn/styles.xml");
|
|
218
218
|
},
|
|
219
219
|
);
|
|
220
|
+
|
|
221
|
+
async function exportAndGetStylesEntries(
|
|
222
|
+
locale?: string,
|
|
223
|
+
) {
|
|
224
|
+
const exporter = new DOCXExporter(
|
|
225
|
+
BlockNoteSchema.create({
|
|
226
|
+
blockSpecs: {
|
|
227
|
+
...defaultBlockSpecs,
|
|
228
|
+
pageBreak: createPageBreakBlockSpec(),
|
|
229
|
+
},
|
|
230
|
+
}),
|
|
231
|
+
docxDefaultSchemaMappings,
|
|
232
|
+
);
|
|
233
|
+
const doc = await exporter.toDocxJsDocument(testDocument, {
|
|
234
|
+
sectionOptions: {},
|
|
235
|
+
documentOptions: {},
|
|
236
|
+
...(locale && { locale }),
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const blob = await Packer.toBlob(doc);
|
|
240
|
+
const zip = new ZipReader(new BlobReader(blob));
|
|
241
|
+
return zip.getEntries();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
it(
|
|
245
|
+
"should export a document without w:lang when no locale is provided",
|
|
246
|
+
{ timeout: 10000 },
|
|
247
|
+
async () => {
|
|
248
|
+
const entries = await exportAndGetStylesEntries();
|
|
249
|
+
|
|
250
|
+
await expect(
|
|
251
|
+
prettify(await getZIPEntryContent(entries, "word/styles.xml")),
|
|
252
|
+
).toMatchFileSnapshot("__snapshots__/noLocale/styles.xml");
|
|
253
|
+
},
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
it(
|
|
257
|
+
"should export a document with w:lang when locale is provided",
|
|
258
|
+
{ timeout: 10000 },
|
|
259
|
+
async () => {
|
|
260
|
+
const entries = await exportAndGetStylesEntries("fr-FR");
|
|
261
|
+
|
|
262
|
+
await expect(
|
|
263
|
+
prettify(await getZIPEntryContent(entries, "word/styles.xml")),
|
|
264
|
+
).toMatchFileSnapshot("__snapshots__/withLocale/styles.xml");
|
|
265
|
+
},
|
|
266
|
+
);
|
|
220
267
|
});
|
|
221
268
|
|
|
222
269
|
function prettify(sourceXml: string) {
|
package/src/docx/docxExporter.ts
CHANGED
|
@@ -193,14 +193,19 @@ export class DOCXExporter<
|
|
|
193
193
|
let externalStyles = (await import("./template/word/styles.xml?raw"))
|
|
194
194
|
.default;
|
|
195
195
|
|
|
196
|
-
// Replace the
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
196
|
+
// Replace the language in styles.xml with the provided locale, or remove
|
|
197
|
+
// the w:lang element entirely if no locale is provided (per ECMA-376
|
|
198
|
+
// §17.3.2.20: omitting w:lang lets the application auto-detect language).
|
|
199
|
+
const trimmedLocale = locale?.trim();
|
|
200
|
+
if (trimmedLocale) {
|
|
201
|
+
externalStyles = externalStyles.replace(
|
|
202
|
+
/(<w:lang\b[^>]*\bw:val=")([^"]+)("[^>]*\/>)/g,
|
|
203
|
+
(_match, prefix, _oldVal, suffix) =>
|
|
204
|
+
`${prefix}${trimmedLocale}${suffix}`,
|
|
205
|
+
);
|
|
206
|
+
} else {
|
|
207
|
+
externalStyles = externalStyles.replace(/\s*<w:lang\b[^>]*\/>/g, "");
|
|
208
|
+
}
|
|
204
209
|
|
|
205
210
|
const bullets = ["•"]; //, "◦", "▪"]; (these don't look great, just use solid bullet for now)
|
|
206
211
|
return {
|
|
@@ -251,7 +256,7 @@ export class DOCXExporter<
|
|
|
251
256
|
}
|
|
252
257
|
|
|
253
258
|
/**
|
|
254
|
-
*
|
|
259
|
+
* Converts blocks to a .docx Blob with optional locale support.
|
|
255
260
|
*/
|
|
256
261
|
public async toBlob(
|
|
257
262
|
blocks: Block<B, I, S>[],
|
|
@@ -260,7 +265,7 @@ export class DOCXExporter<
|
|
|
260
265
|
documentOptions: DocumentOptions;
|
|
261
266
|
/**
|
|
262
267
|
* The document locale in OOXML format (e.g. en-US, fr-FR, de-DE).
|
|
263
|
-
* If omitted,
|
|
268
|
+
* If omitted, no language is set and the consuming application will use its own default.
|
|
264
269
|
*/
|
|
265
270
|
locale?: string;
|
|
266
271
|
} = {
|
|
@@ -285,7 +290,7 @@ export class DOCXExporter<
|
|
|
285
290
|
}
|
|
286
291
|
|
|
287
292
|
/**
|
|
288
|
-
*
|
|
293
|
+
* Converts blocks to a docxjs Document with optional locale support.
|
|
289
294
|
*/
|
|
290
295
|
public async toDocxJsDocument(
|
|
291
296
|
blocks: Block<B, I, S>[],
|
|
@@ -294,7 +299,7 @@ export class DOCXExporter<
|
|
|
294
299
|
documentOptions: DocumentOptions;
|
|
295
300
|
/**
|
|
296
301
|
* The document locale in OOXML format (e.g. en-US, fr-FR, de-DE).
|
|
297
|
-
* If omitted,
|
|
302
|
+
* If omitted, no language is set and the consuming application will use its own default.
|
|
298
303
|
*/
|
|
299
304
|
locale?: string;
|
|
300
305
|
} = {
|
|
@@ -36,26 +36,26 @@ export declare class DOCXExporter<B extends BlockSchema, S extends StyleSchema,
|
|
|
36
36
|
protected getFonts(): Promise<DocumentOptions["fonts"]>;
|
|
37
37
|
protected createDefaultDocumentOptions(locale?: string): Promise<DocumentOptions>;
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* Converts blocks to a .docx Blob with optional locale support.
|
|
40
40
|
*/
|
|
41
41
|
toBlob(blocks: Block<B, I, S>[], options?: {
|
|
42
42
|
sectionOptions: Omit<ISectionOptions, "children">;
|
|
43
43
|
documentOptions: DocumentOptions;
|
|
44
44
|
/**
|
|
45
45
|
* The document locale in OOXML format (e.g. en-US, fr-FR, de-DE).
|
|
46
|
-
* If omitted,
|
|
46
|
+
* If omitted, no language is set and the consuming application will use its own default.
|
|
47
47
|
*/
|
|
48
48
|
locale?: string;
|
|
49
49
|
}): Promise<Blob>;
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
51
|
+
* Converts blocks to a docxjs Document with optional locale support.
|
|
52
52
|
*/
|
|
53
53
|
toDocxJsDocument(blocks: Block<B, I, S>[], options?: {
|
|
54
54
|
sectionOptions: Omit<ISectionOptions, "children">;
|
|
55
55
|
documentOptions: DocumentOptions;
|
|
56
56
|
/**
|
|
57
57
|
* The document locale in OOXML format (e.g. en-US, fr-FR, de-DE).
|
|
58
|
-
* If omitted,
|
|
58
|
+
* If omitted, no language is set and the consuming application will use its own default.
|
|
59
59
|
*/
|
|
60
60
|
locale?: string;
|
|
61
61
|
}): Promise<Document>;
|