framer-motion 10.2.4 → 10.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/dom-entry.js +1 -1
- package/dist/cjs/index.js +24 -8
- package/dist/cjs/{wrap-62da7859.js → wrap-462b1507.js} +97 -48
- package/dist/dom-entry.d.ts +4 -1
- package/dist/es/animation/GroupPlaybackControls.mjs +18 -6
- package/dist/es/animation/create-instant-animation.mjs +6 -2
- package/dist/es/animation/js/index.mjs +48 -19
- package/dist/es/animation/optimized-appear/handoff.mjs +1 -1
- package/dist/es/animation/waapi/create-accelerated-animation.mjs +7 -2
- package/dist/es/projection/node/create-projection-node.mjs +22 -5
- package/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/value/index.mjs +1 -1
- package/dist/framer-motion.dev.js +3593 -3528
- package/dist/framer-motion.js +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/projection.dev.js +102 -36
- package/dist/three-entry.d.ts +6 -2
- package/package.json +7 -7
package/dist/cjs/dom-entry.js
CHANGED
package/dist/cjs/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var React = require('react');
|
|
6
|
-
var wrap = require('./wrap-
|
|
6
|
+
var wrap = require('./wrap-462b1507.js');
|
|
7
7
|
|
|
8
8
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
9
|
|
|
@@ -4227,10 +4227,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
4227
4227
|
this.target = undefined;
|
|
4228
4228
|
this.isLayoutDirty = false;
|
|
4229
4229
|
}
|
|
4230
|
-
|
|
4231
|
-
* Frame calculations
|
|
4232
|
-
*/
|
|
4233
|
-
resolveTargetDelta() {
|
|
4230
|
+
resolveTargetDelta(forceRecalculation = false) {
|
|
4234
4231
|
var _a;
|
|
4235
4232
|
/**
|
|
4236
4233
|
* Once the dirty status of nodes has been spread through the tree, we also
|
|
@@ -4246,7 +4243,8 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
4246
4243
|
* We don't use transform for this step of processing so we don't
|
|
4247
4244
|
* need to check whether any nodes have changed transform.
|
|
4248
4245
|
*/
|
|
4249
|
-
const canSkip = !(
|
|
4246
|
+
const canSkip = !(forceRecalculation ||
|
|
4247
|
+
(isShared && this.isSharedProjectionDirty) ||
|
|
4250
4248
|
this.isProjectionDirty ||
|
|
4251
4249
|
((_a = this.parent) === null || _a === void 0 ? void 0 : _a.isProjectionDirty) ||
|
|
4252
4250
|
this.attemptToResolveRelativeTarget);
|
|
@@ -4258,6 +4256,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
4258
4256
|
*/
|
|
4259
4257
|
if (!this.layout || !(layout || layoutId))
|
|
4260
4258
|
return;
|
|
4259
|
+
this.resolvedRelativeTargetAt = wrap.frameData.timestamp;
|
|
4261
4260
|
/**
|
|
4262
4261
|
* If we don't have a targetDelta but do have a layout, we can attempt to resolve
|
|
4263
4262
|
* a relativeParent. This will allow a component to perform scale correction
|
|
@@ -4298,6 +4297,16 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
4298
4297
|
this.relativeTargetOrigin &&
|
|
4299
4298
|
this.relativeParent &&
|
|
4300
4299
|
this.relativeParent.target) {
|
|
4300
|
+
/**
|
|
4301
|
+
* If the parent target isn't up-to-date, force it to update.
|
|
4302
|
+
* This is an unfortunate de-optimisation as it means any updating relative
|
|
4303
|
+
* projection will cause all the relative parents to recalculate back
|
|
4304
|
+
* up the tree.
|
|
4305
|
+
*/
|
|
4306
|
+
if (this.relativeParent.resolvedRelativeTargetAt !==
|
|
4307
|
+
wrap.frameData.timestamp) {
|
|
4308
|
+
this.relativeParent.resolveTargetDelta(true);
|
|
4309
|
+
}
|
|
4301
4310
|
calcRelativeBox(this.target, this.relativeTarget, this.relativeParent.target);
|
|
4302
4311
|
/**
|
|
4303
4312
|
* If we've only got a targetDelta, resolve it into a target
|
|
@@ -4384,6 +4393,13 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
4384
4393
|
(this.isSharedProjectionDirty || this.isTransformDirty)) {
|
|
4385
4394
|
canSkip = false;
|
|
4386
4395
|
}
|
|
4396
|
+
/**
|
|
4397
|
+
* If we have resolved the target this frame we must recalculate the
|
|
4398
|
+
* projection to ensure it visually represents the internal calculations.
|
|
4399
|
+
*/
|
|
4400
|
+
if (this.resolvedRelativeTargetAt === wrap.frameData.timestamp) {
|
|
4401
|
+
canSkip = false;
|
|
4402
|
+
}
|
|
4387
4403
|
if (canSkip)
|
|
4388
4404
|
return;
|
|
4389
4405
|
const { layout, layoutId } = this.options;
|
|
@@ -5516,7 +5532,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
5516
5532
|
* and warn against mismatches.
|
|
5517
5533
|
*/
|
|
5518
5534
|
if (process.env.NODE_ENV === "development") {
|
|
5519
|
-
wrap.warnOnce(nextValue.version === "10.
|
|
5535
|
+
wrap.warnOnce(nextValue.version === "10.3.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 10.3.0 may not work as expected.`);
|
|
5520
5536
|
}
|
|
5521
5537
|
}
|
|
5522
5538
|
else if (wrap.isMotionValue(prevValue)) {
|
|
@@ -7679,7 +7695,7 @@ sync) {
|
|
|
7679
7695
|
*/
|
|
7680
7696
|
sync.update(() => {
|
|
7681
7697
|
if (value.animation) {
|
|
7682
|
-
value.animation.
|
|
7698
|
+
value.animation.time =
|
|
7683
7699
|
performance.now() - wrap.millisecondsToSeconds(sampledTime);
|
|
7684
7700
|
}
|
|
7685
7701
|
});
|
|
@@ -404,7 +404,7 @@ class MotionValue {
|
|
|
404
404
|
* This will be replaced by the build step with the latest version number.
|
|
405
405
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
406
406
|
*/
|
|
407
|
-
this.version = "10.
|
|
407
|
+
this.version = "10.3.0";
|
|
408
408
|
/**
|
|
409
409
|
* Duration, in milliseconds, since last updating frame.
|
|
410
410
|
*
|
|
@@ -1764,6 +1764,20 @@ function calculateDuration(generator) {
|
|
|
1764
1764
|
return duration;
|
|
1765
1765
|
}
|
|
1766
1766
|
function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, keyframes: keyframes$1, type = "keyframes", repeat = 0, repeatDelay = 0, repeatType = "loop", onPlay, onStop, onComplete, onUpdate, ...options }) {
|
|
1767
|
+
let resolveFinishedPromise;
|
|
1768
|
+
let currentFinishedPromise;
|
|
1769
|
+
/**
|
|
1770
|
+
* Create a new finished Promise every time we enter the
|
|
1771
|
+
* finished state and resolve the old Promise. This is
|
|
1772
|
+
* WAAPI-compatible behaviour.
|
|
1773
|
+
*/
|
|
1774
|
+
const updateFinishedPromise = () => {
|
|
1775
|
+
currentFinishedPromise = new Promise((resolve) => {
|
|
1776
|
+
resolveFinishedPromise = resolve;
|
|
1777
|
+
});
|
|
1778
|
+
};
|
|
1779
|
+
// Create the first finished promise
|
|
1780
|
+
updateFinishedPromise();
|
|
1767
1781
|
let animationDriver;
|
|
1768
1782
|
const generatorFactory = types[type] || keyframes;
|
|
1769
1783
|
/**
|
|
@@ -1809,26 +1823,26 @@ function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, ke
|
|
|
1809
1823
|
resolvedDuration = calculatedDuration + repeatDelay;
|
|
1810
1824
|
totalDuration = resolvedDuration * (repeat + 1) - repeatDelay;
|
|
1811
1825
|
}
|
|
1812
|
-
let
|
|
1826
|
+
let time = 0;
|
|
1813
1827
|
const tick = (timestamp) => {
|
|
1814
1828
|
if (startTime === null)
|
|
1815
1829
|
return;
|
|
1816
1830
|
if (holdTime !== null) {
|
|
1817
|
-
|
|
1831
|
+
time = holdTime;
|
|
1818
1832
|
}
|
|
1819
1833
|
else {
|
|
1820
|
-
|
|
1834
|
+
time = timestamp - startTime;
|
|
1821
1835
|
}
|
|
1822
1836
|
// Rebase on delay
|
|
1823
|
-
|
|
1837
|
+
time = Math.max(time - delay, 0);
|
|
1824
1838
|
/**
|
|
1825
1839
|
* If this animation has finished, set the current time
|
|
1826
1840
|
* to the total duration.
|
|
1827
1841
|
*/
|
|
1828
1842
|
if (playState === "finished" && holdTime === null) {
|
|
1829
|
-
|
|
1843
|
+
time = totalDuration;
|
|
1830
1844
|
}
|
|
1831
|
-
let elapsed =
|
|
1845
|
+
let elapsed = time;
|
|
1832
1846
|
let frameGenerator = generator;
|
|
1833
1847
|
if (repeat) {
|
|
1834
1848
|
/**
|
|
@@ -1836,7 +1850,7 @@ function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, ke
|
|
|
1836
1850
|
* than duration we'll get values like 2.5 (midway through the
|
|
1837
1851
|
* third iteration)
|
|
1838
1852
|
*/
|
|
1839
|
-
const progress =
|
|
1853
|
+
const progress = time / resolvedDuration;
|
|
1840
1854
|
/**
|
|
1841
1855
|
* Get the current iteration (0 indexed). For instance the floor of
|
|
1842
1856
|
* 2.5 is 2.
|
|
@@ -1870,7 +1884,7 @@ function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, ke
|
|
|
1870
1884
|
frameGenerator = mirroredGenerator;
|
|
1871
1885
|
}
|
|
1872
1886
|
}
|
|
1873
|
-
const p =
|
|
1887
|
+
const p = time >= totalDuration
|
|
1874
1888
|
? repeatType === "reverse" && iterationIsOdd
|
|
1875
1889
|
? 0
|
|
1876
1890
|
: 1
|
|
@@ -1883,19 +1897,25 @@ function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, ke
|
|
|
1883
1897
|
onUpdate(mapNumbersToKeyframes ? mapNumbersToKeyframes(value) : value);
|
|
1884
1898
|
}
|
|
1885
1899
|
if (calculatedDuration !== null) {
|
|
1886
|
-
done =
|
|
1900
|
+
done = time >= totalDuration;
|
|
1887
1901
|
}
|
|
1888
1902
|
const isAnimationFinished = holdTime === null &&
|
|
1889
1903
|
(playState === "finished" || (playState === "running" && done));
|
|
1890
1904
|
if (isAnimationFinished) {
|
|
1891
|
-
|
|
1892
|
-
onComplete && onComplete();
|
|
1893
|
-
animationDriver && animationDriver.stop();
|
|
1905
|
+
finish();
|
|
1894
1906
|
}
|
|
1895
1907
|
return state;
|
|
1896
1908
|
};
|
|
1909
|
+
const finish = () => {
|
|
1910
|
+
animationDriver && animationDriver.stop();
|
|
1911
|
+
playState = "finished";
|
|
1912
|
+
onComplete && onComplete();
|
|
1913
|
+
resolveFinishedPromise();
|
|
1914
|
+
updateFinishedPromise();
|
|
1915
|
+
};
|
|
1897
1916
|
const play = () => {
|
|
1898
|
-
|
|
1917
|
+
if (!animationDriver)
|
|
1918
|
+
animationDriver = driver(tick);
|
|
1899
1919
|
const now = animationDriver.now();
|
|
1900
1920
|
onPlay && onPlay();
|
|
1901
1921
|
playState = "running";
|
|
@@ -1914,21 +1934,30 @@ function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, ke
|
|
|
1914
1934
|
play();
|
|
1915
1935
|
}
|
|
1916
1936
|
const controls = {
|
|
1917
|
-
|
|
1918
|
-
return
|
|
1937
|
+
then(resolve, reject) {
|
|
1938
|
+
return currentFinishedPromise.then(resolve, reject);
|
|
1919
1939
|
},
|
|
1920
|
-
|
|
1940
|
+
get time() {
|
|
1941
|
+
return millisecondsToSeconds(time);
|
|
1942
|
+
},
|
|
1943
|
+
set time(newTime) {
|
|
1944
|
+
const timeInMs = secondsToMilliseconds(newTime);
|
|
1921
1945
|
if (holdTime !== null || !animationDriver) {
|
|
1922
|
-
holdTime =
|
|
1946
|
+
holdTime = timeInMs;
|
|
1923
1947
|
}
|
|
1924
1948
|
else {
|
|
1925
|
-
startTime =
|
|
1926
|
-
animationDriver.now() - secondsToMilliseconds(newTime);
|
|
1949
|
+
startTime = animationDriver.now() - timeInMs;
|
|
1927
1950
|
}
|
|
1928
1951
|
},
|
|
1952
|
+
play,
|
|
1953
|
+
pause: () => {
|
|
1954
|
+
playState = "paused";
|
|
1955
|
+
holdTime = time;
|
|
1956
|
+
},
|
|
1929
1957
|
stop: () => {
|
|
1930
1958
|
onStop && onStop();
|
|
1931
1959
|
animationDriver && animationDriver.stop();
|
|
1960
|
+
animationDriver = undefined;
|
|
1932
1961
|
},
|
|
1933
1962
|
sample: (elapsed) => {
|
|
1934
1963
|
startTime = 0;
|
|
@@ -2027,12 +2056,17 @@ function createAcceleratedAnimation(value, valueName, { onUpdate, onComplete, ..
|
|
|
2027
2056
|
* Animation interrupt callback.
|
|
2028
2057
|
*/
|
|
2029
2058
|
return {
|
|
2030
|
-
|
|
2059
|
+
then(resolve, reject) {
|
|
2060
|
+
return animation.finished.then(resolve, reject);
|
|
2061
|
+
},
|
|
2062
|
+
get time() {
|
|
2031
2063
|
return millisecondsToSeconds(animation.currentTime || 0);
|
|
2032
2064
|
},
|
|
2033
|
-
set
|
|
2065
|
+
set time(newTime) {
|
|
2034
2066
|
animation.currentTime = secondsToMilliseconds(newTime);
|
|
2035
2067
|
},
|
|
2068
|
+
play: () => animation.play(),
|
|
2069
|
+
pause: () => animation.pause(),
|
|
2036
2070
|
stop: () => {
|
|
2037
2071
|
/**
|
|
2038
2072
|
* WAAPI doesn't natively have any interruption capabilities.
|
|
@@ -2060,8 +2094,11 @@ function createInstantAnimation({ keyframes, delay: delayBy, onUpdate, onComplet
|
|
|
2060
2094
|
onUpdate && onUpdate(keyframes[keyframes.length - 1]);
|
|
2061
2095
|
onComplete && onComplete();
|
|
2062
2096
|
return {
|
|
2063
|
-
|
|
2064
|
-
|
|
2097
|
+
time: 0,
|
|
2098
|
+
play: (noop),
|
|
2099
|
+
pause: (noop),
|
|
2100
|
+
stop: (noop),
|
|
2101
|
+
then: Promise.resolve,
|
|
2065
2102
|
};
|
|
2066
2103
|
};
|
|
2067
2104
|
return delayBy
|
|
@@ -2296,23 +2333,35 @@ class GroupPlaybackControls {
|
|
|
2296
2333
|
constructor(animations) {
|
|
2297
2334
|
this.animations = animations.filter(Boolean);
|
|
2298
2335
|
}
|
|
2336
|
+
then(onResolve, onReject) {
|
|
2337
|
+
return Promise.all(this.animations).then(onResolve).catch(onReject);
|
|
2338
|
+
}
|
|
2299
2339
|
/**
|
|
2300
2340
|
* TODO: Filter out cancelled or stopped animations before returning
|
|
2301
2341
|
*/
|
|
2302
|
-
get
|
|
2303
|
-
return this.animations[0].
|
|
2342
|
+
get time() {
|
|
2343
|
+
return this.animations[0].time;
|
|
2304
2344
|
}
|
|
2305
2345
|
/**
|
|
2306
|
-
*
|
|
2346
|
+
* time assignment could reasonably run every frame, so
|
|
2307
2347
|
* we iterate using a normal loop to avoid function creation.
|
|
2308
2348
|
*/
|
|
2309
|
-
set
|
|
2349
|
+
set time(time) {
|
|
2310
2350
|
for (let i = 0; i < this.animations.length; i++) {
|
|
2311
|
-
this.animations[i].
|
|
2351
|
+
this.animations[i].time = time;
|
|
2312
2352
|
}
|
|
2313
2353
|
}
|
|
2354
|
+
runAll(methodName) {
|
|
2355
|
+
this.animations.forEach((controls) => controls[methodName]());
|
|
2356
|
+
}
|
|
2357
|
+
play() {
|
|
2358
|
+
this.runAll("play");
|
|
2359
|
+
}
|
|
2360
|
+
pause() {
|
|
2361
|
+
this.runAll("pause");
|
|
2362
|
+
}
|
|
2314
2363
|
stop() {
|
|
2315
|
-
this.
|
|
2364
|
+
this.runAll("stop");
|
|
2316
2365
|
}
|
|
2317
2366
|
}
|
|
2318
2367
|
|
|
@@ -2365,24 +2414,6 @@ function delay(callback, timeout) {
|
|
|
2365
2414
|
return () => cancelSync.read(checkElapsed);
|
|
2366
2415
|
}
|
|
2367
2416
|
|
|
2368
|
-
const isCustomValueType = (v) => {
|
|
2369
|
-
return typeof v === "object" && v.mix;
|
|
2370
|
-
};
|
|
2371
|
-
const getMixer = (v) => (isCustomValueType(v) ? v.mix : undefined);
|
|
2372
|
-
function transform(...args) {
|
|
2373
|
-
const useImmediate = !Array.isArray(args[0]);
|
|
2374
|
-
const argOffset = useImmediate ? 0 : -1;
|
|
2375
|
-
const inputValue = args[0 + argOffset];
|
|
2376
|
-
const inputRange = args[1 + argOffset];
|
|
2377
|
-
const outputRange = args[2 + argOffset];
|
|
2378
|
-
const options = args[3 + argOffset];
|
|
2379
|
-
const interpolator = interpolate(inputRange, outputRange, {
|
|
2380
|
-
mixer: getMixer(outputRange[0]),
|
|
2381
|
-
...options,
|
|
2382
|
-
});
|
|
2383
|
-
return useImmediate ? interpolator(inputValue) : interpolator;
|
|
2384
|
-
}
|
|
2385
|
-
|
|
2386
2417
|
function resolveElements(elements, selectorCache) {
|
|
2387
2418
|
var _a;
|
|
2388
2419
|
if (typeof elements === "string") {
|
|
@@ -2858,6 +2889,24 @@ function inView(elementOrSelector, onStart, { root, margin: rootMargin, amount =
|
|
|
2858
2889
|
return () => observer.disconnect();
|
|
2859
2890
|
}
|
|
2860
2891
|
|
|
2892
|
+
const isCustomValueType = (v) => {
|
|
2893
|
+
return typeof v === "object" && v.mix;
|
|
2894
|
+
};
|
|
2895
|
+
const getMixer = (v) => (isCustomValueType(v) ? v.mix : undefined);
|
|
2896
|
+
function transform(...args) {
|
|
2897
|
+
const useImmediate = !Array.isArray(args[0]);
|
|
2898
|
+
const argOffset = useImmediate ? 0 : -1;
|
|
2899
|
+
const inputValue = args[0 + argOffset];
|
|
2900
|
+
const inputRange = args[1 + argOffset];
|
|
2901
|
+
const outputRange = args[2 + argOffset];
|
|
2902
|
+
const options = args[3 + argOffset];
|
|
2903
|
+
const interpolator = interpolate(inputRange, outputRange, {
|
|
2904
|
+
mixer: getMixer(outputRange[0]),
|
|
2905
|
+
...options,
|
|
2906
|
+
});
|
|
2907
|
+
return useImmediate ? interpolator(inputValue) : interpolator;
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2861
2910
|
const wrap = (min, max, v) => {
|
|
2862
2911
|
const rangeSize = max - min;
|
|
2863
2912
|
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
|
package/dist/dom-entry.d.ts
CHANGED
|
@@ -803,8 +803,11 @@ declare type Transition = (Orchestration & Repeat & TransitionDefinition) | (Orc
|
|
|
803
803
|
* @public
|
|
804
804
|
*/
|
|
805
805
|
interface AnimationPlaybackControls {
|
|
806
|
-
|
|
806
|
+
time: number;
|
|
807
807
|
stop: () => void;
|
|
808
|
+
play: () => void;
|
|
809
|
+
pause: () => void;
|
|
810
|
+
then: (onResolve: VoidFunction, onReject?: VoidFunction) => Promise<void>;
|
|
808
811
|
}
|
|
809
812
|
|
|
810
813
|
/**
|
|
@@ -2,23 +2,35 @@ class GroupPlaybackControls {
|
|
|
2
2
|
constructor(animations) {
|
|
3
3
|
this.animations = animations.filter(Boolean);
|
|
4
4
|
}
|
|
5
|
+
then(onResolve, onReject) {
|
|
6
|
+
return Promise.all(this.animations).then(onResolve).catch(onReject);
|
|
7
|
+
}
|
|
5
8
|
/**
|
|
6
9
|
* TODO: Filter out cancelled or stopped animations before returning
|
|
7
10
|
*/
|
|
8
|
-
get
|
|
9
|
-
return this.animations[0].
|
|
11
|
+
get time() {
|
|
12
|
+
return this.animations[0].time;
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
12
|
-
*
|
|
15
|
+
* time assignment could reasonably run every frame, so
|
|
13
16
|
* we iterate using a normal loop to avoid function creation.
|
|
14
17
|
*/
|
|
15
|
-
set
|
|
18
|
+
set time(time) {
|
|
16
19
|
for (let i = 0; i < this.animations.length; i++) {
|
|
17
|
-
this.animations[i].
|
|
20
|
+
this.animations[i].time = time;
|
|
18
21
|
}
|
|
19
22
|
}
|
|
23
|
+
runAll(methodName) {
|
|
24
|
+
this.animations.forEach((controls) => controls[methodName]());
|
|
25
|
+
}
|
|
26
|
+
play() {
|
|
27
|
+
this.runAll("play");
|
|
28
|
+
}
|
|
29
|
+
pause() {
|
|
30
|
+
this.runAll("pause");
|
|
31
|
+
}
|
|
20
32
|
stop() {
|
|
21
|
-
this.
|
|
33
|
+
this.runAll("stop");
|
|
22
34
|
}
|
|
23
35
|
}
|
|
24
36
|
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { animateValue } from './js/index.mjs';
|
|
2
|
+
import { noop } from '../utils/noop.mjs';
|
|
2
3
|
|
|
3
4
|
function createInstantAnimation({ keyframes, delay: delayBy, onUpdate, onComplete, }) {
|
|
4
5
|
const setValue = () => {
|
|
5
6
|
onUpdate && onUpdate(keyframes[keyframes.length - 1]);
|
|
6
7
|
onComplete && onComplete();
|
|
7
8
|
return {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
time: 0,
|
|
10
|
+
play: (noop),
|
|
11
|
+
pause: (noop),
|
|
12
|
+
stop: (noop),
|
|
13
|
+
then: Promise.resolve,
|
|
10
14
|
};
|
|
11
15
|
};
|
|
12
16
|
return delayBy
|
|
@@ -29,6 +29,20 @@ function calculateDuration(generator) {
|
|
|
29
29
|
return duration;
|
|
30
30
|
}
|
|
31
31
|
function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, keyframes: keyframes$1, type = "keyframes", repeat = 0, repeatDelay = 0, repeatType = "loop", onPlay, onStop, onComplete, onUpdate, ...options }) {
|
|
32
|
+
let resolveFinishedPromise;
|
|
33
|
+
let currentFinishedPromise;
|
|
34
|
+
/**
|
|
35
|
+
* Create a new finished Promise every time we enter the
|
|
36
|
+
* finished state and resolve the old Promise. This is
|
|
37
|
+
* WAAPI-compatible behaviour.
|
|
38
|
+
*/
|
|
39
|
+
const updateFinishedPromise = () => {
|
|
40
|
+
currentFinishedPromise = new Promise((resolve) => {
|
|
41
|
+
resolveFinishedPromise = resolve;
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
// Create the first finished promise
|
|
45
|
+
updateFinishedPromise();
|
|
32
46
|
let animationDriver;
|
|
33
47
|
const generatorFactory = types[type] || keyframes;
|
|
34
48
|
/**
|
|
@@ -74,26 +88,26 @@ function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, ke
|
|
|
74
88
|
resolvedDuration = calculatedDuration + repeatDelay;
|
|
75
89
|
totalDuration = resolvedDuration * (repeat + 1) - repeatDelay;
|
|
76
90
|
}
|
|
77
|
-
let
|
|
91
|
+
let time = 0;
|
|
78
92
|
const tick = (timestamp) => {
|
|
79
93
|
if (startTime === null)
|
|
80
94
|
return;
|
|
81
95
|
if (holdTime !== null) {
|
|
82
|
-
|
|
96
|
+
time = holdTime;
|
|
83
97
|
}
|
|
84
98
|
else {
|
|
85
|
-
|
|
99
|
+
time = timestamp - startTime;
|
|
86
100
|
}
|
|
87
101
|
// Rebase on delay
|
|
88
|
-
|
|
102
|
+
time = Math.max(time - delay, 0);
|
|
89
103
|
/**
|
|
90
104
|
* If this animation has finished, set the current time
|
|
91
105
|
* to the total duration.
|
|
92
106
|
*/
|
|
93
107
|
if (playState === "finished" && holdTime === null) {
|
|
94
|
-
|
|
108
|
+
time = totalDuration;
|
|
95
109
|
}
|
|
96
|
-
let elapsed =
|
|
110
|
+
let elapsed = time;
|
|
97
111
|
let frameGenerator = generator;
|
|
98
112
|
if (repeat) {
|
|
99
113
|
/**
|
|
@@ -101,7 +115,7 @@ function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, ke
|
|
|
101
115
|
* than duration we'll get values like 2.5 (midway through the
|
|
102
116
|
* third iteration)
|
|
103
117
|
*/
|
|
104
|
-
const progress =
|
|
118
|
+
const progress = time / resolvedDuration;
|
|
105
119
|
/**
|
|
106
120
|
* Get the current iteration (0 indexed). For instance the floor of
|
|
107
121
|
* 2.5 is 2.
|
|
@@ -135,7 +149,7 @@ function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, ke
|
|
|
135
149
|
frameGenerator = mirroredGenerator;
|
|
136
150
|
}
|
|
137
151
|
}
|
|
138
|
-
const p =
|
|
152
|
+
const p = time >= totalDuration
|
|
139
153
|
? repeatType === "reverse" && iterationIsOdd
|
|
140
154
|
? 0
|
|
141
155
|
: 1
|
|
@@ -148,19 +162,25 @@ function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, ke
|
|
|
148
162
|
onUpdate(mapNumbersToKeyframes ? mapNumbersToKeyframes(value) : value);
|
|
149
163
|
}
|
|
150
164
|
if (calculatedDuration !== null) {
|
|
151
|
-
done =
|
|
165
|
+
done = time >= totalDuration;
|
|
152
166
|
}
|
|
153
167
|
const isAnimationFinished = holdTime === null &&
|
|
154
168
|
(playState === "finished" || (playState === "running" && done));
|
|
155
169
|
if (isAnimationFinished) {
|
|
156
|
-
|
|
157
|
-
onComplete && onComplete();
|
|
158
|
-
animationDriver && animationDriver.stop();
|
|
170
|
+
finish();
|
|
159
171
|
}
|
|
160
172
|
return state;
|
|
161
173
|
};
|
|
174
|
+
const finish = () => {
|
|
175
|
+
animationDriver && animationDriver.stop();
|
|
176
|
+
playState = "finished";
|
|
177
|
+
onComplete && onComplete();
|
|
178
|
+
resolveFinishedPromise();
|
|
179
|
+
updateFinishedPromise();
|
|
180
|
+
};
|
|
162
181
|
const play = () => {
|
|
163
|
-
|
|
182
|
+
if (!animationDriver)
|
|
183
|
+
animationDriver = driver(tick);
|
|
164
184
|
const now = animationDriver.now();
|
|
165
185
|
onPlay && onPlay();
|
|
166
186
|
playState = "running";
|
|
@@ -179,21 +199,30 @@ function animateValue({ autoplay = true, delay = 0, driver = frameloopDriver, ke
|
|
|
179
199
|
play();
|
|
180
200
|
}
|
|
181
201
|
const controls = {
|
|
182
|
-
|
|
183
|
-
return
|
|
202
|
+
then(resolve, reject) {
|
|
203
|
+
return currentFinishedPromise.then(resolve, reject);
|
|
184
204
|
},
|
|
185
|
-
|
|
205
|
+
get time() {
|
|
206
|
+
return millisecondsToSeconds(time);
|
|
207
|
+
},
|
|
208
|
+
set time(newTime) {
|
|
209
|
+
const timeInMs = secondsToMilliseconds(newTime);
|
|
186
210
|
if (holdTime !== null || !animationDriver) {
|
|
187
|
-
holdTime =
|
|
211
|
+
holdTime = timeInMs;
|
|
188
212
|
}
|
|
189
213
|
else {
|
|
190
|
-
startTime =
|
|
191
|
-
animationDriver.now() - secondsToMilliseconds(newTime);
|
|
214
|
+
startTime = animationDriver.now() - timeInMs;
|
|
192
215
|
}
|
|
193
216
|
},
|
|
217
|
+
play,
|
|
218
|
+
pause: () => {
|
|
219
|
+
playState = "paused";
|
|
220
|
+
holdTime = time;
|
|
221
|
+
},
|
|
194
222
|
stop: () => {
|
|
195
223
|
onStop && onStop();
|
|
196
224
|
animationDriver && animationDriver.stop();
|
|
225
|
+
animationDriver = undefined;
|
|
197
226
|
},
|
|
198
227
|
sample: (elapsed) => {
|
|
199
228
|
startTime = 0;
|
|
@@ -95,12 +95,17 @@ function createAcceleratedAnimation(value, valueName, { onUpdate, onComplete, ..
|
|
|
95
95
|
* Animation interrupt callback.
|
|
96
96
|
*/
|
|
97
97
|
return {
|
|
98
|
-
|
|
98
|
+
then(resolve, reject) {
|
|
99
|
+
return animation.finished.then(resolve, reject);
|
|
100
|
+
},
|
|
101
|
+
get time() {
|
|
99
102
|
return millisecondsToSeconds(animation.currentTime || 0);
|
|
100
103
|
},
|
|
101
|
-
set
|
|
104
|
+
set time(newTime) {
|
|
102
105
|
animation.currentTime = secondsToMilliseconds(newTime);
|
|
103
106
|
},
|
|
107
|
+
play: () => animation.play(),
|
|
108
|
+
pause: () => animation.pause(),
|
|
104
109
|
stop: () => {
|
|
105
110
|
/**
|
|
106
111
|
* WAAPI doesn't natively have any interruption capabilities.
|