mirror of
https://github.com/Choices-js/Choices.git
synced 2024-05-19 14:06:33 +02:00
use CSS queries (#718)
* use matchMedia * use last-of-type * better type check * simplify distanceFromTopWindow * use visibility * update JSDoc
This commit is contained in:
parent
c03fcf5d03
commit
034191c78a
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"', () => {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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/));
|
||||
|
||||
|
|
|
@ -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%);
|
||||
|
|
Loading…
Reference in a new issue