UNPKG

framer-motion

Version:

A simple and powerful JavaScript animation library

88 lines (85 loc) 3.05 kB
import { supportsScrollTimeline } from 'motion-dom'; import { noop } from 'motion-utils'; import { observeTimeline } from './observe.mjs'; import { scrollInfo } from './track.mjs'; function scrollTimelineFallback({ source, container, axis = "y", }) { // Support legacy source argument. Deprecate later. if (source) container = source; // ScrollTimeline records progress as a percentage CSSUnitValue const currentTime = { value: 0 }; const cancel = scrollInfo((info) => { currentTime.value = info[axis].progress * 100; }, { container, axis }); return { currentTime, cancel }; } const timelineCache = new Map(); function getTimeline({ source, container = document.documentElement, axis = "y", } = {}) { // Support legacy source argument. Deprecate later. if (source) container = source; if (!timelineCache.has(container)) { timelineCache.set(container, {}); } const elementCache = timelineCache.get(container); if (!elementCache[axis]) { elementCache[axis] = supportsScrollTimeline() ? new ScrollTimeline({ source: container, axis }) : scrollTimelineFallback({ source: container, axis }); } return elementCache[axis]; } /** * If the onScroll function has two arguments, it's expecting * more specific information about the scroll from scrollInfo. */ function isOnScrollWithInfo(onScroll) { return onScroll.length === 2; } /** * Currently, we only support element tracking with `scrollInfo`, though in * the future we can also offer ViewTimeline support. */ function needsElementTracking(options) { return options && (options.target || options.offset); } function scrollFunction(onScroll, options) { if (isOnScrollWithInfo(onScroll) || needsElementTracking(options)) { return scrollInfo((info) => { onScroll(info[options.axis].progress, info); }, options); } else { return observeTimeline(onScroll, getTimeline(options)); } } function scrollAnimation(animation, options) { animation.flatten(); if (needsElementTracking(options)) { animation.pause(); return scrollInfo((info) => { animation.time = animation.duration * info[options.axis].progress; }, options); } else { const timeline = getTimeline(options); if (animation.attachTimeline) { return animation.attachTimeline(timeline, (valueAnimation) => { valueAnimation.pause(); return observeTimeline((progress) => { valueAnimation.time = valueAnimation.duration * progress; }, timeline); }); } else { return noop; } } } function scroll(onScroll, { axis = "y", ...options } = {}) { const optionsWithDefaults = { axis, ...options }; return typeof onScroll === "function" ? scrollFunction(onScroll, optionsWithDefaults) : scrollAnimation(onScroll, optionsWithDefaults); } export { scroll };