framer-motion
Version:
A simple and powerful JavaScript animation library
103 lines (100 loc) • 3.41 kB
JavaScript
import { clamp, progress, velocityPerSecond } from 'motion-utils';
/**
* A time in milliseconds, beyond which we consider the scroll velocity to be 0.
*/
const maxElapsed = 50;
const createAxisInfo = () => ({
current: 0,
offset: [],
progress: 0,
scrollLength: 0,
targetOffset: 0,
targetLength: 0,
containerLength: 0,
velocity: 0,
});
const createScrollInfo = () => ({
time: 0,
x: createAxisInfo(),
y: createAxisInfo(),
});
/**
* Also iterated with for...in as the list of axes.
*/
const axisKeys = {
x: {
length: "Width",
position: "Left",
},
y: {
length: "Height",
position: "Top",
},
};
const styles = new WeakMap();
/**
* Whether an axis scrolls from its end, which browsers report as a scroll
* position running from 0 to -scrollLength (#3340). This is read from style
* rather than the sign of the scroll position, as elastic overscroll pushes
* the position past 0 in either kind of axis (#3791).
*/
function isReversed(element, axisName) {
/**
* The viewport takes its writing mode and direction from <body>, which
* not every browser reflects in the root element's computed style. It
* doesn't adopt the root element's flex layout.
*/
const isRoot = element === document.scrollingElement;
const source = (isRoot && document.body) || element;
let style = styles.get(source);
if (!style)
styles.set(source, (style = getComputedStyle(source)));
const { writingMode, flexDirection } = style;
const isInline = (axisName === "x") !== /^[vs]/.test(writingMode);
return ((isInline
? (style.direction === "rtl") !== (writingMode === "sideways-lr")
: writingMode.endsWith("rl")) !==
/**
* A reversed flex axis flips this. The main axis is the inline axis
* unless flex-direction is a column.
*/
(!isRoot &&
style.display.includes("flex") &&
(isInline !== (flexDirection[0] === "c")
? flexDirection
: style.flexWrap).endsWith("reverse")));
}
function updateAxisInfo(element, axisName, info, time) {
const axis = info[axisName];
const { length, position } = axisKeys[axisName];
const prev = axis.current;
const prevTime = info.time;
const scrollPosition = element[`scroll${position}`];
axis.current = isReversed(element, axisName)
? -scrollPosition || 0 // Avoid -0
: scrollPosition;
axis.containerLength = element[`client${length}`];
axis.targetLength = element[`scroll${length}`];
axis.scrollLength = axis.targetLength - axis.containerLength;
axis.offset.length = 0;
axis.offset[0] = 0;
axis.offset[1] = axis.scrollLength;
axis.progress = clamp(0, 1, progress(0, axis.scrollLength, axis.current));
const elapsed = time - prevTime;
axis.velocity =
elapsed > maxElapsed
? 0
: velocityPerSecond(axis.current - prev, elapsed);
}
/**
* Measures a scroll container. Runs once per container per frame; every
* handler on that container derives its info from the result.
*/
function updateScrollInfo(element, info, time) {
for (const axis in axisKeys) {
updateAxisInfo(element, axis, info, time);
}
info.time = time;
}
export { axisKeys, createScrollInfo, updateScrollInfo };
//# sourceMappingURL=info.mjs.map