mirror of
https://github.com/Choices-js/Choices.git
synced 2024-05-18 13:36:35 +02:00
Move scrolling logic into list component
This commit is contained in:
parent
f9455b1a25
commit
804a4a442b
|
@ -15,7 +15,6 @@ import {
|
||||||
DEFAULT_CLASSNAMES,
|
DEFAULT_CLASSNAMES,
|
||||||
EVENTS,
|
EVENTS,
|
||||||
KEY_CODES,
|
KEY_CODES,
|
||||||
SCROLLING_SPEED,
|
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { TEMPLATES } from './templates';
|
import { TEMPLATES } from './templates';
|
||||||
import {
|
import {
|
||||||
|
@ -1116,7 +1115,7 @@ class Choices {
|
||||||
if (
|
if (
|
||||||
!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)
|
!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)
|
||||||
) {
|
) {
|
||||||
this._scrollToChoice(nextEl, directionInt);
|
this.choiceList.scrollToChoice(nextEl, directionInt);
|
||||||
}
|
}
|
||||||
this._highlightChoice(nextEl);
|
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) {
|
_highlightChoice(el = null) {
|
||||||
const choices = Array.from(
|
const choices = Array.from(
|
||||||
this.dropdown.element.querySelectorAll('[data-choice-selectable]'),
|
this.dropdown.element.querySelectorAll('[data-choice-selectable]'),
|
||||||
|
@ -2028,7 +1964,7 @@ class Choices {
|
||||||
|
|
||||||
// Scroll back to top of choices list
|
// Scroll back to top of choices list
|
||||||
if (this.config.resetScrollPosition) {
|
if (this.config.resetScrollPosition) {
|
||||||
this.choiceList.scrollTo(0);
|
this.choiceList.scrollToTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have grouped options
|
// If we have grouped options
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { SCROLLING_SPEED } from '../constants';
|
||||||
|
|
||||||
export default class List {
|
export default class List {
|
||||||
constructor({ element }) {
|
constructor({ element }) {
|
||||||
Object.assign(this, { element });
|
Object.assign(this, { element });
|
||||||
|
@ -7,31 +9,81 @@ export default class List {
|
||||||
this.hasChildren = !!this.element.children;
|
this.hasChildren = !!this.element.children;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear List contents
|
|
||||||
*/
|
|
||||||
clear() {
|
clear() {
|
||||||
this.element.innerHTML = '';
|
this.element.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Scroll to passed position on Y axis
|
|
||||||
*/
|
|
||||||
scrollTo(scrollPos = 0) {
|
|
||||||
this.element.scrollTop = scrollPos;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Append node to element
|
|
||||||
*/
|
|
||||||
append(node) {
|
append(node) {
|
||||||
this.element.appendChild(node);
|
this.element.appendChild(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find element that matches passed selector
|
|
||||||
* @return {HTMLElement}
|
|
||||||
*/
|
|
||||||
getChild(selector) {
|
getChild(selector) {
|
||||||
return this.element.querySelector(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', () => {
|
describe('append', () => {
|
||||||
it('appends passed node to element', () => {
|
it('appends passed node to element', () => {
|
||||||
const elementToAppend = document.createElement('span');
|
const elementToAppend = document.createElement('span');
|
||||||
|
|
Loading…
Reference in a new issue