first commit
This commit is contained in:
131
node_modules/motion-dom/dist/es/animation/keyframes/DOMKeyframesResolver.mjs
generated
vendored
Normal file
131
node_modules/motion-dom/dist/es/animation/keyframes/DOMKeyframesResolver.mjs
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
import { positionalKeys } from '../../render/utils/keys-position.mjs';
|
||||
import { findDimensionValueType } from '../../value/types/dimensions.mjs';
|
||||
import { getVariableValue } from '../utils/css-variables-conversion.mjs';
|
||||
import { isCSSVariableToken } from '../utils/is-css-variable.mjs';
|
||||
import { KeyframeResolver } from './KeyframesResolver.mjs';
|
||||
import { isNone } from './utils/is-none.mjs';
|
||||
import { makeNoneKeyframesAnimatable } from './utils/make-none-animatable.mjs';
|
||||
import { isNumOrPxType, positionalValues } from './utils/unit-conversion.mjs';
|
||||
|
||||
class DOMKeyframesResolver extends KeyframeResolver {
|
||||
constructor(unresolvedKeyframes, onComplete, name, motionValue, element) {
|
||||
super(unresolvedKeyframes, onComplete, name, motionValue, element, true);
|
||||
}
|
||||
readKeyframes() {
|
||||
const { unresolvedKeyframes, element, name } = this;
|
||||
if (!element || !element.current)
|
||||
return;
|
||||
super.readKeyframes();
|
||||
/**
|
||||
* If any keyframe is a CSS variable, we need to find its value by sampling the element
|
||||
*/
|
||||
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
||||
let keyframe = unresolvedKeyframes[i];
|
||||
if (typeof keyframe === "string") {
|
||||
keyframe = keyframe.trim();
|
||||
if (isCSSVariableToken(keyframe)) {
|
||||
const resolved = getVariableValue(keyframe, element.current);
|
||||
if (resolved !== undefined) {
|
||||
unresolvedKeyframes[i] = resolved;
|
||||
}
|
||||
if (i === unresolvedKeyframes.length - 1) {
|
||||
this.finalKeyframe = keyframe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Resolve "none" values. We do this potentially twice - once before and once after measuring keyframes.
|
||||
* This could be seen as inefficient but it's a trade-off to avoid measurements in more situations, which
|
||||
* have a far bigger performance impact.
|
||||
*/
|
||||
this.resolveNoneKeyframes();
|
||||
/**
|
||||
* Check to see if unit type has changed. If so schedule jobs that will
|
||||
* temporarily set styles to the destination keyframes.
|
||||
* Skip if we have more than two keyframes or this isn't a positional value.
|
||||
* TODO: We can throw if there are multiple keyframes and the value type changes.
|
||||
*/
|
||||
if (!positionalKeys.has(name) || unresolvedKeyframes.length !== 2) {
|
||||
return;
|
||||
}
|
||||
const [origin, target] = unresolvedKeyframes;
|
||||
const originType = findDimensionValueType(origin);
|
||||
const targetType = findDimensionValueType(target);
|
||||
/**
|
||||
* Either we don't recognise these value types or we can animate between them.
|
||||
*/
|
||||
if (originType === targetType)
|
||||
return;
|
||||
/**
|
||||
* If both values are numbers or pixels, we can animate between them by
|
||||
* converting them to numbers.
|
||||
*/
|
||||
if (isNumOrPxType(originType) && isNumOrPxType(targetType)) {
|
||||
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
||||
const value = unresolvedKeyframes[i];
|
||||
if (typeof value === "string") {
|
||||
unresolvedKeyframes[i] = parseFloat(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (positionalValues[name]) {
|
||||
/**
|
||||
* Else, the only way to resolve this is by measuring the element.
|
||||
*/
|
||||
this.needsMeasurement = true;
|
||||
}
|
||||
}
|
||||
resolveNoneKeyframes() {
|
||||
const { unresolvedKeyframes, name } = this;
|
||||
const noneKeyframeIndexes = [];
|
||||
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
||||
if (unresolvedKeyframes[i] === null ||
|
||||
isNone(unresolvedKeyframes[i])) {
|
||||
noneKeyframeIndexes.push(i);
|
||||
}
|
||||
}
|
||||
if (noneKeyframeIndexes.length) {
|
||||
makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name);
|
||||
}
|
||||
}
|
||||
measureInitialState() {
|
||||
const { element, unresolvedKeyframes, name } = this;
|
||||
if (!element || !element.current)
|
||||
return;
|
||||
if (name === "height") {
|
||||
this.suspendedScrollY = window.pageYOffset;
|
||||
}
|
||||
this.measuredOrigin = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
|
||||
unresolvedKeyframes[0] = this.measuredOrigin;
|
||||
// Set final key frame to measure after next render
|
||||
const measureKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
|
||||
if (measureKeyframe !== undefined) {
|
||||
element.getValue(name, measureKeyframe).jump(measureKeyframe, false);
|
||||
}
|
||||
}
|
||||
measureEndState() {
|
||||
const { element, name, unresolvedKeyframes } = this;
|
||||
if (!element || !element.current)
|
||||
return;
|
||||
const value = element.getValue(name);
|
||||
value && value.jump(this.measuredOrigin, false);
|
||||
const finalKeyframeIndex = unresolvedKeyframes.length - 1;
|
||||
const finalKeyframe = unresolvedKeyframes[finalKeyframeIndex];
|
||||
unresolvedKeyframes[finalKeyframeIndex] = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
|
||||
if (finalKeyframe !== null && this.finalKeyframe === undefined) {
|
||||
this.finalKeyframe = finalKeyframe;
|
||||
}
|
||||
// If we removed transform values, reapply them before the next render
|
||||
if (this.removedTransforms?.length) {
|
||||
this.removedTransforms.forEach(([unsetTransformName, unsetTransformValue]) => {
|
||||
element
|
||||
.getValue(unsetTransformName)
|
||||
.set(unsetTransformValue);
|
||||
});
|
||||
}
|
||||
this.resolveNoneKeyframes();
|
||||
}
|
||||
}
|
||||
|
||||
export { DOMKeyframesResolver };
|
||||
147
node_modules/motion-dom/dist/es/animation/keyframes/KeyframesResolver.mjs
generated
vendored
Normal file
147
node_modules/motion-dom/dist/es/animation/keyframes/KeyframesResolver.mjs
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
import { fillWildcards } from './utils/fill-wildcards.mjs';
|
||||
import { removeNonTranslationalTransform } from './utils/unit-conversion.mjs';
|
||||
import { frame } from '../../frameloop/frame.mjs';
|
||||
|
||||
const toResolve = new Set();
|
||||
let isScheduled = false;
|
||||
let anyNeedsMeasurement = false;
|
||||
let isForced = false;
|
||||
function measureAllKeyframes() {
|
||||
if (anyNeedsMeasurement) {
|
||||
const resolversToMeasure = Array.from(toResolve).filter((resolver) => resolver.needsMeasurement);
|
||||
const elementsToMeasure = new Set(resolversToMeasure.map((resolver) => resolver.element));
|
||||
const transformsToRestore = new Map();
|
||||
/**
|
||||
* Write pass
|
||||
* If we're measuring elements we want to remove bounding box-changing transforms.
|
||||
*/
|
||||
elementsToMeasure.forEach((element) => {
|
||||
const removedTransforms = removeNonTranslationalTransform(element);
|
||||
if (!removedTransforms.length)
|
||||
return;
|
||||
transformsToRestore.set(element, removedTransforms);
|
||||
element.render();
|
||||
});
|
||||
// Read
|
||||
resolversToMeasure.forEach((resolver) => resolver.measureInitialState());
|
||||
// Write
|
||||
elementsToMeasure.forEach((element) => {
|
||||
element.render();
|
||||
const restore = transformsToRestore.get(element);
|
||||
if (restore) {
|
||||
restore.forEach(([key, value]) => {
|
||||
element.getValue(key)?.set(value);
|
||||
});
|
||||
}
|
||||
});
|
||||
// Read
|
||||
resolversToMeasure.forEach((resolver) => resolver.measureEndState());
|
||||
// Write
|
||||
resolversToMeasure.forEach((resolver) => {
|
||||
if (resolver.suspendedScrollY !== undefined) {
|
||||
window.scrollTo(0, resolver.suspendedScrollY);
|
||||
}
|
||||
});
|
||||
}
|
||||
anyNeedsMeasurement = false;
|
||||
isScheduled = false;
|
||||
toResolve.forEach((resolver) => resolver.complete(isForced));
|
||||
toResolve.clear();
|
||||
}
|
||||
function readAllKeyframes() {
|
||||
toResolve.forEach((resolver) => {
|
||||
resolver.readKeyframes();
|
||||
if (resolver.needsMeasurement) {
|
||||
anyNeedsMeasurement = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
function flushKeyframeResolvers() {
|
||||
isForced = true;
|
||||
readAllKeyframes();
|
||||
measureAllKeyframes();
|
||||
isForced = false;
|
||||
}
|
||||
class KeyframeResolver {
|
||||
constructor(unresolvedKeyframes, onComplete, name, motionValue, element, isAsync = false) {
|
||||
this.state = "pending";
|
||||
/**
|
||||
* Track whether this resolver is async. If it is, it'll be added to the
|
||||
* resolver queue and flushed in the next frame. Resolvers that aren't going
|
||||
* to trigger read/write thrashing don't need to be async.
|
||||
*/
|
||||
this.isAsync = false;
|
||||
/**
|
||||
* Track whether this resolver needs to perform a measurement
|
||||
* to resolve its keyframes.
|
||||
*/
|
||||
this.needsMeasurement = false;
|
||||
this.unresolvedKeyframes = [...unresolvedKeyframes];
|
||||
this.onComplete = onComplete;
|
||||
this.name = name;
|
||||
this.motionValue = motionValue;
|
||||
this.element = element;
|
||||
this.isAsync = isAsync;
|
||||
}
|
||||
scheduleResolve() {
|
||||
this.state = "scheduled";
|
||||
if (this.isAsync) {
|
||||
toResolve.add(this);
|
||||
if (!isScheduled) {
|
||||
isScheduled = true;
|
||||
frame.read(readAllKeyframes);
|
||||
frame.resolveKeyframes(measureAllKeyframes);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.readKeyframes();
|
||||
this.complete();
|
||||
}
|
||||
}
|
||||
readKeyframes() {
|
||||
const { unresolvedKeyframes, name, element, motionValue } = this;
|
||||
// If initial keyframe is null we need to read it from the DOM
|
||||
if (unresolvedKeyframes[0] === null) {
|
||||
const currentValue = motionValue?.get();
|
||||
// TODO: This doesn't work if the final keyframe is a wildcard
|
||||
const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
|
||||
if (currentValue !== undefined) {
|
||||
unresolvedKeyframes[0] = currentValue;
|
||||
}
|
||||
else if (element && name) {
|
||||
const valueAsRead = element.readValue(name, finalKeyframe);
|
||||
if (valueAsRead !== undefined && valueAsRead !== null) {
|
||||
unresolvedKeyframes[0] = valueAsRead;
|
||||
}
|
||||
}
|
||||
if (unresolvedKeyframes[0] === undefined) {
|
||||
unresolvedKeyframes[0] = finalKeyframe;
|
||||
}
|
||||
if (motionValue && currentValue === undefined) {
|
||||
motionValue.set(unresolvedKeyframes[0]);
|
||||
}
|
||||
}
|
||||
fillWildcards(unresolvedKeyframes);
|
||||
}
|
||||
setFinalKeyframe() { }
|
||||
measureInitialState() { }
|
||||
renderEndStyles() { }
|
||||
measureEndState() { }
|
||||
complete(isForcedComplete = false) {
|
||||
this.state = "complete";
|
||||
this.onComplete(this.unresolvedKeyframes, this.finalKeyframe, isForcedComplete);
|
||||
toResolve.delete(this);
|
||||
}
|
||||
cancel() {
|
||||
if (this.state === "scheduled") {
|
||||
toResolve.delete(this);
|
||||
this.state = "pending";
|
||||
}
|
||||
}
|
||||
resume() {
|
||||
if (this.state === "pending")
|
||||
this.scheduleResolve();
|
||||
}
|
||||
}
|
||||
|
||||
export { KeyframeResolver, flushKeyframeResolvers };
|
||||
11
node_modules/motion-dom/dist/es/animation/keyframes/get-final.mjs
generated
vendored
Normal file
11
node_modules/motion-dom/dist/es/animation/keyframes/get-final.mjs
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
const isNotNull = (value) => value !== null;
|
||||
function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe, speed = 1) {
|
||||
const resolvedKeyframes = keyframes.filter(isNotNull);
|
||||
const useFirstKeyframe = speed < 0 || (repeat && repeatType !== "loop" && repeat % 2 === 1);
|
||||
const index = useFirstKeyframe ? 0 : resolvedKeyframes.length - 1;
|
||||
return !index || finalKeyframe === undefined
|
||||
? resolvedKeyframes[index]
|
||||
: finalKeyframe;
|
||||
}
|
||||
|
||||
export { getFinalKeyframe };
|
||||
9
node_modules/motion-dom/dist/es/animation/keyframes/offsets/default.mjs
generated
vendored
Normal file
9
node_modules/motion-dom/dist/es/animation/keyframes/offsets/default.mjs
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { fillOffset } from './fill.mjs';
|
||||
|
||||
function defaultOffset(arr) {
|
||||
const offset = [0];
|
||||
fillOffset(offset, arr.length - 1);
|
||||
return offset;
|
||||
}
|
||||
|
||||
export { defaultOffset };
|
||||
12
node_modules/motion-dom/dist/es/animation/keyframes/offsets/fill.mjs
generated
vendored
Normal file
12
node_modules/motion-dom/dist/es/animation/keyframes/offsets/fill.mjs
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { progress } from 'motion-utils';
|
||||
import { mixNumber } from '../../../utils/mix/number.mjs';
|
||||
|
||||
function fillOffset(offset, remaining) {
|
||||
const min = offset[offset.length - 1];
|
||||
for (let i = 1; i <= remaining; i++) {
|
||||
const offsetProgress = progress(0, remaining, i);
|
||||
offset.push(mixNumber(min, 1, offsetProgress));
|
||||
}
|
||||
}
|
||||
|
||||
export { fillOffset };
|
||||
5
node_modules/motion-dom/dist/es/animation/keyframes/offsets/time.mjs
generated
vendored
Normal file
5
node_modules/motion-dom/dist/es/animation/keyframes/offsets/time.mjs
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
function convertOffsetToTimes(offset, duration) {
|
||||
return offset.map((o) => o * duration);
|
||||
}
|
||||
|
||||
export { convertOffsetToTimes };
|
||||
11
node_modules/motion-dom/dist/es/animation/keyframes/utils/apply-px-defaults.mjs
generated
vendored
Normal file
11
node_modules/motion-dom/dist/es/animation/keyframes/utils/apply-px-defaults.mjs
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import { pxValues } from '../../waapi/utils/px-values.mjs';
|
||||
|
||||
function applyPxDefaults(keyframes, name) {
|
||||
for (let i = 0; i < keyframes.length; i++) {
|
||||
if (typeof keyframes[i] === "number" && pxValues.has(name)) {
|
||||
keyframes[i] = keyframes[i] + "px";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { applyPxDefaults };
|
||||
7
node_modules/motion-dom/dist/es/animation/keyframes/utils/fill-wildcards.mjs
generated
vendored
Normal file
7
node_modules/motion-dom/dist/es/animation/keyframes/utils/fill-wildcards.mjs
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
function fillWildcards(keyframes) {
|
||||
for (let i = 1; i < keyframes.length; i++) {
|
||||
keyframes[i] ?? (keyframes[i] = keyframes[i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
export { fillWildcards };
|
||||
15
node_modules/motion-dom/dist/es/animation/keyframes/utils/is-none.mjs
generated
vendored
Normal file
15
node_modules/motion-dom/dist/es/animation/keyframes/utils/is-none.mjs
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { isZeroValueString } from 'motion-utils';
|
||||
|
||||
function isNone(value) {
|
||||
if (typeof value === "number") {
|
||||
return value === 0;
|
||||
}
|
||||
else if (value !== null) {
|
||||
return value === "none" || value === "0" || isZeroValueString(value);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export { isNone };
|
||||
30
node_modules/motion-dom/dist/es/animation/keyframes/utils/make-none-animatable.mjs
generated
vendored
Normal file
30
node_modules/motion-dom/dist/es/animation/keyframes/utils/make-none-animatable.mjs
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import { analyseComplexValue } from '../../../value/types/complex/index.mjs';
|
||||
import { getAnimatableNone } from '../../../value/types/utils/animatable-none.mjs';
|
||||
|
||||
/**
|
||||
* If we encounter keyframes like "none" or "0" and we also have keyframes like
|
||||
* "#fff" or "200px 200px" we want to find a keyframe to serve as a template for
|
||||
* the "none" keyframes. In this case "#fff" or "200px 200px" - then these get turned into
|
||||
* zero equivalents, i.e. "#fff0" or "0px 0px".
|
||||
*/
|
||||
const invalidTemplates = new Set(["auto", "none", "0"]);
|
||||
function makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name) {
|
||||
let i = 0;
|
||||
let animatableTemplate = undefined;
|
||||
while (i < unresolvedKeyframes.length && !animatableTemplate) {
|
||||
const keyframe = unresolvedKeyframes[i];
|
||||
if (typeof keyframe === "string" &&
|
||||
!invalidTemplates.has(keyframe) &&
|
||||
analyseComplexValue(keyframe).values.length) {
|
||||
animatableTemplate = unresolvedKeyframes[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (animatableTemplate && name) {
|
||||
for (const noneIndex of noneKeyframeIndexes) {
|
||||
unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { makeNoneKeyframesAnimatable };
|
||||
36
node_modules/motion-dom/dist/es/animation/keyframes/utils/unit-conversion.mjs
generated
vendored
Normal file
36
node_modules/motion-dom/dist/es/animation/keyframes/utils/unit-conversion.mjs
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
import { parseValueFromTransform } from '../../../render/dom/parse-transform.mjs';
|
||||
import { transformPropOrder } from '../../../render/utils/keys-transform.mjs';
|
||||
import { number } from '../../../value/types/numbers/index.mjs';
|
||||
import { px } from '../../../value/types/numbers/units.mjs';
|
||||
|
||||
const isNumOrPxType = (v) => v === number || v === px;
|
||||
const transformKeys = new Set(["x", "y", "z"]);
|
||||
const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
|
||||
function removeNonTranslationalTransform(visualElement) {
|
||||
const removedTransforms = [];
|
||||
nonTranslationalTransformKeys.forEach((key) => {
|
||||
const value = visualElement.getValue(key);
|
||||
if (value !== undefined) {
|
||||
removedTransforms.push([key, value.get()]);
|
||||
value.set(key.startsWith("scale") ? 1 : 0);
|
||||
}
|
||||
});
|
||||
return removedTransforms;
|
||||
}
|
||||
const positionalValues = {
|
||||
// Dimensions
|
||||
width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
|
||||
height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
|
||||
top: (_bbox, { top }) => parseFloat(top),
|
||||
left: (_bbox, { left }) => parseFloat(left),
|
||||
bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
|
||||
right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
|
||||
// Transform
|
||||
x: (_bbox, { transform }) => parseValueFromTransform(transform, "x"),
|
||||
y: (_bbox, { transform }) => parseValueFromTransform(transform, "y"),
|
||||
};
|
||||
// Alias translate longform names
|
||||
positionalValues.translateX = positionalValues.x;
|
||||
positionalValues.translateY = positionalValues.y;
|
||||
|
||||
export { isNumOrPxType, positionalValues, removeNonTranslationalTransform };
|
||||
Reference in New Issue
Block a user