diff --git a/src/Truncate.js b/src/Truncate.js index f206f76b..d1c35412 100644 --- a/src/Truncate.js +++ b/src/Truncate.js @@ -127,7 +127,11 @@ export default class Truncate extends Component { return; } - const targetWidth = target.parentNode.getBoundingClientRect().width; + const targetParentStyles = window.getComputedStyle(target.parentNode); + const targetParentPadding = parseFloat(targetParentStyles['padding-left'] || 0) + + parseFloat(targetParentStyles['padding-right'] || 0); + const targetWidth = target.parentNode.getBoundingClientRect().width - + targetParentPadding; // Delay calculation until parent node is inserted to the document // Mounting order in React is ChildComponent, ParentComponent @@ -152,7 +156,14 @@ export default class Truncate extends Component { } measureWidth(text) { - return this.canvas.measureText(text).width; + const { + refs: { + target + } + } = this; + const targetStyles = window.getComputedStyle(target); + const letterSpacing = parseFloat(targetStyles['letter-spacing']) || 0; + return this.canvas.measureText(text).width + (letterSpacing * text.length); } ellipsisWidth(node) { diff --git a/test/Truncate.js b/test/Truncate.js index 09c3575a..9d8ea780 100644 --- a/test/Truncate.js +++ b/test/Truncate.js @@ -122,6 +122,17 @@ describe('', () => { ).children[0]; + const spacingAndPaddingStyles = { + padding: '10px', + letterSpacing: '1px' + }; + + const renderIntoBoxWithPaddingAndLetterSpacing = component => renderIntoDocument( +
+ {component} +
+ ).children[0]; + before(() => { sinon.stub(global.window.HTMLDivElement.prototype, 'getBoundingClientRect', () => ({ width }) @@ -164,6 +175,22 @@ describe('', () => { `); }); + it('should take padding and letter-spacing into account', () => { + const component = renderIntoBoxWithPaddingAndLetterSpacing( + + This text should + stop after here + and not contain the + next lines + + ); + + expect(component, 'to display text', ` + This text + should stop… + `); + }); + it('should preserve newlines', () => { const component = renderIntoBox( @@ -379,9 +406,8 @@ describe('', () => { }); }); - it('should recalculate when resizing the window', () => { + it('should recalculate when resizing the window', (done) => { const calcTargetWidth = sinon.spy(Truncate.prototype, 'calcTargetWidth'); - try { renderIntoDocument(); @@ -391,9 +417,9 @@ describe('', () => { expect(calcTargetWidth, 'was called times', numCalled + 1); } finally { - Truncate.prototype.calcTargetWidth.restore(); + Truncate.prototype.calcTargetWidth.restore(done()); } - }); + }).timeout(2500); it('should clean up all event listeners on window when unmounting', () => { const events = new Set();