diff --git a/config/jsdom.js b/config/jsdom.js index 301e35c..7584ba3 100644 --- a/config/jsdom.js +++ b/config/jsdom.js @@ -42,6 +42,7 @@ global.HTMLSelectElement = window.HTMLSelectElement; global.HTMLInputElement = window.HTMLInputElement; global.DocumentFragment = window.DocumentFragment; global.requestAnimationFrame = window.requestAnimationFrame; +window.matchMedia = () => true; copyProps(window, global); diff --git a/src/scripts/choices.js b/src/scripts/choices.js index 98c176d..158aef0 100644 --- a/src/scripts/choices.js +++ b/src/scripts/choices.js @@ -384,7 +384,7 @@ class Choices { requestAnimationFrame(() => { this.dropdown.show(); - this.containerOuter.open(this.dropdown.distanceFromTopWindow()); + this.containerOuter.open(this.dropdown.distanceFromTopWindow); if (!preventInputFocus && this._canSearch) { this.input.focus(); @@ -1463,9 +1463,9 @@ class Choices { let nextEl; if (skipKey) { if (directionInt > 0) { - nextEl = Array.from( - this.dropdown.element.querySelectorAll(selectableChoiceIdentifier), - ).pop(); + nextEl = this.dropdown.element.querySelector( + `${selectableChoiceIdentifier}:last-of-type`, + ); } else { nextEl = this.dropdown.element.querySelector( selectableChoiceIdentifier, diff --git a/src/scripts/components/container.js b/src/scripts/components/container.js index e03bda9..5e8d0ce 100644 --- a/src/scripts/components/container.js +++ b/src/scripts/components/container.js @@ -1,4 +1,4 @@ -import { getWindowHeight, wrap } from '../lib/utils'; +import { wrap } from '../lib/utils'; export default class Container { constructor({ element, type, classNames, position }) { @@ -38,8 +38,8 @@ export default class Container { * @param {Number} dropdownPos * @returns */ - shouldFlip(dropdownPos, windowHeight = getWindowHeight()) { - if (dropdownPos === undefined) { + shouldFlip(dropdownPos) { + if (typeof dropdownPos !== 'number') { return false; } @@ -47,7 +47,8 @@ export default class Container { // greater than the window height flip the dropdown. let shouldFlip = false; if (this.position === 'auto') { - shouldFlip = dropdownPos >= windowHeight; + shouldFlip = !window.matchMedia(`(min-height: ${dropdownPos + 1}px)`) + .matches; } else if (this.position === 'top') { shouldFlip = true; } diff --git a/src/scripts/components/container.test.js b/src/scripts/components/container.test.js index f4be133..a10cb97 100644 --- a/src/scripts/components/container.test.js +++ b/src/scripts/components/container.test.js @@ -102,18 +102,6 @@ describe('components/container', () => { beforeEach(() => { instance.position = 'auto'; }); - - describe('dropdownPos is greater than window height', () => { - it('returns false', () => { - expect(instance.shouldFlip(100, 1000)).to.equal(false); - }); - }); - - describe('dropdownPos is less than window height', () => { - it('returns true', () => { - expect(instance.shouldFlip(100, 50)).to.equal(true); - }); - }); }); describe('position config option set to "top"', () => { diff --git a/src/scripts/components/dropdown.js b/src/scripts/components/dropdown.js index e1f61a8..01d4bdb 100644 --- a/src/scripts/components/dropdown.js +++ b/src/scripts/components/dropdown.js @@ -6,17 +6,11 @@ export default class Dropdown { } /** - * Determine how far the top of our element is from - * the top of the window - * @return {Number} Vertical position + * Bottom position of dropdown in viewport coordinates + * @type {number} Vertical position */ - distanceFromTopWindow() { - this.dimensions = this.element.getBoundingClientRect(); - this.position = Math.ceil( - this.dimensions.top + window.pageYOffset + this.element.offsetHeight, - ); - - return this.position; + get distanceFromTopWindow() { + return this.element.getBoundingClientRect().bottom; } /** diff --git a/src/scripts/components/dropdown.test.js b/src/scripts/components/dropdown.test.js index 900b5a8..2a30e26 100644 --- a/src/scripts/components/dropdown.test.js +++ b/src/scripts/components/dropdown.test.js @@ -34,15 +34,13 @@ describe('components/dropdown', () => { describe('distanceFromTopWindow', () => { let top; - let offset; let dimensions; let getBoundingClientRectStub; beforeEach(() => { top = 100; - offset = 50; dimensions = { - bottom: 0, + bottom: 121, height: 0, left: 0, right: 0, @@ -53,31 +51,17 @@ describe('components/dropdown', () => { getBoundingClientRectStub = sinon .stub(instance.element, 'getBoundingClientRect') .returns(dimensions); - - window.pageYOffset = 50; }); afterEach(() => { getBoundingClientRectStub.restore(); }); - it('determines how far the top of our element is from the top of the window', () => { - const expectedResponse = top + offset; - const actualResponse = instance.distanceFromTopWindow(); + it('determines how far the top of our element is from the top of the viewport', () => { + const expectedResponse = dimensions.bottom; + const actualResponse = instance.distanceFromTopWindow; expect(actualResponse).to.equal(expectedResponse); }); - - it('assigns dimensions to instance', () => { - instance.distanceFromTopWindow(); - const expectedResponse = dimensions; - expect(instance.dimensions).to.equal(expectedResponse); - }); - - it('assigns posisiton to instance', () => { - instance.distanceFromTopWindow(); - const expectedResponse = top + offset; - expect(instance.position).to.equal(expectedResponse); - }); }); describe('getChild', () => { diff --git a/src/scripts/lib/utils.js b/src/scripts/lib/utils.js index 0d65253..586736c 100644 --- a/src/scripts/lib/utils.js +++ b/src/scripts/lib/utils.js @@ -130,19 +130,6 @@ export const dispatchEvent = (element, type, customArgs = null) => { return element.dispatchEvent(event); }; -export const getWindowHeight = () => { - const { body } = document; - const html = document.documentElement; - - return Math.max( - body.scrollHeight, - body.offsetHeight, - html.clientHeight, - html.scrollHeight, - html.offsetHeight, - ); -}; - export const isIE11 = userAgent => !!(userAgent.match(/Trident/) && userAgent.match(/rv[ :]11/)); diff --git a/src/styles/choices.scss b/src/styles/choices.scss index f5f654e..8a45d4e 100644 --- a/src/styles/choices.scss +++ b/src/styles/choices.scss @@ -217,7 +217,7 @@ $choices-icon-cross-inverse: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiI } .#{$choices-selector}__list--dropdown { - display: none; + visibility: hidden; z-index: 1; position: absolute; width: 100%; @@ -229,8 +229,9 @@ $choices-icon-cross-inverse: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiI border-bottom-right-radius: $choices-border-radius; overflow: hidden; word-break: break-all; + will-change: visibility; &.is-active { - display: block; + visibility: visible; } .is-open & { border-color: darken($choices-keyline-color, 15%);