From 8ab0387857dd6f0971dd34a611952bf8b0067ce8 Mon Sep 17 00:00:00 2001 From: Philipp Eichhorn Date: Tue, 22 May 2018 14:14:02 +0200 Subject: [PATCH] perf: removed forced reflow ("layout thrashing") by reading testEl.offsetWidth in a separate animation frame --- src/scripts/src/components/input.js | 12 ++++++++---- src/scripts/src/components/input.test.js | 2 +- src/scripts/src/lib/utils.js | 22 +++++++++++++--------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/scripts/src/components/input.js b/src/scripts/src/components/input.js index 4e98599..a8811d2 100644 --- a/src/scripts/src/components/input.js +++ b/src/scripts/src/components/input.js @@ -127,16 +127,20 @@ export default class Input { this.element.value.length >= (this.placeholderValue.length / 1.25)) || enforceWidth ) { - this.element.style.width = this.calcWidth(); + this.calcWidth((width) => { + this.element.style.width = width; + }); } } else { // If there is no placeholder, resize input to contents - this.element.style.width = this.calcWidth(); + this.calcWidth((width) => { + this.element.style.width = width; + }); } } - calcWidth() { - return calcWidthOfInput(this.element); + calcWidth(callback) { + return calcWidthOfInput(this.element, callback); } setActiveDescendant(activeDescendantID) { diff --git a/src/scripts/src/components/input.test.js b/src/scripts/src/components/input.test.js index e5957c9..dc75f70 100644 --- a/src/scripts/src/components/input.test.js +++ b/src/scripts/src/components/input.test.js @@ -271,7 +271,7 @@ describe('components/input', () => { const inputWidth = '200px'; beforeEach(() => { - calcWidthStub = stub(instance, 'calcWidth').returns(inputWidth); + calcWidthStub = stub(instance, 'calcWidth').callsArgWith(0, inputWidth); }); afterEach(() => { diff --git a/src/scripts/src/lib/utils.js b/src/scripts/src/lib/utils.js index 5c3f66b..e1c0478 100644 --- a/src/scripts/src/lib/utils.js +++ b/src/scripts/src/lib/utils.js @@ -482,10 +482,10 @@ export const strToEl = (function() { }()); /** - * Sets the width of a passed input based on its value - * @return {Number} Width of input + * Determines the width of a passed input based on its value and passes + * it to the supplied callback function. */ -export const calcWidthOfInput = (input) => { +export const calcWidthOfInput = (input, callback) => { const value = input.value || input.placeholder; let width = input.offsetWidth; @@ -514,14 +514,18 @@ export const calcWidthOfInput = (input) => { document.body.appendChild(testEl); - if (value && testEl.offsetWidth !== input.offsetWidth) { - width = testEl.offsetWidth + 4; - } + requestAnimationFrame(() => { + if (value && testEl.offsetWidth !== input.offsetWidth) { + width = testEl.offsetWidth + 4; + } - document.body.removeChild(testEl); + document.body.removeChild(testEl); + + callback.call(this, `${width}px`); + }); + } else { + callback.call(this, `${width}px`); } - - return `${width}px`; }; /**