UNPKG

choices.js

Version:

A vanilla JS customisable text input/select box plugin

90 lines (69 loc) 2.48 kB
import { SCROLLING_SPEED } from '../constants'; export default class List { element: HTMLElement; scrollPos: number; height: number; constructor({ element }: { element: HTMLElement }) { this.element = element; this.scrollPos = this.element.scrollTop; this.height = this.element.offsetHeight; } prepend(node: Element | DocumentFragment): void { const child = this.element.firstElementChild; if (child) { this.element.insertBefore(node, child); } else { this.element.append(node); } } scrollToTop(): void { this.element.scrollTop = 0; } scrollToChildElement(element: HTMLElement, direction: 1 | -1): void { if (!element) { return; } const listHeight = this.element.offsetHeight; // Scroll position of dropdown const listScrollPosition = this.element.scrollTop + listHeight; const elementHeight = element.offsetHeight; // Distance from bottom of element to top of parent const elementPos = element.offsetTop + elementHeight; // Difference between the element and scroll position const destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop; requestAnimationFrame(() => { this._animateScroll(destination, direction); }); } _scrollDown(scrollPos: number, strength: number, destination: number): void { const easing = (destination - scrollPos) / strength; const distance = easing > 1 ? easing : 1; this.element.scrollTop = scrollPos + distance; } _scrollUp(scrollPos: number, strength: number, destination: number): void { const easing = (scrollPos - destination) / strength; const distance = easing > 1 ? easing : 1; this.element.scrollTop = scrollPos - distance; } _animateScroll(destination: number, direction: number): void { const strength = SCROLLING_SPEED; const choiceListScrollTop = this.element.scrollTop; let continueAnimation = false; if (direction > 0) { this._scrollDown(choiceListScrollTop, strength, destination); if (choiceListScrollTop < destination) { continueAnimation = true; } } else { this._scrollUp(choiceListScrollTop, strength, destination); if (choiceListScrollTop > destination) { continueAnimation = true; } } if (continueAnimation) { requestAnimationFrame(() => { this._animateScroll(destination, direction); }); } } }