diff --git a/CHANGELOG.md b/CHANGELOG.md index 839d77f..2734ea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht ### Fixed +- Preserved explicit paragraph `defRPr` text colors when a shape also provides a theme + `fontRef` color, preventing light theme text from overriding authored paragraph colors. - Keep near-fit, single-paragraph square-wrapped headings on one line with a conservative 2% browser-metric correction while preserving deliberate multi-line text. - Resolve macOS PowerPoint exports and macro hosts by exact full path, close only that presentation, diff --git a/test/unit/renderer/ShapeRenderer.test.ts b/test/unit/renderer/ShapeRenderer.test.ts index 063c596..d87e740 100644 --- a/test/unit/renderer/ShapeRenderer.test.ts +++ b/test/unit/renderer/ShapeRenderer.test.ts @@ -6034,6 +6034,50 @@ describe('ShapeRenderer', () => { expect(hasWhiteText).toBe(true); }); + it('keeps paragraph defRPr color over shape fontRef color', () => { + const xml = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + Paragraph Color + + + + `; + + const el = renderShape(parseShapeNode(parseXml(xml)), createMockRenderContext()); + const textSpan = Array.from(el.querySelectorAll('span')).find( + (span) => span.textContent === 'Paragraph Color', + ); + + expect(textSpan).toBeDefined(); + expect(textSpan!.style.color).toBe('rgb(36, 59, 83)'); + }); + // --------------------------------------------------------------------------- // Dynamic normAutofit scaling (lines ~1142-1162 in ShapeRenderer.ts) // In jsdom, scrollHeight often equals clientHeight, so the scale branch may not diff --git a/test/unit/renderer/TextRenderer.branches.test.ts b/test/unit/renderer/TextRenderer.branches.test.ts index fdf7e96..f9826b5 100644 --- a/test/unit/renderer/TextRenderer.branches.test.ts +++ b/test/unit/renderer/TextRenderer.branches.test.ts @@ -1546,6 +1546,82 @@ describe('TextRenderer — branch coverage (uncovered paths)', () => { expect(span!.style.color).toBe('rgb(255, 0, 0)'); }); + it('prefers explicit paragraph defRPr color over fontRefColor', () => { + const body = makeTextBody({ + paragraphs: [ + { + properties: xmlNode( + '', + ), + runs: [{ text: 'Paragraph color wins' }], + level: 0, + }, + ], + }); + const ctx = createMockRenderContext(); + const container = document.createElement('div'); + renderTextBody(body, undefined, ctx, container, { + fontRefColor: '#FFFFFF', + }); + const span = container.querySelector('span'); + expect(span!.style.color).toBe('rgb(36, 59, 83)'); + }); + + it('uses fontRefColor when paragraph defRPr has no color', () => { + const body = makeTextBody({ + paragraphs: [ + { + properties: xmlNode(''), + runs: [{ text: 'Shape style color wins' }], + level: 0, + }, + ], + }); + const ctx = createMockRenderContext(); + const container = document.createElement('div'); + renderTextBody(body, undefined, ctx, container, { + fontRefColor: '#FFFFFF', + }); + const span = container.querySelector('span'); + expect(span!.style.color).toBe('rgb(255, 255, 255)'); + }); + + it('keeps fontRefColor precedence over inherited list style colors', () => { + const body = makeTextBody({ + listStyle: + '', + paragraphs: [{ runs: [{ text: 'Shape style color wins' }], level: 0 }], + }); + const ctx = createMockRenderContext(); + const container = document.createElement('div'); + renderTextBody(body, undefined, ctx, container, { + fontRefColor: '#FFFFFF', + }); + const span = container.querySelector('span'); + expect(span!.style.color).toBe('rgb(255, 255, 255)'); + }); + + it('prefers explicit paragraph defRPr color over cellTextColor', () => { + const body = makeTextBody({ + paragraphs: [ + { + properties: xmlNode( + '', + ), + runs: [{ text: 'Paragraph color wins' }], + level: 0, + }, + ], + }); + const ctx = createMockRenderContext(); + const container = document.createElement('div'); + renderTextBody(body, undefined, ctx, container, { + cellTextColor: '#FF0000', + }); + const span = container.querySelector('span'); + expect(span!.style.color).toBe('rgb(36, 59, 83)'); + }); + it('uses cellTextColor as fallback when no other color set', () => { const body = makeTextBody({ paragraphs: [