UNPKG

@blocknote/xl-docx-exporter

Version:

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

364 lines (363 loc) 10.6 kB
import { COLORS_DEFAULT as e, Exporter as t, UnreachableCaseError as n, mapTableCell as r } from "@blocknote/core"; import { AlignmentType as i, CheckBox as a, Document as o, ExternalHyperlink as s, ImageRun as c, LevelFormat as l, Packer as u, PageBreak as d, Paragraph as f, ShadingType as p, Tab as m, Table as h, TableCell as g, TableRow as _, TextRun as v } from "docx"; //#region ../../shared/util/imageUtil.ts async function y(e) { if (typeof window < "u") { let t = await createImageBitmap(e), { width: n, height: r } = t; return t.close(), { width: n, height: r }; } else { let t = (await import("image-meta")).imageMeta, n = t(new Uint8Array(await e.arrayBuffer())); if (!n.width || !n.height) throw Error("Image dimensions not found"); return { width: n.width, height: n.height }; } } //#endregion //#region src/docx/util/Table.tsx var b = (e, t) => { let i = Array(e.headerRows ?? 0).fill(!0), a = Array(e.headerCols ?? 0).fill(!0); return new h({ layout: "autofit", columnWidths: e.columnWidths.map((e) => (e ?? 120) * .75 * 20), rows: e.rows.map((o, s) => { let c = i[s]; return new _({ tableHeader: c, children: o.cells.map((i, o) => { let s = e.columnWidths?.[o], l = r(i), u = a[o]; return new g({ width: s ? { size: s * .75 * 20, type: "dxa" } : void 0, columnSpan: l.props.colspan, rowSpan: l.props.rowspan, shading: l.props.backgroundColor === "default" || !l.props.backgroundColor ? void 0 : { type: p.SOLID, color: (() => { let e = t.options.colors[l.props.backgroundColor]?.background; if (e) return e.slice(1); })() }, children: [new f({ children: t.transformInlineContent(l.content), alignment: !l.props.textAlignment || l.props.textAlignment === "left" ? void 0 : l.props.textAlignment === "center" ? "center" : l.props.textAlignment === "right" ? "right" : l.props.textAlignment === "justify" ? "distribute" : (() => { throw new n(l.props.textAlignment); })(), run: { bold: c || u, color: l.props.textColor === "default" || !l.props.textColor ? void 0 : (() => { let e = t.options.colors[l.props.textColor]?.text; if (e) return e.slice(1); })() } })] }); }) }); }) }); }; //#endregion //#region src/docx/defaultSchema/blocks.ts function x(e, t) { return { shading: e.backgroundColor === "default" || !e.backgroundColor ? void 0 : { type: p.CLEAR, fill: (() => { let n = t[e.backgroundColor]?.background; if (n) return n.slice(1); })() }, run: e.textColor === "default" || !e.textColor ? void 0 : { color: (() => { let n = t[e.textColor]?.text; if (n) return n.slice(1); })() }, alignment: !e.textAlignment || e.textAlignment === "left" ? void 0 : e.textAlignment === "center" ? "center" : e.textAlignment === "right" ? "right" : e.textAlignment === "justify" ? "distribute" : (() => { throw new n(e.textAlignment); })() }; } var S = { paragraph: (e, t) => new f({ ...x(e.props, t.options.colors), children: t.transformInlineContent(e.content) }), toggleListItem: (e, t) => new f({ ...x(e.props, t.options.colors), children: [new v({ children: ["> "] }), ...t.transformInlineContent(e.content)] }), numberedListItem: (e, t, n) => new f({ ...x(e.props, t.options.colors), children: t.transformInlineContent(e.content), numbering: { reference: "blocknote-numbered-list", level: n } }), bulletListItem: (e, t, n) => new f({ ...x(e.props, t.options.colors), children: t.transformInlineContent(e.content), numbering: { reference: "blocknote-bullet-list", level: n } }), checkListItem: (e, t) => new f({ ...x(e.props, t.options.colors), children: [ new a({ checked: e.props.checked }), new v({ children: [" "] }), ...t.transformInlineContent(e.content) ] }), heading: (e, t) => new f({ ...x(e.props, t.options.colors), children: t.transformInlineContent(e.content), heading: `Heading${e.props.level}` }), quote: (e, t) => new f({ style: "BlockQuote", ...x(e.props, t.options.colors), children: t.transformInlineContent(e.content) }), audio: (e, t) => [C(e.props, "Open audio", t), ...w(e.props, t)], video: (e, t) => [C(e.props, "Open video", t), ...w(e.props, t)], file: (e, t) => [C(e.props, "Open file", t), ...w(e.props, t)], codeBlock: (e) => new f({ style: "SourceCode", children: [...(e.content[0]?.text || "").split("\n").map((e, t) => new v({ text: e, break: +(t > 0) }))] }), pageBreak: () => new f({ children: [new d()] }), divider: () => new f({ border: { top: { color: "auto", space: 1, style: "single", size: 1 } } }), column: (e, t, n, r, i) => new g({ width: { size: `${e.props.width * 100}%`, type: "pct" }, children: (i || []).flatMap((e) => Array.isArray(e) ? e : [e]) }), columnList: (e, t, n, r, i) => new h({ layout: "autofit", borders: { bottom: { style: "nil" }, top: { style: "nil" }, left: { style: "nil" }, right: { style: "nil" }, insideHorizontal: { style: "nil" }, insideVertical: { style: "nil" } }, rows: [new _({ children: i.map((e, t, n) => new g({ width: { size: `${parseFloat(`${e.options.width?.size || "100%"}`) / (n.length * 100) * 100}%`, type: "pct" }, children: e.options.children })) })] }), image: async (e, t) => { let n = await t.resolveFile(e.props.url), { width: r, height: i } = await y(n); return [new f({ ...x(e.props, t.options.colors), children: [new c({ data: await n.arrayBuffer(), type: "gif", altText: e.props.caption ? { description: e.props.caption, name: e.props.caption, title: e.props.caption } : void 0, transformation: { width: e.props.previewWidth || r, height: (e.props.previewWidth || r) / r * i } })] }), ...w(e.props, t)]; }, table: (e, t) => b(e.content, t) }; function C(e, t, n) { return new f({ ...x(e, n.options.colors), children: [new s({ children: [new v({ text: e.name || t, style: "Hyperlink" })], link: e.url })] }); } function w(e, t) { return e.caption ? [new f({ ...x(e, t.options.colors), children: [new v({ text: e.caption })], style: "Caption" })] : []; } //#endregion //#region src/docx/defaultSchema/index.ts var T = { blockMapping: S, inlineContentMapping: { link: (e, t) => new s({ children: e.content.map((e) => t.transformStyledText(e, !0)), link: e.href }), text: (e, t) => t.transformStyledText(e) }, styleMapping: { bold: (e) => e ? { bold: e } : {}, italic: (e) => e ? { italics: e } : {}, underline: (e) => e ? { underline: { type: "single" } } : {}, strike: (e) => e ? { strike: e } : {}, backgroundColor: (e, t) => { if (!e) return {}; let n = t.options.colors[e]?.background; return n ? { shading: { type: p.CLEAR, fill: n.slice(1) } } : {}; }, textColor: (e, t) => { if (!e) return {}; let n = t.options.colors[e]?.text; return n ? { color: n.slice(1) } : {}; }, code: (e) => e ? { style: "VerbatimChar" } : {} } }; //#endregion //#region ../../shared/api/corsProxy.ts async function E(e) { return "https://corsproxy.api.blocknotejs.org/corsproxy/?url=" + encodeURIComponent(e); } //#endregion //#region ../../shared/util/fileUtil.ts async function D(e) { { let t = e.default; return await (await fetch(t)).arrayBuffer(); } } //#endregion //#region src/docx/docxExporter.ts var O = 16 * .75 * 1.5 * 20, k = class extends t { constructor(t, n, r) { let i = { colors: e, resolveFileUrl: E, ...r }; super(t, n, i), this.schema = t, this.mappings = n; } transformStyledText(e, t) { let n = this.mapStyles(e.styles), r = Object.assign({}, ...n); return new v({ ...r, style: t ? "Hyperlink" : r.style, text: e.text }); } async transformBlocks(e, t = 0) { let n = []; for (let r of e) { let e = await this.transformBlocks(r.children, t + 1); ["columnList", "column"].includes(r.type) || (e = e.map((e, t) => (e instanceof f && !e.properties.numberingReferences.length && e.addRunToFront(new v({ children: [new m()] })), e))); let i = await this.mapBlock(r, t, 0, e); ["columnList", "column"].includes(r.type) ? n.push(i) : Array.isArray(i) ? n.push(...i, ...e) : n.push(i, ...e); } return n; } async getFonts() { let e = await D(await import("./Inter_18pt-Regular-DVodnrPc.js")), t = await D(await import("./GeistMono-Regular-DC6WVheu.js")); if (e instanceof ArrayBuffer || t instanceof ArrayBuffer) { let n = (await import("buffer/")).Buffer; e instanceof ArrayBuffer && (e = n.from(e)), t instanceof ArrayBuffer && (t = n.from(t)); } return [{ name: "Inter", data: e }, { name: "GeistMono", data: t }]; } async createDefaultDocumentOptions(e) { let t = (await import("./styles-C7Ws_DIi.js")).default, n = e?.trim(); t = n ? t.replace(/(<w:lang\b[^>]*\bw:val=")([^"]+)("[^>]*\/>)/g, (e, t, r, i) => `${t}${n}${i}`) : t.replace(/\s*<w:lang\b[^>]*\/>/g, ""); let r = ["•"]; return { numbering: { config: [{ reference: "blocknote-numbered-list", levels: Array.from({ length: 9 }, (e, t) => ({ start: 1, level: t, format: l.DECIMAL, text: `%${t + 1}.`, alignment: i.LEFT, style: { paragraph: { indent: { left: O * (t + 1), hanging: O } } } })) }, { reference: "blocknote-bullet-list", levels: Array.from({ length: 9 }, (e, t) => ({ start: 1, level: t, format: l.BULLET, text: r[t % r.length], alignment: i.LEFT, style: { paragraph: { indent: { left: O * (t + 1), hanging: O } } } })) }] }, fonts: await this.getFonts(), defaultTabStop: 200, externalStyles: t }; } async toBlob(e, t = { sectionOptions: {}, documentOptions: {} }) { let n = await this.toDocxJsDocument(e, t), r = globalThis.Buffer; try { return globalThis.Buffer || (globalThis.Buffer = (await import("buffer")).default.Buffer), u.toBlob(n); } finally { globalThis.Buffer = r; } } async toDocxJsDocument(e, t = { sectionOptions: {}, documentOptions: {} }) { return new o({ ...await this.createDefaultDocumentOptions(t.locale), ...t.documentOptions, sections: [{ children: await this.transformBlocks(e), ...t.sectionOptions }] }); } }; //#endregion export { k as DOCXExporter, T as docxDefaultSchemaMappings }; //# sourceMappingURL=blocknote-xl-docx-exporter.js.map