mirror of
https://github.com/Choices-js/Choices.git
synced 2024-05-02 22:03:11 +02:00
Move scrolling logic into list component
This commit is contained in:
parent
f9455b1a25
commit
804a4a442b
|
@ -15,7 +15,6 @@ import {
|
|||
DEFAULT_CLASSNAMES,
|
||||
EVENTS,
|
||||
KEY_CODES,
|
||||
SCROLLING_SPEED,
|
||||
} from './constants';
|
||||
import { TEMPLATES } from './templates';
|
||||
import {
|
||||
|
@ -1116,7 +1115,7 @@ class Choices {
|
|||
if (
|
||||
!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)
|
||||
) {
|
||||
this._scrollToChoice(nextEl, directionInt);
|
||||
this.choiceList.scrollToChoice(nextEl, directionInt);
|
||||
}
|
||||
this._highlightChoice(nextEl);
|
||||
}
|
||||
|
@ -1392,69 +1391,6 @@ class Choices {
|
|||
}
|
||||
}
|
||||
|
||||
_scrollToChoice(choice, direction) {
|
||||
if (!choice) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dropdownHeight = this.choiceList.element.offsetHeight;
|
||||
const choiceHeight = choice.offsetHeight;
|
||||
// Distance from bottom of element to top of parent
|
||||
const choicePos = choice.offsetTop + choiceHeight;
|
||||
// Scroll position of dropdown
|
||||
const containerScrollPos =
|
||||
this.choiceList.element.scrollTop + dropdownHeight;
|
||||
// Difference between the choice and scroll position
|
||||
const endPoint =
|
||||
direction > 0
|
||||
? this.choiceList.element.scrollTop + choicePos - containerScrollPos
|
||||
: choice.offsetTop;
|
||||
|
||||
const scrollDown = (scrollPos, strength) => {
|
||||
const easing = (endPoint - scrollPos) / strength;
|
||||
const distance = easing > 1 ? easing : 1;
|
||||
|
||||
this.choiceList.scrollTo(scrollPos + distance);
|
||||
};
|
||||
|
||||
const scrollUp = (scrollPos, strength) => {
|
||||
const easing = (scrollPos - endPoint) / strength;
|
||||
const distance = easing > 1 ? easing : 1;
|
||||
|
||||
this.choiceList.scrollTo(scrollPos - distance);
|
||||
};
|
||||
|
||||
const animateScroll = () => {
|
||||
const strength = SCROLLING_SPEED;
|
||||
const choiceListScrollTop = this.choiceList.element.scrollTop;
|
||||
let continueAnimation = false;
|
||||
|
||||
if (direction > 0) {
|
||||
scrollDown(choiceListScrollTop, strength);
|
||||
|
||||
if (choiceListScrollTop < endPoint) {
|
||||
continueAnimation = true;
|
||||
}
|
||||
} else {
|
||||
scrollUp(choiceListScrollTop, strength);
|
||||
|
||||
if (choiceListScrollTop > endPoint) {
|
||||
continueAnimation = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (continueAnimation) {
|
||||
requestAnimationFrame(time => {
|
||||
animateScroll(time, endPoint, direction);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
requestAnimationFrame(time => {
|
||||
animateScroll(time, endPoint, direction);
|
||||
});
|
||||
}
|
||||
|
||||
_highlightChoice(el = null) {
|
||||
const choices = Array.from(
|
||||
this.dropdown.element.querySelectorAll('[data-choice-selectable]'),
|
||||
|
@ -2028,7 +1964,7 @@ class Choices {
|
|||
|
||||
// Scroll back to top of choices list
|
||||
if (this.config.resetScrollPosition) {
|
||||
this.choiceList.scrollTo(0);
|
||||
this.choiceList.scrollToTop();
|
||||
}
|
||||
|
||||
// If we have grouped options
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { SCROLLING_SPEED } from '../constants';
|
||||
|
||||
export default class List {
|
||||
constructor({ element }) {
|
||||
Object.assign(this, { element });
|
||||
|
@ -7,31 +9,81 @@ export default class List {
|
|||
this.hasChildren = !!this.element.children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear List contents
|
||||
*/
|
||||
clear() {
|
||||
this.element.innerHTML = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to passed position on Y axis
|
||||
*/
|
||||
scrollTo(scrollPos = 0) {
|
||||
this.element.scrollTop = scrollPos;
|
||||
}
|
||||
/**
|
||||
* Append node to element
|
||||
*/
|
||||
append(node) {
|
||||
this.element.appendChild(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find element that matches passed selector
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
getChild(selector) {
|
||||
return this.element.querySelector(selector);
|
||||
}
|
||||
|
||||
scrollToTop() {
|
||||
this.element.scrollTop = 0;
|
||||
}
|
||||
|
||||
scrollToChoice(choice, direction) {
|
||||
if (!choice) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dropdownHeight = this.element.offsetHeight;
|
||||
const choiceHeight = choice.offsetHeight;
|
||||
// Distance from bottom of element to top of parent
|
||||
const choicePos = choice.offsetTop + choiceHeight;
|
||||
// Scroll position of dropdown
|
||||
const containerScrollPos = this.element.scrollTop + dropdownHeight;
|
||||
// Difference between the choice and scroll position
|
||||
const endpoint =
|
||||
direction > 0
|
||||
? this.element.scrollTop + choicePos - containerScrollPos
|
||||
: choice.offsetTop;
|
||||
|
||||
requestAnimationFrame(time => {
|
||||
this._animateScroll(time, endpoint, direction);
|
||||
});
|
||||
}
|
||||
|
||||
_scrollDown(scrollPos, strength, endpoint) {
|
||||
const easing = (endpoint - scrollPos) / strength;
|
||||
const distance = easing > 1 ? easing : 1;
|
||||
|
||||
this.element.scrollTop = scrollPos + distance;
|
||||
}
|
||||
|
||||
_scrollUp(scrollPos, strength, endpoint) {
|
||||
const easing = (scrollPos - endpoint) / strength;
|
||||
const distance = easing > 1 ? easing : 1;
|
||||
|
||||
this.element.scrollTop = scrollPos - distance;
|
||||
}
|
||||
|
||||
_animateScroll(time, endpoint, direction) {
|
||||
const strength = SCROLLING_SPEED;
|
||||
const choiceListScrollTop = this.element.scrollTop;
|
||||
let continueAnimation = false;
|
||||
|
||||
if (direction > 0) {
|
||||
this._scrollDown(choiceListScrollTop, strength, endpoint);
|
||||
|
||||
if (choiceListScrollTop < endpoint) {
|
||||
continueAnimation = true;
|
||||
}
|
||||
} else {
|
||||
this._scrollUp(choiceListScrollTop, strength, endpoint);
|
||||
|
||||
if (choiceListScrollTop > endpoint) {
|
||||
continueAnimation = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (continueAnimation) {
|
||||
requestAnimationFrame(time => {
|
||||
this._animateScroll(time, endpoint, direction);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,25 +33,6 @@ describe('components/list', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('scrollTo', () => {
|
||||
describe('passing position', () => {
|
||||
it('scrolls element to passed position', () => {
|
||||
const scrollPosition = 20;
|
||||
expect(instance.element.scrollTop).to.equal(0);
|
||||
instance.scrollTo(scrollPosition);
|
||||
expect(instance.element.scrollTop).to.equal(scrollPosition);
|
||||
});
|
||||
});
|
||||
|
||||
describe('not passing position', () => {
|
||||
it('scrolls element to default position', () => {
|
||||
expect(instance.element.scrollTop).to.equal(0);
|
||||
instance.scrollTo();
|
||||
expect(instance.element.scrollTop).to.equal(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('append', () => {
|
||||
it('appends passed node to element', () => {
|
||||
const elementToAppend = document.createElement('span');
|
||||
|
|
Loading…
Reference in a new issue