framer-motion
Version:
<p align="center"> <img src="https://user-images.githubusercontent.com/38039349/60953119-d3c6f300-a2fc-11e9-9596-4978e5d52180.png" width="176" height="170" alt="Framer Motion" /> </p>
1,262 lines (1,211 loc) • 276 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
(global = global || self, factory(global.Motion = {}, global.React));
}(this, function (exports, React) { 'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
/**
* Uses the ref that is passed in, or creates a new one
* @param external - External ref
* @internal
*/
function useExternalRef(external) {
// We're conditionally calling `useRef` here which is sort of naughty as hooks
// shouldn't be called conditionally. However, Framer Motion will break if this
// condition changes anyway. It might be possible to use an invariant here to
// make it explicit, but I expect changing `ref` is not normal behaviour.
var ref = !external || typeof external === "function" ? React.useRef(null) : external;
React.useEffect(function () {
if (external && typeof external === "function") {
external(ref.current);
return function () { return external(null); };
}
}, []);
return ref;
}
var warning = function () { };
var invariant = function () { };
{
warning = function (check, message) {
if (!check && typeof console !== 'undefined') {
console.warn(message);
}
};
invariant = function (check, message) {
if (!check) {
throw new Error(message);
}
};
}
var prevTime = 0;
var onNextFrame = typeof window !== 'undefined' && window.requestAnimationFrame !== undefined
? function (callback) { return window.requestAnimationFrame(callback); }
: function (callback) {
var timestamp = Date.now();
var timeToCall = Math.max(0, 16.7 - (timestamp - prevTime));
prevTime = timestamp + timeToCall;
setTimeout(function () { return callback(prevTime); }, timeToCall);
};
var createStep = (function (setRunNextFrame) {
var processToRun = [];
var processToRunNextFrame = [];
var numThisFrame = 0;
var isProcessing = false;
var i = 0;
var cancelled = new WeakSet();
var toKeepAlive = new WeakSet();
var renderStep = {
cancel: function (process) {
var indexOfCallback = processToRunNextFrame.indexOf(process);
cancelled.add(process);
if (indexOfCallback !== -1) {
processToRunNextFrame.splice(indexOfCallback, 1);
}
},
process: function (frame) {
var _a;
isProcessing = true;
_a = [
processToRunNextFrame,
processToRun
], processToRun = _a[0], processToRunNextFrame = _a[1];
processToRunNextFrame.length = 0;
numThisFrame = processToRun.length;
if (numThisFrame) {
var process_1;
for (i = 0; i < numThisFrame; i++) {
process_1 = processToRun[i];
process_1(frame);
if (toKeepAlive.has(process_1) === true && !cancelled.has(process_1)) {
renderStep.schedule(process_1);
setRunNextFrame(true);
}
}
}
isProcessing = false;
},
schedule: function (process, keepAlive, immediate) {
if (keepAlive === void 0) { keepAlive = false; }
if (immediate === void 0) { immediate = false; }
invariant(typeof process === 'function', 'Argument must be a function');
var addToCurrentBuffer = immediate && isProcessing;
var buffer = addToCurrentBuffer ? processToRun : processToRunNextFrame;
cancelled.delete(process);
if (keepAlive)
toKeepAlive.add(process);
if (buffer.indexOf(process) === -1) {
buffer.push(process);
if (addToCurrentBuffer)
numThisFrame = processToRun.length;
}
}
};
return renderStep;
});
var StepId;
(function (StepId) {
StepId["Read"] = "read";
StepId["Update"] = "update";
StepId["Render"] = "render";
StepId["PostRender"] = "postRender";
StepId["FixedUpdate"] = "fixedUpdate";
})(StepId || (StepId = {}));
var maxElapsed = 40;
var defaultElapsed = (1 / 60) * 1000;
var useDefaultElapsed = true;
var willRunNextFrame = false;
var isProcessing = false;
var frame = {
delta: 0,
timestamp: 0
};
var stepsOrder = [
StepId.Read,
StepId.Update,
StepId.Render,
StepId.PostRender
];
var setWillRunNextFrame = function (willRun) { return (willRunNextFrame = willRun); };
var _a = stepsOrder.reduce(function (acc, key) {
var step = createStep(setWillRunNextFrame);
acc.sync[key] = function (process, keepAlive, immediate) {
if (keepAlive === void 0) { keepAlive = false; }
if (immediate === void 0) { immediate = false; }
if (!willRunNextFrame)
startLoop();
step.schedule(process, keepAlive, immediate);
return process;
};
acc.cancelSync[key] = function (process) { return step.cancel(process); };
acc.steps[key] = step;
return acc;
}, {
steps: {},
sync: {},
cancelSync: {}
}), steps = _a.steps, sync = _a.sync, cancelSync = _a.cancelSync;
var processStep = function (stepId) { return steps[stepId].process(frame); };
var processFrame = function (timestamp) {
willRunNextFrame = false;
frame.delta = useDefaultElapsed
? defaultElapsed
: Math.max(Math.min(timestamp - frame.timestamp, maxElapsed), 1);
if (!useDefaultElapsed)
defaultElapsed = frame.delta;
frame.timestamp = timestamp;
isProcessing = true;
stepsOrder.forEach(processStep);
isProcessing = false;
if (willRunNextFrame) {
useDefaultElapsed = false;
onNextFrame(processFrame);
}
};
var startLoop = function () {
willRunNextFrame = true;
useDefaultElapsed = true;
if (!isProcessing)
onNextFrame(processFrame);
};
var getFrameData = function () { return frame; };
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
var __assign$1 = function() {
__assign$1 = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign$1.apply(this, arguments);
};
var clamp = function (min, max) { return function (v) {
return Math.max(Math.min(v, max), min);
}; };
var sanitize = function (v) { return (v % 1 ? Number(v.toFixed(5)) : v); };
var floatRegex = /(-)?(\d[\d\.]*)/g;
var colorRegex = /(#[0-9a-f]{6}|#[0-9a-f]{3}|#(?:[0-9a-f]{2}){2,4}|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d\.]+%?\))/gi;
var singleColorRegex = /^(#[0-9a-f]{3}|#(?:[0-9a-f]{2}){2,4}|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d\.]+%?\))$/i;
var number = {
test: function (v) { return typeof v === 'number'; },
parse: parseFloat,
transform: function (v) { return v; }
};
var alpha = __assign$1({}, number, { transform: clamp(0, 1) });
var scale = __assign$1({}, number, { default: 1 });
var createUnitType = function (unit) { return ({
test: function (v) {
return typeof v === 'string' && v.endsWith(unit) && v.split(' ').length === 1;
},
parse: parseFloat,
transform: function (v) { return "" + v + unit; }
}); };
var degrees = createUnitType('deg');
var percent = createUnitType('%');
var px = createUnitType('px');
var vh = createUnitType('vh');
var vw = createUnitType('vw');
var progressPercentage = __assign$1({}, percent, { parse: function (v) { return percent.parse(v) / 100; }, transform: function (v) { return percent.transform(v * 100); } });
var getValueFromFunctionString = function (value) {
return value.substring(value.indexOf('(') + 1, value.lastIndexOf(')'));
};
var clampRgbUnit = clamp(0, 255);
var isRgba = function (v) { return v.red !== undefined; };
var isHsla = function (v) { return v.hue !== undefined; };
var splitColorValues = function (terms) {
return function (v) {
if (typeof v !== 'string')
return v;
var values = {};
var valuesArray = getValueFromFunctionString(v).split(/,\s*/);
for (var i = 0; i < 4; i++) {
values[terms[i]] =
valuesArray[i] !== undefined ? parseFloat(valuesArray[i]) : 1;
}
return values;
};
};
var rgbaTemplate = function (_a) {
var red = _a.red, green = _a.green, blue = _a.blue, _b = _a.alpha, alpha$$1 = _b === void 0 ? 1 : _b;
return "rgba(" + red + ", " + green + ", " + blue + ", " + alpha$$1 + ")";
};
var hslaTemplate = function (_a) {
var hue = _a.hue, saturation = _a.saturation, lightness = _a.lightness, _b = _a.alpha, alpha$$1 = _b === void 0 ? 1 : _b;
return "hsla(" + hue + ", " + saturation + ", " + lightness + ", " + alpha$$1 + ")";
};
var rgbUnit = __assign$1({}, number, { transform: function (v) { return Math.round(clampRgbUnit(v)); } });
function isColorString(color, colorType) {
return color.startsWith(colorType) && singleColorRegex.test(color);
}
var rgba = {
test: function (v) { return (typeof v === 'string' ? isColorString(v, 'rgb') : isRgba(v)); },
parse: splitColorValues(['red', 'green', 'blue', 'alpha']),
transform: function (_a) {
var red = _a.red, green = _a.green, blue = _a.blue, _b = _a.alpha, alpha$$1 = _b === void 0 ? 1 : _b;
return rgbaTemplate({
red: rgbUnit.transform(red),
green: rgbUnit.transform(green),
blue: rgbUnit.transform(blue),
alpha: sanitize(alpha.transform(alpha$$1))
});
}
};
var hsla = {
test: function (v) { return (typeof v === 'string' ? isColorString(v, 'hsl') : isHsla(v)); },
parse: splitColorValues(['hue', 'saturation', 'lightness', 'alpha']),
transform: function (_a) {
var hue = _a.hue, saturation = _a.saturation, lightness = _a.lightness, _b = _a.alpha, alpha$$1 = _b === void 0 ? 1 : _b;
return hslaTemplate({
hue: Math.round(hue),
saturation: percent.transform(sanitize(saturation)),
lightness: percent.transform(sanitize(lightness)),
alpha: sanitize(alpha.transform(alpha$$1))
});
}
};
var hex = __assign$1({}, rgba, { test: function (v) { return typeof v === 'string' && isColorString(v, '#'); }, parse: function (v) {
var r = '';
var g = '';
var b = '';
if (v.length > 4) {
r = v.substr(1, 2);
g = v.substr(3, 2);
b = v.substr(5, 2);
}
else {
r = v.substr(1, 1);
g = v.substr(2, 1);
b = v.substr(3, 1);
r += r;
g += g;
b += b;
}
return {
red: parseInt(r, 16),
green: parseInt(g, 16),
blue: parseInt(b, 16),
alpha: 1
};
} });
var color = {
test: function (v) {
return (typeof v === 'string' && singleColorRegex.test(v)) ||
isRgba(v) ||
isHsla(v);
},
parse: function (v) {
if (rgba.test(v)) {
return rgba.parse(v);
}
else if (hsla.test(v)) {
return hsla.parse(v);
}
else if (hex.test(v)) {
return hex.parse(v);
}
return v;
},
transform: function (v) {
if (isRgba(v)) {
return rgba.transform(v);
}
else if (isHsla(v)) {
return hsla.transform(v);
}
return v;
}
};
var COLOR_TOKEN = '${c}';
var NUMBER_TOKEN = '${n}';
var convertNumbersToZero = function (v) {
return typeof v === 'number' ? 0 : v;
};
var complex = {
test: function (v) {
if (typeof v !== 'string' || !isNaN(v))
return false;
var numValues = 0;
var foundNumbers = v.match(floatRegex);
var foundColors = v.match(colorRegex);
if (foundNumbers)
numValues += foundNumbers.length;
if (foundColors)
numValues += foundColors.length;
return numValues > 0;
},
parse: function (v) {
var input = v;
var parsed = [];
var foundColors = input.match(colorRegex);
if (foundColors) {
input = input.replace(colorRegex, COLOR_TOKEN);
parsed.push.apply(parsed, foundColors.map(color.parse));
}
var foundNumbers = input.match(floatRegex);
if (foundNumbers) {
parsed.push.apply(parsed, foundNumbers.map(number.parse));
}
return parsed;
},
createTransformer: function (prop) {
var template = prop;
var token = 0;
var foundColors = prop.match(colorRegex);
var numColors = foundColors ? foundColors.length : 0;
if (foundColors) {
for (var i = 0; i < numColors; i++) {
template = template.replace(foundColors[i], COLOR_TOKEN);
token++;
}
}
var foundNumbers = template.match(floatRegex);
var numNumbers = foundNumbers ? foundNumbers.length : 0;
if (foundNumbers) {
for (var i = 0; i < numNumbers; i++) {
template = template.replace(foundNumbers[i], NUMBER_TOKEN);
token++;
}
}
return function (v) {
var output = template;
for (var i = 0; i < token; i++) {
output = output.replace(i < numColors ? COLOR_TOKEN : NUMBER_TOKEN, i < numColors ? color.transform(v[i]) : sanitize(v[i]));
}
return output;
};
},
getAnimatableNone: function (target) {
var parsedTarget = complex.parse(target);
var targetTransformer = complex.createTransformer(target);
return targetTransformer(parsedTarget.map(convertNumbersToZero));
}
};
var zeroPoint = {
x: 0,
y: 0,
z: 0
};
var isNum = function (v) { return typeof v === 'number'; };
var curryRange = (function (func) { return function (min, max, v) { return (v !== undefined ? func(min, max, v) : function (cv) { return func(min, max, cv); }); }; });
var clamp$1 = function (min, max, v) {
return Math.min(Math.max(v, min), max);
};
var clamp$1$1 = curryRange(clamp$1);
var isPoint = (function (point) {
return point.hasOwnProperty('x') && point.hasOwnProperty('y');
});
var isPoint3D = (function (point) {
return isPoint(point) && point.hasOwnProperty('z');
});
var distance1D = function (a, b) { return Math.abs(a - b); };
var distance = (function (a, b) {
if (b === void 0) { b = zeroPoint; }
if (isNum(a) && isNum(b)) {
return distance1D(a, b);
}
else if (isPoint(a) && isPoint(b)) {
var xDelta = distance1D(a.x, b.x);
var yDelta = distance1D(a.y, b.y);
var zDelta = isPoint3D(a) && isPoint3D(b) ? distance1D(a.z, b.z) : 0;
return Math.sqrt(Math.pow(xDelta, 2) + Math.pow(yDelta, 2) + Math.pow(zDelta, 2));
}
return 0;
});
var progress = (function (from, to, value) {
var toFromDifference = to - from;
return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
});
var mix = (function (from, to, progress) {
return -progress * from + progress * to + from;
});
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
var __assign$2 = function() {
__assign$2 = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign$2.apply(this, arguments);
};
var mixLinearColor = function (from, to, v) {
var fromExpo = from * from;
var toExpo = to * to;
return Math.sqrt(Math.max(0, v * (toExpo - fromExpo) + fromExpo));
};
var colorTypes = [hex, rgba, hsla];
var getColorType = function (v) {
return colorTypes.find(function (type) { return type.test(v); });
};
var notAnimatable = function (color$$1) {
return "'" + color$$1 + "' is not an animatable color. Use the equivalent color code instead.";
};
var mixColor = (function (from, to) {
var fromColorType = getColorType(from);
var toColorType = getColorType(to);
invariant(!!fromColorType, notAnimatable(from));
invariant(!!toColorType, notAnimatable(to));
invariant(fromColorType.transform === toColorType.transform, 'Both colors must be hex/RGBA, OR both must be HSLA.');
var fromColor = fromColorType.parse(from);
var toColor = toColorType.parse(to);
var blended = __assign$2({}, fromColor);
var mixFunc = fromColorType === hsla ? mix : mixLinearColor;
return function (v) {
for (var key in blended) {
if (key !== 'alpha') {
blended[key] = mixFunc(fromColor[key], toColor[key], v);
}
}
blended.alpha = mix(fromColor.alpha, toColor.alpha, v);
return fromColorType.transform(blended);
};
});
var combineFunctions = function (a, b) { return function (v) { return b(a(v)); }; };
var pipe = (function () {
var transformers = [];
for (var _i = 0; _i < arguments.length; _i++) {
transformers[_i] = arguments[_i];
}
return transformers.reduce(combineFunctions);
});
function getMixer(origin, target) {
if (isNum(origin)) {
return function (v) { return mix(origin, target, v); };
}
else if (color.test(origin)) {
return mixColor(origin, target);
}
else {
return mixComplex(origin, target);
}
}
var mixArray = function (from, to) {
var output = from.slice();
var numValues = output.length;
var blendValue = from.map(function (fromThis, i) { return getMixer(fromThis, to[i]); });
return function (v) {
for (var i = 0; i < numValues; i++) {
output[i] = blendValue[i](v);
}
return output;
};
};
var mixObject = function (origin, target) {
var output = __assign$2({}, origin, target);
var blendValue = {};
for (var key in output) {
if (origin[key] !== undefined && target[key] !== undefined) {
blendValue[key] = getMixer(origin[key], target[key]);
}
}
return function (v) {
for (var key in blendValue) {
output[key] = blendValue[key](v);
}
return output;
};
};
function analyse(value) {
var parsed = complex.parse(value);
var numValues = parsed.length;
var numNumbers = 0;
var numRGB = 0;
var numHSL = 0;
for (var i = 0; i < numValues; i++) {
if (numNumbers || typeof parsed[i] === 'number') {
numNumbers++;
}
else {
if (parsed[i].hue !== undefined) {
numHSL++;
}
else {
numRGB++;
}
}
}
return { parsed: parsed, numNumbers: numNumbers, numRGB: numRGB, numHSL: numHSL };
}
var mixComplex = function (origin, target) {
var template = complex.createTransformer(target);
var originStats = analyse(origin);
var targetStats = analyse(target);
invariant(originStats.numHSL === targetStats.numHSL &&
originStats.numRGB === targetStats.numRGB &&
originStats.numNumbers >= targetStats.numNumbers, "Complex values '" + origin + "' and '" + target + "' too different to mix. Ensure all colors are of the same type.");
return pipe(mixArray(originStats.parsed, targetStats.parsed), template);
};
var mixNumber = function (from, to) { return function (p) { return mix(from, to, p); }; };
function detectMixerFactory(v) {
if (typeof v === 'number') {
return mixNumber;
}
else if (typeof v === 'string') {
if (color.test(v)) {
return mixColor;
}
else {
return mixComplex;
}
}
else if (Array.isArray(v)) {
return mixArray;
}
else if (typeof v === 'object') {
return mixObject;
}
}
function createMixers(output, ease, customMixer) {
var mixers = [];
var mixerFactory = customMixer || detectMixerFactory(output[0]);
var numMixers = output.length - 1;
for (var i = 0; i < numMixers; i++) {
var mixer = mixerFactory(output[i], output[i + 1]);
if (ease) {
var easingFunction = Array.isArray(ease) ? ease[i] : ease;
mixer = pipe(easingFunction, mixer);
}
mixers.push(mixer);
}
return mixers;
}
function fastInterpolate(_a, _b) {
var from = _a[0], to = _a[1];
var mixer = _b[0];
return function (v) { return mixer(progress(from, to, v)); };
}
function slowInterpolate(input, mixers) {
var inputLength = input.length;
var lastInputIndex = inputLength - 1;
return function (v) {
var mixerIndex = 0;
var foundMixerIndex = false;
if (v <= input[0]) {
foundMixerIndex = true;
}
else if (v >= input[lastInputIndex]) {
mixerIndex = lastInputIndex - 1;
foundMixerIndex = true;
}
if (!foundMixerIndex) {
var i = 1;
for (; i < inputLength; i++) {
if (input[i] > v || i === lastInputIndex) {
break;
}
}
mixerIndex = i - 1;
}
var progressInRange = progress(input[mixerIndex], input[mixerIndex + 1], v);
return mixers[mixerIndex](progressInRange);
};
}
function interpolate(input, output, _a) {
var _b = _a === void 0 ? {} : _a, _c = _b.clamp, clamp = _c === void 0 ? true : _c, ease = _b.ease, mixer = _b.mixer;
var inputLength = input.length;
invariant(inputLength === output.length, 'Both input and output ranges must be the same length');
invariant(!ease || !Array.isArray(ease) || ease.length === inputLength - 1, 'Array of easing functions must be of length `input.length - 1`, as it applies to the transitions **between** the defined values.');
if (input[0] > input[inputLength - 1]) {
input = [].concat(input);
output = [].concat(output);
input.reverse();
output.reverse();
}
var mixers = createMixers(output, ease, mixer);
var interpolator = inputLength === 2
? fastInterpolate(input, mixers)
: slowInterpolate(input, mixers);
return clamp
? pipe(clamp$1$1(input[0], input[inputLength - 1]), interpolator)
: interpolator;
}
var velocityPerSecond = (function (velocity, frameDuration) {
return frameDuration ? velocity * (1000 / frameDuration) : 0;
});
var wrap = function (min, max, v) {
var rangeSize = max - min;
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
};
var wrap$1 = curryRange(wrap);
var clampProgress = clamp$1$1(0, 1);
var isFloat = function (value) {
return !isNaN(parseFloat(value));
};
/**
* `MotionValue` is used to track the state and velocity of motion values.
*
* @public
*/
var MotionValue = /** @class */ (function () {
/**
* @param init - The initiating value
* @param config - Optional configuration options
*
* - `transformer`: A function to transform incoming values with.
*
* @internal
*/
function MotionValue(init, _a) {
var _this = this;
var _b = _a === void 0 ? {} : _a, transformer = _b.transformer, parent = _b.parent;
/**
* Duration, in milliseconds, since last updating frame.
*
* @internal
*/
this.timeDelta = 0;
/**
* Timestamp of the last time this `MotionValue` was updated.
*
* @internal
*/
this.lastUpdated = 0;
/**
* Tracks whether this value can output a velocity. Currently this is only true
* if the value is numerical, but we might be able to widen the scope here and support
* other value types.
*
* @internal
*/
this.canTrackVelocity = false;
this.updateAndNotify = function (v, render) {
if (render === void 0) { render = true; }
_this.prev = _this.current;
_this.current = _this.transformer ? _this.transformer(v) : v;
if (_this.updateSubscribers && _this.prev !== _this.current) {
_this.updateSubscribers.forEach(_this.notifySubscriber);
}
if (_this.children) {
_this.children.forEach(_this.setChild);
}
if (render && _this.renderSubscribers) {
_this.renderSubscribers.forEach(_this.notifySubscriber);
}
// Update timestamp
var _a = getFrameData(), delta = _a.delta, timestamp = _a.timestamp;
if (_this.lastUpdated !== timestamp) {
_this.timeDelta = delta;
_this.lastUpdated = timestamp;
sync.postRender(_this.scheduleVelocityCheck);
}
};
/**
* Notify a subscriber with the latest value.
*
* This is an instanced and bound function to prevent generating a new
* function once per frame.
*
* @param subscriber - The subscriber to notify.
*
* @internal
*/
this.notifySubscriber = function (subscriber) {
subscriber(_this.current);
};
/**
* Schedule a velocity check for the next frame.
*
* This is an instanced and bound function to prevent generating a new
* function once per frame.
*
* @internal
*/
this.scheduleVelocityCheck = function () { return sync.postRender(_this.velocityCheck); };
/**
* Updates `prev` with `current` if the value hasn't been updated this frame.
* This ensures velocity calculations return `0`.
*
* This is an instanced and bound function to prevent generating a new
* function once per frame.
*
* @internal
*/
this.velocityCheck = function (_a) {
var timestamp = _a.timestamp;
if (timestamp !== _this.lastUpdated) {
_this.prev = _this.current;
}
};
/**
* Updates child `MotionValue`.
*
* @param child - Child `MotionValue`.
*
* @internal
*/
this.setChild = function (child) { return child.set(_this.current); };
this.parent = parent;
this.transformer = transformer;
this.set(init, false);
this.canTrackVelocity = isFloat(this.current);
}
/**
* Creates a new `MotionValue` that's subscribed to the output of this one.
*
* @param config - Optional configuration options
*
* - `transformer`: A function to transform incoming values with.
*
* @internal
*/
MotionValue.prototype.addChild = function (config) {
if (config === void 0) { config = {}; }
var child = new MotionValue(this.current, __assign({ parent: this }, config));
if (!this.children)
this.children = new Set();
this.children.add(child);
return child;
};
/**
* Stops a `MotionValue` from being subscribed to this one.
*
* @param child - The subscribed `MotionValue`
*
* @internal
*/
MotionValue.prototype.removeChild = function (child) {
if (!this.children) {
return;
}
this.children.delete(child);
};
/**
* Subscribes a subscriber function to a subscription list.
*
* @param subscriptions - A `Set` of subscribers.
* @param subscription - A subscriber function.
*/
MotionValue.prototype.subscribeTo = function (subscriptions, subscription) {
var _this = this;
var updateSubscriber = function () { return subscription(_this.current); };
subscriptions.add(updateSubscriber);
return function () { return subscriptions.delete(updateSubscriber); };
};
/**
* Adds a function that will be notified when the `MotionValue` is updated.
*
* It returns a function that, when called, will cancel the subscription.
*
* When calling `onChange` inside a React component, it should be wrapped with the
* `useEffect` hook. As it returns an unsubscribe function, this should be returned
* from the `useEffect` function to ensure you don't add duplicate subscribers..
*
* @library
*
* ```jsx
* function MyComponent() {
* const x = useMotionValue(0)
* const y = useMotionValue(0)
* const opacity = useMotionValue(1)
*
* useEffect(() => {
* function updateOpacity() {
* const maxXY = Math.max(x.get(), y.get())
* const newOpacity = transform(maxXY, [0, 100], [1, 0])
* opacity.set(newOpacity)
* }
*
* const unsubscribeX = x.onChange(updateOpacity)
* const unsubscribeY = y.onChange(updateOpacity)
*
* return () => {
* unsubscribeX()
* unsubscribeY()
* }
* }, [])
*
* return <Frame x={x} />
* }
* ```
*
* @motion
*
* ```jsx
* export const MyComponent = () => {
* const x = useMotionValue(0)
* const y = useMotionValue(0)
* const opacity = useMotionValue(1)
*
* useEffect(() => {
* function updateOpacity() {
* const maxXY = Math.max(x.get(), y.get())
* const newOpacity = transform(maxXY, [0, 100], [1, 0])
* opacity.set(newOpacity)
* }
*
* const unsubscribeX = x.onChange(updateOpacity)
* const unsubscribeY = y.onChange(updateOpacity)
*
* return () => {
* unsubscribeX()
* unsubscribeY()
* }
* }, [])
*
* return <motion.div style={{ x }} />
* }
* ```
*
* @internalremarks
*
* We could look into a `useOnChange` hook if the above lifecycle management proves confusing.
*
* ```jsx
* useOnChange(x, () => {})
* ```
*
* @param subscriber - A function that receives the latest value.
* @returns A function that, when called, will cancel this subscription.
*
* @public
*/
MotionValue.prototype.onChange = function (subscription) {
if (!this.updateSubscribers)
this.updateSubscribers = new Set();
return this.subscribeTo(this.updateSubscribers, subscription);
};
/**
* Adds a function that will be notified when the `MotionValue` requests a render.
*
* @param subscriber - A function that's provided the latest value.
* @returns A function that, when called, will cancel this subscription.
*
* @internal
*/
MotionValue.prototype.onRenderRequest = function (subscription) {
if (!this.renderSubscribers)
this.renderSubscribers = new Set();
// Render immediately
this.notifySubscriber(subscription);
return this.subscribeTo(this.renderSubscribers, subscription);
};
/**
* Attaches a passive effect to the `MotionValue`.
*
* @internal
*/
MotionValue.prototype.attach = function (passiveEffect) {
this.passiveEffect = passiveEffect;
};
/**
* Sets the state of the `MotionValue`.
*
* @remarks
*
* ```jsx
* const x = useMotionValue(0)
* x.set(10)
* ```
*
* @param latest - Latest value to set.
* @param render - Whether to notify render subscribers. Defaults to `true`
*
* @public
*/
MotionValue.prototype.set = function (v, render) {
if (render === void 0) { render = true; }
if (!render || !this.passiveEffect) {
this.updateAndNotify(v, render);
}
else {
this.passiveEffect(v, this.updateAndNotify);
}
};
/**
* Returns the latest state of `MotionValue`
*
* @returns - The latest state of `MotionValue`
*
* @public
*/
MotionValue.prototype.get = function () {
return this.current;
};
/**
* Returns the latest velocity of `MotionValue`
*
* @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical.
*
* @public
*/
MotionValue.prototype.getVelocity = function () {
// This could be isFloat(this.prev) && isFloat(this.current), but that would be wasteful
return this.canTrackVelocity
? // These casts could be avoided if parseFloat would be typed better
velocityPerSecond(parseFloat(this.current) -
parseFloat(this.prev), this.timeDelta)
: 0;
};
/**
* Registers a new animation to control this `MotionValue`. Only one
* animation can drive a `MotionValue` at one time.
*
* ```jsx
* value.start()
* ```
*
* @param animation - A function that starts the provided animation
*
* @internal
*/
MotionValue.prototype.start = function (animation) {
var _this = this;
this.stop();
return new Promise(function (resolve) {
_this.stopAnimation = animation(resolve);
}).then(function () { return _this.clearAnimation(); });
};
/**
* Stop the currently active animation.
*
* @public
*/
MotionValue.prototype.stop = function () {
if (this.stopAnimation)
this.stopAnimation();
this.clearAnimation();
};
/**
* Returns `true` if this value is currently animating.
*
* @public
*/
MotionValue.prototype.isAnimating = function () {
return !!this.stopAnimation;
};
MotionValue.prototype.clearAnimation = function () {
this.stopAnimation = null;
};
/**
* Destroy and clean up subscribers to this `MotionValue`.
*
* The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically
* handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually
* created a `MotionValue` via the `motionValue` function.
*
* @public
*/
MotionValue.prototype.destroy = function () {
this.updateSubscribers && this.updateSubscribers.clear();
this.renderSubscribers && this.renderSubscribers.clear();
this.parent && this.parent.removeChild(this);
this.stop();
};
return MotionValue;
}());
/**
* @internal
*/
function motionValue(init, opts) {
return new MotionValue(init, opts);
}
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
var __assign$3 = function () {
__assign$3 = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign$3.apply(this, arguments);
};
function __rest$1(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]];
return t;
}
var createStyler = function (_a) {
var onRead = _a.onRead,
onRender = _a.onRender,
_b = _a.uncachedValues,
uncachedValues = _b === void 0 ? new Set() : _b,
_c = _a.useCache,
useCache = _c === void 0 ? true : _c;
return function (_a) {
if (_a === void 0) {
_a = {};
}
var props = __rest$1(_a, []);
var state = {};
var changedValues = [];
var hasChanged = false;
function setValue(key, value) {
if (key.startsWith('--')) {
props.hasCSSVariable = true;
}
var currentValue = state[key];
state[key] = value;
if (state[key] === currentValue) return;
if (changedValues.indexOf(key) === -1) {
changedValues.push(key);
}
if (!hasChanged) {
hasChanged = true;
sync.render(styler.render);
}
}
var styler = {
get: function (key, forceRead) {
if (forceRead === void 0) {
forceRead = false;
}
var useCached = !forceRead && useCache && !uncachedValues.has(key) && state[key] !== undefined;
return useCached ? state[key] : onRead(key, props);
},
set: function (values, value) {
if (typeof values === 'string') {
setValue(values, value);
} else {
for (var key in values) {
setValue(key, values[key]);
}
}
return this;
},
render: function (forceRender) {
if (forceRender === void 0) {
forceRender = false;
}
if (hasChanged || forceRender === true) {
onRender(state, props, changedValues);
hasChanged = false;
changedValues.length = 0;
}
return this;
}
};
return styler;
};
};
var CAMEL_CASE_PATTERN = /([a-z])([A-Z])/g;
var REPLACE_TEMPLATE = '$1-$2';
var camelToDash = function (str) {
return str.replace(CAMEL_CASE_PATTERN, REPLACE_TEMPLATE).toLowerCase();
};
var camelCache = /*#__PURE__*/new Map();
var dashCache = /*#__PURE__*/new Map();
var prefixes = ['Webkit', 'Moz', 'O', 'ms', ''];
var numPrefixes = prefixes.length;
var isBrowser = typeof document !== 'undefined';
var testElement;
var setDashPrefix = function (key, prefixed) {
return dashCache.set(key, camelToDash(prefixed));
};
var testPrefix = function (key) {
testElement = testElement || document.createElement('div');
for (var i = 0; i < numPrefixes; i++) {
var prefix = prefixes[i];
var noPrefix = prefix === '';
var prefixedPropertyName = noPrefix ? key : prefix + key.charAt(0).toUpperCase() + key.slice(1);
if (prefixedPropertyName in testElement.style || noPrefix) {
camelCache.set(key, prefixedPropertyName);
setDashPrefix(key, "" + (noPrefix ? '' : '-') + camelToDash(prefixedPropertyName));
}
}
};
var setServerProperty = function (key) {
return setDashPrefix(key, key);
};
var prefixer = function (key, asDashCase) {
if (asDashCase === void 0) {
asDashCase = false;
}
var cache = asDashCase ? dashCache : camelCache;
if (!cache.has(key)) isBrowser ? testPrefix(key) : setServerProperty(key);
return cache.get(key) || key;
};
var axes = ['', 'X', 'Y', 'Z'];
var order = ['translate', 'scale', 'rotate', 'skew', 'transformPerspective'];
var transformProps = /*#__PURE__*/order.reduce(function (acc, key) {
return axes.reduce(function (axesAcc, axesKey) {
axesAcc.push(key + axesKey);
return axesAcc;
}, acc);
}, ['x', 'y', 'z']);
var transformPropDictionary = /*#__PURE__*/transformProps.reduce(function (dict, key) {
dict[key] = true;
return dict;
}, {});
function isTransformProp(key) {
return transformPropDictionary[key] === true;
}
function sortTransformProps(a, b) {
return transformProps.indexOf(a) - transformProps.indexOf(b);
}
var transformOriginProps = /*#__PURE__*/new Set(['originX', 'originY', 'originZ']);
function isTransformOriginProp(key) {
return transformOriginProps.has(key);
}
var int = /*#__PURE__*/__assign$3({}, number, { transform: Math.round });
var valueTypes = {
color: color,
backgroundColor: color,
outlineColor: color,