Mission Control Dashboard - Initial implementation

This commit is contained in:
Daniel Arroyo
2026-03-27 18:36:05 +00:00
parent 257cea2c7d
commit a8fb4d4555
12516 changed files with 2307128 additions and 2 deletions

View File

@@ -0,0 +1,142 @@
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, containsCSSVariable } 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 { positionalValues, isNumOrPxType } 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);
/**
* If one keyframe contains embedded CSS variables (e.g. in calc()) and the other
* doesn't, we need to measure to convert to pixels. This handles GitHub issue #3410.
*/
const originHasVar = containsCSSVariable(origin);
const targetHasVar = containsCSSVariable(target);
if (originHasVar !== targetHasVar && positionalValues[name]) {
this.needsMeasurement = true;
return;
}
/**
* 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 };
//# sourceMappingURL=DOMKeyframesResolver.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,148 @@
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 };
//# sourceMappingURL=KeyframesResolver.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
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 };
//# sourceMappingURL=get-final.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"get-final.mjs","sources":["../../../../src/animation/keyframes/get-final.ts"],"sourcesContent":["import { AnimationPlaybackOptions } from \"../types\"\n\nconst isNotNull = (value: unknown) => value !== null\n\nexport function getFinalKeyframe<T>(\n keyframes: T[],\n { repeat, repeatType = \"loop\" }: AnimationPlaybackOptions,\n finalKeyframe?: T,\n speed: number = 1\n): T {\n const resolvedKeyframes = keyframes.filter(isNotNull)\n const useFirstKeyframe =\n speed < 0 || (repeat && repeatType !== \"loop\" && repeat % 2 === 1)\n const index = useFirstKeyframe ? 0 : resolvedKeyframes.length - 1\n\n return !index || finalKeyframe === undefined\n ? resolvedKeyframes[index]\n : finalKeyframe\n}\n"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG,CAAC,KAAc,KAAK,KAAK,KAAK,IAAI;SAEpC,gBAAgB,CAC5B,SAAc,EACd,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,EAA4B,EACzD,aAAiB,EACjB,QAAgB,CAAC,EAAA;IAEjB,MAAM,iBAAiB,GAAG,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC;AACrD,IAAA,MAAM,gBAAgB,GAClB,KAAK,GAAG,CAAC,KAAK,MAAM,IAAI,UAAU,KAAK,MAAM,IAAI,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC;AACtE,IAAA,MAAM,KAAK,GAAG,gBAAgB,GAAG,CAAC,GAAG,iBAAiB,CAAC,MAAM,GAAG,CAAC;AAEjE,IAAA,OAAO,CAAC,KAAK,IAAI,aAAa,KAAK;AAC/B,UAAE,iBAAiB,CAAC,KAAK;UACvB,aAAa;AACvB;;;;"}

View File

@@ -0,0 +1,10 @@
import { fillOffset } from './fill.mjs';
function defaultOffset(arr) {
const offset = [0];
fillOffset(offset, arr.length - 1);
return offset;
}
export { defaultOffset };
//# sourceMappingURL=default.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"default.mjs","sources":["../../../../../src/animation/keyframes/offsets/default.ts"],"sourcesContent":["import { fillOffset } from \"./fill\"\n\nexport function defaultOffset(arr: any[]): number[] {\n const offset = [0]\n fillOffset(offset, arr.length - 1)\n return offset\n}\n"],"names":[],"mappings":";;AAEM,SAAU,aAAa,CAAC,GAAU,EAAA;AACpC,IAAA,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC;IAClB,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;AAClC,IAAA,OAAO,MAAM;AACjB;;;;"}

View File

@@ -0,0 +1,13 @@
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 };
//# sourceMappingURL=fill.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fill.mjs","sources":["../../../../../src/animation/keyframes/offsets/fill.ts"],"sourcesContent":["import { progress } from \"motion-utils\"\nimport { mixNumber } from \"../../../utils/mix/number\"\n\nexport function fillOffset(offset: number[], remaining: number): void {\n const min = offset[offset.length - 1]\n for (let i = 1; i <= remaining; i++) {\n const offsetProgress = progress(0, remaining, i)\n offset.push(mixNumber(min, 1, offsetProgress))\n }\n}\n"],"names":[],"mappings":";;;AAGM,SAAU,UAAU,CAAC,MAAgB,EAAE,SAAiB,EAAA;IAC1D,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;AACrC,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;AAChD,QAAA,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC;IAClD;AACJ;;;;"}

View File

@@ -0,0 +1,6 @@
function convertOffsetToTimes(offset, duration) {
return offset.map((o) => o * duration);
}
export { convertOffsetToTimes };
//# sourceMappingURL=time.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"time.mjs","sources":["../../../../../src/animation/keyframes/offsets/time.ts"],"sourcesContent":["export function convertOffsetToTimes(offset: number[], duration: number) {\n return offset.map((o) => o * duration)\n}\n"],"names":[],"mappings":"AAAM,SAAU,oBAAoB,CAAC,MAAgB,EAAE,QAAgB,EAAA;AACnE,IAAA,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;AAC1C;;;;"}

View File

@@ -0,0 +1,12 @@
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 };
//# sourceMappingURL=apply-px-defaults.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"apply-px-defaults.mjs","sources":["../../../../../src/animation/keyframes/utils/apply-px-defaults.ts"],"sourcesContent":["import { UnresolvedValueKeyframe, ValueKeyframe } from \"../../types\"\nimport { pxValues } from \"../../waapi/utils/px-values\"\n\nexport function applyPxDefaults(\n keyframes: ValueKeyframe[] | UnresolvedValueKeyframe[],\n name: string\n) {\n for (let i = 0; i < keyframes.length; i++) {\n if (typeof keyframes[i] === \"number\" && pxValues.has(name)) {\n keyframes[i] = keyframes[i] + \"px\"\n }\n }\n}\n"],"names":[],"mappings":";;AAGM,SAAU,eAAe,CAC3B,SAAsD,EACtD,IAAY,EAAA;AAEZ,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACvC,QAAA,IAAI,OAAO,SAAS,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACxD,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;QACtC;IACJ;AACJ;;;;"}

View File

@@ -0,0 +1,8 @@
function fillWildcards(keyframes) {
for (let i = 1; i < keyframes.length; i++) {
keyframes[i] ?? (keyframes[i] = keyframes[i - 1]);
}
}
export { fillWildcards };
//# sourceMappingURL=fill-wildcards.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fill-wildcards.mjs","sources":["../../../../../src/animation/keyframes/utils/fill-wildcards.ts"],"sourcesContent":["import { UnresolvedValueKeyframe, ValueKeyframe } from \"../../types\"\n\nexport function fillWildcards(\n keyframes: ValueKeyframe[] | UnresolvedValueKeyframe[]\n) {\n for (let i = 1; i < keyframes.length; i++) {\n keyframes[i] ??= keyframes[i - 1]\n }\n}\n"],"names":[],"mappings":"AAEM,SAAU,aAAa,CACzB,SAAsD,EAAA;AAEtD,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACvC,QAAA,SAAS,CAAC,CAAC,CAAA,KAAX,SAAS,CAAC,CAAC,CAAA,GAAM,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACrC;AACJ;;;;"}

View File

@@ -0,0 +1,16 @@
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 };
//# sourceMappingURL=is-none.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"is-none.mjs","sources":["../../../../../src/animation/keyframes/utils/is-none.ts"],"sourcesContent":["import { isZeroValueString } from \"motion-utils\"\nimport { AnyResolvedKeyframe } from \"../../types\"\n\nexport function isNone(value: AnyResolvedKeyframe | null) {\n if (typeof value === \"number\") {\n return value === 0\n } else if (value !== null) {\n return value === \"none\" || value === \"0\" || isZeroValueString(value)\n } else {\n return true\n }\n}\n"],"names":[],"mappings":";;AAGM,SAAU,MAAM,CAAC,KAAiC,EAAA;AACpD,IAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAC3B,OAAO,KAAK,KAAK,CAAC;IACtB;AAAO,SAAA,IAAI,KAAK,KAAK,IAAI,EAAE;AACvB,QAAA,OAAO,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,GAAG,IAAI,iBAAiB,CAAC,KAAK,CAAC;IACxE;SAAO;AACH,QAAA,OAAO,IAAI;IACf;AACJ;;;;"}

View File

@@ -0,0 +1,31 @@
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 };
//# sourceMappingURL=make-none-animatable.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"make-none-animatable.mjs","sources":["../../../../../src/animation/keyframes/utils/make-none-animatable.ts"],"sourcesContent":["import { analyseComplexValue } from \"../../../value/types/complex\"\nimport { getAnimatableNone } from \"../../../value/types/utils/animatable-none\"\nimport { AnyResolvedKeyframe } from \"../../types\"\nimport { UnresolvedKeyframes } from \"../KeyframesResolver\"\n\n/**\n * If we encounter keyframes like \"none\" or \"0\" and we also have keyframes like\n * \"#fff\" or \"200px 200px\" we want to find a keyframe to serve as a template for\n * the \"none\" keyframes. In this case \"#fff\" or \"200px 200px\" - then these get turned into\n * zero equivalents, i.e. \"#fff0\" or \"0px 0px\".\n */\nconst invalidTemplates = new Set([\"auto\", \"none\", \"0\"])\n\nexport function makeNoneKeyframesAnimatable(\n unresolvedKeyframes: UnresolvedKeyframes<AnyResolvedKeyframe>,\n noneKeyframeIndexes: number[],\n name?: string\n) {\n let i = 0\n let animatableTemplate: string | undefined = undefined\n while (i < unresolvedKeyframes.length && !animatableTemplate) {\n const keyframe = unresolvedKeyframes[i]\n if (\n typeof keyframe === \"string\" &&\n !invalidTemplates.has(keyframe) &&\n analyseComplexValue(keyframe).values.length\n ) {\n animatableTemplate = unresolvedKeyframes[i] as string\n }\n i++\n }\n\n if (animatableTemplate && name) {\n for (const noneIndex of noneKeyframeIndexes) {\n unresolvedKeyframes[noneIndex] = getAnimatableNone(\n name,\n animatableTemplate\n )\n }\n }\n}\n"],"names":[],"mappings":";;;AAKA;;;;;AAKG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;SAEvC,2BAA2B,CACvC,mBAA6D,EAC7D,mBAA6B,EAC7B,IAAa,EAAA;IAEb,IAAI,CAAC,GAAG,CAAC;IACT,IAAI,kBAAkB,GAAuB,SAAS;IACtD,OAAO,CAAC,GAAG,mBAAmB,CAAC,MAAM,IAAI,CAAC,kBAAkB,EAAE;AAC1D,QAAA,MAAM,QAAQ,GAAG,mBAAmB,CAAC,CAAC,CAAC;QACvC,IACI,OAAO,QAAQ,KAAK,QAAQ;AAC5B,YAAA,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC/B,mBAAmB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,EAC7C;AACE,YAAA,kBAAkB,GAAG,mBAAmB,CAAC,CAAC,CAAW;QACzD;AACA,QAAA,CAAC,EAAE;IACP;AAEA,IAAA,IAAI,kBAAkB,IAAI,IAAI,EAAE;AAC5B,QAAA,KAAK,MAAM,SAAS,IAAI,mBAAmB,EAAE;YACzC,mBAAmB,CAAC,SAAS,CAAC,GAAG,iBAAiB,CAC9C,IAAI,EACJ,kBAAkB,CACrB;QACL;IACJ;AACJ;;;;"}

