import raf from 'raf'; import getScroll, { isWindow } from './getScroll'; import { easeInOutCubic } from './easings'; interface ScrollToOptions { /** Scroll container, default as window */ getContainer?: () => HTMLElement | Window | Document; /** Scroll end callback */ callback?: () => any; /** Animation duration, default as 450 */ duration?: number; } export default function scrollTo(y: number, options: ScrollToOptions = {}) { const { getContainer = () => window, callback, duration = 450 } = options; const container = getContainer(); const scrollTop = getScroll(container, true); const startTime = Date.now(); const frameFunc = () => { const timestamp = Date.now(); const time = timestamp - startTime; const nextScrollTop = easeInOutCubic(time > duration ? duration : time, scrollTop, y, duration); if (isWindow(container)) { (container as Window).scrollTo(window.pageXOffset, nextScrollTop); } else if (container instanceof Document) { container.documentElement.scrollTop = nextScrollTop; } else { (container as HTMLElement).scrollTop = nextScrollTop; } if (time < duration) { raf(frameFunc); } else if (typeof callback === 'function') { callback(); } }; raf(frameFunc); }