LeDDGroup/scroll-utility

View on GitHub
src/scroll.ts

Summary

Maintainability
A
1 hr
Test Coverage
import { AnimationManager } from "./animation-manager"
import { EasingFunction, defaultEasingFunction } from "./default-settings"
import * as ScrollElement from "./element"
 
type ElementOrQuery = Window | Element | string
type ScrollOptions = [number?, EasingFunction?]
 
type ScrollType = ((value: number, ...args: ScrollOptions) => Scroll) & {
size: (value: number, ...args: ScrollOptions) => Scroll
scrollSize: (value: number, ...args: ScrollOptions) => Scroll
element: (elementOrQuery: ElementOrQuery, value?: number, ...args: ScrollOptions) => Scroll
}
 
Identical blocks of code found in 2 locations. Consider refactoring.
function getElementFromQuery(elementOrQuery: ElementOrQuery): Element | Window {
if (typeof elementOrQuery === "string") {
return document.querySelector(elementOrQuery) as Element
}
return elementOrQuery
}
 
class Scroll {
private animationManager: AnimationManager
private element: Element | Window = window
private horizontal: boolean
public duration: number
public onScroll: ((external?: boolean) => void) | null | undefined
public easing: EasingFunction
constructor(
options: {
element?: ElementOrQuery
horizontal?: boolean
onScroll?: (external?: boolean) => void
duration?: number
easing?: EasingFunction
} = {},
) {
const element = getElementFromQuery(options.element || window)
this.element = element === document.documentElement ? window : element
this.horizontal = !!options.horizontal
this.onScroll = options.onScroll
this.duration = options.duration || 0
this.easing = options.easing || defaultEasingFunction
this.element.addEventListener("scroll", () => {
const changed = Math.floor(this.animationManager.position) !== Math.floor(this.scrollPosition)
if (changed) {
this.animationManager.position = this.scrollPosition
}
this.onScroll && this.onScroll(changed)
})
this.animationManager = new AnimationManager(
this.scrollPosition,
value => ScrollElement.scrollTo(this.element, value, this.horizontal),
() => this.scrollSize,
)
}
get size() {
return ScrollElement.getSize(this.element, this.horizontal)
}
get scrollSize() {
return ScrollElement.getScrollSize(this.element, this.horizontal) - this.size
}
get scrollPosition() {
return ScrollElement.getScrollPosition(this.element, this.horizontal)
}
getRelativeElementPosition(elementOrQuery: ElementOrQuery): number {
return ScrollElement.getRelativeElementPosition(this.element, elementOrQuery, this.horizontal)
}
stopAllAnimations() {
this.animationManager.stopAllAnimations()
}
scrollTo: ScrollType = Object.assign(
(position: number, ...args: ScrollOptions): Scroll => {
this.scrollBy(position - this.scrollPosition, ...args)
return this
},
{
size: (value: number, ...args: ScrollOptions) => this.scrollTo(this.size * value, ...args),
scrollSize: (value: number, ...args: ScrollOptions) =>
this.scrollTo(this.scrollSize * value, ...args),
element: (elementOrQuery: ElementOrQuery, value: number = 0, ...args: ScrollOptions) => {
return this.scrollBy(
ScrollElement.getDistToCenterElement(
this.element,
elementOrQuery,
this.horizontal,
value,
),
...args,
)
},
},
)
scrollBy: ScrollType = Object.assign(
(value: number, ...args: ScrollOptions): Scroll => {
const [duration, easing] = args
this.animationManager.createScrollAnimation({
distToScroll: value,
duration: duration || this.duration,
easing: easing || this.easing,
})
 
return this
},
{
size: (value: number, ...args: ScrollOptions) => this.scrollBy(this.size * value, ...args),
scrollSize: (value: number, ...args: ScrollOptions) =>
this.scrollBy(this.scrollSize * value, ...args),
element: (elementOrQuery: ElementOrQuery, value: number = 1, ...args: ScrollOptions) => {
return this.scrollBy(
ScrollElement.getSizeWithBorders(elementOrQuery, this.horizontal) * value,
...args,
)
},
},
)
}
 
export { Scroll }