UNPKG

@blocknote/xl-docx-exporter

Version:

A "Notion-style" block-based extensible text editor built on top of Prosemirror and Tiptap.

1 lines 37.6 kB
{"version":3,"file":"blocknote-xl-docx-exporter.cjs","names":[],"sources":["../../../shared/util/imageUtil.ts","../src/docx/util/Table.tsx","../src/docx/defaultSchema/blocks.ts","../src/docx/defaultSchema/inlinecontent.ts","../src/docx/defaultSchema/styles.ts","../src/docx/defaultSchema/index.ts","../../../shared/api/corsProxy.ts","../../../shared/util/fileUtil.ts","../src/docx/docxExporter.ts"],"sourcesContent":["export async function getImageDimensions(blob: Blob) {\n if (typeof window !== \"undefined\" && import.meta.env.NODE_ENV !== \"test\") {\n const bmp = await createImageBitmap(blob);\n const { width, height } = bmp;\n bmp.close(); // free memory\n return { width, height };\n } else {\n // node or vitest\n const imageMetaFunc = (await import(\"image-meta\")).imageMeta;\n const bytes = new Uint8Array(await blob.arrayBuffer());\n const meta = imageMetaFunc(bytes);\n if (!meta.width || !meta.height) {\n throw new Error(\"Image dimensions not found\");\n }\n return { width: meta.width, height: meta.height };\n }\n}\n","import {\n Exporter,\n InlineContentSchema,\n mapTableCell,\n TableContent,\n UnreachableCaseError,\n} from \"@blocknote/core\";\nimport {\n Table as DocxTable,\n Paragraph,\n ParagraphChild,\n ShadingType,\n TableCell,\n TableRow,\n} from \"docx\";\n\nexport const Table = (\n data: TableContent<InlineContentSchema>,\n t: Exporter<any, any, any, any, ParagraphChild, any, any>,\n) => {\n const DEFAULT_COLUMN_WIDTH = 120;\n\n // If headerRows is 1, then the first row is a header row\n const headerRows = new Array(data.headerRows ?? 0).fill(true);\n // If headerCols is 1, then the first column is a header column\n const headerCols = new Array(data.headerCols ?? 0).fill(true);\n\n return new DocxTable({\n layout: \"autofit\",\n columnWidths: data.columnWidths.map(\n (w) =>\n (w ?? DEFAULT_COLUMN_WIDTH) * /* to points */ 0.75 * /* to twips */ 20,\n ),\n rows: data.rows.map((row, rowIndex) => {\n const isHeaderRow = headerRows[rowIndex];\n return new TableRow({\n tableHeader: isHeaderRow,\n children: row.cells.map((c, colIndex) => {\n const width = data.columnWidths?.[colIndex];\n const cell = mapTableCell(c);\n const isHeaderColumn = headerCols[colIndex];\n\n return new TableCell({\n width: width\n ? {\n // The type is twentieths of a point (dxa)\n size: width * 0.75 * 20,\n type: \"dxa\",\n }\n : undefined,\n columnSpan: cell.props.colspan,\n rowSpan: cell.props.rowspan,\n shading:\n cell.props.backgroundColor === \"default\" ||\n !cell.props.backgroundColor\n ? undefined\n : {\n type: ShadingType.SOLID,\n color: (() => {\n const color =\n t.options.colors[cell.props.backgroundColor]\n ?.background;\n if (!color) {\n return undefined;\n }\n return color.slice(1);\n })(),\n },\n children: [\n new Paragraph({\n children: t.transformInlineContent(cell.content),\n\n alignment:\n !cell.props.textAlignment ||\n cell.props.textAlignment === \"left\"\n ? undefined\n : cell.props.textAlignment === \"center\"\n ? \"center\"\n : cell.props.textAlignment === \"right\"\n ? \"right\"\n : cell.props.textAlignment === \"justify\"\n ? \"distribute\"\n : (() => {\n throw new UnreachableCaseError(\n cell.props.textAlignment,\n );\n })(),\n run: {\n // TODO add support for table headers exporting, bolding seems to not be working at the moment\n bold: isHeaderRow || isHeaderColumn,\n // TODO table paragraph color seems to not be working at the moment\n // Probably because the runs are setting their own color\n color:\n cell.props.textColor === \"default\" || !cell.props.textColor\n ? undefined\n : (() => {\n const color =\n t.options.colors[cell.props.textColor]?.text;\n if (!color) {\n return undefined;\n }\n return color.slice(1);\n })(),\n },\n }),\n ],\n });\n }),\n });\n }),\n });\n};\n","import {\n BlockMapping,\n COLORS_DEFAULT,\n createPageBreakBlockConfig,\n DefaultBlockSchema,\n DefaultProps,\n StyledText,\n UnreachableCaseError,\n} from \"@blocknote/core\";\nimport { getImageDimensions } from \"@shared/util/imageUtil.js\";\nimport {\n CheckBox,\n Table as DocxTable,\n ExternalHyperlink,\n ImageRun,\n IParagraphOptions,\n PageBreak,\n Paragraph,\n ParagraphChild,\n ShadingType,\n TableCell,\n TableRow,\n TextRun,\n} from \"docx\";\nimport { Table } from \"../util/Table.js\";\nimport { multiColumnSchema } from \"@blocknote/xl-multi-column\";\n\nfunction blockPropsToStyles(\n props: Partial<DefaultProps>,\n colors: typeof COLORS_DEFAULT,\n): IParagraphOptions {\n return {\n shading:\n props.backgroundColor === \"default\" || !props.backgroundColor\n ? undefined\n : {\n type: ShadingType.CLEAR,\n fill: (() => {\n const color = colors[props.backgroundColor]?.background;\n if (!color) {\n return undefined;\n }\n return color.slice(1);\n })(),\n },\n run:\n props.textColor === \"default\" || !props.textColor\n ? undefined\n : {\n color: (() => {\n const color = colors[props.textColor]?.text;\n if (!color) {\n return undefined;\n }\n return color.slice(1);\n })(),\n },\n alignment:\n !props.textAlignment || props.textAlignment === \"left\"\n ? undefined\n : props.textAlignment === \"center\"\n ? \"center\"\n : props.textAlignment === \"right\"\n ? \"right\"\n : props.textAlignment === \"justify\"\n ? \"distribute\"\n : (() => {\n throw new UnreachableCaseError(props.textAlignment);\n })(),\n };\n}\nexport const docxBlockMappingForDefaultSchema: BlockMapping<\n DefaultBlockSchema & {\n pageBreak: ReturnType<typeof createPageBreakBlockConfig>;\n } & typeof multiColumnSchema.blockSchema,\n any,\n any,\n | Promise<Paragraph[] | Paragraph | DocxTable>\n | Paragraph[]\n | Paragraph\n | DocxTable,\n ParagraphChild\n> = {\n paragraph: (block, exporter) => {\n return new Paragraph({\n ...blockPropsToStyles(block.props, exporter.options.colors),\n children: exporter.transformInlineContent(block.content),\n });\n },\n toggleListItem: (block, exporter) => {\n return new Paragraph({\n ...blockPropsToStyles(block.props, exporter.options.colors),\n children: [\n new TextRun({\n children: [\"> \"],\n }),\n ...exporter.transformInlineContent(block.content),\n ],\n });\n },\n numberedListItem: (block, exporter, nestingLevel) => {\n return new Paragraph({\n ...blockPropsToStyles(block.props, exporter.options.colors),\n children: exporter.transformInlineContent(block.content),\n numbering: {\n reference: \"blocknote-numbered-list\",\n level: nestingLevel,\n },\n });\n },\n bulletListItem: (block, exporter, nestingLevel) => {\n return new Paragraph({\n ...blockPropsToStyles(block.props, exporter.options.colors),\n children: exporter.transformInlineContent(block.content),\n numbering: {\n reference: \"blocknote-bullet-list\",\n level: nestingLevel,\n },\n });\n },\n checkListItem: (block, exporter) => {\n return new Paragraph({\n ...blockPropsToStyles(block.props, exporter.options.colors),\n children: [\n new CheckBox({ checked: block.props.checked }),\n new TextRun({\n children: [\" \"],\n }),\n ...exporter.transformInlineContent(block.content),\n ],\n });\n },\n heading: (block, exporter) => {\n return new Paragraph({\n ...blockPropsToStyles(block.props, exporter.options.colors),\n children: exporter.transformInlineContent(block.content),\n heading: `Heading${block.props.level as 1 | 2 | 3 | 4 | 5 | 6}`,\n });\n },\n quote: (block, exporter) => {\n return new Paragraph({\n style: \"BlockQuote\",\n ...blockPropsToStyles(block.props, exporter.options.colors),\n children: exporter.transformInlineContent(block.content),\n });\n },\n audio: (block, exporter) => {\n return [\n file(block.props, \"Open audio\", exporter),\n ...caption(block.props, exporter),\n ];\n },\n video: (block, exporter) => {\n return [\n file(block.props, \"Open video\", exporter),\n ...caption(block.props, exporter),\n ];\n },\n file: (block, exporter) => {\n return [\n file(block.props, \"Open file\", exporter),\n ...caption(block.props, exporter),\n ];\n },\n codeBlock: (block) => {\n const textContent = (block.content as StyledText<any>[])[0]?.text || \"\";\n\n return new Paragraph({\n style: \"SourceCode\",\n children: [\n ...textContent.split(\"\\n\").map((line, index) => {\n return new TextRun({\n text: line,\n break: index > 0 ? 1 : 0,\n });\n }),\n ],\n });\n },\n pageBreak: () => {\n return new Paragraph({\n children: [new PageBreak()],\n });\n },\n divider: () => {\n return new Paragraph({\n border: {\n top: {\n color: \"auto\",\n space: 1,\n style: \"single\",\n size: 1,\n },\n },\n });\n },\n column: (block, _exporter, _nestingLevel, _numberedListIndex, children) => {\n return new TableCell({\n width: {\n size: `${block.props.width * 100}%`,\n type: \"pct\",\n },\n children: (children || []).flatMap((child) => {\n if (Array.isArray(child)) {\n return child;\n }\n\n return [child];\n }),\n }) as any;\n },\n columnList: (\n _block,\n _exporter,\n _nestingLevel,\n _numberedListIndex,\n children,\n ) => {\n return new DocxTable({\n layout: \"autofit\",\n borders: {\n bottom: { style: \"nil\" },\n top: { style: \"nil\" },\n left: { style: \"nil\" },\n right: { style: \"nil\" },\n insideHorizontal: { style: \"nil\" },\n insideVertical: { style: \"nil\" },\n },\n rows: [\n new TableRow({\n children: (children as unknown as TableCell[]).map(\n (cell, _index, children) => {\n return new TableCell({\n width: {\n size: `${(parseFloat(`${cell.options.width?.size || \"100%\"}`) / (children.length * 100)) * 100}%`,\n type: \"pct\",\n },\n children: cell.options.children,\n });\n },\n ),\n }),\n ],\n });\n },\n image: async (block, exporter) => {\n const blob = await exporter.resolveFile(block.props.url);\n const { width, height } = await getImageDimensions(blob);\n\n return [\n new Paragraph({\n ...blockPropsToStyles(block.props, exporter.options.colors),\n children: [\n new ImageRun({\n data: await blob.arrayBuffer(),\n // it would be nicer to set the actual data type here, but then we'd need to use a mime type / image type\n // detector. atm passing gif does not seem to be causing issues as the \"type\" is mainly used by docxjs internally\n // (i.e.: to make sure it's not svg)\n type: \"gif\",\n altText: block.props.caption\n ? {\n description: block.props.caption,\n name: block.props.caption,\n title: block.props.caption,\n }\n : undefined,\n transformation: {\n width: block.props.previewWidth || width,\n height: ((block.props.previewWidth || width) / width) * height,\n },\n }),\n ],\n }),\n ...caption(block.props, exporter),\n ];\n },\n table: (block, exporter) => {\n return Table(block.content, exporter);\n },\n};\n\nfunction file(\n props: Partial<DefaultProps & { name: string; url: string }>,\n defaultText: string,\n exporter: any,\n) {\n return new Paragraph({\n ...blockPropsToStyles(props, exporter.options.colors),\n children: [\n new ExternalHyperlink({\n children: [\n new TextRun({\n text: props.name || defaultText,\n style: \"Hyperlink\",\n }),\n ],\n link: props.url!,\n }),\n ],\n });\n}\n\nfunction caption(\n props: Partial<DefaultProps & { caption: string }>,\n exporter: any,\n) {\n if (!props.caption) {\n return [];\n }\n return [\n new Paragraph({\n ...blockPropsToStyles(props, exporter.options.colors),\n children: [\n new TextRun({\n text: props.caption,\n }),\n ],\n style: \"Caption\",\n }),\n ];\n}\n","import {\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n InlineContentMapping,\n} from \"@blocknote/core\";\nimport { ExternalHyperlink, ParagraphChild, TextRun } from \"docx\";\nimport type { DOCXExporter } from \"../docxExporter.js\";\n\nexport const docxInlineContentMappingForDefaultSchema: InlineContentMapping<\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n ParagraphChild,\n TextRun\n> = {\n link: (ic, exporter) => {\n return new ExternalHyperlink({\n children: ic.content.map((content) => {\n return (exporter as DOCXExporter<any, any, any>).transformStyledText(\n content,\n true,\n );\n }),\n link: ic.href,\n });\n },\n text: (ic, t) => {\n return t.transformStyledText(ic);\n },\n};\n","import { DefaultStyleSchema, StyleMapping } from \"@blocknote/core\";\nimport { IRunPropertiesOptions, ShadingType } from \"docx\";\n\nexport const docxStyleMappingForDefaultSchema: StyleMapping<\n DefaultStyleSchema,\n IRunPropertiesOptions\n> = {\n bold: (val) => {\n if (!val) {\n return {};\n }\n return {\n bold: val,\n };\n },\n italic: (val) => {\n if (!val) {\n return {};\n }\n return {\n italics: val,\n };\n },\n underline: (val) => {\n if (!val) {\n return {};\n }\n return {\n underline: {\n type: \"single\",\n },\n };\n },\n strike: (val) => {\n if (!val) {\n return {};\n }\n return {\n strike: val,\n };\n },\n backgroundColor: (val, exporter) => {\n if (!val) {\n return {};\n }\n const color = exporter.options.colors[val]?.background;\n if (!color) {\n return {};\n }\n return {\n shading: {\n type: ShadingType.CLEAR,\n fill: color.slice(1),\n },\n };\n },\n textColor: (val, exporter) => {\n if (!val) {\n return {};\n }\n const color = exporter.options.colors[val]?.text;\n if (!color) {\n return {};\n }\n return {\n color: color.slice(1),\n };\n },\n code: (val) => {\n if (!val) {\n return {};\n }\n return {\n style: \"VerbatimChar\",\n };\n },\n};\n","import { docxBlockMappingForDefaultSchema } from \"./blocks.js\";\nimport { docxInlineContentMappingForDefaultSchema } from \"./inlinecontent.js\";\nimport { docxStyleMappingForDefaultSchema } from \"./styles.js\";\n\nexport const docxDefaultSchemaMappings = {\n blockMapping: docxBlockMappingForDefaultSchema,\n inlineContentMapping: docxInlineContentMappingForDefaultSchema,\n styleMapping: docxStyleMappingForDefaultSchema,\n};\n","export async function corsProxyResolveFileUrl(url: string) {\n return (\n \"https://corsproxy.api.blocknotejs.org/corsproxy/?url=\" +\n encodeURIComponent(url)\n );\n}\n","/**\n *\n * Helper functions so that we can import files both on vitest, browser and node\n * TODO: should find a way to test automatically in all environments\n */\n\nexport async function loadFileDataUrl(\n requireUrl: { default: string },\n mimeType: string,\n) {\n if (import.meta.env.NODE_ENV === \"test\") {\n const buffer = await loadFileBuffer(requireUrl);\n const fileBase64 = buffer.toString(\"base64\");\n\n const dataUrl = `data:${mimeType};base64,${fileBase64}`;\n return dataUrl;\n } else {\n // in browser, this is already a data url\n return requireUrl.default as string;\n }\n}\n\nexport async function loadFontDataUrl(requireUrl: { default: string }) {\n return loadFileDataUrl(requireUrl, \"font/ttf\");\n}\n\nexport async function loadFileBuffer(requireUrl: {\n default: string;\n}): Promise<Buffer | ArrayBuffer> {\n if (import.meta.env.NODE_ENV === \"test\") {\n // in vitest, this is the url we need to load with readfilesync\n // eslint-disable-next-line\n const fs = require(\"fs\");\n let url = requireUrl.default;\n\n if (url.startsWith(\"/@fs/\")) {\n url = url.substring(\"/@fs\".length);\n }\n // On Windows, vite/vitest may yield paths like \"/C:/...\" after removing /@fs\n // Node on Windows treats paths starting with \"/\" as relative to current drive,\n // which would produce \"C:\\C:\\...\". Strip leading slash when followed by a drive letter.\n if (/^\\/[A-Za-z]:/.test(url)) {\n url = url.slice(1);\n }\n const buffer = fs.readFileSync(url);\n return buffer;\n } else {\n // in browser, this is already a data url\n const dataUrl = requireUrl.default as string;\n // convert to buffer on browser\n const response = await fetch(dataUrl);\n const arrayBuffer = await response.arrayBuffer();\n return arrayBuffer;\n }\n}\n\n/**\n * usage:\n * \n * await loadFontDataUrl(\n await import(\"../fonts/inter/Inter_18pt-Italic.ttf\")\n );\n */\n","import {\n Block,\n BlockNoteSchema,\n BlockSchema,\n COLORS_DEFAULT,\n InlineContentSchema,\n StyleSchema,\n StyledText,\n} from \"@blocknote/core\";\nimport {\n AlignmentType,\n Document,\n IRunPropertiesOptions,\n ISectionOptions,\n LevelFormat,\n Packer,\n Paragraph,\n ParagraphChild,\n Tab,\n Table,\n TextRun,\n} from \"docx\";\n\nimport { Exporter, ExporterOptions } from \"@blocknote/core\";\nimport { corsProxyResolveFileUrl } from \"@shared/api/corsProxy.js\";\nimport { loadFileBuffer } from \"@shared/util/fileUtil.js\";\n\n// get constructor arg type from Document\ntype DocumentOptions = Partial<ConstructorParameters<typeof Document>[0]>;\n\nconst DEFAULT_TAB_STOP =\n /* default font size */ 16 *\n /* 1 pixel is 0.75 points */ 0.75 *\n /* 1.5em*/ 1.5 *\n /* 1 point is 20 twips */ 20;\n\n/**\n * Exports a BlockNote document to a .docx file using the docxjs library.\n */\nexport class DOCXExporter<\n B extends BlockSchema,\n S extends StyleSchema,\n I extends InlineContentSchema,\n> extends Exporter<\n B,\n I,\n S,\n Promise<Paragraph[] | Paragraph | Table> | Paragraph[] | Paragraph | Table,\n ParagraphChild,\n IRunPropertiesOptions,\n TextRun\n> {\n public constructor(\n /**\n * The schema of your editor. The mappings are automatically typed checked against this schema.\n */\n protected readonly schema: BlockNoteSchema<B, I, S>,\n /**\n * The mappings that map the BlockNote schema to the docxjs content.\n * Pass {@link docxDefaultSchemaMappings} for the default schema.\n */\n protected readonly mappings: Exporter<\n NoInfer<B>,\n NoInfer<I>,\n NoInfer<S>,\n | Promise<Paragraph[] | Paragraph | Table>\n | Paragraph[]\n | Paragraph\n | Table,\n ParagraphChild,\n IRunPropertiesOptions,\n TextRun\n >[\"mappings\"],\n options?: Partial<ExporterOptions>,\n ) {\n const defaults = {\n colors: COLORS_DEFAULT,\n resolveFileUrl: corsProxyResolveFileUrl,\n } satisfies Partial<ExporterOptions>;\n\n const newOptions = {\n ...defaults,\n ...options,\n };\n super(schema, mappings, newOptions);\n }\n\n /**\n * Mostly for internal use, you probably want to use `toBlob` or `toDocxJsDocument` instead.\n */\n public transformStyledText(styledText: StyledText<S>, hyperlink?: boolean) {\n const stylesArray = this.mapStyles(styledText.styles);\n\n const styles: IRunPropertiesOptions = Object.assign(\n {} as IRunPropertiesOptions,\n ...stylesArray,\n );\n\n return new TextRun({\n ...styles,\n style: hyperlink ? \"Hyperlink\" : styles.style,\n text: styledText.text,\n });\n }\n\n /**\n * Mostly for internal use, you probably want to use `toBlob` or `toDocxJsDocument` instead.\n */\n public async transformBlocks(\n blocks: Block<B, I, S>[],\n nestingLevel = 0,\n ): Promise<Array<Paragraph | Table>> {\n const ret: Array<Paragraph | Table> = [];\n\n for (const b of blocks) {\n let children = await this.transformBlocks(b.children, nestingLevel + 1);\n\n if (![\"columnList\", \"column\"].includes(b.type)) {\n children = children.map((c, _i) => {\n // NOTE: nested tables not supported (we can't insert the new Tab before a table)\n if (\n c instanceof Paragraph &&\n !(c as any).properties.numberingReferences.length\n ) {\n c.addRunToFront(\n new TextRun({\n children: [new Tab()],\n }),\n );\n }\n return c;\n });\n }\n\n const self = await this.mapBlock(\n b as any,\n nestingLevel,\n 0 /*unused*/,\n children,\n ); // TODO: any\n if ([\"columnList\", \"column\"].includes(b.type)) {\n ret.push(self as Table);\n } else if (Array.isArray(self)) {\n ret.push(...self, ...children);\n } else {\n ret.push(self, ...children);\n }\n }\n return ret;\n }\n\n protected async getFonts(): Promise<DocumentOptions[\"fonts\"]> {\n // Unfortunately, loading the variable font doesn't work\n // \"./src/fonts/Inter-VariableFont_opsz,wght.ttf\",\n\n let interFont = await loadFileBuffer(\n await import(\"@shared/assets/fonts/inter/Inter_18pt-Regular.ttf\"),\n );\n let geistMonoFont = await loadFileBuffer(\n await import(\"@shared/assets/fonts/GeistMono-Regular.ttf\"),\n );\n\n if (\n interFont instanceof ArrayBuffer ||\n geistMonoFont instanceof ArrayBuffer\n ) {\n // conversion with Polyfill needed because docxjs requires Buffer\n // NOTE: the buffer/ import is intentional and as documented in\n // the `buffer` package usage instructions\n // https://github.com/feross/buffer?tab=readme-ov-file#usage\n const Buffer = (await import(\"buffer/\")).Buffer;\n\n if (interFont instanceof ArrayBuffer) {\n interFont = Buffer.from(interFont) as unknown as Buffer;\n }\n if (geistMonoFont instanceof ArrayBuffer) {\n geistMonoFont = Buffer.from(geistMonoFont) as unknown as Buffer;\n }\n }\n\n return [\n { name: \"Inter\", data: interFont },\n {\n name: \"GeistMono\",\n data: geistMonoFont,\n },\n ];\n }\n\n protected async createDefaultDocumentOptions(\n locale?: string,\n ): Promise<DocumentOptions> {\n let externalStyles = (await import(\"./template/word/styles.xml?raw\"))\n .default;\n\n // Replace the language in styles.xml with the provided locale, or remove\n // the w:lang element entirely if no locale is provided (per ECMA-376\n // §17.3.2.20: omitting w:lang lets the application auto-detect language).\n const trimmedLocale = locale?.trim();\n if (trimmedLocale) {\n externalStyles = externalStyles.replace(\n /(<w:lang\\b[^>]*\\bw:val=\")([^\"]+)(\"[^>]*\\/>)/g,\n (_match, prefix, _oldVal, suffix) =>\n `${prefix}${trimmedLocale}${suffix}`,\n );\n } else {\n externalStyles = externalStyles.replace(/\\s*<w:lang\\b[^>]*\\/>/g, \"\");\n }\n\n const bullets = [\"\"]; //, \"\", \"\"]; (these don't look great, just use solid bullet for now)\n return {\n numbering: {\n config: [\n {\n reference: \"blocknote-numbered-list\",\n levels: Array.from({ length: 9 }, (_, i) => ({\n start: 1,\n level: i,\n format: LevelFormat.DECIMAL,\n text: `%${i + 1}.`,\n alignment: AlignmentType.LEFT,\n style: {\n paragraph: {\n indent: {\n left: DEFAULT_TAB_STOP * (i + 1),\n hanging: DEFAULT_TAB_STOP,\n },\n },\n },\n })),\n },\n {\n reference: \"blocknote-bullet-list\",\n levels: Array.from({ length: 9 }, (_, i) => ({\n start: 1,\n level: i,\n format: LevelFormat.BULLET,\n text: bullets[i % bullets.length],\n alignment: AlignmentType.LEFT,\n style: {\n paragraph: {\n indent: {\n left: DEFAULT_TAB_STOP * (i + 1),\n hanging: DEFAULT_TAB_STOP,\n },\n },\n },\n })),\n },\n ],\n },\n fonts: await this.getFonts(),\n defaultTabStop: 200,\n externalStyles,\n };\n }\n\n /**\n * Converts blocks to a .docx Blob with optional locale support.\n */\n public async toBlob(\n blocks: Block<B, I, S>[],\n options: {\n sectionOptions: Omit<ISectionOptions, \"children\">;\n documentOptions: DocumentOptions;\n /**\n * The document locale in OOXML format (e.g. en-US, fr-FR, de-DE).\n * If omitted, no language is set and the consuming application will use its own default.\n */\n locale?: string;\n } = {\n sectionOptions: {},\n documentOptions: {},\n },\n ) {\n const doc = await this.toDocxJsDocument(blocks, options);\n type GlobalThis = typeof globalThis & { Buffer?: any };\n const prevBuffer = (globalThis as GlobalThis).Buffer;\n try {\n if (!(globalThis as GlobalThis).Buffer) {\n // load Buffer polyfill because docxjs requires this\n (globalThis as GlobalThis).Buffer = (\n await import(\"buffer\")\n ).default.Buffer;\n }\n return Packer.toBlob(doc);\n } finally {\n (globalThis as GlobalThis).Buffer = prevBuffer;\n }\n }\n\n /**\n * Converts blocks to a docxjs Document with optional locale support.\n */\n public async toDocxJsDocument(\n blocks: Block<B, I, S>[],\n options: {\n sectionOptions: Omit<ISectionOptions, \"children\">;\n documentOptions: DocumentOptions;\n /**\n * The document locale in OOXML format (e.g. en-US, fr-FR, de-DE).\n * If omitted, no language is set and the consuming application will use its own default.\n */\n locale?: string;\n } = {\n sectionOptions: {},\n documentOptions: {},\n },\n ) {\n const doc = new Document({\n ...(await this.createDefaultDocumentOptions(options.locale)),\n ...options.documentOptions,\n sections: [\n {\n children: await this.transformBlocks(blocks),\n ...options.sectionOptions,\n },\n ],\n });\n\n return doc;\n }\n}\n"],"mappings":"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"}