motion-v
Version:
<p align="center"> <img width="100" height="100" alt="Motion logo" src="https://user-images.githubusercontent.com/7850794/164965523-3eced4c4-6020-467e-acde-f11b7900ad62.png" /> </p> <h1 align="center">Motion for Vue</h1>
1,482 lines • 363 kB
JavaScript
"use strict";
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
const vue = require("vue");
const heyListen = require("hey-listen");
const core = require("@vueuse/core");
function addUniqueItem(arr, item) {
if (arr.indexOf(item) === -1)
arr.push(item);
}
function removeItem(arr, item) {
const index = arr.indexOf(item);
if (index > -1)
arr.splice(index, 1);
}
function moveItem$1([...arr], fromIndex, toIndex) {
const startIndex = fromIndex < 0 ? arr.length + fromIndex : fromIndex;
if (startIndex >= 0 && startIndex < arr.length) {
const endIndex = toIndex < 0 ? arr.length + toIndex : toIndex;
const [item] = arr.splice(fromIndex, 1);
arr.splice(endIndex, 0, item);
}
return arr;
}
const clamp = (min, max, v) => {
if (v > max)
return max;
if (v < min)
return min;
return v;
};
function formatErrorMessage(message, errorCode) {
return errorCode ? `${message}. For more information and steps for solving, visit https://motion.dev/troubleshooting/${errorCode}` : message;
}
exports.warning = () => {
};
exports.invariant = () => {
};
if (process.env.NODE_ENV !== "production") {
exports.warning = (check, message, errorCode) => {
if (!check && typeof console !== "undefined") {
console.warn(formatErrorMessage(message, errorCode));
}
};
exports.invariant = (check, message, errorCode) => {
if (!check) {
throw new Error(formatErrorMessage(message, errorCode));
}
};
}
const MotionGlobalConfig = {};
const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
function isObject(value) {
return typeof value === "object" && value !== null;
}
const isZeroValueString = (v) => /^0[^.\s]+$/u.test(v);
// @__NO_SIDE_EFFECTS__
function memo(callback) {
let result;
return () => {
if (result === void 0)
result = callback();
return result;
};
}
const noop = /* @__NO_SIDE_EFFECTS__ */ (any) => any;
const combineFunctions = (a, b) => (v) => b(a(v));
const pipe = (...transformers) => transformers.reduce(combineFunctions);
const progress = /* @__NO_SIDE_EFFECTS__ */ (from, to, value) => {
const toFromDifference = to - from;
return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
};
class SubscriptionManager {
constructor() {
this.subscriptions = [];
}
add(handler) {
addUniqueItem(this.subscriptions, handler);
return () => removeItem(this.subscriptions, handler);
}
notify(a, b, c) {
const numSubscriptions = this.subscriptions.length;
if (!numSubscriptions)
return;
if (numSubscriptions === 1) {
this.subscriptions[0](a, b, c);
} else {
for (let i = 0; i < numSubscriptions; i++) {
const handler = this.subscriptions[i];
handler && handler(a, b, c);
}
}
}
getSize() {
return this.subscriptions.length;
}
clear() {
this.subscriptions.length = 0;
}
}
const secondsToMilliseconds = /* @__NO_SIDE_EFFECTS__ */ (seconds) => seconds * 1e3;
const millisecondsToSeconds = /* @__NO_SIDE_EFFECTS__ */ (milliseconds) => milliseconds / 1e3;
function velocityPerSecond(velocity, frameDuration) {
return frameDuration ? velocity * (1e3 / frameDuration) : 0;
}
const warned = /* @__PURE__ */ new Set();
function hasWarned(message) {
return warned.has(message);
}
function warnOnce(condition, message, errorCode) {
if (condition || warned.has(message))
return;
console.warn(formatErrorMessage(message, errorCode));
warned.add(message);
}
const wrap = (min, max, v) => {
const rangeSize = max - min;
return ((v - min) % rangeSize + rangeSize) % rangeSize + min;
};
const calcBezier = (t, a1, a2) => (((1 - 3 * a2 + 3 * a1) * t + (3 * a2 - 6 * a1)) * t + 3 * a1) * t;
const subdivisionPrecision = 1e-7;
const subdivisionMaxIterations = 12;
function binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {
let currentX;
let currentT;
let i = 0;
do {
currentT = lowerBound + (upperBound - lowerBound) / 2;
currentX = calcBezier(currentT, mX1, mX2) - x;
if (currentX > 0) {
upperBound = currentT;
} else {
lowerBound = currentT;
}
} while (Math.abs(currentX) > subdivisionPrecision && ++i < subdivisionMaxIterations);
return currentT;
}
function cubicBezier(mX1, mY1, mX2, mY2) {
if (mX1 === mY1 && mX2 === mY2)
return noop;
const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);
return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);
}
const mirrorEasing = (easing) => (p) => p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;
const reverseEasing = (easing) => (p) => 1 - easing(1 - p);
const backOut = /* @__PURE__ */ cubicBezier(0.33, 1.53, 0.69, 0.99);
const backIn = /* @__PURE__ */ reverseEasing(backOut);
const backInOut = /* @__PURE__ */ mirrorEasing(backIn);
const anticipate = (p) => (p *= 2) < 1 ? 0.5 * backIn(p) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
const circIn = (p) => 1 - Math.sin(Math.acos(p));
const circOut = reverseEasing(circIn);
const circInOut = mirrorEasing(circIn);
const easeIn = /* @__PURE__ */ cubicBezier(0.42, 0, 1, 1);
const easeOut = /* @__PURE__ */ cubicBezier(0, 0, 0.58, 1);
const easeInOut = /* @__PURE__ */ cubicBezier(0.42, 0, 0.58, 1);
function steps(numSteps, direction = "end") {
return (progress2) => {
progress2 = direction === "end" ? Math.min(progress2, 0.999) : Math.max(progress2, 1e-3);
const expanded = progress2 * numSteps;
const rounded = direction === "end" ? Math.floor(expanded) : Math.ceil(expanded);
return clamp(0, 1, rounded / numSteps);
};
}
const isEasingArray = (ease2) => {
return Array.isArray(ease2) && typeof ease2[0] !== "number";
};
function getEasingForSegment(easing, i) {
return isEasingArray(easing) ? easing[wrap(0, easing.length, i)] : easing;
}
const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
const easingLookup = {
linear: noop,
easeIn,
easeInOut,
easeOut,
circIn,
circInOut,
circOut,
backIn,
backInOut,
backOut,
anticipate
};
const isValidEasing = (easing) => {
return typeof easing === "string";
};
const easingDefinitionToFunction = (definition) => {
if (isBezierDefinition(definition)) {
exports.invariant(definition.length === 4, `Cubic bezier arrays must contain four numerical values.`, "cubic-bezier-length");
const [x1, y1, x2, y2] = definition;
return cubicBezier(x1, y1, x2, y2);
} else if (isValidEasing(definition)) {
exports.invariant(easingLookup[definition] !== void 0, `Invalid easing type '${definition}'`, "invalid-easing-type");
return easingLookup[definition];
}
return definition;
};
const stepsOrder = [
"setup",
// Compute
"read",
// Read
"resolveKeyframes",
// Write/Read/Write/Read
"preUpdate",
// Compute
"update",
// Compute
"preRender",
// Compute
"render",
// Write
"postRender"
// Compute
];
const statsBuffer = {
value: null,
addProjectionMetrics: null
};
function createRenderStep(runNextFrame, stepName) {
let thisFrame = /* @__PURE__ */ new Set();
let nextFrame = /* @__PURE__ */ new Set();
let isProcessing = false;
let flushNextFrame = false;
const toKeepAlive = /* @__PURE__ */ new WeakSet();
let latestFrameData = {
delta: 0,
timestamp: 0,
isProcessing: false
};
let numCalls = 0;
function triggerCallback(callback) {
if (toKeepAlive.has(callback)) {
step.schedule(callback);
runNextFrame();
}
numCalls++;
callback(latestFrameData);
}
const step = {
/**
* Schedule a process to run on the next frame.
*/
schedule: (callback, keepAlive = false, immediate = false) => {
const addToCurrentFrame = immediate && isProcessing;
const queue = addToCurrentFrame ? thisFrame : nextFrame;
if (keepAlive)
toKeepAlive.add(callback);
if (!queue.has(callback))
queue.add(callback);
return callback;
},
/**
* Cancel the provided callback from running on the next frame.
*/
cancel: (callback) => {
nextFrame.delete(callback);
toKeepAlive.delete(callback);
},
/**
* Execute all schedule callbacks.
*/
process: (frameData2) => {
latestFrameData = frameData2;
if (isProcessing) {
flushNextFrame = true;
return;
}
isProcessing = true;
[thisFrame, nextFrame] = [nextFrame, thisFrame];
thisFrame.forEach(triggerCallback);
if (stepName && statsBuffer.value) {
statsBuffer.value.frameloop[stepName].push(numCalls);
}
numCalls = 0;
thisFrame.clear();
isProcessing = false;
if (flushNextFrame) {
flushNextFrame = false;
step.process(frameData2);
}
}
};
return step;
}
const maxElapsed$1 = 40;
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
let runNextFrame = false;
let useDefaultElapsed = true;
const state = {
delta: 0,
timestamp: 0,
isProcessing: false
};
const flagRunNextFrame = () => runNextFrame = true;
const steps2 = stepsOrder.reduce((acc, key) => {
acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : void 0);
return acc;
}, {});
const { setup, read, resolveKeyframes, preUpdate, update, preRender, render, postRender } = steps2;
const processBatch = () => {
const timestamp = MotionGlobalConfig.useManualTiming ? state.timestamp : performance.now();
runNextFrame = false;
if (!MotionGlobalConfig.useManualTiming) {
state.delta = useDefaultElapsed ? 1e3 / 60 : Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
}
state.timestamp = timestamp;
state.isProcessing = true;
setup.process(state);
read.process(state);
resolveKeyframes.process(state);
preUpdate.process(state);
update.process(state);
preRender.process(state);
render.process(state);
postRender.process(state);
state.isProcessing = false;
if (runNextFrame && allowKeepAlive) {
useDefaultElapsed = false;
scheduleNextBatch(processBatch);
}
};
const wake = () => {
runNextFrame = true;
useDefaultElapsed = true;
if (!state.isProcessing) {
scheduleNextBatch(processBatch);
}
};
const schedule = stepsOrder.reduce((acc, key) => {
const step = steps2[key];
acc[key] = (process2, keepAlive = false, immediate = false) => {
if (!runNextFrame)
wake();
return step.schedule(process2, keepAlive, immediate);
};
return acc;
}, {});
const cancel = (process2) => {
for (let i = 0; i < stepsOrder.length; i++) {
steps2[stepsOrder[i]].cancel(process2);
}
};
return { schedule, cancel, state, steps: steps2 };
}
const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps } = /* @__PURE__ */ createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
let now;
function clearTime() {
now = void 0;
}
const time = {
now: () => {
if (now === void 0) {
time.set(frameData.isProcessing || MotionGlobalConfig.useManualTiming ? frameData.timestamp : performance.now());
}
return now;
},
set: (newTime) => {
now = newTime;
queueMicrotask(clearTime);
}
};
const activeAnimations = {
layout: 0,
mainThread: 0,
waapi: 0
};
const checkStringStartsWith = (token) => (key) => typeof key === "string" && key.startsWith(token);
const isCSSVariableName = /* @__PURE__ */ checkStringStartsWith("--");
const startsAsVariableToken = /* @__PURE__ */ checkStringStartsWith("var(--");
const isCSSVariableToken = (value) => {
const startsWithToken = startsAsVariableToken(value);
if (!startsWithToken)
return false;
return singleCssVariableRegex.test(value.split("/*")[0].trim());
};
const singleCssVariableRegex = /var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;
const number = {
test: (v) => typeof v === "number",
parse: parseFloat,
transform: (v) => v
};
const alpha = {
...number,
transform: (v) => clamp(0, 1, v)
};
const scale = {
...number,
default: 1
};
const sanitize = (v) => Math.round(v * 1e5) / 1e5;
const floatRegex = /-?(?:\d+(?:\.\d+)?|\.\d+)/gu;
function isNullish(v) {
return v == null;
}
const singleColorRegex = /^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu;
const isColorString = (type, testProp) => (v) => {
return Boolean(typeof v === "string" && singleColorRegex.test(v) && v.startsWith(type) || testProp && !isNullish(v) && Object.prototype.hasOwnProperty.call(v, testProp));
};
const splitColor = (aName, bName, cName) => (v) => {
if (typeof v !== "string")
return v;
const [a, b, c, alpha2] = v.match(floatRegex);
return {
[aName]: parseFloat(a),
[bName]: parseFloat(b),
[cName]: parseFloat(c),
alpha: alpha2 !== void 0 ? parseFloat(alpha2) : 1
};
};
const clampRgbUnit = (v) => clamp(0, 255, v);
const rgbUnit = {
...number,
transform: (v) => Math.round(clampRgbUnit(v))
};
const rgba = {
test: /* @__PURE__ */ isColorString("rgb", "red"),
parse: /* @__PURE__ */ splitColor("red", "green", "blue"),
transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => "rgba(" + rgbUnit.transform(red) + ", " + rgbUnit.transform(green) + ", " + rgbUnit.transform(blue) + ", " + sanitize(alpha.transform(alpha$1)) + ")"
};
function parseHex(v) {
let r = "";
let g = "";
let b = "";
let a = "";
if (v.length > 5) {
r = v.substring(1, 3);
g = v.substring(3, 5);
b = v.substring(5, 7);
a = v.substring(7, 9);
} else {
r = v.substring(1, 2);
g = v.substring(2, 3);
b = v.substring(3, 4);
a = v.substring(4, 5);
r += r;
g += g;
b += b;
a += a;
}
return {
red: parseInt(r, 16),
green: parseInt(g, 16),
blue: parseInt(b, 16),
alpha: a ? parseInt(a, 16) / 255 : 1
};
}
const hex = {
test: /* @__PURE__ */ isColorString("#"),
parse: parseHex,
transform: rgba.transform
};
const createUnitType = /* @__NO_SIDE_EFFECTS__ */ (unit) => ({
test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1,
parse: parseFloat,
transform: (v) => `${v}${unit}`
});
const degrees = /* @__PURE__ */ createUnitType("deg");
const percent = /* @__PURE__ */ createUnitType("%");
const px = /* @__PURE__ */ createUnitType("px");
const vh = /* @__PURE__ */ createUnitType("vh");
const vw = /* @__PURE__ */ createUnitType("vw");
const progressPercentage = /* @__PURE__ */ (() => ({
...percent,
parse: (v) => percent.parse(v) / 100,
transform: (v) => percent.transform(v * 100)
}))();
const hsla = {
test: /* @__PURE__ */ isColorString("hsl", "hue"),
parse: /* @__PURE__ */ splitColor("hue", "saturation", "lightness"),
transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {
return "hsla(" + Math.round(hue) + ", " + percent.transform(sanitize(saturation)) + ", " + percent.transform(sanitize(lightness)) + ", " + sanitize(alpha.transform(alpha$1)) + ")";
}
};
const color = {
test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),
parse: (v) => {
if (rgba.test(v)) {
return rgba.parse(v);
} else if (hsla.test(v)) {
return hsla.parse(v);
} else {
return hex.parse(v);
}
},
transform: (v) => {
return typeof v === "string" ? v : v.hasOwnProperty("red") ? rgba.transform(v) : hsla.transform(v);
},
getAnimatableNone: (v) => {
const parsed = color.parse(v);
parsed.alpha = 0;
return color.transform(parsed);
}
};
const colorRegex = /(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;
function test(v) {
var _a, _b;
return isNaN(v) && typeof v === "string" && (((_a = v.match(floatRegex)) == null ? void 0 : _a.length) || 0) + (((_b = v.match(colorRegex)) == null ? void 0 : _b.length) || 0) > 0;
}
const NUMBER_TOKEN = "number";
const COLOR_TOKEN = "color";
const VAR_TOKEN = "var";
const VAR_FUNCTION_TOKEN = "var(";
const SPLIT_TOKEN = "${}";
const complexRegex = /var\s*\(\s*--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)|#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\)|-?(?:\d+(?:\.\d+)?|\.\d+)/giu;
function analyseComplexValue(value) {
const originalValue = value.toString();
const values = [];
const indexes = {
color: [],
number: [],
var: []
};
const types = [];
let i = 0;
const tokenised = originalValue.replace(complexRegex, (parsedValue) => {
if (color.test(parsedValue)) {
indexes.color.push(i);
types.push(COLOR_TOKEN);
values.push(color.parse(parsedValue));
} else if (parsedValue.startsWith(VAR_FUNCTION_TOKEN)) {
indexes.var.push(i);
types.push(VAR_TOKEN);
values.push(parsedValue);
} else {
indexes.number.push(i);
types.push(NUMBER_TOKEN);
values.push(parseFloat(parsedValue));
}
++i;
return SPLIT_TOKEN;
});
const split = tokenised.split(SPLIT_TOKEN);
return { values, split, indexes, types };
}
function parseComplexValue(v) {
return analyseComplexValue(v).values;
}
function createTransformer(source) {
const { split, types } = analyseComplexValue(source);
const numSections = split.length;
return (v) => {
let output = "";
for (let i = 0; i < numSections; i++) {
output += split[i];
if (v[i] !== void 0) {
const type = types[i];
if (type === NUMBER_TOKEN) {
output += sanitize(v[i]);
} else if (type === COLOR_TOKEN) {
output += color.transform(v[i]);
} else {
output += v[i];
}
}
}
return output;
};
}
const convertNumbersToZero = (v) => typeof v === "number" ? 0 : color.test(v) ? color.getAnimatableNone(v) : v;
function getAnimatableNone$1(v) {
const parsed = parseComplexValue(v);
const transformer = createTransformer(v);
return transformer(parsed.map(convertNumbersToZero));
}
const complex = {
test,
parse: parseComplexValue,
createTransformer,
getAnimatableNone: getAnimatableNone$1
};
function hueToRgb(p, q, t) {
if (t < 0)
t += 1;
if (t > 1)
t -= 1;
if (t < 1 / 6)
return p + (q - p) * 6 * t;
if (t < 1 / 2)
return q;
if (t < 2 / 3)
return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
function hslaToRgba({ hue, saturation, lightness, alpha: alpha2 }) {
hue /= 360;
saturation /= 100;
lightness /= 100;
let red = 0;
let green = 0;
let blue = 0;
if (!saturation) {
red = green = blue = lightness;
} else {
const q = lightness < 0.5 ? lightness * (1 + saturation) : lightness + saturation - lightness * saturation;
const p = 2 * lightness - q;
red = hueToRgb(p, q, hue + 1 / 3);
green = hueToRgb(p, q, hue);
blue = hueToRgb(p, q, hue - 1 / 3);
}
return {
red: Math.round(red * 255),
green: Math.round(green * 255),
blue: Math.round(blue * 255),
alpha: alpha2
};
}
function mixImmediate(a, b) {
return (p) => p > 0 ? b : a;
}
const mixNumber$1 = (from, to, progress2) => {
return from + (to - from) * progress2;
};
const mixLinearColor = (from, to, v) => {
const fromExpo = from * from;
const expo = v * (to * to - fromExpo) + fromExpo;
return expo < 0 ? 0 : Math.sqrt(expo);
};
const colorTypes = [hex, rgba, hsla];
const getColorType = (v) => colorTypes.find((type) => type.test(v));
function asRGBA(color2) {
const type = getColorType(color2);
exports.warning(Boolean(type), `'${color2}' is not an animatable color. Use the equivalent color code instead.`, "color-not-animatable");
if (!Boolean(type))
return false;
let model = type.parse(color2);
if (type === hsla) {
model = hslaToRgba(model);
}
return model;
}
const mixColor = (from, to) => {
const fromRGBA = asRGBA(from);
const toRGBA = asRGBA(to);
if (!fromRGBA || !toRGBA) {
return mixImmediate(from, to);
}
const blended = { ...fromRGBA };
return (v) => {
blended.red = mixLinearColor(fromRGBA.red, toRGBA.red, v);
blended.green = mixLinearColor(fromRGBA.green, toRGBA.green, v);
blended.blue = mixLinearColor(fromRGBA.blue, toRGBA.blue, v);
blended.alpha = mixNumber$1(fromRGBA.alpha, toRGBA.alpha, v);
return rgba.transform(blended);
};
};
const invisibleValues = /* @__PURE__ */ new Set(["none", "hidden"]);
function mixVisibility(origin, target) {
if (invisibleValues.has(origin)) {
return (p) => p <= 0 ? origin : target;
} else {
return (p) => p >= 1 ? target : origin;
}
}
function mixNumber(a, b) {
return (p) => mixNumber$1(a, b, p);
}
function getMixer(a) {
if (typeof a === "number") {
return mixNumber;
} else if (typeof a === "string") {
return isCSSVariableToken(a) ? mixImmediate : color.test(a) ? mixColor : mixComplex;
} else if (Array.isArray(a)) {
return mixArray;
} else if (typeof a === "object") {
return color.test(a) ? mixColor : mixObject;
}
return mixImmediate;
}
function mixArray(a, b) {
const output = [...a];
const numValues = output.length;
const blendValue = a.map((v, i) => getMixer(v)(v, b[i]));
return (p) => {
for (let i = 0; i < numValues; i++) {
output[i] = blendValue[i](p);
}
return output;
};
}
function mixObject(a, b) {
const output = { ...a, ...b };
const blendValue = {};
for (const key in output) {
if (a[key] !== void 0 && b[key] !== void 0) {
blendValue[key] = getMixer(a[key])(a[key], b[key]);
}
}
return (v) => {
for (const key in blendValue) {
output[key] = blendValue[key](v);
}
return output;
};
}
function matchOrder(origin, target) {
const orderedOrigin = [];
const pointers = { color: 0, var: 0, number: 0 };
for (let i = 0; i < target.values.length; i++) {
const type = target.types[i];
const originIndex = origin.indexes[type][pointers[type]];
const originValue = origin.values[originIndex] ?? 0;
orderedOrigin[i] = originValue;
pointers[type]++;
}
return orderedOrigin;
}
const mixComplex = (origin, target) => {
const template = complex.createTransformer(target);
const originStats = analyseComplexValue(origin);
const targetStats = analyseComplexValue(target);
const canInterpolate = originStats.indexes.var.length === targetStats.indexes.var.length && originStats.indexes.color.length === targetStats.indexes.color.length && originStats.indexes.number.length >= targetStats.indexes.number.length;
if (canInterpolate) {
if (invisibleValues.has(origin) && !targetStats.values.length || invisibleValues.has(target) && !originStats.values.length) {
return mixVisibility(origin, target);
}
return pipe(mixArray(matchOrder(originStats, targetStats), targetStats.values), template);
} else {
exports.warning(true, `Complex values '${origin}' and '${target}' too different to mix. Ensure all colors are of the same type, and that each contains the same quantity of number and color values. Falling back to instant transition.`, "complex-values-different");
return mixImmediate(origin, target);
}
};
function mix(from, to, p) {
if (typeof from === "number" && typeof to === "number" && typeof p === "number") {
return mixNumber$1(from, to, p);
}
const mixer = getMixer(from);
return mixer(from, to);
}
const frameloopDriver = (update) => {
const passTimestamp = ({ timestamp }) => update(timestamp);
return {
start: (keepAlive = true) => frame.update(passTimestamp, keepAlive),
stop: () => cancelFrame(passTimestamp),
/**
* If we're processing this frame we can use the
* framelocked timestamp to keep things in sync.
*/
now: () => frameData.isProcessing ? frameData.timestamp : time.now()
};
};
const generateLinearEasing = (easing, duration, resolution = 10) => {
let points = "";
const numPoints = Math.max(Math.round(duration / resolution), 2);
for (let i = 0; i < numPoints; i++) {
points += Math.round(easing(i / (numPoints - 1)) * 1e4) / 1e4 + ", ";
}
return `linear(${points.substring(0, points.length - 2)})`;
};
const maxGeneratorDuration = 2e4;
function calcGeneratorDuration(generator) {
let duration = 0;
const timeStep = 50;
let state = generator.next(duration);
while (!state.done && duration < maxGeneratorDuration) {
duration += timeStep;
state = generator.next(duration);
}
return duration >= maxGeneratorDuration ? Infinity : duration;
}
function createGeneratorEasing(options, scale2 = 100, createGenerator) {
const generator = createGenerator({ ...options, keyframes: [0, scale2] });
const duration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);
return {
type: "keyframes",
ease: (progress2) => {
return generator.next(duration * progress2).value / scale2;
},
duration: /* @__PURE__ */ millisecondsToSeconds(duration)
};
}
const velocitySampleDuration = 5;
function calcGeneratorVelocity(resolveValue, t, current2) {
const prevT = Math.max(t - velocitySampleDuration, 0);
return velocityPerSecond(current2 - resolveValue(prevT), t - prevT);
}
const springDefaults = {
// Default spring physics
stiffness: 100,
damping: 10,
mass: 1,
velocity: 0,
// Default duration/bounce-based options
duration: 800,
// in ms
bounce: 0.3,
visualDuration: 0.3,
// in seconds
// Rest thresholds
restSpeed: {
granular: 0.01,
default: 2
},
restDelta: {
granular: 5e-3,
default: 0.5
},
// Limits
minDuration: 0.01,
// in seconds
maxDuration: 10,
// in seconds
minDamping: 0.05,
maxDamping: 1
};
const safeMin = 1e-3;
function findSpring({ duration = springDefaults.duration, bounce = springDefaults.bounce, velocity = springDefaults.velocity, mass = springDefaults.mass }) {
let envelope;
let derivative;
exports.warning(duration <= /* @__PURE__ */ secondsToMilliseconds(springDefaults.maxDuration), "Spring duration must be 10 seconds or less", "spring-duration-limit");
let dampingRatio = 1 - bounce;
dampingRatio = clamp(springDefaults.minDamping, springDefaults.maxDamping, dampingRatio);
duration = clamp(springDefaults.minDuration, springDefaults.maxDuration, /* @__PURE__ */ millisecondsToSeconds(duration));
if (dampingRatio < 1) {
envelope = (undampedFreq2) => {
const exponentialDecay = undampedFreq2 * dampingRatio;
const delta = exponentialDecay * duration;
const a = exponentialDecay - velocity;
const b = calcAngularFreq(undampedFreq2, dampingRatio);
const c = Math.exp(-delta);
return safeMin - a / b * c;
};
derivative = (undampedFreq2) => {
const exponentialDecay = undampedFreq2 * dampingRatio;
const delta = exponentialDecay * duration;
const d = delta * velocity + velocity;
const e = Math.pow(dampingRatio, 2) * Math.pow(undampedFreq2, 2) * duration;
const f = Math.exp(-delta);
const g = calcAngularFreq(Math.pow(undampedFreq2, 2), dampingRatio);
const factor = -envelope(undampedFreq2) + safeMin > 0 ? -1 : 1;
return factor * ((d - e) * f) / g;
};
} else {
envelope = (undampedFreq2) => {
const a = Math.exp(-undampedFreq2 * duration);
const b = (undampedFreq2 - velocity) * duration + 1;
return -safeMin + a * b;
};
derivative = (undampedFreq2) => {
const a = Math.exp(-undampedFreq2 * duration);
const b = (velocity - undampedFreq2) * (duration * duration);
return a * b;
};
}
const initialGuess = 5 / duration;
const undampedFreq = approximateRoot(envelope, derivative, initialGuess);
duration = /* @__PURE__ */ secondsToMilliseconds(duration);
if (isNaN(undampedFreq)) {
return {
stiffness: springDefaults.stiffness,
damping: springDefaults.damping,
duration
};
} else {
const stiffness = Math.pow(undampedFreq, 2) * mass;
return {
stiffness,
damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),
duration
};
}
}
const rootIterations = 12;
function approximateRoot(envelope, derivative, initialGuess) {
let result = initialGuess;
for (let i = 1; i < rootIterations; i++) {
result = result - envelope(result) / derivative(result);
}
return result;
}
function calcAngularFreq(undampedFreq, dampingRatio) {
return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
}
const durationKeys = ["duration", "bounce"];
const physicsKeys = ["stiffness", "damping", "mass"];
function isSpringType(options, keys2) {
return keys2.some((key) => options[key] !== void 0);
}
function getSpringOptions(options) {
let springOptions = {
velocity: springDefaults.velocity,
stiffness: springDefaults.stiffness,
damping: springDefaults.damping,
mass: springDefaults.mass,
isResolvedFromDuration: false,
...options
};
if (!isSpringType(options, physicsKeys) && isSpringType(options, durationKeys)) {
if (options.visualDuration) {
const visualDuration = options.visualDuration;
const root = 2 * Math.PI / (visualDuration * 1.2);
const stiffness = root * root;
const damping = 2 * clamp(0.05, 1, 1 - (options.bounce || 0)) * Math.sqrt(stiffness);
springOptions = {
...springOptions,
mass: springDefaults.mass,
stiffness,
damping
};
} else {
const derived = findSpring(options);
springOptions = {
...springOptions,
...derived,
mass: springDefaults.mass
};
springOptions.isResolvedFromDuration = true;
}
}
return springOptions;
}
function spring(optionsOrVisualDuration = springDefaults.visualDuration, bounce = springDefaults.bounce) {
const options = typeof optionsOrVisualDuration !== "object" ? {
visualDuration: optionsOrVisualDuration,
keyframes: [0, 1],
bounce
} : optionsOrVisualDuration;
let { restSpeed, restDelta } = options;
const origin = options.keyframes[0];
const target = options.keyframes[options.keyframes.length - 1];
const state = { done: false, value: origin };
const { stiffness, damping, mass, duration, velocity, isResolvedFromDuration } = getSpringOptions({
...options,
velocity: -/* @__PURE__ */ millisecondsToSeconds(options.velocity || 0)
});
const initialVelocity = velocity || 0;
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
const initialDelta = target - origin;
const undampedAngularFreq = /* @__PURE__ */ millisecondsToSeconds(Math.sqrt(stiffness / mass));
const isGranularScale = Math.abs(initialDelta) < 5;
restSpeed || (restSpeed = isGranularScale ? springDefaults.restSpeed.granular : springDefaults.restSpeed.default);
restDelta || (restDelta = isGranularScale ? springDefaults.restDelta.granular : springDefaults.restDelta.default);
let resolveSpring;
if (dampingRatio < 1) {
const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio);
resolveSpring = (t) => {
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
return target - envelope * ((initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) / angularFreq * Math.sin(angularFreq * t) + initialDelta * Math.cos(angularFreq * t));
};
} else if (dampingRatio === 1) {
resolveSpring = (t) => target - Math.exp(-undampedAngularFreq * t) * (initialDelta + (initialVelocity + undampedAngularFreq * initialDelta) * t);
} else {
const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
resolveSpring = (t) => {
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
const freqForT = Math.min(dampedAngularFreq * t, 300);
return target - envelope * ((initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) * Math.sinh(freqForT) + dampedAngularFreq * initialDelta * Math.cosh(freqForT)) / dampedAngularFreq;
};
}
const generator = {
calculatedDuration: isResolvedFromDuration ? duration || null : null,
next: (t) => {
const current2 = resolveSpring(t);
if (!isResolvedFromDuration) {
let currentVelocity = t === 0 ? initialVelocity : 0;
if (dampingRatio < 1) {
currentVelocity = t === 0 ? /* @__PURE__ */ secondsToMilliseconds(initialVelocity) : calcGeneratorVelocity(resolveSpring, t, current2);
}
const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
const isBelowDisplacementThreshold = Math.abs(target - current2) <= restDelta;
state.done = isBelowVelocityThreshold && isBelowDisplacementThreshold;
} else {
state.done = t >= duration;
}
state.value = state.done ? target : current2;
return state;
},
toString: () => {
const calculatedDuration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);
const easing = generateLinearEasing((progress2) => generator.next(calculatedDuration * progress2).value, calculatedDuration, 30);
return calculatedDuration + "ms " + easing;
},
toTransition: () => {
}
};
return generator;
}
spring.applyToOptions = (options) => {
const generatorOptions = createGeneratorEasing(options, 100, spring);
options.ease = generatorOptions.ease;
options.duration = /* @__PURE__ */ secondsToMilliseconds(generatorOptions.duration);
options.type = "keyframes";
return options;
};
function inertia({ keyframes: keyframes2, velocity = 0, power = 0.8, timeConstant = 325, bounceDamping = 10, bounceStiffness = 500, modifyTarget, min, max, restDelta = 0.5, restSpeed }) {
const origin = keyframes2[0];
const state = {
done: false,
value: origin
};
const isOutOfBounds = (v) => min !== void 0 && v < min || max !== void 0 && v > max;
const nearestBoundary = (v) => {
if (min === void 0)
return max;
if (max === void 0)
return min;
return Math.abs(min - v) < Math.abs(max - v) ? min : max;
};
let amplitude = power * velocity;
const ideal = origin + amplitude;
const target = modifyTarget === void 0 ? ideal : modifyTarget(ideal);
if (target !== ideal)
amplitude = target - origin;
const calcDelta = (t) => -amplitude * Math.exp(-t / timeConstant);
const calcLatest = (t) => target + calcDelta(t);
const applyFriction = (t) => {
const delta = calcDelta(t);
const latest = calcLatest(t);
state.done = Math.abs(delta) <= restDelta;
state.value = state.done ? target : latest;
};
let timeReachedBoundary;
let spring$1;
const checkCatchBoundary = (t) => {
if (!isOutOfBounds(state.value))
return;
timeReachedBoundary = t;
spring$1 = spring({
keyframes: [state.value, nearestBoundary(state.value)],
velocity: calcGeneratorVelocity(calcLatest, t, state.value),
// TODO: This should be passing * 1000
damping: bounceDamping,
stiffness: bounceStiffness,
restDelta,
restSpeed
});
};
checkCatchBoundary(0);
return {
calculatedDuration: null,
next: (t) => {
let hasUpdatedFrame = false;
if (!spring$1 && timeReachedBoundary === void 0) {
hasUpdatedFrame = true;
applyFriction(t);
checkCatchBoundary(t);
}
if (timeReachedBoundary !== void 0 && t >= timeReachedBoundary) {
return spring$1.next(t - timeReachedBoundary);
} else {
!hasUpdatedFrame && applyFriction(t);
return state;
}
}
};
}
function createMixers(output, ease2, customMixer) {
const mixers = [];
const mixerFactory = customMixer || MotionGlobalConfig.mix || mix;
const numMixers = output.length - 1;
for (let i = 0; i < numMixers; i++) {
let mixer = mixerFactory(output[i], output[i + 1]);
if (ease2) {
const easingFunction = Array.isArray(ease2) ? ease2[i] || noop : ease2;
mixer = pipe(easingFunction, mixer);
}
mixers.push(mixer);
}
return mixers;
}
function interpolate(input, output, { clamp: isClamp = true, ease: ease2, mixer } = {}) {
const inputLength = input.length;
exports.invariant(inputLength === output.length, "Both input and output ranges must be the same length", "range-length");
if (inputLength === 1)
return () => output[0];
if (inputLength === 2 && output[0] === output[1])
return () => output[1];
const isZeroDeltaRange = input[0] === input[1];
if (input[0] > input[inputLength - 1]) {
input = [...input].reverse();
output = [...output].reverse();
}
const mixers = createMixers(output, ease2, mixer);
const numMixers = mixers.length;
const interpolator = (v) => {
if (isZeroDeltaRange && v < input[0])
return output[0];
let i = 0;
if (numMixers > 1) {
for (; i < input.length - 2; i++) {
if (v < input[i + 1])
break;
}
}
const progressInRange = /* @__PURE__ */ progress(input[i], input[i + 1], v);
return mixers[i](progressInRange);
};
return isClamp ? (v) => interpolator(clamp(input[0], input[inputLength - 1], v)) : interpolator;
}
function fillOffset(offset, remaining) {
const min = offset[offset.length - 1];
for (let i = 1; i <= remaining; i++) {
const offsetProgress = /* @__PURE__ */ progress(0, remaining, i);
offset.push(mixNumber$1(min, 1, offsetProgress));
}
}
function defaultOffset$1(arr) {
const offset = [0];
fillOffset(offset, arr.length - 1);
return offset;
}
function convertOffsetToTimes(offset, duration) {
return offset.map((o) => o * duration);
}
function defaultEasing(values, easing) {
return values.map(() => easing || easeInOut).splice(0, values.length - 1);
}
function keyframes({ duration = 300, keyframes: keyframeValues, times, ease: ease2 = "easeInOut" }) {
const easingFunctions = isEasingArray(ease2) ? ease2.map(easingDefinitionToFunction) : easingDefinitionToFunction(ease2);
const state = {
done: false,
value: keyframeValues[0]
};
const absoluteTimes = convertOffsetToTimes(
// Only use the provided offsets if they're the correct length
// TODO Maybe we should warn here if there's a length mismatch
times && times.length === keyframeValues.length ? times : defaultOffset$1(keyframeValues),
duration
);
const mapTimeToKeyframe = interpolate(absoluteTimes, keyframeValues, {
ease: Array.isArray(easingFunctions) ? easingFunctions : defaultEasing(keyframeValues, easingFunctions)
});
return {
calculatedDuration: duration,
next: (t) => {
state.value = mapTimeToKeyframe(t);
state.done = t >= duration;
return state;
}
};
}
const isNotNull$1 = (value) => value !== null;
function getFinalKeyframe$1(keyframes2, { repeat, repeatType = "loop" }, finalKeyframe, speed = 1) {
const resolvedKeyframes = keyframes2.filter(isNotNull$1);
const useFirstKeyframe = speed < 0 || repeat && repeatType !== "loop" && repeat % 2 === 1;
const index = useFirstKeyframe ? 0 : resolvedKeyframes.length - 1;
return !index || finalKeyframe === void 0 ? resolvedKeyframes[index] : finalKeyframe;
}
const transitionTypeMap = {
decay: inertia,
inertia,
tween: keyframes,
keyframes,
spring
};
function replaceTransitionType(transition) {
if (typeof transition.type === "string") {
transition.type = transitionTypeMap[transition.type];
}
}
class WithPromise {
constructor() {
this.updateFinished();
}
get finished() {
return this._finished;
}
updateFinished() {
this._finished = new Promise((resolve) => {
this.resolve = resolve;
});
}
notifyFinished() {
this.resolve();
}
/**
* Allows the animation to be awaited.
*
* @deprecated Use `finished` instead.
*/
then(onResolve, onReject) {
return this.finished.then(onResolve, onReject);
}
}
const percentToProgress = (percent2) => percent2 / 100;
class JSAnimation extends WithPromise {
constructor(options) {
super();
this.state = "idle";
this.startTime = null;
this.isStopped = false;
this.currentTime = 0;
this.holdTime = null;
this.playbackSpeed = 1;
this.stop = () => {
var _a, _b;
const { motionValue: motionValue2 } = this.options;
if (motionValue2 && motionValue2.updatedAt !== time.now()) {
this.tick(time.now());
}
this.isStopped = true;
if (this.state === "idle")
return;
this.teardown();
(_b = (_a = this.options).onStop) == null ? void 0 : _b.call(_a);
};
activeAnimations.mainThread++;
this.options = options;
this.initAnimation();
this.play();
if (options.autoplay === false)
this.pause();
}
initAnimation() {
const { options } = this;
replaceTransitionType(options);
const { type = keyframes, repeat = 0, repeatDelay = 0, repeatType, velocity = 0 } = options;
let { keyframes: keyframes$1 } = options;
const generatorFactory = type || keyframes;
if (process.env.NODE_ENV !== "production" && generatorFactory !== keyframes) {
exports.invariant(keyframes$1.length <= 2, `Only two keyframes currently supported with spring and inertia animations. Trying to animate ${keyframes$1}`, "spring-two-frames");
}
if (generatorFactory !== keyframes && typeof keyframes$1[0] !== "number") {
this.mixKeyframes = pipe(percentToProgress, mix(keyframes$1[0], keyframes$1[1]));
keyframes$1 = [0, 100];
}
const generator = generatorFactory({ ...options, keyframes: keyframes$1 });
if (repeatType === "mirror") {
this.mirroredGenerator = generatorFactory({
...options,
keyframes: [...keyframes$1].reverse(),
velocity: -velocity
});
}
if (generator.calculatedDuration === null) {
generator.calculatedDuration = calcGeneratorDuration(generator);
}
const { calculatedDuration } = generator;
this.calculatedDuration = calculatedDuration;
this.resolvedDuration = calculatedDuration + repeatDelay;
this.totalDuration = this.resolvedDuration * (repeat + 1) - repeatDelay;
this.generator = generator;
}
updateTime(timestamp) {
const animationTime = Math.round(timestamp - this.startTime) * this.playbackSpeed;
if (this.holdTime !== null) {
this.currentTime = this.holdTime;
} else {
this.currentTime = animationTime;
}
}
tick(timestamp, sample = false) {
const { generator, totalDuration, mixKeyframes, mirroredGenerator, resolvedDuration, calculatedDuration } = this;
if (this.startTime === null)
return generator.next(0);
const { delay: delay2 = 0, keyframes: keyframes2, repeat, repeatType, repeatDelay, type, onUpdate, finalKeyframe } = this.options;
if (this.speed > 0) {
this.startTime = Math.min(this.startTime, timestamp);
} else if (this.speed < 0) {
this.startTime = Math.min(timestamp - totalDuration / this.speed, this.startTime);
}
if (sample) {
this.currentTime = timestamp;
} else {
this.updateTime(timestamp);
}
const timeWithoutDelay = this.currentTime - delay2 * (this.playbackSpeed >= 0 ? 1 : -1);
const isInDelayPhase = this.playbackSpeed >= 0 ? timeWithoutDelay < 0 : timeWithoutDelay > totalDuration;
this.currentTime = Math.max(timeWithoutDelay, 0);
if (this.state === "finished" && this.holdTime === null) {
this.currentTime = totalDuration;
}
let elapsed = this.currentTime;
let frameGenerator = generator;
if (repeat) {
const progress2 = Math.min(this.currentTime, totalDuration) / resolvedDuration;
let currentIteration = Math.floor(progress2);
let iterationProgress = progress2 % 1;
if (!iterationProgress && progress2 >= 1) {
iterationProgress = 1;
}
iterationProgress === 1 && currentIteration--;
currentIteration = Math.min(currentIteration, repeat + 1);
const isOddIteration = Boolean(currentIteration % 2);
if (isOddIteration) {
if (repeatType === "reverse") {
iterationProgress = 1 - iterationProgress;
if (repeatDelay) {
iterationProgress -= repeatDelay / resolvedDuration;
}
} else if (repeatType === "mirror") {
frameGenerator = mirroredGenerator;
}
}
elapsed = clamp(0, 1, iterationProgress) * resolvedDuration;
}
const state = isInDelayPhase ? { done: false, value: keyframes2[0] } : frameGenerator.next(elapsed);
if (mixKeyframes) {
state.value = mixKeyframes(state.value);
}
let { done } = state;
if (!isInDelayPhase && calculatedDuration !== null) {
done = this.playbackSpeed >= 0 ? this.currentTime >= totalDuration : this.currentTime <= 0;
}
const isAnimationFinished = this.holdTime === null && (this.state === "finished" || this.state === "running" && done);
if (isAnimationFinished && type !== inertia) {
state.value = getFinalKeyframe$1(keyframes2, this.options, finalKeyframe, this.speed);
}
if (onUpdate) {
onUpdate(state.value);
}
if (isAnimationFinished) {
this.finish();
}
return state;
}
/**
* Allows the returned animation to be awaited or promise-chained. Currently
* resolves when the animation finishes at all but in a future update could/should
* reject if its cancels.
*/
then(resolve, reject) {
return this.finished.then(resolve, reject);
}
get duration() {
return /* @__PURE__ */ millisecondsToSeconds(this.calculatedDuration);
}
get time() {
return /* @__PURE__ */ millisecondsToSeconds(this.currentTime);
}
set time(newTime) {
var _a;
newTime = /* @__PURE__ */ secondsToMilliseconds(newTime);
this.currentTime = newTime;
if (this.startTime === null || this.holdTime !== null || this.playbackSpeed === 0) {
this.holdTime = newTime;
} else if (this.driver) {
this.startTime = this.driver.now() - newTime / this.playbackSpeed;
}
(_a = this.driver) == null ? void 0 : _a.start(false);
}
get speed() {
return this.playbackSpeed;
}
set speed(newSpeed) {
this.updateTime(time.now());
const hasChanged2 = this.playbackSpeed !== newSpeed;
this.playbackSpeed = newSpeed;
if (hasChanged2) {
this.time = /* @__PURE__ */ millisecondsToSeconds(this.currentTime);
}
}
play() {
var _a, _b;
if (this.isStopped)
return;
const { driver = frameloopDriver, startTime } = this.options;
if (!this.driver) {
this.driver = driver((timestamp) => this.tick(timestamp));
}
(_b = (_a = this.options).onPlay) == null ? void 0 : _b.call(_a);
const now2 = this.driver.now();
if (this.state === "finished") {
this.updateFinished();
this.startTime = now2;
} else if (this.holdTime !== null) {
this.startTime = now2 - this.holdTime;
} else if (!this.startTime) {
this.startTime = startTime ?? now2;
}
if (this.state === "finished" && this.speed < 0) {
this.startTime += this.calculatedDuration;
}
this.holdTime = null;
this.state = "running";
this.driver.start();
}
pause() {
this.state = "paused";
this.updateTime(time.now());
this.holdTime = this.currentTime;
}
complete() {
if (this.state !== "running") {
this.play();
}
this.state = "finished";
this.holdTime = null;
}
finish() {
var _a, _b;
this.notifyFinished();
this.teardown();
this.state = "finished";
(_b = (_a = this.options).onComplete) == null ? void 0 : _b.call(_a);
}
cancel() {
var _a, _b;
this.holdTime = null;
this.startTime = 0;
this.tick(0);
this.teardown();
(_b = (_a = this.options).onCancel) == null ? void 0 : _b.call(_a);
}
teardown() {
this.state = "idle";
this.stopDriver();
this.startTime = this.holdTime = null;
activeAnimations.mainThread--;
}
stopDriver() {
if (!this.driver)
return;
this.driver.stop();
this.driver = void 0;
}
sample(sampleTime) {
this.startTime = 0;
return this.tick(sampleTime, true);
}
attachTimeline(timeline) {
var _a;
if (this.options.allowFlatten) {
this.options.type = "keyframes";
this.options.ease = "linear";
this.initAnimation();
}
(_a = this.driver) == null ? void 0 : _a.stop();
return timeline.observe(this);
}
}
function animateValue(options) {
return new JSAnimation(options);
}
function fillWildcards(keyframes2) {
for (let i = 1; i < keyframes2.length; i++) {
keyframes2[i] ?? (keyframes2[i] = keyframes2[i - 1]);
}
}
const radToDeg = (rad) => rad * 180 / Math.PI;
const rotate = (v) => {
const angle = radToDeg(Math.atan2(v[1], v[0]));
return rebaseAngle(angle);
};
const matrix2dParsers = {
x: 4,
y: 5,
translateX: 4,
translateY: 5,
scaleX: 0,
scaleY: 3,
scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2,
rotate,
rotateZ: rotate,
skewX: (v) => radToDeg(Math.atan(v[1])),
skewY: (v) => radToDeg(Math.atan(v[2])),
skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2
};
const rebaseAngle = (angle) => {
angle = angle % 360;
if (angle < 0)
angle += 360;
return angle;
};
const rotateZ = rotate;
const scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]);
const scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]);
const matrix3dParsers = {
x: 12,
y: 13,
z: 14,
translateX: 12,
translateY: 13,
translateZ: 14,
scaleX,
scaleY,
scale: (v) => (scaleX(v) + scaleY(v)) / 2,
rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))),
rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))),
rotateZ,
rotate: rotateZ,
skewX: (v) => radToDeg(Math.atan(v[4])),
skewY: (v) => radToDeg(Math.atan(v[1])),
skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2
};
function defaultTransformValue(name) {
return name.includes("scale") ? 1 : 0;
}
function parseValueFromTransform(transform2, name) {
if (!transform2 || transform2 === "none") {
return defaultTransformValue(name);
}
const matrix3dMatch = transform