Mission Control Dashboard - Initial implementation
This commit is contained in:
479
node_modules/framer-motion/dist/cjs/dom-mini.js
generated
vendored
Normal file
479
node_modules/framer-motion/dist/cjs/dom-mini.js
generated
vendored
Normal file
@@ -0,0 +1,479 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
var motionDom = require('motion-dom');
|
||||
var motionUtils = require('motion-utils');
|
||||
|
||||
function isDOMKeyframes(keyframes) {
|
||||
return typeof keyframes === "object" && !Array.isArray(keyframes);
|
||||
}
|
||||
|
||||
function resolveSubjects(subject, keyframes, scope, selectorCache) {
|
||||
if (subject == null) {
|
||||
return [];
|
||||
}
|
||||
if (typeof subject === "string" && isDOMKeyframes(keyframes)) {
|
||||
return motionDom.resolveElements(subject, scope, selectorCache);
|
||||
}
|
||||
else if (subject instanceof NodeList) {
|
||||
return Array.from(subject);
|
||||
}
|
||||
else if (Array.isArray(subject)) {
|
||||
return subject.filter((s) => s != null);
|
||||
}
|
||||
else {
|
||||
return [subject];
|
||||
}
|
||||
}
|
||||
|
||||
function calculateRepeatDuration(duration, repeat, _repeatDelay) {
|
||||
return duration * (repeat + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a absolute or relative time definition and current/prev time state of the sequence,
|
||||
* calculate an absolute time for the next keyframes.
|
||||
*/
|
||||
function calcNextTime(current, next, prev, labels) {
|
||||
if (typeof next === "number") {
|
||||
return next;
|
||||
}
|
||||
else if (next.startsWith("-") || next.startsWith("+")) {
|
||||
return Math.max(0, current + parseFloat(next));
|
||||
}
|
||||
else if (next === "<") {
|
||||
return prev;
|
||||
}
|
||||
else if (next.startsWith("<")) {
|
||||
return Math.max(0, prev + parseFloat(next.slice(1)));
|
||||
}
|
||||
else {
|
||||
return labels.get(next) ?? current;
|
||||
}
|
||||
}
|
||||
|
||||
function eraseKeyframes(sequence, startTime, endTime) {
|
||||
for (let i = 0; i < sequence.length; i++) {
|
||||
const keyframe = sequence[i];
|
||||
if (keyframe.at > startTime && keyframe.at < endTime) {
|
||||
motionUtils.removeItem(sequence, keyframe);
|
||||
// If we remove this item we have to push the pointer back one
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
function addKeyframes(sequence, keyframes, easing, offset, startTime, endTime) {
|
||||
/**
|
||||
* Erase every existing value between currentTime and targetTime,
|
||||
* this will essentially splice this timeline into any currently
|
||||
* defined ones.
|
||||
*/
|
||||
eraseKeyframes(sequence, startTime, endTime);
|
||||
for (let i = 0; i < keyframes.length; i++) {
|
||||
sequence.push({
|
||||
value: keyframes[i],
|
||||
at: motionDom.mixNumber(startTime, endTime, offset[i]),
|
||||
easing: motionUtils.getEasingForSegment(easing, i),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take an array of times that represent repeated keyframes. For instance
|
||||
* if we have original times of [0, 0.5, 1] then our repeated times will
|
||||
* be [0, 0.5, 1, 1, 1.5, 2]. Loop over the times and scale them back
|
||||
* down to a 0-1 scale.
|
||||
*/
|
||||
function normalizeTimes(times, repeat) {
|
||||
for (let i = 0; i < times.length; i++) {
|
||||
times[i] = times[i] / (repeat + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function compareByTime(a, b) {
|
||||
if (a.at === b.at) {
|
||||
if (a.value === null)
|
||||
return 1;
|
||||
if (b.value === null)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return a.at - b.at;
|
||||
}
|
||||
}
|
||||
|
||||
const defaultSegmentEasing = "easeInOut";
|
||||
const MAX_REPEAT = 20;
|
||||
function createAnimationsFromSequence(sequence, { defaultTransition = {}, ...sequenceTransition } = {}, scope, generators) {
|
||||
const defaultDuration = defaultTransition.duration || 0.3;
|
||||
const animationDefinitions = new Map();
|
||||
const sequences = new Map();
|
||||
const elementCache = {};
|
||||
const timeLabels = new Map();
|
||||
let prevTime = 0;
|
||||
let currentTime = 0;
|
||||
let totalDuration = 0;
|
||||
/**
|
||||
* Build the timeline by mapping over the sequence array and converting
|
||||
* the definitions into keyframes and offsets with absolute time values.
|
||||
* These will later get converted into relative offsets in a second pass.
|
||||
*/
|
||||
for (let i = 0; i < sequence.length; i++) {
|
||||
const segment = sequence[i];
|
||||
/**
|
||||
* If this is a timeline label, mark it and skip the rest of this iteration.
|
||||
*/
|
||||
if (typeof segment === "string") {
|
||||
timeLabels.set(segment, currentTime);
|
||||
continue;
|
||||
}
|
||||
else if (!Array.isArray(segment)) {
|
||||
timeLabels.set(segment.name, calcNextTime(currentTime, segment.at, prevTime, timeLabels));
|
||||
continue;
|
||||
}
|
||||
let [subject, keyframes, transition = {}] = segment;
|
||||
/**
|
||||
* If a relative or absolute time value has been specified we need to resolve
|
||||
* it in relation to the currentTime.
|
||||
*/
|
||||
if (transition.at !== undefined) {
|
||||
currentTime = calcNextTime(currentTime, transition.at, prevTime, timeLabels);
|
||||
}
|
||||
/**
|
||||
* Keep track of the maximum duration in this definition. This will be
|
||||
* applied to currentTime once the definition has been parsed.
|
||||
*/
|
||||
let maxDuration = 0;
|
||||
const resolveValueSequence = (valueKeyframes, valueTransition, valueSequence, elementIndex = 0, numSubjects = 0) => {
|
||||
const valueKeyframesAsList = keyframesAsList(valueKeyframes);
|
||||
const { delay = 0, times = motionDom.defaultOffset(valueKeyframesAsList), type = defaultTransition.type || "keyframes", repeat, repeatType, repeatDelay = 0, ...remainingTransition } = valueTransition;
|
||||
let { ease = defaultTransition.ease || "easeOut", duration } = valueTransition;
|
||||
/**
|
||||
* Resolve stagger() if defined.
|
||||
*/
|
||||
const calculatedDelay = typeof delay === "function"
|
||||
? delay(elementIndex, numSubjects)
|
||||
: delay;
|
||||
/**
|
||||
* If this animation should and can use a spring, generate a spring easing function.
|
||||
*/
|
||||
const numKeyframes = valueKeyframesAsList.length;
|
||||
const createGenerator = motionDom.isGenerator(type)
|
||||
? type
|
||||
: generators?.[type || "keyframes"];
|
||||
if (numKeyframes <= 2 && createGenerator) {
|
||||
/**
|
||||
* As we're creating an easing function from a spring,
|
||||
* ideally we want to generate it using the real distance
|
||||
* between the two keyframes. However this isn't always
|
||||
* possible - in these situations we use 0-100.
|
||||
*/
|
||||
let absoluteDelta = 100;
|
||||
if (numKeyframes === 2 &&
|
||||
isNumberKeyframesArray(valueKeyframesAsList)) {
|
||||
const delta = valueKeyframesAsList[1] - valueKeyframesAsList[0];
|
||||
absoluteDelta = Math.abs(delta);
|
||||
}
|
||||
const springTransition = {
|
||||
...defaultTransition,
|
||||
...remainingTransition,
|
||||
};
|
||||
if (duration !== undefined) {
|
||||
springTransition.duration = motionUtils.secondsToMilliseconds(duration);
|
||||
}
|
||||
const springEasing = motionDom.createGeneratorEasing(springTransition, absoluteDelta, createGenerator);
|
||||
ease = springEasing.ease;
|
||||
duration = springEasing.duration;
|
||||
}
|
||||
duration ?? (duration = defaultDuration);
|
||||
const startTime = currentTime + calculatedDelay;
|
||||
/**
|
||||
* If there's only one time offset of 0, fill in a second with length 1
|
||||
*/
|
||||
if (times.length === 1 && times[0] === 0) {
|
||||
times[1] = 1;
|
||||
}
|
||||
/**
|
||||
* Fill out if offset if fewer offsets than keyframes
|
||||
*/
|
||||
const remainder = times.length - valueKeyframesAsList.length;
|
||||
remainder > 0 && motionDom.fillOffset(times, remainder);
|
||||
/**
|
||||
* If only one value has been set, ie [1], push a null to the start of
|
||||
* the keyframe array. This will let us mark a keyframe at this point
|
||||
* that will later be hydrated with the previous value.
|
||||
*/
|
||||
valueKeyframesAsList.length === 1 &&
|
||||
valueKeyframesAsList.unshift(null);
|
||||
/**
|
||||
* Handle repeat options
|
||||
*/
|
||||
if (repeat) {
|
||||
motionUtils.invariant(repeat < MAX_REPEAT, "Repeat count too high, must be less than 20", "repeat-count-high");
|
||||
duration = calculateRepeatDuration(duration, repeat);
|
||||
const originalKeyframes = [...valueKeyframesAsList];
|
||||
const originalTimes = [...times];
|
||||
ease = Array.isArray(ease) ? [...ease] : [ease];
|
||||
const originalEase = [...ease];
|
||||
for (let repeatIndex = 0; repeatIndex < repeat; repeatIndex++) {
|
||||
valueKeyframesAsList.push(...originalKeyframes);
|
||||
for (let keyframeIndex = 0; keyframeIndex < originalKeyframes.length; keyframeIndex++) {
|
||||
times.push(originalTimes[keyframeIndex] + (repeatIndex + 1));
|
||||
ease.push(keyframeIndex === 0
|
||||
? "linear"
|
||||
: motionUtils.getEasingForSegment(originalEase, keyframeIndex - 1));
|
||||
}
|
||||
}
|
||||
normalizeTimes(times, repeat);
|
||||
}
|
||||
const targetTime = startTime + duration;
|
||||
/**
|
||||
* Add keyframes, mapping offsets to absolute time.
|
||||
*/
|
||||
addKeyframes(valueSequence, valueKeyframesAsList, ease, times, startTime, targetTime);
|
||||
maxDuration = Math.max(calculatedDelay + duration, maxDuration);
|
||||
totalDuration = Math.max(targetTime, totalDuration);
|
||||
};
|
||||
if (motionDom.isMotionValue(subject)) {
|
||||
const subjectSequence = getSubjectSequence(subject, sequences);
|
||||
resolveValueSequence(keyframes, transition, getValueSequence("default", subjectSequence));
|
||||
}
|
||||
else {
|
||||
const subjects = resolveSubjects(subject, keyframes, scope, elementCache);
|
||||
const numSubjects = subjects.length;
|
||||
/**
|
||||
* For every element in this segment, process the defined values.
|
||||
*/
|
||||
for (let subjectIndex = 0; subjectIndex < numSubjects; subjectIndex++) {
|
||||
/**
|
||||
* Cast necessary, but we know these are of this type
|
||||
*/
|
||||
keyframes = keyframes;
|
||||
transition = transition;
|
||||
const thisSubject = subjects[subjectIndex];
|
||||
const subjectSequence = getSubjectSequence(thisSubject, sequences);
|
||||
for (const key in keyframes) {
|
||||
resolveValueSequence(keyframes[key], getValueTransition(transition, key), getValueSequence(key, subjectSequence), subjectIndex, numSubjects);
|
||||
}
|
||||
}
|
||||
}
|
||||
prevTime = currentTime;
|
||||
currentTime += maxDuration;
|
||||
}
|
||||
/**
|
||||
* For every element and value combination create a new animation.
|
||||
*/
|
||||
sequences.forEach((valueSequences, element) => {
|
||||
for (const key in valueSequences) {
|
||||
const valueSequence = valueSequences[key];
|
||||
/**
|
||||
* Arrange all the keyframes in ascending time order.
|
||||
*/
|
||||
valueSequence.sort(compareByTime);
|
||||
const keyframes = [];
|
||||
const valueOffset = [];
|
||||
const valueEasing = [];
|
||||
/**
|
||||
* For each keyframe, translate absolute times into
|
||||
* relative offsets based on the total duration of the timeline.
|
||||
*/
|
||||
for (let i = 0; i < valueSequence.length; i++) {
|
||||
const { at, value, easing } = valueSequence[i];
|
||||
keyframes.push(value);
|
||||
valueOffset.push(motionUtils.progress(0, totalDuration, at));
|
||||
valueEasing.push(easing || "easeOut");
|
||||
}
|
||||
/**
|
||||
* If the first keyframe doesn't land on offset: 0
|
||||
* provide one by duplicating the initial keyframe. This ensures
|
||||
* it snaps to the first keyframe when the animation starts.
|
||||
*/
|
||||
if (valueOffset[0] !== 0) {
|
||||
valueOffset.unshift(0);
|
||||
keyframes.unshift(keyframes[0]);
|
||||
valueEasing.unshift(defaultSegmentEasing);
|
||||
}
|
||||
/**
|
||||
* If the last keyframe doesn't land on offset: 1
|
||||
* provide one with a null wildcard value. This will ensure it
|
||||
* stays static until the end of the animation.
|
||||
*/
|
||||
if (valueOffset[valueOffset.length - 1] !== 1) {
|
||||
valueOffset.push(1);
|
||||
keyframes.push(null);
|
||||
}
|
||||
if (!animationDefinitions.has(element)) {
|
||||
animationDefinitions.set(element, {
|
||||
keyframes: {},
|
||||
transition: {},
|
||||
});
|
||||
}
|
||||
const definition = animationDefinitions.get(element);
|
||||
definition.keyframes[key] = keyframes;
|
||||
/**
|
||||
* Exclude `type` from defaultTransition since springs have been
|
||||
* converted to duration-based easing functions in resolveValueSequence.
|
||||
* Including `type: "spring"` would cause JSAnimation to error when
|
||||
* the merged keyframes array has more than 2 keyframes.
|
||||
*/
|
||||
const { type: _type, ...remainingDefaultTransition } = defaultTransition;
|
||||
definition.transition[key] = {
|
||||
...remainingDefaultTransition,
|
||||
duration: totalDuration,
|
||||
ease: valueEasing,
|
||||
times: valueOffset,
|
||||
...sequenceTransition,
|
||||
};
|
||||
}
|
||||
});
|
||||
return animationDefinitions;
|
||||
}
|
||||
function getSubjectSequence(subject, sequences) {
|
||||
!sequences.has(subject) && sequences.set(subject, {});
|
||||
return sequences.get(subject);
|
||||
}
|
||||
function getValueSequence(name, sequences) {
|
||||
if (!sequences[name])
|
||||
sequences[name] = [];
|
||||
return sequences[name];
|
||||
}
|
||||
function keyframesAsList(keyframes) {
|
||||
return Array.isArray(keyframes) ? keyframes : [keyframes];
|
||||
}
|
||||
function getValueTransition(transition, key) {
|
||||
return transition && transition[key]
|
||||
? {
|
||||
...transition,
|
||||
...transition[key],
|
||||
}
|
||||
: { ...transition };
|
||||
}
|
||||
const isNumber = (keyframe) => typeof keyframe === "number";
|
||||
const isNumberKeyframesArray = (keyframes) => keyframes.every(isNumber);
|
||||
|
||||
function animateElements(elementOrSelector, keyframes, options, scope) {
|
||||
// Gracefully handle null/undefined elements (e.g., from querySelector returning null)
|
||||
if (elementOrSelector == null) {
|
||||
return [];
|
||||
}
|
||||
const elements = motionDom.resolveElements(elementOrSelector, scope);
|
||||
const numElements = elements.length;
|
||||
motionUtils.invariant(Boolean(numElements), "No valid elements provided.", "no-valid-elements");
|
||||
/**
|
||||
* WAAPI doesn't support interrupting animations.
|
||||
*
|
||||
* Therefore, starting animations requires a three-step process:
|
||||
* 1. Stop existing animations (write styles to DOM)
|
||||
* 2. Resolve keyframes (read styles from DOM)
|
||||
* 3. Create new animations (write styles to DOM)
|
||||
*
|
||||
* The hybrid `animate()` function uses AsyncAnimation to resolve
|
||||
* keyframes before creating new animations, which removes style
|
||||
* thrashing. Here, we have much stricter filesize constraints.
|
||||
* Therefore we do this in a synchronous way that ensures that
|
||||
* at least within `animate()` calls there is no style thrashing.
|
||||
*
|
||||
* In the motion-native-animate-mini-interrupt benchmark this
|
||||
* was 80% faster than a single loop.
|
||||
*/
|
||||
const animationDefinitions = [];
|
||||
/**
|
||||
* Step 1: Build options and stop existing animations (write)
|
||||
*/
|
||||
for (let i = 0; i < numElements; i++) {
|
||||
const element = elements[i];
|
||||
const elementTransition = { ...options };
|
||||
/**
|
||||
* Resolve stagger function if provided.
|
||||
*/
|
||||
if (typeof elementTransition.delay === "function") {
|
||||
elementTransition.delay = elementTransition.delay(i, numElements);
|
||||
}
|
||||
for (const valueName in keyframes) {
|
||||
let valueKeyframes = keyframes[valueName];
|
||||
if (!Array.isArray(valueKeyframes)) {
|
||||
valueKeyframes = [valueKeyframes];
|
||||
}
|
||||
const valueOptions = {
|
||||
...motionDom.getValueTransition(elementTransition, valueName),
|
||||
};
|
||||
valueOptions.duration && (valueOptions.duration = motionUtils.secondsToMilliseconds(valueOptions.duration));
|
||||
valueOptions.delay && (valueOptions.delay = motionUtils.secondsToMilliseconds(valueOptions.delay));
|
||||
/**
|
||||
* If there's an existing animation playing on this element then stop it
|
||||
* before creating a new one.
|
||||
*/
|
||||
const map = motionDom.getAnimationMap(element);
|
||||
const key = motionDom.animationMapKey(valueName, valueOptions.pseudoElement || "");
|
||||
const currentAnimation = map.get(key);
|
||||
currentAnimation && currentAnimation.stop();
|
||||
animationDefinitions.push({
|
||||
map,
|
||||
key,
|
||||
unresolvedKeyframes: valueKeyframes,
|
||||
options: {
|
||||
...valueOptions,
|
||||
element,
|
||||
name: valueName,
|
||||
allowFlatten: !elementTransition.type && !elementTransition.ease,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Step 2: Resolve keyframes (read)
|
||||
*/
|
||||
for (let i = 0; i < animationDefinitions.length; i++) {
|
||||
const { unresolvedKeyframes, options: animationOptions } = animationDefinitions[i];
|
||||
const { element, name, pseudoElement } = animationOptions;
|
||||
if (!pseudoElement && unresolvedKeyframes[0] === null) {
|
||||
unresolvedKeyframes[0] = motionDom.getComputedStyle(element, name);
|
||||
}
|
||||
motionDom.fillWildcards(unresolvedKeyframes);
|
||||
motionDom.applyPxDefaults(unresolvedKeyframes, name);
|
||||
/**
|
||||
* If we only have one keyframe, explicitly read the initial keyframe
|
||||
* from the computed style. This is to ensure consistency with WAAPI behaviour
|
||||
* for restarting animations, for instance .play() after finish, when it
|
||||
* has one vs two keyframes.
|
||||
*/
|
||||
if (!pseudoElement && unresolvedKeyframes.length < 2) {
|
||||
unresolvedKeyframes.unshift(motionDom.getComputedStyle(element, name));
|
||||
}
|
||||
animationOptions.keyframes = unresolvedKeyframes;
|
||||
}
|
||||
/**
|
||||
* Step 3: Create new animations (write)
|
||||
*/
|
||||
const animations = [];
|
||||
for (let i = 0; i < animationDefinitions.length; i++) {
|
||||
const { map, key, options: animationOptions } = animationDefinitions[i];
|
||||
const animation = new motionDom.NativeAnimation(animationOptions);
|
||||
map.set(key, animation);
|
||||
animation.finished.finally(() => map.delete(key));
|
||||
animations.push(animation);
|
||||
}
|
||||
return animations;
|
||||
}
|
||||
|
||||
function animateSequence(definition, options) {
|
||||
const animations = [];
|
||||
createAnimationsFromSequence(definition, options).forEach(({ keyframes, transition }, element) => {
|
||||
animations.push(...animateElements(element, keyframes, transition));
|
||||
});
|
||||
return new motionDom.GroupAnimationWithThen(animations);
|
||||
}
|
||||
|
||||
const createScopedWaapiAnimate = (scope) => {
|
||||
function scopedAnimate(elementOrSelector, keyframes, options) {
|
||||
return new motionDom.GroupAnimationWithThen(animateElements(elementOrSelector, keyframes, options, scope));
|
||||
}
|
||||
return scopedAnimate;
|
||||
};
|
||||
const animateMini = /*@__PURE__*/ createScopedWaapiAnimate();
|
||||
|
||||
exports.animate = animateMini;
|
||||
exports.animateSequence = animateSequence;
|
||||
//# sourceMappingURL=dom-mini.js.map
|
||||
Reference in New Issue
Block a user