From e4a9be715c83e14db6bb1c8358ba3541384bfd2e Mon Sep 17 00:00:00 2001 From: jalery922 Date: Fri, 13 Dec 2024 18:09:14 +0800 Subject: [PATCH 1/4] fix(docx): export list and suffix-break of text --- packages/docx/src/docx/exportDocx.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/docx/src/docx/exportDocx.ts b/packages/docx/src/docx/exportDocx.ts index 94b7648..b316276 100644 --- a/packages/docx/src/docx/exportDocx.ts +++ b/packages/docx/src/docx/exportDocx.ts @@ -119,6 +119,7 @@ function convertElementListToDocxChildren( element.valueList ?.map(item => item.value) .join('') + .replace(/^\n/, '') .split('\n') .map( (text, index) => @@ -175,11 +176,16 @@ function convertElementListToDocxChildren( ) || []) ) } else { + let suffixBreak if (/^\n/.test(element.value)) { appendParagraph() element.value = element.value.replace(/^\n/, '') + } else if (/\n$/.test(element.value)) { + suffixBreak = true + element.value = element.value.replace(/\n$/, '') } paragraphChild.push(convertElementToParagraphChild(element)) + suffixBreak && appendParagraph() } } appendParagraph() From 637e76a40b11d8f5e3996117e18ae4af3f24df43 Mon Sep 17 00:00:00 2001 From: jalery922 Date: Mon, 16 Dec 2024 13:52:17 +0800 Subject: [PATCH 2/4] improve(docx): support rowFlex --- packages/docx/src/docx/exportDocx.ts | 87 ++++++++++++++++++---------- 1 file changed, 56 insertions(+), 31 deletions(-) diff --git a/packages/docx/src/docx/exportDocx.ts b/packages/docx/src/docx/exportDocx.ts index b316276..9eca7df 100644 --- a/packages/docx/src/docx/exportDocx.ts +++ b/packages/docx/src/docx/exportDocx.ts @@ -4,7 +4,8 @@ import { ElementType, TitleLevel, ListStyle, - Command + Command, + RowFlex } from '@hufe921/canvas-editor' import { Document, @@ -22,7 +23,8 @@ import { WidthType, TableRow, TableCell, - MathRun + MathRun, + AlignmentType } from 'docx' import { saveAs } from './utils' @@ -36,6 +38,14 @@ const titleLevelToHeadingLevel = { [TitleLevel.SIXTH]: HeadingLevel.HEADING_6 } +// 水平对齐映射 +const RowFlexToAlignmentType = { + [RowFlex.LEFT]: AlignmentType.LEFT, + [RowFlex.CENTER]: AlignmentType.CENTER, + [RowFlex.RIGHT]: AlignmentType.RIGHT, + [RowFlex.ALIGNMENT]: AlignmentType.BOTH +} + function convertElementToParagraphChild(element: IElement): ParagraphChild { if (element.type === ElementType.IMAGE) { return new ImageRun({ @@ -88,14 +98,18 @@ function convertElementListToDocxChildren( let paragraphChild: ParagraphChild[] = [] + let alignment: AlignmentType | undefined = undefined + function appendParagraph() { if (paragraphChild.length) { children.push( new Paragraph({ + alignment, children: paragraphChild }) ) paragraphChild = [] + alignment = undefined } } @@ -103,40 +117,45 @@ function convertElementListToDocxChildren( const element = elementList[e] if (element.type === ElementType.TITLE) { appendParagraph() + const valueList = element.valueList || [] + const rowFlex = valueList[0]?.rowFlex children.push( new Paragraph({ heading: titleLevelToHeadingLevel[element.level!], - children: - element.valueList?.map(child => - convertElementToParagraphChild(child) - ) || [] + alignment: rowFlex ? RowFlexToAlignmentType[rowFlex] : undefined, + children: valueList.map(child => + convertElementToParagraphChild(child) + ) }) ) } else if (element.type === ElementType.LIST) { appendParagraph() // 拆分列表 - const listChildren = - element.valueList - ?.map(item => item.value) - .join('') - .replace(/^\n/, '') - .split('\n') - .map( - (text, index) => - new Paragraph({ - children: [ - new TextRun({ - text: `${ - !element.listStyle || - element.listStyle === ListStyle.DECIMAL - ? `${index + 1}. ` - : `• ` - }${text}` - }) - ] - }) - ) || [] - children.push(...listChildren) + const valueList = element.valueList || [] + const isDecimal = + !element.listStyle || element.listStyle === ListStyle.DECIMAL + valueList.reduce((count, cur) => { + if (cur.value !== '\n') { + cur.value + .replace(/^\n/, '') + .split('\n') + .forEach(text => { + children.push( + new Paragraph({ + alignment: cur.rowFlex + ? RowFlexToAlignmentType[cur.rowFlex] + : undefined, + children: [ + new TextRun({ + text: `${isDecimal ? `${++count}. ` : `• `}${text}` + }) + ] + }) + ) + }) + } + return count + }, 0) } else if (element.type === ElementType.TABLE) { appendParagraph() const { trList } = element @@ -170,10 +189,13 @@ function convertElementListToDocxChildren( }) ) } else if (element.type === ElementType.DATE) { + const valueList = element.valueList || [] + const rowFlex = valueList[0]?.rowFlex + if (rowFlex && !alignment) { + alignment = RowFlexToAlignmentType[rowFlex] + } paragraphChild.push( - ...(element.valueList?.map(child => - convertElementToParagraphChild(child) - ) || []) + ...valueList.map(child => convertElementToParagraphChild(child)) ) } else { let suffixBreak @@ -184,6 +206,9 @@ function convertElementListToDocxChildren( suffixBreak = true element.value = element.value.replace(/\n$/, '') } + if (element.rowFlex && !alignment) { + alignment = RowFlexToAlignmentType[element.rowFlex] + } paragraphChild.push(convertElementToParagraphChild(element)) suffixBreak && appendParagraph() } From fe8072a83bcb473d4b541be486d539b1064687d2 Mon Sep 17 00:00:00 2001 From: jalery922 Date: Thu, 12 Dec 2024 16:22:44 +0800 Subject: [PATCH 3/4] improve(docx): support define function to convert px to pt --- packages/docx/src/docx/exportDocx.ts | 60 +++++++++++++++++----------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/packages/docx/src/docx/exportDocx.ts b/packages/docx/src/docx/exportDocx.ts index 9eca7df..b61b88c 100644 --- a/packages/docx/src/docx/exportDocx.ts +++ b/packages/docx/src/docx/exportDocx.ts @@ -5,7 +5,8 @@ import { TitleLevel, ListStyle, Command, - RowFlex + RowFlex, + IEditorData } from '@hufe921/canvas-editor' import { Document, @@ -46,6 +47,10 @@ const RowFlexToAlignmentType = { [RowFlex.ALIGNMENT]: AlignmentType.BOTH } +type PxToPtHandler = (size?: number) => number + +let pxToPtHandler: PxToPtHandler = (size?: number) => (size || 16) / 0.75 + function convertElementToParagraphChild(element: IElement): ParagraphChild { if (element.type === ElementType.IMAGE) { return new ImageRun({ @@ -79,7 +84,7 @@ function convertElementToParagraphChild(element: IElement): ParagraphChild { font: element.font, text: element.value, bold: element.bold, - size: `${(element.size || 16) / 0.75}pt`, + size: `${pxToPtHandler(element.size)}pt`, color: Color(element.color).hex() || '#000000', italics: element.italic, strike: element.strikeout, @@ -227,31 +232,38 @@ declare module '@hufe921/canvas-editor' { } } +export function createDocumentByData(data: IEditorData) { + const { header, main, footer } = data + return new Document({ + sections: [ + { + headers: { + default: new Header({ + children: convertElementListToDocxChildren(header || []) + }) + }, + footers: { + default: new Footer({ + children: convertElementListToDocxChildren(footer || []) + }) + }, + children: convertElementListToDocxChildren(main || []) + } + ] + }) +} + +export function setPxToPtHandler(handler: PxToPtHandler) { + if (typeof handler === 'function') { + pxToPtHandler = handler + } +} + export default function (command: Command) { return function (options: IExportDocxOption) { const { fileName } = options - const { - data: { header, main, footer } - } = command.getValue() - - const doc = new Document({ - sections: [ - { - headers: { - default: new Header({ - children: convertElementListToDocxChildren(header || []) - }) - }, - footers: { - default: new Footer({ - children: convertElementListToDocxChildren(footer || []) - }) - }, - children: convertElementListToDocxChildren(main || []) - } - ] - }) - + const { data } = command.getValue() + const doc = createDocumentByData(data) Packer.toBlob(doc).then(blob => { saveAs(blob, `${fileName}.docx`) }) From ffd39007fd68140de5cd1cf6b90d5d41bf4c3a2f Mon Sep 17 00:00:00 2001 From: jalery922 Date: Tue, 18 Mar 2025 10:24:08 +0800 Subject: [PATCH 4/4] fix(docx): support multiple line break --- packages/docx/src/docx/exportDocx.ts | 34 ++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/packages/docx/src/docx/exportDocx.ts b/packages/docx/src/docx/exportDocx.ts index b61b88c..936dfd1 100644 --- a/packages/docx/src/docx/exportDocx.ts +++ b/packages/docx/src/docx/exportDocx.ts @@ -203,19 +203,29 @@ function convertElementListToDocxChildren( ...valueList.map(child => convertElementToParagraphChild(child)) ) } else { - let suffixBreak - if (/^\n/.test(element.value)) { - appendParagraph() - element.value = element.value.replace(/^\n/, '') - } else if (/\n$/.test(element.value)) { - suffixBreak = true - element.value = element.value.replace(/\n$/, '') - } - if (element.rowFlex && !alignment) { - alignment = RowFlexToAlignmentType[element.rowFlex] + if (/\n/.test(element.value)) { + let valueList = element.value.split('\n') + // \n\n... + if (valueList.every(value => value === '')) { + valueList = valueList.slice(1) + } + valueList.forEach(value => { + if (value !== '') { + if (element.rowFlex && !alignment) { + alignment = RowFlexToAlignmentType[element.rowFlex] + } + paragraphChild.push( + convertElementToParagraphChild({ ...element, value }) + ) + } + appendParagraph() + }) + } else { + if (element.rowFlex && !alignment) { + alignment = RowFlexToAlignmentType[element.rowFlex] + } + paragraphChild.push(convertElementToParagraphChild(element)) } - paragraphChild.push(convertElementToParagraphChild(element)) - suffixBreak && appendParagraph() } } appendParagraph()