View File

@@ -0,0 +1,47 @@
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", boxSizing }) => {
const width = x.max - x.min;
return boxSizing === "border-box"
? width
: width - parseFloat(paddingLeft) - parseFloat(paddingRight);
},
height: ({ y }, { paddingTop = "0", paddingBottom = "0", boxSizing }) => {
const height = y.max - y.min;
return boxSizing === "border-box"
? height
: height - 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 };
//# sourceMappingURL=unit-conversion.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"unit-conversion.mjs","sources":["../../../../../src/animation/keyframes/utils/unit-conversion.ts"],"sourcesContent":["import type { Box } from \"motion-utils\"\nimport { parseValueFromTransform } from \"../../../render/dom/parse-transform\"\nimport { transformPropOrder } from \"../../../render/utils/keys-transform\"\nimport { MotionValue } from \"../../../value\"\nimport { number } from \"../../../value/types/numbers\"\nimport { px } from \"../../../value/types/numbers/units\"\nimport { ValueType } from \"../../../value/types/types\"\nimport { AnyResolvedKeyframe } from \"../../types\"\nimport { WithRender } from \"../types\"\n\nexport const isNumOrPxType = (v?: ValueType): v is ValueType =>\n v === number || v === px\n\ntype GetActualMeasurementInPixels = (\n bbox: Box,\n computedStyle: Partial<CSSStyleDeclaration>\n) => number\n\nconst transformKeys = new Set([\"x\", \"y\", \"z\"])\nconst nonTranslationalTransformKeys = transformPropOrder.filter(\n (key) => !transformKeys.has(key)\n)\n\ntype RemovedTransforms = [string, AnyResolvedKeyframe][]\nexport function removeNonTranslationalTransform(visualElement: WithRender) {\n const removedTransforms: RemovedTransforms = []\n\n nonTranslationalTransformKeys.forEach((key) => {\n const value: MotionValue<AnyResolvedKeyframe> | undefined =\n visualElement.getValue(key)\n if (value !== undefined) {\n removedTransforms.push([key, value.get()])\n value.set(key.startsWith(\"scale\") ? 1 : 0)\n }\n })\n\n return removedTransforms\n}\n\nexport const positionalValues: { [key: string]: GetActualMeasurementInPixels } =\n {\n // Dimensions\n width: (\n { x },\n { paddingLeft = \"0\", paddingRight = \"0\", boxSizing }\n ) => {\n const width = x.max - x.min\n return boxSizing === \"border-box\"\n ? width\n : width - parseFloat(paddingLeft) - parseFloat(paddingRight)\n },\n height: (\n { y },\n { paddingTop = \"0\", paddingBottom = \"0\", boxSizing }\n ) => {\n const height = y.max - y.min\n return boxSizing === \"border-box\"\n ? height\n : height - parseFloat(paddingTop) - parseFloat(paddingBottom)\n },\n\n top: (_bbox, { top }) => parseFloat(top as string),\n left: (_bbox, { left }) => parseFloat(left as string),\n bottom: ({ y }, { top }) => parseFloat(top as string) + (y.max - y.min),\n right: ({ x }, { left }) =>\n parseFloat(left as string) + (x.max - x.min),\n\n // Transform\n x: (_bbox, { transform }) => parseValueFromTransform(transform, \"x\"),\n y: (_bbox, { transform }) => parseValueFromTransform(transform, \"y\"),\n }\n\n// Alias translate longform names\npositionalValues.translateX = positionalValues.x\npositionalValues.translateY = positionalValues.y\n"],"names":[],"mappings":";;;;;AAUO,MAAM,aAAa,GAAG,CAAC,CAAa,KACvC,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK;AAO1B,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAC9C,MAAM,6BAA6B,GAAG,kBAAkB,CAAC,MAAM,CAC3D,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CACnC;AAGK,SAAU,+BAA+B,CAAC,aAAyB,EAAA;IACrE,MAAM,iBAAiB,GAAsB,EAAE;AAE/C,IAAA,6BAA6B,CAAC,OAAO,CAAC,CAAC,GAAG,KAAI;QAC1C,MAAM,KAAK,GACP,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC;AAC/B,QAAA,IAAI,KAAK,KAAK,SAAS,EAAE;AACrB,YAAA,iBAAiB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;AAC1C,YAAA,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9C;AACJ,IAAA,CAAC,CAAC;AAEF,IAAA,OAAO,iBAAiB;AAC5B;AAEO,MAAM,gBAAgB,GACzB;;AAEI,IAAA,KAAK,EAAE,CACH,EAAE,CAAC,EAAE,EACL,EAAE,WAAW,GAAG,GAAG,EAAE,YAAY,GAAG,GAAG,EAAE,SAAS,EAAE,KACpD;QACA,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG;QAC3B,OAAO,SAAS,KAAK;AACjB,cAAE;AACF,cAAE,KAAK,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,UAAU,CAAC,YAAY,CAAC;IACpE,CAAC;AACD,IAAA,MAAM,EAAE,CACJ,EAAE,CAAC,EAAE,EACL,EAAE,UAAU,GAAG,GAAG,EAAE,aAAa,GAAG,GAAG,EAAE,SAAS,EAAE,KACpD;QACA,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG;QAC5B,OAAO,SAAS,KAAK;AACjB,cAAE;AACF,cAAE,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC,aAAa,CAAC;IACrE,CAAC;AAED,IAAA,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,KAAK,UAAU,CAAC,GAAa,CAAC;AAClD,IAAA,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,UAAU,CAAC,IAAc,CAAC;IACrD,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,UAAU,CAAC,GAAa,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;IACvE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KACnB,UAAU,CAAC,IAAc,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;;AAGhD,IAAA,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,uBAAuB,CAAC,SAAS,EAAE,GAAG,CAAC;AACpE,IAAA,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,uBAAuB,CAAC,SAAS,EAAE,GAAG,CAAC;;AAG5E;AACA,gBAAgB,CAAC,UAAU,GAAG,gBAAgB,CAAC,CAAC;AAChD,gBAAgB,CAAC,UAAU,GAAG,gBAAgB,CAAC,CAAC;;;;"}