diff --git a/packages/pdf/src/templates/shared/rich-text-html.test.ts b/packages/pdf/src/templates/shared/rich-text-html.test.ts index 669777520..adf2640d8 100644 --- a/packages/pdf/src/templates/shared/rich-text-html.test.ts +++ b/packages/pdf/src/templates/shared/rich-text-html.test.ts @@ -17,6 +17,51 @@ describe("normalizeRichTextHtml", () => { expect(normalizeRichTextHtml("bold text")).toBe("
bold text
"); }); + it("moves trailing whitespace outside bold tags", () => { + expect(normalizeRichTextHtml("Built and deployed
")).toBe( + "Built and deployed
", + ); + }); + + it("moves leading whitespace outside bold tags", () => { + expect(normalizeRichTextHtml("Built and deployed
")).toBe( + "Built and deployed
", + ); + }); + + it("preserves whitespace moved outside top-level bold tags", () => { + expect(normalizeRichTextHtml("Built ")).toBe("Built
"); + expect(normalizeRichTextHtml(" Built")).toBe("Built
"); + }); + + it.each([" ", " ", " "])( + "moves encoded non-breaking spaces outside bold boundaries: %s", + (whitespace) => { + expect(normalizeRichTextHtml(`Built${whitespace}and deployed
`)).toBe( + `Built${whitespace}and deployed
`, + ); + expect(normalizeRichTextHtml(`Built${whitespace}and deployed
`)).toBe( + `Built${whitespace}and deployed
`, + ); + }, + ); + + it("preserves > characters inside quoted bold-tag attributes", () => { + expect(normalizeRichTextHtml('Built and deployed
')).toBe( + 'Built and deployed
', + ); + }); + + it("preserves closing bold tags inside quoted attributes", () => { + expect(normalizeRichTextHtml('Built next
')).toBe( + 'Built next
', + ); + }); + + it("preserves whitespace inside bold text", () => { + expect(normalizeRichTextHtml("two words
")).toBe("two words
"); + }); + it("preserves block-levelas-is", () => { expect(normalizeRichTextHtml("
Already wrapped
")).toBe("Already wrapped
"); }); diff --git a/packages/pdf/src/templates/shared/rich-text-html.ts b/packages/pdf/src/templates/shared/rich-text-html.ts index db01e9c30..c587ea806 100644 --- a/packages/pdf/src/templates/shared/rich-text-html.ts +++ b/packages/pdf/src/templates/shared/rich-text-html.ts @@ -69,6 +69,31 @@ const isMeaningfulNode = (node: Node): boolean => const isElement = (node: Node): node is HTMLElement => node.nodeType === NodeType.ELEMENT_NODE; +const LEADING_BOLD_BOUNDARY_WHITESPACE = /^(?:[\u0020\u00a0]| | | )+/i; +const TRAILING_BOLD_BOUNDARY_WHITESPACE = /(?:[\u0020\u00a0]| | | )+$/i; + +const normalizeBoldBoundaryWhitespace = (root: ReturnType${inlineHtml}
`); + if (inlineHtml.trim()) normalized.push(`${inlineHtml}
`); inlineNodes = []; };