motion 12.4.12 → 12.5.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/debug.js +12 -12
- package/dist/cjs/index.js +1353 -1315
- package/dist/cjs/mini.js +7 -7
- package/dist/cjs/react-client.js +618 -560
- package/dist/cjs/react-m.js +20 -19
- package/dist/cjs/react-mini.js +1 -1
- package/dist/es/framer-motion/dist/es/animation/animate/single-value.mjs +2 -1
- package/dist/es/framer-motion/dist/es/animation/animators/BaseAnimation.mjs +2 -1
- package/dist/es/framer-motion/dist/es/animation/animators/MainThreadAnimation.mjs +1 -1
- package/dist/es/framer-motion/dist/es/animation/animators/drivers/driver-frameloop.mjs +3 -2
- package/dist/es/framer-motion/dist/es/animation/animators/waapi/index.mjs +2 -2
- package/dist/es/framer-motion/dist/es/animation/generators/utils/velocity.mjs +2 -1
- package/dist/es/framer-motion/dist/es/animation/interfaces/motion-value.mjs +2 -2
- package/dist/es/framer-motion/dist/es/animation/interfaces/visual-element-target.mjs +1 -1
- package/dist/es/framer-motion/dist/es/animation/optimized-appear/start.mjs +4 -4
- package/dist/es/framer-motion/dist/es/animation/sequence/utils/edit.mjs +2 -1
- package/dist/es/framer-motion/dist/es/components/AnimatePresence/index.mjs +1 -1
- package/dist/es/framer-motion/dist/es/components/Reorder/utils/check-reorder.mjs +2 -1
- package/dist/es/framer-motion/dist/es/gestures/drag/VisualElementDragControls.mjs +1 -1
- package/dist/es/framer-motion/dist/es/gestures/hover.mjs +1 -1
- package/dist/es/framer-motion/dist/es/gestures/pan/PanSession.mjs +1 -1
- package/dist/es/framer-motion/dist/es/gestures/pan/index.mjs +1 -1
- package/dist/es/framer-motion/dist/es/gestures/press.mjs +1 -1
- package/dist/es/framer-motion/dist/es/motion/features/layout/MeasureLayout.mjs +3 -2
- package/dist/es/framer-motion/dist/es/motion/utils/use-visual-element.mjs +7 -6
- package/dist/es/framer-motion/dist/es/projection/node/create-projection-node.mjs +6 -6
- package/dist/es/framer-motion/dist/es/projection/shared/stack.mjs +2 -1
- package/dist/es/framer-motion/dist/es/render/VisualElement.mjs +6 -5
- package/dist/es/framer-motion/dist/es/render/components/create-proxy.mjs +2 -1
- package/dist/es/framer-motion/dist/es/render/dom/DOMVisualElement.mjs +1 -1
- package/dist/es/framer-motion/dist/es/render/dom/scroll/info.mjs +1 -1
- package/dist/es/framer-motion/dist/es/render/dom/scroll/observe.mjs +2 -1
- package/dist/es/framer-motion/dist/es/render/dom/scroll/on-scroll-handler.mjs +2 -1
- package/dist/es/framer-motion/dist/es/render/dom/scroll/track.mjs +2 -1
- package/dist/es/framer-motion/dist/es/render/dom/utils/unit-conversion.mjs +3 -20
- package/dist/es/framer-motion/dist/es/render/html/HTMLVisualElement.mjs +2 -3
- package/dist/es/framer-motion/dist/es/render/html/utils/parse-transform.mjs +83 -0
- package/dist/es/framer-motion/dist/es/render/svg/SVGVisualElement.mjs +2 -1
- package/dist/es/framer-motion/dist/es/render/svg/config-motion.mjs +2 -1
- package/dist/es/framer-motion/dist/es/render/utils/KeyframesResolver.mjs +2 -1
- package/dist/es/framer-motion/dist/es/render/utils/flat-tree.mjs +2 -1
- package/dist/es/framer-motion/dist/es/render/utils/motion-values.mjs +4 -3
- package/dist/es/framer-motion/dist/es/render/utils/setters.mjs +2 -1
- package/dist/es/framer-motion/dist/es/utils/delay.mjs +2 -2
- package/dist/es/framer-motion/dist/es/utils/reduced-motion/use-reduced-motion.mjs +2 -1
- package/dist/es/framer-motion/dist/es/utils/use-animation-frame.mjs +2 -1
- package/dist/es/framer-motion/dist/es/utils/use-force-update.mjs +2 -1
- package/dist/es/framer-motion/dist/es/utils/use-instant-transition.mjs +2 -1
- package/dist/es/framer-motion/dist/es/value/scroll/use-element-scroll.mjs +2 -1
- package/dist/es/framer-motion/dist/es/value/scroll/use-viewport-scroll.mjs +2 -1
- package/dist/es/framer-motion/dist/es/value/use-combine-values.mjs +3 -2
- package/dist/es/framer-motion/dist/es/value/use-computed.mjs +2 -1
- package/dist/es/framer-motion/dist/es/value/use-inverted-scale.mjs +3 -3
- package/dist/es/framer-motion/dist/es/value/use-motion-value.mjs +2 -1
- package/dist/es/framer-motion/dist/es/value/use-scroll.mjs +4 -4
- package/dist/es/framer-motion/dist/es/value/use-spring.mjs +1 -1
- package/dist/es/framer-motion/dist/es/value/use-transform.mjs +1 -1
- package/dist/es/framer-motion/dist/es/value/use-velocity.mjs +2 -1
- package/dist/es/framer-motion/dist/es/value/use-will-change/WillChangeMotionValue.mjs +3 -2
- package/dist/es/motion/lib/debug.mjs +1 -1
- package/dist/es/motion/lib/index.mjs +3 -4
- package/dist/es/motion/lib/react.mjs +19 -20
- package/dist/es/{framer-motion → motion-dom}/dist/es/frameloop/batcher.mjs +2 -1
- package/dist/es/{framer-motion → motion-dom}/dist/es/frameloop/frame.mjs +1 -1
- package/dist/es/motion-dom/dist/es/frameloop/microtask.mjs +6 -0
- package/dist/es/{framer-motion → motion-dom}/dist/es/frameloop/sync-time.mjs +2 -1
- package/dist/es/motion-dom/dist/es/utils/supports/scroll-timeline.mjs +1 -1
- package/dist/es/{framer-motion → motion-dom}/dist/es/value/index.mjs +6 -11
- package/dist/motion.dev.js +1353 -1315
- package/dist/motion.js +1 -1
- package/package.json +3 -3
- package/dist/es/framer-motion/dist/es/frameloop/index-legacy.mjs +0 -20
- package/dist/es/framer-motion/dist/es/frameloop/microtask.mjs +0 -5
- package/dist/es/{framer-motion → motion-dom}/dist/es/frameloop/order.mjs +0 -0
- package/dist/es/{framer-motion → motion-dom}/dist/es/frameloop/render-step.mjs +0 -0
- package/dist/es/{framer-motion → motion-dom}/dist/es/stats/animation-count.mjs +0 -0
- package/dist/es/{framer-motion → motion-dom}/dist/es/stats/buffer.mjs +0 -0
- package/dist/es/{framer-motion → motion-dom}/dist/es/stats/index.mjs +1 -1
- /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/array.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils/GlobalConfig.mjs → motion-utils/dist/es/global-config.mjs} +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/subscription-manager.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/velocity-per-second.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/warn-once.mjs +0 -0
package/dist/cjs/index.js
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
function addUniqueItem(arr, item) {
|
|
6
|
+
if (arr.indexOf(item) === -1)
|
|
7
|
+
arr.push(item);
|
|
8
|
+
}
|
|
9
|
+
function removeItem(arr, item) {
|
|
10
|
+
const index = arr.indexOf(item);
|
|
11
|
+
if (index > -1)
|
|
12
|
+
arr.splice(index, 1);
|
|
13
|
+
}
|
|
14
|
+
|
|
5
15
|
/*#__NO_SIDE_EFFECTS__*/
|
|
6
16
|
const noop = (any) => any;
|
|
7
17
|
|
|
@@ -20,6 +30,11 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
20
30
|
};
|
|
21
31
|
}
|
|
22
32
|
|
|
33
|
+
const MotionGlobalConfig = {
|
|
34
|
+
skipAnimations: false,
|
|
35
|
+
useManualTiming: false,
|
|
36
|
+
};
|
|
37
|
+
|
|
23
38
|
/*#__NO_SIDE_EFFECTS__*/
|
|
24
39
|
function memo(callback) {
|
|
25
40
|
let result;
|
|
@@ -48,6 +63,43 @@ const progress = (from, to, value) => {
|
|
|
48
63
|
return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
|
|
49
64
|
};
|
|
50
65
|
|
|
66
|
+
class SubscriptionManager {
|
|
67
|
+
constructor() {
|
|
68
|
+
this.subscriptions = [];
|
|
69
|
+
}
|
|
70
|
+
add(handler) {
|
|
71
|
+
addUniqueItem(this.subscriptions, handler);
|
|
72
|
+
return () => removeItem(this.subscriptions, handler);
|
|
73
|
+
}
|
|
74
|
+
notify(a, b, c) {
|
|
75
|
+
const numSubscriptions = this.subscriptions.length;
|
|
76
|
+
if (!numSubscriptions)
|
|
77
|
+
return;
|
|
78
|
+
if (numSubscriptions === 1) {
|
|
79
|
+
/**
|
|
80
|
+
* If there's only a single handler we can just call it without invoking a loop.
|
|
81
|
+
*/
|
|
82
|
+
this.subscriptions[0](a, b, c);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
for (let i = 0; i < numSubscriptions; i++) {
|
|
86
|
+
/**
|
|
87
|
+
* Check whether the handler exists before firing as it's possible
|
|
88
|
+
* the subscriptions were modified during this loop running.
|
|
89
|
+
*/
|
|
90
|
+
const handler = this.subscriptions[i];
|
|
91
|
+
handler && handler(a, b, c);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
getSize() {
|
|
96
|
+
return this.subscriptions.length;
|
|
97
|
+
}
|
|
98
|
+
clear() {
|
|
99
|
+
this.subscriptions.length = 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
51
103
|
/**
|
|
52
104
|
* Converts seconds to milliseconds
|
|
53
105
|
*
|
|
@@ -59,7 +111,27 @@ const secondsToMilliseconds = (seconds) => seconds * 1000;
|
|
|
59
111
|
/*#__NO_SIDE_EFFECTS__*/
|
|
60
112
|
const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
|
|
61
113
|
|
|
62
|
-
|
|
114
|
+
/*
|
|
115
|
+
Convert velocity into velocity per second
|
|
116
|
+
|
|
117
|
+
@param [number]: Unit per frame
|
|
118
|
+
@param [number]: Frame duration in ms
|
|
119
|
+
*/
|
|
120
|
+
function velocityPerSecond(velocity, frameDuration) {
|
|
121
|
+
return frameDuration ? velocity * (1000 / frameDuration) : 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const warned = new Set();
|
|
125
|
+
function warnOnce(condition, message, element) {
|
|
126
|
+
if (condition || warned.has(message))
|
|
127
|
+
return;
|
|
128
|
+
console.warn(message);
|
|
129
|
+
if (element)
|
|
130
|
+
console.warn(element);
|
|
131
|
+
warned.add(message);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const supportsScrollTimeline = /* @__PURE__ */ memo(() => window.ScrollTimeline !== undefined);
|
|
63
135
|
|
|
64
136
|
class BaseGroupPlaybackControls {
|
|
65
137
|
constructor(animations) {
|
|
@@ -354,103 +426,297 @@ function mapEasingToNativeEasing(easing, duration) {
|
|
|
354
426
|
}
|
|
355
427
|
}
|
|
356
428
|
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
429
|
+
const stepsOrder = [
|
|
430
|
+
"read", // Read
|
|
431
|
+
"resolveKeyframes", // Write/Read/Write/Read
|
|
432
|
+
"update", // Compute
|
|
433
|
+
"preRender", // Compute
|
|
434
|
+
"render", // Write
|
|
435
|
+
"postRender", // Compute
|
|
436
|
+
];
|
|
437
|
+
|
|
438
|
+
const statsBuffer = {
|
|
439
|
+
value: null,
|
|
440
|
+
addProjectionMetrics: null,
|
|
360
441
|
};
|
|
361
|
-
function isDragActive() {
|
|
362
|
-
return isDragging.x || isDragging.y;
|
|
363
|
-
}
|
|
364
442
|
|
|
365
|
-
function
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
443
|
+
function createRenderStep(runNextFrame, stepName) {
|
|
444
|
+
/**
|
|
445
|
+
* We create and reuse two queues, one to queue jobs for the current frame
|
|
446
|
+
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
447
|
+
*/
|
|
448
|
+
let thisFrame = new Set();
|
|
449
|
+
let nextFrame = new Set();
|
|
450
|
+
/**
|
|
451
|
+
* Track whether we're currently processing jobs in this step. This way
|
|
452
|
+
* we can decide whether to schedule new jobs for this frame or next.
|
|
453
|
+
*/
|
|
454
|
+
let isProcessing = false;
|
|
455
|
+
let flushNextFrame = false;
|
|
456
|
+
/**
|
|
457
|
+
* A set of processes which were marked keepAlive when scheduled.
|
|
458
|
+
*/
|
|
459
|
+
const toKeepAlive = new WeakSet();
|
|
460
|
+
let latestFrameData = {
|
|
461
|
+
delta: 0.0,
|
|
462
|
+
timestamp: 0.0,
|
|
463
|
+
isProcessing: false,
|
|
464
|
+
};
|
|
465
|
+
let numCalls = 0;
|
|
466
|
+
function triggerCallback(callback) {
|
|
467
|
+
if (toKeepAlive.has(callback)) {
|
|
468
|
+
step.schedule(callback);
|
|
469
|
+
runNextFrame();
|
|
379
470
|
}
|
|
380
|
-
|
|
381
|
-
|
|
471
|
+
numCalls++;
|
|
472
|
+
callback(latestFrameData);
|
|
382
473
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
if (typeof onHoverEnd !== "function" || !target)
|
|
416
|
-
return;
|
|
417
|
-
const onPointerLeave = (leaveEvent) => {
|
|
418
|
-
if (!isValidHover(leaveEvent))
|
|
474
|
+
const step = {
|
|
475
|
+
/**
|
|
476
|
+
* Schedule a process to run on the next frame.
|
|
477
|
+
*/
|
|
478
|
+
schedule: (callback, keepAlive = false, immediate = false) => {
|
|
479
|
+
const addToCurrentFrame = immediate && isProcessing;
|
|
480
|
+
const queue = addToCurrentFrame ? thisFrame : nextFrame;
|
|
481
|
+
if (keepAlive)
|
|
482
|
+
toKeepAlive.add(callback);
|
|
483
|
+
if (!queue.has(callback))
|
|
484
|
+
queue.add(callback);
|
|
485
|
+
return callback;
|
|
486
|
+
},
|
|
487
|
+
/**
|
|
488
|
+
* Cancel the provided callback from running on the next frame.
|
|
489
|
+
*/
|
|
490
|
+
cancel: (callback) => {
|
|
491
|
+
nextFrame.delete(callback);
|
|
492
|
+
toKeepAlive.delete(callback);
|
|
493
|
+
},
|
|
494
|
+
/**
|
|
495
|
+
* Execute all schedule callbacks.
|
|
496
|
+
*/
|
|
497
|
+
process: (frameData) => {
|
|
498
|
+
latestFrameData = frameData;
|
|
499
|
+
/**
|
|
500
|
+
* If we're already processing we've probably been triggered by a flushSync
|
|
501
|
+
* inside an existing process. Instead of executing, mark flushNextFrame
|
|
502
|
+
* as true and ensure we flush the following frame at the end of this one.
|
|
503
|
+
*/
|
|
504
|
+
if (isProcessing) {
|
|
505
|
+
flushNextFrame = true;
|
|
419
506
|
return;
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
507
|
+
}
|
|
508
|
+
isProcessing = true;
|
|
509
|
+
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
510
|
+
// Execute this frame
|
|
511
|
+
thisFrame.forEach(triggerCallback);
|
|
512
|
+
/**
|
|
513
|
+
* If we're recording stats then
|
|
514
|
+
*/
|
|
515
|
+
if (stepName && statsBuffer.value) {
|
|
516
|
+
statsBuffer.value.frameloop[stepName].push(numCalls);
|
|
517
|
+
}
|
|
518
|
+
numCalls = 0;
|
|
519
|
+
// Clear the frame so no callbacks remain. This is to avoid
|
|
520
|
+
// memory leaks should this render step not run for a while.
|
|
521
|
+
thisFrame.clear();
|
|
522
|
+
isProcessing = false;
|
|
523
|
+
if (flushNextFrame) {
|
|
524
|
+
flushNextFrame = false;
|
|
525
|
+
step.process(frameData);
|
|
526
|
+
}
|
|
527
|
+
},
|
|
424
528
|
};
|
|
425
|
-
|
|
426
|
-
element.addEventListener("pointerenter", onPointerEnter, eventOptions);
|
|
427
|
-
});
|
|
428
|
-
return cancel;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
function capturePointer(event, action) {
|
|
432
|
-
const actionName = `${action}PointerCapture`;
|
|
433
|
-
if (event.target instanceof Element &&
|
|
434
|
-
actionName in event.target &&
|
|
435
|
-
event.pointerId !== undefined) {
|
|
436
|
-
try {
|
|
437
|
-
event.target[actionName](event.pointerId);
|
|
438
|
-
}
|
|
439
|
-
catch (e) { }
|
|
440
|
-
}
|
|
529
|
+
return step;
|
|
441
530
|
}
|
|
442
531
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
532
|
+
const maxElapsed$1 = 40;
|
|
533
|
+
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
534
|
+
let runNextFrame = false;
|
|
535
|
+
let useDefaultElapsed = true;
|
|
536
|
+
const state = {
|
|
537
|
+
delta: 0.0,
|
|
538
|
+
timestamp: 0.0,
|
|
539
|
+
isProcessing: false,
|
|
540
|
+
};
|
|
541
|
+
const flagRunNextFrame = () => (runNextFrame = true);
|
|
542
|
+
const steps = stepsOrder.reduce((acc, key) => {
|
|
543
|
+
acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : undefined);
|
|
544
|
+
return acc;
|
|
545
|
+
}, {});
|
|
546
|
+
const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
|
|
547
|
+
const processBatch = () => {
|
|
548
|
+
const timestamp = performance.now();
|
|
549
|
+
runNextFrame = false;
|
|
550
|
+
{
|
|
551
|
+
state.delta = useDefaultElapsed
|
|
552
|
+
? 1000 / 60
|
|
553
|
+
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
|
|
554
|
+
}
|
|
555
|
+
state.timestamp = timestamp;
|
|
556
|
+
state.isProcessing = true;
|
|
557
|
+
// Unrolled render loop for better per-frame performance
|
|
558
|
+
read.process(state);
|
|
559
|
+
resolveKeyframes.process(state);
|
|
560
|
+
update.process(state);
|
|
561
|
+
preRender.process(state);
|
|
562
|
+
render.process(state);
|
|
563
|
+
postRender.process(state);
|
|
564
|
+
state.isProcessing = false;
|
|
565
|
+
if (runNextFrame && allowKeepAlive) {
|
|
566
|
+
useDefaultElapsed = false;
|
|
567
|
+
scheduleNextBatch(processBatch);
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
const wake = () => {
|
|
571
|
+
runNextFrame = true;
|
|
572
|
+
useDefaultElapsed = true;
|
|
573
|
+
if (!state.isProcessing) {
|
|
574
|
+
scheduleNextBatch(processBatch);
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
const schedule = stepsOrder.reduce((acc, key) => {
|
|
578
|
+
const step = steps[key];
|
|
579
|
+
acc[key] = (process, keepAlive = false, immediate = false) => {
|
|
580
|
+
if (!runNextFrame)
|
|
581
|
+
wake();
|
|
582
|
+
return step.schedule(process, keepAlive, immediate);
|
|
583
|
+
};
|
|
584
|
+
return acc;
|
|
585
|
+
}, {});
|
|
586
|
+
const cancel = (process) => {
|
|
587
|
+
for (let i = 0; i < stepsOrder.length; i++) {
|
|
588
|
+
steps[stepsOrder[i]].cancel(process);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
return { schedule, cancel, state, steps };
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps, } = /* @__PURE__ */ createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
|
|
595
|
+
|
|
596
|
+
let now;
|
|
597
|
+
function clearTime() {
|
|
598
|
+
now = undefined;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* An eventloop-synchronous alternative to performance.now().
|
|
602
|
+
*
|
|
603
|
+
* Ensures that time measurements remain consistent within a synchronous context.
|
|
604
|
+
* Usually calling performance.now() twice within the same synchronous context
|
|
605
|
+
* will return different values which isn't useful for animations when we're usually
|
|
606
|
+
* trying to sync animations to the same frame.
|
|
607
|
+
*/
|
|
608
|
+
const time = {
|
|
609
|
+
now: () => {
|
|
610
|
+
if (now === undefined) {
|
|
611
|
+
time.set(frameData.isProcessing || MotionGlobalConfig.useManualTiming
|
|
612
|
+
? frameData.timestamp
|
|
613
|
+
: performance.now());
|
|
614
|
+
}
|
|
615
|
+
return now;
|
|
616
|
+
},
|
|
617
|
+
set: (newTime) => {
|
|
618
|
+
now = newTime;
|
|
619
|
+
queueMicrotask(clearTime);
|
|
620
|
+
},
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
const isDragging = {
|
|
624
|
+
x: false,
|
|
625
|
+
y: false,
|
|
626
|
+
};
|
|
627
|
+
function isDragActive() {
|
|
628
|
+
return isDragging.x || isDragging.y;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
function resolveElements(elementOrSelector, scope, selectorCache) {
|
|
632
|
+
var _a;
|
|
633
|
+
if (elementOrSelector instanceof EventTarget) {
|
|
634
|
+
return [elementOrSelector];
|
|
635
|
+
}
|
|
636
|
+
else if (typeof elementOrSelector === "string") {
|
|
637
|
+
let root = document;
|
|
638
|
+
if (scope) {
|
|
639
|
+
// TODO: Refactor to utils package
|
|
640
|
+
// invariant(
|
|
641
|
+
// Boolean(scope.current),
|
|
642
|
+
// "Scope provided, but no element detected."
|
|
643
|
+
// )
|
|
644
|
+
root = scope.current;
|
|
645
|
+
}
|
|
646
|
+
const elements = (_a = selectorCache === null || selectorCache === void 0 ? void 0 : selectorCache[elementOrSelector]) !== null && _a !== void 0 ? _a : root.querySelectorAll(elementOrSelector);
|
|
647
|
+
return elements ? Array.from(elements) : [];
|
|
648
|
+
}
|
|
649
|
+
return Array.from(elementOrSelector);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function setupGesture(elementOrSelector, options) {
|
|
653
|
+
const elements = resolveElements(elementOrSelector);
|
|
654
|
+
const gestureAbortController = new AbortController();
|
|
655
|
+
const eventOptions = {
|
|
656
|
+
passive: true,
|
|
657
|
+
...options,
|
|
658
|
+
signal: gestureAbortController.signal,
|
|
659
|
+
};
|
|
660
|
+
const cancel = () => gestureAbortController.abort();
|
|
661
|
+
return [elements, eventOptions, cancel];
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function isValidHover(event) {
|
|
665
|
+
return !(event.pointerType === "touch" || isDragActive());
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Create a hover gesture. hover() is different to .addEventListener("pointerenter")
|
|
669
|
+
* in that it has an easier syntax, filters out polyfilled touch events, interoperates
|
|
670
|
+
* with drag gestures, and automatically removes the "pointerennd" event listener when the hover ends.
|
|
671
|
+
*
|
|
672
|
+
* @public
|
|
673
|
+
*/
|
|
674
|
+
function hover(elementOrSelector, onHoverStart, options = {}) {
|
|
675
|
+
const [elements, eventOptions, cancel] = setupGesture(elementOrSelector, options);
|
|
676
|
+
const onPointerEnter = (enterEvent) => {
|
|
677
|
+
if (!isValidHover(enterEvent))
|
|
678
|
+
return;
|
|
679
|
+
const { target } = enterEvent;
|
|
680
|
+
const onHoverEnd = onHoverStart(target, enterEvent);
|
|
681
|
+
if (typeof onHoverEnd !== "function" || !target)
|
|
682
|
+
return;
|
|
683
|
+
const onPointerLeave = (leaveEvent) => {
|
|
684
|
+
if (!isValidHover(leaveEvent))
|
|
685
|
+
return;
|
|
686
|
+
onHoverEnd(leaveEvent);
|
|
687
|
+
target.removeEventListener("pointerleave", onPointerLeave);
|
|
688
|
+
};
|
|
689
|
+
target.addEventListener("pointerleave", onPointerLeave, eventOptions);
|
|
690
|
+
};
|
|
691
|
+
elements.forEach((element) => {
|
|
692
|
+
element.addEventListener("pointerenter", onPointerEnter, eventOptions);
|
|
693
|
+
});
|
|
694
|
+
return cancel;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function capturePointer(event, action) {
|
|
698
|
+
const actionName = `${action}PointerCapture`;
|
|
699
|
+
if (event.target instanceof Element &&
|
|
700
|
+
actionName in event.target &&
|
|
701
|
+
event.pointerId !== undefined) {
|
|
702
|
+
try {
|
|
703
|
+
event.target[actionName](event.pointerId);
|
|
704
|
+
}
|
|
705
|
+
catch (e) { }
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Recursively traverse up the tree to check whether the provided child node
|
|
711
|
+
* is the parent or a descendant of it.
|
|
712
|
+
*
|
|
713
|
+
* @param parent - Element to find
|
|
714
|
+
* @param child - Element to test against parent
|
|
715
|
+
*/
|
|
716
|
+
const isNodeOrChild = (parent, child) => {
|
|
717
|
+
if (!child) {
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
454
720
|
else if (parent === child) {
|
|
455
721
|
return true;
|
|
456
722
|
}
|
|
@@ -622,1290 +888,1018 @@ function checkOutside(event, rect) {
|
|
|
622
888
|
event.clientY > rect.bottom);
|
|
623
889
|
}
|
|
624
890
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
/*
|
|
634
|
-
Convert velocity into velocity per second
|
|
635
|
-
|
|
636
|
-
@param [number]: Unit per frame
|
|
637
|
-
@param [number]: Frame duration in ms
|
|
638
|
-
*/
|
|
639
|
-
function velocityPerSecond(velocity, frameDuration) {
|
|
640
|
-
return frameDuration ? velocity * (1000 / frameDuration) : 0;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
const velocitySampleDuration = 5; // ms
|
|
644
|
-
function calcGeneratorVelocity(resolveValue, t, current) {
|
|
645
|
-
const prevT = Math.max(t - velocitySampleDuration, 0);
|
|
646
|
-
return velocityPerSecond(current - resolveValue(prevT), t - prevT);
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
const springDefaults = {
|
|
650
|
-
// Default spring physics
|
|
651
|
-
stiffness: 100,
|
|
652
|
-
damping: 10,
|
|
653
|
-
mass: 1.0,
|
|
654
|
-
velocity: 0.0,
|
|
655
|
-
// Default duration/bounce-based options
|
|
656
|
-
duration: 800, // in ms
|
|
657
|
-
bounce: 0.3,
|
|
658
|
-
visualDuration: 0.3, // in seconds
|
|
659
|
-
// Rest thresholds
|
|
660
|
-
restSpeed: {
|
|
661
|
-
granular: 0.01,
|
|
662
|
-
default: 2,
|
|
663
|
-
},
|
|
664
|
-
restDelta: {
|
|
665
|
-
granular: 0.005,
|
|
666
|
-
default: 0.5,
|
|
667
|
-
},
|
|
668
|
-
// Limits
|
|
669
|
-
minDuration: 0.01, // in seconds
|
|
670
|
-
maxDuration: 10.0, // in seconds
|
|
671
|
-
minDamping: 0.05,
|
|
672
|
-
maxDamping: 1,
|
|
891
|
+
/**
|
|
892
|
+
* Maximum time between the value of two frames, beyond which we
|
|
893
|
+
* assume the velocity has since been 0.
|
|
894
|
+
*/
|
|
895
|
+
const MAX_VELOCITY_DELTA = 30;
|
|
896
|
+
const isFloat = (value) => {
|
|
897
|
+
return !isNaN(parseFloat(value));
|
|
673
898
|
};
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
let dampingRatio = 1 - bounce;
|
|
899
|
+
/**
|
|
900
|
+
* `MotionValue` is used to track the state and velocity of motion values.
|
|
901
|
+
*
|
|
902
|
+
* @public
|
|
903
|
+
*/
|
|
904
|
+
class MotionValue {
|
|
681
905
|
/**
|
|
682
|
-
*
|
|
906
|
+
* @param init - The initiating value
|
|
907
|
+
* @param config - Optional configuration options
|
|
908
|
+
*
|
|
909
|
+
* - `transformer`: A function to transform incoming values with.
|
|
683
910
|
*/
|
|
684
|
-
|
|
685
|
-
duration = clamp(springDefaults.minDuration, springDefaults.maxDuration, millisecondsToSeconds(duration));
|
|
686
|
-
if (dampingRatio < 1) {
|
|
911
|
+
constructor(init, options = {}) {
|
|
687
912
|
/**
|
|
688
|
-
*
|
|
913
|
+
* This will be replaced by the build step with the latest version number.
|
|
914
|
+
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
689
915
|
*/
|
|
690
|
-
|
|
691
|
-
const exponentialDecay = undampedFreq * dampingRatio;
|
|
692
|
-
const delta = exponentialDecay * duration;
|
|
693
|
-
const a = exponentialDecay - velocity;
|
|
694
|
-
const b = calcAngularFreq(undampedFreq, dampingRatio);
|
|
695
|
-
const c = Math.exp(-delta);
|
|
696
|
-
return safeMin - (a / b) * c;
|
|
697
|
-
};
|
|
698
|
-
derivative = (undampedFreq) => {
|
|
699
|
-
const exponentialDecay = undampedFreq * dampingRatio;
|
|
700
|
-
const delta = exponentialDecay * duration;
|
|
701
|
-
const d = delta * velocity + velocity;
|
|
702
|
-
const e = Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration;
|
|
703
|
-
const f = Math.exp(-delta);
|
|
704
|
-
const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio);
|
|
705
|
-
const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1;
|
|
706
|
-
return (factor * ((d - e) * f)) / g;
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
else {
|
|
916
|
+
this.version = "12.5.0";
|
|
710
917
|
/**
|
|
711
|
-
*
|
|
918
|
+
* Tracks whether this value can output a velocity. Currently this is only true
|
|
919
|
+
* if the value is numerical, but we might be able to widen the scope here and support
|
|
920
|
+
* other value types.
|
|
921
|
+
*
|
|
922
|
+
* @internal
|
|
712
923
|
*/
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
924
|
+
this.canTrackVelocity = null;
|
|
925
|
+
/**
|
|
926
|
+
* An object containing a SubscriptionManager for each active event.
|
|
927
|
+
*/
|
|
928
|
+
this.events = {};
|
|
929
|
+
this.updateAndNotify = (v, render = true) => {
|
|
930
|
+
const currentTime = time.now();
|
|
931
|
+
/**
|
|
932
|
+
* If we're updating the value during another frame or eventloop
|
|
933
|
+
* than the previous frame, then the we set the previous frame value
|
|
934
|
+
* to current.
|
|
935
|
+
*/
|
|
936
|
+
if (this.updatedAt !== currentTime) {
|
|
937
|
+
this.setPrevFrameValue();
|
|
938
|
+
}
|
|
939
|
+
this.prev = this.current;
|
|
940
|
+
this.setCurrent(v);
|
|
941
|
+
// Update update subscribers
|
|
942
|
+
if (this.current !== this.prev && this.events.change) {
|
|
943
|
+
this.events.change.notify(this.current);
|
|
944
|
+
}
|
|
945
|
+
// Update render subscribers
|
|
946
|
+
if (render && this.events.renderRequest) {
|
|
947
|
+
this.events.renderRequest.notify(this.current);
|
|
948
|
+
}
|
|
722
949
|
};
|
|
950
|
+
this.hasAnimated = false;
|
|
951
|
+
this.setCurrent(init);
|
|
952
|
+
this.owner = options.owner;
|
|
723
953
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
damping: springDefaults.damping,
|
|
731
|
-
duration,
|
|
732
|
-
};
|
|
954
|
+
setCurrent(current) {
|
|
955
|
+
this.current = current;
|
|
956
|
+
this.updatedAt = time.now();
|
|
957
|
+
if (this.canTrackVelocity === null && current !== undefined) {
|
|
958
|
+
this.canTrackVelocity = isFloat(this.current);
|
|
959
|
+
}
|
|
733
960
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
stiffness,
|
|
738
|
-
damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),
|
|
739
|
-
duration,
|
|
740
|
-
};
|
|
961
|
+
setPrevFrameValue(prevFrameValue = this.current) {
|
|
962
|
+
this.prevFrameValue = prevFrameValue;
|
|
963
|
+
this.prevUpdatedAt = this.updatedAt;
|
|
741
964
|
}
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
965
|
+
/**
|
|
966
|
+
* Adds a function that will be notified when the `MotionValue` is updated.
|
|
967
|
+
*
|
|
968
|
+
* It returns a function that, when called, will cancel the subscription.
|
|
969
|
+
*
|
|
970
|
+
* When calling `onChange` inside a React component, it should be wrapped with the
|
|
971
|
+
* `useEffect` hook. As it returns an unsubscribe function, this should be returned
|
|
972
|
+
* from the `useEffect` function to ensure you don't add duplicate subscribers..
|
|
973
|
+
*
|
|
974
|
+
* ```jsx
|
|
975
|
+
* export const MyComponent = () => {
|
|
976
|
+
* const x = useMotionValue(0)
|
|
977
|
+
* const y = useMotionValue(0)
|
|
978
|
+
* const opacity = useMotionValue(1)
|
|
979
|
+
*
|
|
980
|
+
* useEffect(() => {
|
|
981
|
+
* function updateOpacity() {
|
|
982
|
+
* const maxXY = Math.max(x.get(), y.get())
|
|
983
|
+
* const newOpacity = transform(maxXY, [0, 100], [1, 0])
|
|
984
|
+
* opacity.set(newOpacity)
|
|
985
|
+
* }
|
|
986
|
+
*
|
|
987
|
+
* const unsubscribeX = x.on("change", updateOpacity)
|
|
988
|
+
* const unsubscribeY = y.on("change", updateOpacity)
|
|
989
|
+
*
|
|
990
|
+
* return () => {
|
|
991
|
+
* unsubscribeX()
|
|
992
|
+
* unsubscribeY()
|
|
993
|
+
* }
|
|
994
|
+
* }, [])
|
|
995
|
+
*
|
|
996
|
+
* return <motion.div style={{ x }} />
|
|
997
|
+
* }
|
|
998
|
+
* ```
|
|
999
|
+
*
|
|
1000
|
+
* @param subscriber - A function that receives the latest value.
|
|
1001
|
+
* @returns A function that, when called, will cancel this subscription.
|
|
1002
|
+
*
|
|
1003
|
+
* @deprecated
|
|
1004
|
+
*/
|
|
1005
|
+
onChange(subscription) {
|
|
1006
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1007
|
+
warnOnce(false, `value.onChange(callback) is deprecated. Switch to value.on("change", callback).`);
|
|
1008
|
+
}
|
|
1009
|
+
return this.on("change", subscription);
|
|
748
1010
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
const durationKeys = ["duration", "bounce"];
|
|
756
|
-
const physicsKeys = ["stiffness", "damping", "mass"];
|
|
757
|
-
function isSpringType(options, keys) {
|
|
758
|
-
return keys.some((key) => options[key] !== undefined);
|
|
759
|
-
}
|
|
760
|
-
function getSpringOptions(options) {
|
|
761
|
-
let springOptions = {
|
|
762
|
-
velocity: springDefaults.velocity,
|
|
763
|
-
stiffness: springDefaults.stiffness,
|
|
764
|
-
damping: springDefaults.damping,
|
|
765
|
-
mass: springDefaults.mass,
|
|
766
|
-
isResolvedFromDuration: false,
|
|
767
|
-
...options,
|
|
768
|
-
};
|
|
769
|
-
// stiffness/damping/mass overrides duration/bounce
|
|
770
|
-
if (!isSpringType(options, physicsKeys) &&
|
|
771
|
-
isSpringType(options, durationKeys)) {
|
|
772
|
-
if (options.visualDuration) {
|
|
773
|
-
const visualDuration = options.visualDuration;
|
|
774
|
-
const root = (2 * Math.PI) / (visualDuration * 1.2);
|
|
775
|
-
const stiffness = root * root;
|
|
776
|
-
const damping = 2 *
|
|
777
|
-
clamp(0.05, 1, 1 - (options.bounce || 0)) *
|
|
778
|
-
Math.sqrt(stiffness);
|
|
779
|
-
springOptions = {
|
|
780
|
-
...springOptions,
|
|
781
|
-
mass: springDefaults.mass,
|
|
782
|
-
stiffness,
|
|
783
|
-
damping,
|
|
784
|
-
};
|
|
1011
|
+
on(eventName, callback) {
|
|
1012
|
+
if (!this.events[eventName]) {
|
|
1013
|
+
this.events[eventName] = new SubscriptionManager();
|
|
785
1014
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
1015
|
+
const unsubscribe = this.events[eventName].add(callback);
|
|
1016
|
+
if (eventName === "change") {
|
|
1017
|
+
return () => {
|
|
1018
|
+
unsubscribe();
|
|
1019
|
+
/**
|
|
1020
|
+
* If we have no more change listeners by the start
|
|
1021
|
+
* of the next frame, stop active animations.
|
|
1022
|
+
*/
|
|
1023
|
+
frame.read(() => {
|
|
1024
|
+
if (!this.events.change.getSize()) {
|
|
1025
|
+
this.stop();
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
792
1028
|
};
|
|
793
|
-
springOptions.isResolvedFromDuration = true;
|
|
794
1029
|
}
|
|
1030
|
+
return unsubscribe;
|
|
795
1031
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
const options = typeof optionsOrVisualDuration !== "object"
|
|
800
|
-
? {
|
|
801
|
-
visualDuration: optionsOrVisualDuration,
|
|
802
|
-
keyframes: [0, 1],
|
|
803
|
-
bounce,
|
|
1032
|
+
clearListeners() {
|
|
1033
|
+
for (const eventManagers in this.events) {
|
|
1034
|
+
this.events[eventManagers].clear();
|
|
804
1035
|
}
|
|
805
|
-
|
|
806
|
-
let { restSpeed, restDelta } = options;
|
|
807
|
-
const origin = options.keyframes[0];
|
|
808
|
-
const target = options.keyframes[options.keyframes.length - 1];
|
|
1036
|
+
}
|
|
809
1037
|
/**
|
|
810
|
-
*
|
|
811
|
-
* to reduce GC during animation.
|
|
1038
|
+
* Attaches a passive effect to the `MotionValue`.
|
|
812
1039
|
*/
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
});
|
|
818
|
-
const initialVelocity = velocity || 0.0;
|
|
819
|
-
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
|
|
820
|
-
const initialDelta = target - origin;
|
|
821
|
-
const undampedAngularFreq = millisecondsToSeconds(Math.sqrt(stiffness / mass));
|
|
1040
|
+
attach(passiveEffect, stopPassiveEffect) {
|
|
1041
|
+
this.passiveEffect = passiveEffect;
|
|
1042
|
+
this.stopPassiveEffect = stopPassiveEffect;
|
|
1043
|
+
}
|
|
822
1044
|
/**
|
|
823
|
-
*
|
|
824
|
-
* when the spring is finished.
|
|
1045
|
+
* Sets the state of the `MotionValue`.
|
|
825
1046
|
*
|
|
826
|
-
*
|
|
827
|
-
*
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
dampingRatio * undampedAngularFreq * initialDelta) /
|
|
846
|
-
angularFreq) *
|
|
847
|
-
Math.sin(angularFreq * t) +
|
|
848
|
-
initialDelta * Math.cos(angularFreq * t)));
|
|
849
|
-
};
|
|
1047
|
+
* @remarks
|
|
1048
|
+
*
|
|
1049
|
+
* ```jsx
|
|
1050
|
+
* const x = useMotionValue(0)
|
|
1051
|
+
* x.set(10)
|
|
1052
|
+
* ```
|
|
1053
|
+
*
|
|
1054
|
+
* @param latest - Latest value to set.
|
|
1055
|
+
* @param render - Whether to notify render subscribers. Defaults to `true`
|
|
1056
|
+
*
|
|
1057
|
+
* @public
|
|
1058
|
+
*/
|
|
1059
|
+
set(v, render = true) {
|
|
1060
|
+
if (!render || !this.passiveEffect) {
|
|
1061
|
+
this.updateAndNotify(v, render);
|
|
1062
|
+
}
|
|
1063
|
+
else {
|
|
1064
|
+
this.passiveEffect(v, this.updateAndNotify);
|
|
1065
|
+
}
|
|
850
1066
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
(initialVelocity + undampedAngularFreq * initialDelta) * t);
|
|
1067
|
+
setWithVelocity(prev, current, delta) {
|
|
1068
|
+
this.set(current);
|
|
1069
|
+
this.prev = undefined;
|
|
1070
|
+
this.prevFrameValue = prev;
|
|
1071
|
+
this.prevUpdatedAt = this.updatedAt - delta;
|
|
857
1072
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
Math.sinh(freqForT) +
|
|
870
|
-
dampedAngularFreq *
|
|
871
|
-
initialDelta *
|
|
872
|
-
Math.cosh(freqForT))) /
|
|
873
|
-
dampedAngularFreq);
|
|
874
|
-
};
|
|
1073
|
+
/**
|
|
1074
|
+
* Set the state of the `MotionValue`, stopping any active animations,
|
|
1075
|
+
* effects, and resets velocity to `0`.
|
|
1076
|
+
*/
|
|
1077
|
+
jump(v, endAnimation = true) {
|
|
1078
|
+
this.updateAndNotify(v);
|
|
1079
|
+
this.prev = v;
|
|
1080
|
+
this.prevUpdatedAt = this.prevFrameValue = undefined;
|
|
1081
|
+
endAnimation && this.stop();
|
|
1082
|
+
if (this.stopPassiveEffect)
|
|
1083
|
+
this.stopPassiveEffect();
|
|
875
1084
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
1085
|
+
/**
|
|
1086
|
+
* Returns the latest state of `MotionValue`
|
|
1087
|
+
*
|
|
1088
|
+
* @returns - The latest state of `MotionValue`
|
|
1089
|
+
*
|
|
1090
|
+
* @public
|
|
1091
|
+
*/
|
|
1092
|
+
get() {
|
|
1093
|
+
return this.current;
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* @public
|
|
1097
|
+
*/
|
|
1098
|
+
getPrevious() {
|
|
1099
|
+
return this.prev;
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Returns the latest velocity of `MotionValue`
|
|
1103
|
+
*
|
|
1104
|
+
* @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical.
|
|
1105
|
+
*
|
|
1106
|
+
* @public
|
|
1107
|
+
*/
|
|
1108
|
+
getVelocity() {
|
|
1109
|
+
const currentTime = time.now();
|
|
1110
|
+
if (!this.canTrackVelocity ||
|
|
1111
|
+
this.prevFrameValue === undefined ||
|
|
1112
|
+
currentTime - this.updatedAt > MAX_VELOCITY_DELTA) {
|
|
1113
|
+
return 0;
|
|
1114
|
+
}
|
|
1115
|
+
const delta = Math.min(this.updatedAt - this.prevUpdatedAt, MAX_VELOCITY_DELTA);
|
|
1116
|
+
// Casts because of parseFloat's poor typing
|
|
1117
|
+
return velocityPerSecond(parseFloat(this.current) -
|
|
1118
|
+
parseFloat(this.prevFrameValue), delta);
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Registers a new animation to control this `MotionValue`. Only one
|
|
1122
|
+
* animation can drive a `MotionValue` at one time.
|
|
1123
|
+
*
|
|
1124
|
+
* ```jsx
|
|
1125
|
+
* value.start()
|
|
1126
|
+
* ```
|
|
1127
|
+
*
|
|
1128
|
+
* @param animation - A function that starts the provided animation
|
|
1129
|
+
*/
|
|
1130
|
+
start(startAnimation) {
|
|
1131
|
+
this.stop();
|
|
1132
|
+
return new Promise((resolve) => {
|
|
1133
|
+
this.hasAnimated = true;
|
|
1134
|
+
this.animation = startAnimation(resolve);
|
|
1135
|
+
if (this.events.animationStart) {
|
|
1136
|
+
this.events.animationStart.notify();
|
|
897
1137
|
}
|
|
898
|
-
|
|
899
|
-
|
|
1138
|
+
}).then(() => {
|
|
1139
|
+
if (this.events.animationComplete) {
|
|
1140
|
+
this.events.animationComplete.notify();
|
|
900
1141
|
}
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1142
|
+
this.clearAnimation();
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Stop the currently active animation.
|
|
1147
|
+
*
|
|
1148
|
+
* @public
|
|
1149
|
+
*/
|
|
1150
|
+
stop() {
|
|
1151
|
+
if (this.animation) {
|
|
1152
|
+
this.animation.stop();
|
|
1153
|
+
if (this.events.animationCancel) {
|
|
1154
|
+
this.events.animationCancel.notify();
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
this.clearAnimation();
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Returns `true` if this value is currently animating.
|
|
1161
|
+
*
|
|
1162
|
+
* @public
|
|
1163
|
+
*/
|
|
1164
|
+
isAnimating() {
|
|
1165
|
+
return !!this.animation;
|
|
1166
|
+
}
|
|
1167
|
+
clearAnimation() {
|
|
1168
|
+
delete this.animation;
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Destroy and clean up subscribers to this `MotionValue`.
|
|
1172
|
+
*
|
|
1173
|
+
* The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically
|
|
1174
|
+
* handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually
|
|
1175
|
+
* created a `MotionValue` via the `motionValue` function.
|
|
1176
|
+
*
|
|
1177
|
+
* @public
|
|
1178
|
+
*/
|
|
1179
|
+
destroy() {
|
|
1180
|
+
this.clearListeners();
|
|
1181
|
+
this.stop();
|
|
1182
|
+
if (this.stopPassiveEffect) {
|
|
1183
|
+
this.stopPassiveEffect();
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
911
1186
|
}
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
const rangeSize = max - min;
|
|
915
|
-
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
|
|
916
|
-
};
|
|
917
|
-
|
|
918
|
-
const isEasingArray = (ease) => {
|
|
919
|
-
return Array.isArray(ease) && typeof ease[0] !== "number";
|
|
920
|
-
};
|
|
921
|
-
|
|
922
|
-
function getEasingForSegment(easing, i) {
|
|
923
|
-
return isEasingArray(easing) ? easing[wrap(0, easing.length, i)] : easing;
|
|
1187
|
+
function motionValue(init, options) {
|
|
1188
|
+
return new MotionValue(init, options);
|
|
924
1189
|
}
|
|
925
1190
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
So progress = 0.5 would change
|
|
933
|
-
|
|
934
|
-
from -------- to
|
|
935
|
-
|
|
936
|
-
to
|
|
937
|
-
|
|
938
|
-
from ---- to
|
|
939
|
-
|
|
940
|
-
E.g. from = 10, to = 20, progress = 0.5 => 15
|
|
941
|
-
|
|
942
|
-
@param [number]: Lower limit of range
|
|
943
|
-
@param [number]: Upper limit of range
|
|
944
|
-
@param [number]: The progress between lower and upper limits expressed 0-1
|
|
945
|
-
@return [number]: Value as calculated from progress within range (not limited within range)
|
|
946
|
-
*/
|
|
947
|
-
const mixNumber$1 = (from, to, progress) => {
|
|
948
|
-
return from + (to - from) * progress;
|
|
1191
|
+
const clamp = (min, max, v) => {
|
|
1192
|
+
if (v > max)
|
|
1193
|
+
return max;
|
|
1194
|
+
if (v < min)
|
|
1195
|
+
return min;
|
|
1196
|
+
return v;
|
|
949
1197
|
};
|
|
950
1198
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
offset.push(mixNumber$1(min, 1, offsetProgress));
|
|
956
|
-
}
|
|
1199
|
+
const velocitySampleDuration = 5; // ms
|
|
1200
|
+
function calcGeneratorVelocity(resolveValue, t, current) {
|
|
1201
|
+
const prevT = Math.max(t - velocitySampleDuration, 0);
|
|
1202
|
+
return velocityPerSecond(current - resolveValue(prevT), t - prevT);
|
|
957
1203
|
}
|
|
958
1204
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1205
|
+
const springDefaults = {
|
|
1206
|
+
// Default spring physics
|
|
1207
|
+
stiffness: 100,
|
|
1208
|
+
damping: 10,
|
|
1209
|
+
mass: 1.0,
|
|
1210
|
+
velocity: 0.0,
|
|
1211
|
+
// Default duration/bounce-based options
|
|
1212
|
+
duration: 800, // in ms
|
|
1213
|
+
bounce: 0.3,
|
|
1214
|
+
visualDuration: 0.3, // in seconds
|
|
1215
|
+
// Rest thresholds
|
|
1216
|
+
restSpeed: {
|
|
1217
|
+
granular: 0.01,
|
|
1218
|
+
default: 2,
|
|
1219
|
+
},
|
|
1220
|
+
restDelta: {
|
|
1221
|
+
granular: 0.005,
|
|
1222
|
+
default: 0.5,
|
|
1223
|
+
},
|
|
1224
|
+
// Limits
|
|
1225
|
+
minDuration: 0.01, // in seconds
|
|
1226
|
+
maxDuration: 10.0, // in seconds
|
|
1227
|
+
minDamping: 0.05,
|
|
1228
|
+
maxDamping: 1,
|
|
1229
|
+
};
|
|
970
1230
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1231
|
+
const safeMin = 0.001;
|
|
1232
|
+
function findSpring({ duration = springDefaults.duration, bounce = springDefaults.bounce, velocity = springDefaults.velocity, mass = springDefaults.mass, }) {
|
|
1233
|
+
let envelope;
|
|
1234
|
+
let derivative;
|
|
1235
|
+
warning(duration <= secondsToMilliseconds(springDefaults.maxDuration), "Spring duration must be 10 seconds or less");
|
|
1236
|
+
let dampingRatio = 1 - bounce;
|
|
1237
|
+
/**
|
|
1238
|
+
* Restrict dampingRatio and duration to within acceptable ranges.
|
|
1239
|
+
*/
|
|
1240
|
+
dampingRatio = clamp(springDefaults.minDamping, springDefaults.maxDamping, dampingRatio);
|
|
1241
|
+
duration = clamp(springDefaults.minDuration, springDefaults.maxDuration, millisecondsToSeconds(duration));
|
|
1242
|
+
if (dampingRatio < 1) {
|
|
1243
|
+
/**
|
|
1244
|
+
* Underdamped spring
|
|
1245
|
+
*/
|
|
1246
|
+
envelope = (undampedFreq) => {
|
|
1247
|
+
const exponentialDecay = undampedFreq * dampingRatio;
|
|
1248
|
+
const delta = exponentialDecay * duration;
|
|
1249
|
+
const a = exponentialDecay - velocity;
|
|
1250
|
+
const b = calcAngularFreq(undampedFreq, dampingRatio);
|
|
1251
|
+
const c = Math.exp(-delta);
|
|
1252
|
+
return safeMin - (a / b) * c;
|
|
1253
|
+
};
|
|
1254
|
+
derivative = (undampedFreq) => {
|
|
1255
|
+
const exponentialDecay = undampedFreq * dampingRatio;
|
|
1256
|
+
const delta = exponentialDecay * duration;
|
|
1257
|
+
const d = delta * velocity + velocity;
|
|
1258
|
+
const e = Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration;
|
|
1259
|
+
const f = Math.exp(-delta);
|
|
1260
|
+
const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio);
|
|
1261
|
+
const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1;
|
|
1262
|
+
return (factor * ((d - e) * f)) / g;
|
|
1263
|
+
};
|
|
980
1264
|
}
|
|
981
1265
|
else {
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
var _a;
|
|
996
|
-
if (typeof next === "number") {
|
|
997
|
-
return next;
|
|
998
|
-
}
|
|
999
|
-
else if (next.startsWith("-") || next.startsWith("+")) {
|
|
1000
|
-
return Math.max(0, current + parseFloat(next));
|
|
1266
|
+
/**
|
|
1267
|
+
* Critically-damped spring
|
|
1268
|
+
*/
|
|
1269
|
+
envelope = (undampedFreq) => {
|
|
1270
|
+
const a = Math.exp(-undampedFreq * duration);
|
|
1271
|
+
const b = (undampedFreq - velocity) * duration + 1;
|
|
1272
|
+
return -safeMin + a * b;
|
|
1273
|
+
};
|
|
1274
|
+
derivative = (undampedFreq) => {
|
|
1275
|
+
const a = Math.exp(-undampedFreq * duration);
|
|
1276
|
+
const b = (velocity - undampedFreq) * (duration * duration);
|
|
1277
|
+
return a * b;
|
|
1278
|
+
};
|
|
1001
1279
|
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1280
|
+
const initialGuess = 5 / duration;
|
|
1281
|
+
const undampedFreq = approximateRoot(envelope, derivative, initialGuess);
|
|
1282
|
+
duration = secondsToMilliseconds(duration);
|
|
1283
|
+
if (isNaN(undampedFreq)) {
|
|
1284
|
+
return {
|
|
1285
|
+
stiffness: springDefaults.stiffness,
|
|
1286
|
+
damping: springDefaults.damping,
|
|
1287
|
+
duration,
|
|
1288
|
+
};
|
|
1004
1289
|
}
|
|
1005
1290
|
else {
|
|
1006
|
-
|
|
1291
|
+
const stiffness = Math.pow(undampedFreq, 2) * mass;
|
|
1292
|
+
return {
|
|
1293
|
+
stiffness,
|
|
1294
|
+
damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),
|
|
1295
|
+
duration,
|
|
1296
|
+
};
|
|
1007
1297
|
}
|
|
1008
1298
|
}
|
|
1009
|
-
|
|
1010
|
-
function
|
|
1011
|
-
|
|
1012
|
-
|
|
1299
|
+
const rootIterations = 12;
|
|
1300
|
+
function approximateRoot(envelope, derivative, initialGuess) {
|
|
1301
|
+
let result = initialGuess;
|
|
1302
|
+
for (let i = 1; i < rootIterations; i++) {
|
|
1303
|
+
result = result - envelope(result) / derivative(result);
|
|
1304
|
+
}
|
|
1305
|
+
return result;
|
|
1013
1306
|
}
|
|
1014
|
-
function
|
|
1015
|
-
|
|
1016
|
-
if (index > -1)
|
|
1017
|
-
arr.splice(index, 1);
|
|
1307
|
+
function calcAngularFreq(undampedFreq, dampingRatio) {
|
|
1308
|
+
return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
|
|
1018
1309
|
}
|
|
1019
1310
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1311
|
+
const durationKeys = ["duration", "bounce"];
|
|
1312
|
+
const physicsKeys = ["stiffness", "damping", "mass"];
|
|
1313
|
+
function isSpringType(options, keys) {
|
|
1314
|
+
return keys.some((key) => options[key] !== undefined);
|
|
1315
|
+
}
|
|
1316
|
+
function getSpringOptions(options) {
|
|
1317
|
+
let springOptions = {
|
|
1318
|
+
velocity: springDefaults.velocity,
|
|
1319
|
+
stiffness: springDefaults.stiffness,
|
|
1320
|
+
damping: springDefaults.damping,
|
|
1321
|
+
mass: springDefaults.mass,
|
|
1322
|
+
isResolvedFromDuration: false,
|
|
1323
|
+
...options,
|
|
1324
|
+
};
|
|
1325
|
+
// stiffness/damping/mass overrides duration/bounce
|
|
1326
|
+
if (!isSpringType(options, physicsKeys) &&
|
|
1327
|
+
isSpringType(options, durationKeys)) {
|
|
1328
|
+
if (options.visualDuration) {
|
|
1329
|
+
const visualDuration = options.visualDuration;
|
|
1330
|
+
const root = (2 * Math.PI) / (visualDuration * 1.2);
|
|
1331
|
+
const stiffness = root * root;
|
|
1332
|
+
const damping = 2 *
|
|
1333
|
+
clamp(0.05, 1, 1 - (options.bounce || 0)) *
|
|
1334
|
+
Math.sqrt(stiffness);
|
|
1335
|
+
springOptions = {
|
|
1336
|
+
...springOptions,
|
|
1337
|
+
mass: springDefaults.mass,
|
|
1338
|
+
stiffness,
|
|
1339
|
+
damping,
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
else {
|
|
1343
|
+
const derived = findSpring(options);
|
|
1344
|
+
springOptions = {
|
|
1345
|
+
...springOptions,
|
|
1346
|
+
...derived,
|
|
1347
|
+
mass: springDefaults.mass,
|
|
1348
|
+
};
|
|
1349
|
+
springOptions.isResolvedFromDuration = true;
|
|
1027
1350
|
}
|
|
1028
1351
|
}
|
|
1352
|
+
return springOptions;
|
|
1029
1353
|
}
|
|
1030
|
-
function
|
|
1354
|
+
function spring(optionsOrVisualDuration = springDefaults.visualDuration, bounce = springDefaults.bounce) {
|
|
1355
|
+
const options = typeof optionsOrVisualDuration !== "object"
|
|
1356
|
+
? {
|
|
1357
|
+
visualDuration: optionsOrVisualDuration,
|
|
1358
|
+
keyframes: [0, 1],
|
|
1359
|
+
bounce,
|
|
1360
|
+
}
|
|
1361
|
+
: optionsOrVisualDuration;
|
|
1362
|
+
let { restSpeed, restDelta } = options;
|
|
1363
|
+
const origin = options.keyframes[0];
|
|
1364
|
+
const target = options.keyframes[options.keyframes.length - 1];
|
|
1031
1365
|
/**
|
|
1032
|
-
*
|
|
1033
|
-
*
|
|
1034
|
-
* defined ones.
|
|
1366
|
+
* This is the Iterator-spec return value. We ensure it's mutable rather than using a generator
|
|
1367
|
+
* to reduce GC during animation.
|
|
1035
1368
|
*/
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1369
|
+
const state = { done: false, value: origin };
|
|
1370
|
+
const { stiffness, damping, mass, duration, velocity, isResolvedFromDuration, } = getSpringOptions({
|
|
1371
|
+
...options,
|
|
1372
|
+
velocity: -millisecondsToSeconds(options.velocity || 0),
|
|
1373
|
+
});
|
|
1374
|
+
const initialVelocity = velocity || 0.0;
|
|
1375
|
+
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
|
|
1376
|
+
const initialDelta = target - origin;
|
|
1377
|
+
const undampedAngularFreq = millisecondsToSeconds(Math.sqrt(stiffness / mass));
|
|
1378
|
+
/**
|
|
1379
|
+
* If we're working on a granular scale, use smaller defaults for determining
|
|
1380
|
+
* when the spring is finished.
|
|
1381
|
+
*
|
|
1382
|
+
* These defaults have been selected emprically based on what strikes a good
|
|
1383
|
+
* ratio between feeling good and finishing as soon as changes are imperceptible.
|
|
1384
|
+
*/
|
|
1385
|
+
const isGranularScale = Math.abs(initialDelta) < 5;
|
|
1386
|
+
restSpeed || (restSpeed = isGranularScale
|
|
1387
|
+
? springDefaults.restSpeed.granular
|
|
1388
|
+
: springDefaults.restSpeed.default);
|
|
1389
|
+
restDelta || (restDelta = isGranularScale
|
|
1390
|
+
? springDefaults.restDelta.granular
|
|
1391
|
+
: springDefaults.restDelta.default);
|
|
1392
|
+
let resolveSpring;
|
|
1393
|
+
if (dampingRatio < 1) {
|
|
1394
|
+
const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio);
|
|
1395
|
+
// Underdamped spring
|
|
1396
|
+
resolveSpring = (t) => {
|
|
1397
|
+
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
|
1398
|
+
return (target -
|
|
1399
|
+
envelope *
|
|
1400
|
+
(((initialVelocity +
|
|
1401
|
+
dampingRatio * undampedAngularFreq * initialDelta) /
|
|
1402
|
+
angularFreq) *
|
|
1403
|
+
Math.sin(angularFreq * t) +
|
|
1404
|
+
initialDelta * Math.cos(angularFreq * t)));
|
|
1405
|
+
};
|
|
1043
1406
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
*
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
* down to a 0-1 scale.
|
|
1051
|
-
*/
|
|
1052
|
-
function normalizeTimes(times, repeat) {
|
|
1053
|
-
for (let i = 0; i < times.length; i++) {
|
|
1054
|
-
times[i] = times[i] / (repeat + 1);
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
function compareByTime(a, b) {
|
|
1059
|
-
if (a.at === b.at) {
|
|
1060
|
-
if (a.value === null)
|
|
1061
|
-
return 1;
|
|
1062
|
-
if (b.value === null)
|
|
1063
|
-
return -1;
|
|
1064
|
-
return 0;
|
|
1407
|
+
else if (dampingRatio === 1) {
|
|
1408
|
+
// Critically damped spring
|
|
1409
|
+
resolveSpring = (t) => target -
|
|
1410
|
+
Math.exp(-undampedAngularFreq * t) *
|
|
1411
|
+
(initialDelta +
|
|
1412
|
+
(initialVelocity + undampedAngularFreq * initialDelta) * t);
|
|
1065
1413
|
}
|
|
1066
1414
|
else {
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
/**
|
|
1083
|
-
* Build the timeline by mapping over the sequence array and converting
|
|
1084
|
-
* the definitions into keyframes and offsets with absolute time values.
|
|
1085
|
-
* These will later get converted into relative offsets in a second pass.
|
|
1086
|
-
*/
|
|
1087
|
-
for (let i = 0; i < sequence.length; i++) {
|
|
1088
|
-
const segment = sequence[i];
|
|
1089
|
-
/**
|
|
1090
|
-
* If this is a timeline label, mark it and skip the rest of this iteration.
|
|
1091
|
-
*/
|
|
1092
|
-
if (typeof segment === "string") {
|
|
1093
|
-
timeLabels.set(segment, currentTime);
|
|
1094
|
-
continue;
|
|
1095
|
-
}
|
|
1096
|
-
else if (!Array.isArray(segment)) {
|
|
1097
|
-
timeLabels.set(segment.name, calcNextTime(currentTime, segment.at, prevTime, timeLabels));
|
|
1098
|
-
continue;
|
|
1099
|
-
}
|
|
1100
|
-
let [subject, keyframes, transition = {}] = segment;
|
|
1101
|
-
/**
|
|
1102
|
-
* If a relative or absolute time value has been specified we need to resolve
|
|
1103
|
-
* it in relation to the currentTime.
|
|
1104
|
-
*/
|
|
1105
|
-
if (transition.at !== undefined) {
|
|
1106
|
-
currentTime = calcNextTime(currentTime, transition.at, prevTime, timeLabels);
|
|
1107
|
-
}
|
|
1108
|
-
/**
|
|
1109
|
-
* Keep track of the maximum duration in this definition. This will be
|
|
1110
|
-
* applied to currentTime once the definition has been parsed.
|
|
1111
|
-
*/
|
|
1112
|
-
let maxDuration = 0;
|
|
1113
|
-
const resolveValueSequence = (valueKeyframes, valueTransition, valueSequence, elementIndex = 0, numSubjects = 0) => {
|
|
1114
|
-
const valueKeyframesAsList = keyframesAsList(valueKeyframes);
|
|
1115
|
-
const { delay = 0, times = defaultOffset$1(valueKeyframesAsList), type = "keyframes", repeat, repeatType, repeatDelay = 0, ...remainingTransition } = valueTransition;
|
|
1116
|
-
let { ease = defaultTransition.ease || "easeOut", duration } = valueTransition;
|
|
1117
|
-
/**
|
|
1118
|
-
* Resolve stagger() if defined.
|
|
1119
|
-
*/
|
|
1120
|
-
const calculatedDelay = typeof delay === "function"
|
|
1121
|
-
? delay(elementIndex, numSubjects)
|
|
1122
|
-
: delay;
|
|
1123
|
-
/**
|
|
1124
|
-
* If this animation should and can use a spring, generate a spring easing function.
|
|
1125
|
-
*/
|
|
1126
|
-
const numKeyframes = valueKeyframesAsList.length;
|
|
1127
|
-
const createGenerator = isGenerator(type)
|
|
1128
|
-
? type
|
|
1129
|
-
: generators === null || generators === void 0 ? void 0 : generators[type];
|
|
1130
|
-
if (numKeyframes <= 2 && createGenerator) {
|
|
1131
|
-
/**
|
|
1132
|
-
* As we're creating an easing function from a spring,
|
|
1133
|
-
* ideally we want to generate it using the real distance
|
|
1134
|
-
* between the two keyframes. However this isn't always
|
|
1135
|
-
* possible - in these situations we use 0-100.
|
|
1136
|
-
*/
|
|
1137
|
-
let absoluteDelta = 100;
|
|
1138
|
-
if (numKeyframes === 2 &&
|
|
1139
|
-
isNumberKeyframesArray(valueKeyframesAsList)) {
|
|
1140
|
-
const delta = valueKeyframesAsList[1] - valueKeyframesAsList[0];
|
|
1141
|
-
absoluteDelta = Math.abs(delta);
|
|
1142
|
-
}
|
|
1143
|
-
const springTransition = { ...remainingTransition };
|
|
1144
|
-
if (duration !== undefined) {
|
|
1145
|
-
springTransition.duration = secondsToMilliseconds(duration);
|
|
1146
|
-
}
|
|
1147
|
-
const springEasing = createGeneratorEasing(springTransition, absoluteDelta, createGenerator);
|
|
1148
|
-
ease = springEasing.ease;
|
|
1149
|
-
duration = springEasing.duration;
|
|
1150
|
-
}
|
|
1151
|
-
duration !== null && duration !== void 0 ? duration : (duration = defaultDuration);
|
|
1152
|
-
const startTime = currentTime + calculatedDelay;
|
|
1153
|
-
/**
|
|
1154
|
-
* If there's only one time offset of 0, fill in a second with length 1
|
|
1155
|
-
*/
|
|
1156
|
-
if (times.length === 1 && times[0] === 0) {
|
|
1157
|
-
times[1] = 1;
|
|
1158
|
-
}
|
|
1159
|
-
/**
|
|
1160
|
-
* Fill out if offset if fewer offsets than keyframes
|
|
1161
|
-
*/
|
|
1162
|
-
const remainder = times.length - valueKeyframesAsList.length;
|
|
1163
|
-
remainder > 0 && fillOffset(times, remainder);
|
|
1164
|
-
/**
|
|
1165
|
-
* If only one value has been set, ie [1], push a null to the start of
|
|
1166
|
-
* the keyframe array. This will let us mark a keyframe at this point
|
|
1167
|
-
* that will later be hydrated with the previous value.
|
|
1168
|
-
*/
|
|
1169
|
-
valueKeyframesAsList.length === 1 &&
|
|
1170
|
-
valueKeyframesAsList.unshift(null);
|
|
1171
|
-
/**
|
|
1172
|
-
* Handle repeat options
|
|
1173
|
-
*/
|
|
1174
|
-
if (repeat) {
|
|
1175
|
-
exports.invariant(repeat < MAX_REPEAT, "Repeat count too high, must be less than 20");
|
|
1176
|
-
duration = calculateRepeatDuration(duration, repeat);
|
|
1177
|
-
const originalKeyframes = [...valueKeyframesAsList];
|
|
1178
|
-
const originalTimes = [...times];
|
|
1179
|
-
ease = Array.isArray(ease) ? [...ease] : [ease];
|
|
1180
|
-
const originalEase = [...ease];
|
|
1181
|
-
for (let repeatIndex = 0; repeatIndex < repeat; repeatIndex++) {
|
|
1182
|
-
valueKeyframesAsList.push(...originalKeyframes);
|
|
1183
|
-
for (let keyframeIndex = 0; keyframeIndex < originalKeyframes.length; keyframeIndex++) {
|
|
1184
|
-
times.push(originalTimes[keyframeIndex] + (repeatIndex + 1));
|
|
1185
|
-
ease.push(keyframeIndex === 0
|
|
1186
|
-
? "linear"
|
|
1187
|
-
: getEasingForSegment(originalEase, keyframeIndex - 1));
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
normalizeTimes(times, repeat);
|
|
1191
|
-
}
|
|
1192
|
-
const targetTime = startTime + duration;
|
|
1193
|
-
/**
|
|
1194
|
-
* Add keyframes, mapping offsets to absolute time.
|
|
1195
|
-
*/
|
|
1196
|
-
addKeyframes(valueSequence, valueKeyframesAsList, ease, times, startTime, targetTime);
|
|
1197
|
-
maxDuration = Math.max(calculatedDelay + duration, maxDuration);
|
|
1198
|
-
totalDuration = Math.max(targetTime, totalDuration);
|
|
1415
|
+
// Overdamped spring
|
|
1416
|
+
const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
|
|
1417
|
+
resolveSpring = (t) => {
|
|
1418
|
+
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
|
1419
|
+
// When performing sinh or cosh values can hit Infinity so we cap them here
|
|
1420
|
+
const freqForT = Math.min(dampedAngularFreq * t, 300);
|
|
1421
|
+
return (target -
|
|
1422
|
+
(envelope *
|
|
1423
|
+
((initialVelocity +
|
|
1424
|
+
dampingRatio * undampedAngularFreq * initialDelta) *
|
|
1425
|
+
Math.sinh(freqForT) +
|
|
1426
|
+
dampedAngularFreq *
|
|
1427
|
+
initialDelta *
|
|
1428
|
+
Math.cosh(freqForT))) /
|
|
1429
|
+
dampedAngularFreq);
|
|
1199
1430
|
};
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
/**
|
|
1208
|
-
* For every element in this segment, process the defined values.
|
|
1209
|
-
*/
|
|
1210
|
-
for (let subjectIndex = 0; subjectIndex < numSubjects; subjectIndex++) {
|
|
1431
|
+
}
|
|
1432
|
+
const generator = {
|
|
1433
|
+
calculatedDuration: isResolvedFromDuration ? duration || null : null,
|
|
1434
|
+
next: (t) => {
|
|
1435
|
+
const current = resolveSpring(t);
|
|
1436
|
+
if (!isResolvedFromDuration) {
|
|
1437
|
+
let currentVelocity = 0.0;
|
|
1211
1438
|
/**
|
|
1212
|
-
*
|
|
1439
|
+
* We only need to calculate velocity for under-damped springs
|
|
1440
|
+
* as over- and critically-damped springs can't overshoot, so
|
|
1441
|
+
* checking only for displacement is enough.
|
|
1213
1442
|
*/
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
resolveValueSequence(keyframes[key], getValueTransition(transition, key), getValueSequence(key, subjectSequence), subjectIndex, numSubjects);
|
|
1443
|
+
if (dampingRatio < 1) {
|
|
1444
|
+
currentVelocity =
|
|
1445
|
+
t === 0
|
|
1446
|
+
? secondsToMilliseconds(initialVelocity)
|
|
1447
|
+
: calcGeneratorVelocity(resolveSpring, t, current);
|
|
1220
1448
|
}
|
|
1449
|
+
const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
|
|
1450
|
+
const isBelowDisplacementThreshold = Math.abs(target - current) <= restDelta;
|
|
1451
|
+
state.done =
|
|
1452
|
+
isBelowVelocityThreshold && isBelowDisplacementThreshold;
|
|
1221
1453
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
currentTime += maxDuration;
|
|
1225
|
-
}
|
|
1226
|
-
/**
|
|
1227
|
-
* For every element and value combination create a new animation.
|
|
1228
|
-
*/
|
|
1229
|
-
sequences.forEach((valueSequences, element) => {
|
|
1230
|
-
for (const key in valueSequences) {
|
|
1231
|
-
const valueSequence = valueSequences[key];
|
|
1232
|
-
/**
|
|
1233
|
-
* Arrange all the keyframes in ascending time order.
|
|
1234
|
-
*/
|
|
1235
|
-
valueSequence.sort(compareByTime);
|
|
1236
|
-
const keyframes = [];
|
|
1237
|
-
const valueOffset = [];
|
|
1238
|
-
const valueEasing = [];
|
|
1239
|
-
/**
|
|
1240
|
-
* For each keyframe, translate absolute times into
|
|
1241
|
-
* relative offsets based on the total duration of the timeline.
|
|
1242
|
-
*/
|
|
1243
|
-
for (let i = 0; i < valueSequence.length; i++) {
|
|
1244
|
-
const { at, value, easing } = valueSequence[i];
|
|
1245
|
-
keyframes.push(value);
|
|
1246
|
-
valueOffset.push(progress(0, totalDuration, at));
|
|
1247
|
-
valueEasing.push(easing || "easeOut");
|
|
1248
|
-
}
|
|
1249
|
-
/**
|
|
1250
|
-
* If the first keyframe doesn't land on offset: 0
|
|
1251
|
-
* provide one by duplicating the initial keyframe. This ensures
|
|
1252
|
-
* it snaps to the first keyframe when the animation starts.
|
|
1253
|
-
*/
|
|
1254
|
-
if (valueOffset[0] !== 0) {
|
|
1255
|
-
valueOffset.unshift(0);
|
|
1256
|
-
keyframes.unshift(keyframes[0]);
|
|
1257
|
-
valueEasing.unshift(defaultSegmentEasing);
|
|
1258
|
-
}
|
|
1259
|
-
/**
|
|
1260
|
-
* If the last keyframe doesn't land on offset: 1
|
|
1261
|
-
* provide one with a null wildcard value. This will ensure it
|
|
1262
|
-
* stays static until the end of the animation.
|
|
1263
|
-
*/
|
|
1264
|
-
if (valueOffset[valueOffset.length - 1] !== 1) {
|
|
1265
|
-
valueOffset.push(1);
|
|
1266
|
-
keyframes.push(null);
|
|
1267
|
-
}
|
|
1268
|
-
if (!animationDefinitions.has(element)) {
|
|
1269
|
-
animationDefinitions.set(element, {
|
|
1270
|
-
keyframes: {},
|
|
1271
|
-
transition: {},
|
|
1272
|
-
});
|
|
1273
|
-
}
|
|
1274
|
-
const definition = animationDefinitions.get(element);
|
|
1275
|
-
definition.keyframes[key] = keyframes;
|
|
1276
|
-
definition.transition[key] = {
|
|
1277
|
-
...defaultTransition,
|
|
1278
|
-
duration: totalDuration,
|
|
1279
|
-
ease: valueEasing,
|
|
1280
|
-
times: valueOffset,
|
|
1281
|
-
...sequenceTransition,
|
|
1282
|
-
};
|
|
1283
|
-
}
|
|
1284
|
-
});
|
|
1285
|
-
return animationDefinitions;
|
|
1286
|
-
}
|
|
1287
|
-
function getSubjectSequence(subject, sequences) {
|
|
1288
|
-
!sequences.has(subject) && sequences.set(subject, {});
|
|
1289
|
-
return sequences.get(subject);
|
|
1290
|
-
}
|
|
1291
|
-
function getValueSequence(name, sequences) {
|
|
1292
|
-
if (!sequences[name])
|
|
1293
|
-
sequences[name] = [];
|
|
1294
|
-
return sequences[name];
|
|
1295
|
-
}
|
|
1296
|
-
function keyframesAsList(keyframes) {
|
|
1297
|
-
return Array.isArray(keyframes) ? keyframes : [keyframes];
|
|
1298
|
-
}
|
|
1299
|
-
function getValueTransition(transition, key) {
|
|
1300
|
-
return transition && transition[key]
|
|
1301
|
-
? {
|
|
1302
|
-
...transition,
|
|
1303
|
-
...transition[key],
|
|
1304
|
-
}
|
|
1305
|
-
: { ...transition };
|
|
1306
|
-
}
|
|
1307
|
-
const isNumber = (keyframe) => typeof keyframe === "number";
|
|
1308
|
-
const isNumberKeyframesArray = (keyframes) => keyframes.every(isNumber);
|
|
1309
|
-
|
|
1310
|
-
const visualElementStore = new WeakMap();
|
|
1311
|
-
|
|
1312
|
-
/**
|
|
1313
|
-
* Generate a list of every possible transform key.
|
|
1314
|
-
*/
|
|
1315
|
-
const transformPropOrder = [
|
|
1316
|
-
"transformPerspective",
|
|
1317
|
-
"x",
|
|
1318
|
-
"y",
|
|
1319
|
-
"z",
|
|
1320
|
-
"translateX",
|
|
1321
|
-
"translateY",
|
|
1322
|
-
"translateZ",
|
|
1323
|
-
"scale",
|
|
1324
|
-
"scaleX",
|
|
1325
|
-
"scaleY",
|
|
1326
|
-
"rotate",
|
|
1327
|
-
"rotateX",
|
|
1328
|
-
"rotateY",
|
|
1329
|
-
"rotateZ",
|
|
1330
|
-
"skew",
|
|
1331
|
-
"skewX",
|
|
1332
|
-
"skewY",
|
|
1333
|
-
];
|
|
1334
|
-
/**
|
|
1335
|
-
* A quick lookup for transform props.
|
|
1336
|
-
*/
|
|
1337
|
-
const transformProps = new Set(transformPropOrder);
|
|
1338
|
-
|
|
1339
|
-
const positionalKeys = new Set([
|
|
1340
|
-
"width",
|
|
1341
|
-
"height",
|
|
1342
|
-
"top",
|
|
1343
|
-
"left",
|
|
1344
|
-
"right",
|
|
1345
|
-
"bottom",
|
|
1346
|
-
...transformPropOrder,
|
|
1347
|
-
]);
|
|
1348
|
-
|
|
1349
|
-
const isKeyframesTarget = (v) => {
|
|
1350
|
-
return Array.isArray(v);
|
|
1351
|
-
};
|
|
1352
|
-
|
|
1353
|
-
const resolveFinalValueInKeyframes = (v) => {
|
|
1354
|
-
// TODO maybe throw if v.length - 1 is placeholder token?
|
|
1355
|
-
return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
|
|
1356
|
-
};
|
|
1357
|
-
|
|
1358
|
-
const MotionGlobalConfig = {
|
|
1359
|
-
skipAnimations: false,
|
|
1360
|
-
useManualTiming: false,
|
|
1361
|
-
};
|
|
1362
|
-
|
|
1363
|
-
const stepsOrder = [
|
|
1364
|
-
"read", // Read
|
|
1365
|
-
"resolveKeyframes", // Write/Read/Write/Read
|
|
1366
|
-
"update", // Compute
|
|
1367
|
-
"preRender", // Compute
|
|
1368
|
-
"render", // Write
|
|
1369
|
-
"postRender", // Compute
|
|
1370
|
-
];
|
|
1371
|
-
|
|
1372
|
-
const statsBuffer = {
|
|
1373
|
-
value: null,
|
|
1374
|
-
addProjectionMetrics: null,
|
|
1375
|
-
};
|
|
1376
|
-
|
|
1377
|
-
function createRenderStep(runNextFrame, stepName) {
|
|
1378
|
-
/**
|
|
1379
|
-
* We create and reuse two queues, one to queue jobs for the current frame
|
|
1380
|
-
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
1381
|
-
*/
|
|
1382
|
-
let thisFrame = new Set();
|
|
1383
|
-
let nextFrame = new Set();
|
|
1384
|
-
/**
|
|
1385
|
-
* Track whether we're currently processing jobs in this step. This way
|
|
1386
|
-
* we can decide whether to schedule new jobs for this frame or next.
|
|
1387
|
-
*/
|
|
1388
|
-
let isProcessing = false;
|
|
1389
|
-
let flushNextFrame = false;
|
|
1390
|
-
/**
|
|
1391
|
-
* A set of processes which were marked keepAlive when scheduled.
|
|
1392
|
-
*/
|
|
1393
|
-
const toKeepAlive = new WeakSet();
|
|
1394
|
-
let latestFrameData = {
|
|
1395
|
-
delta: 0.0,
|
|
1396
|
-
timestamp: 0.0,
|
|
1397
|
-
isProcessing: false,
|
|
1398
|
-
};
|
|
1399
|
-
let numCalls = 0;
|
|
1400
|
-
function triggerCallback(callback) {
|
|
1401
|
-
if (toKeepAlive.has(callback)) {
|
|
1402
|
-
step.schedule(callback);
|
|
1403
|
-
runNextFrame();
|
|
1404
|
-
}
|
|
1405
|
-
numCalls++;
|
|
1406
|
-
callback(latestFrameData);
|
|
1407
|
-
}
|
|
1408
|
-
const step = {
|
|
1409
|
-
/**
|
|
1410
|
-
* Schedule a process to run on the next frame.
|
|
1411
|
-
*/
|
|
1412
|
-
schedule: (callback, keepAlive = false, immediate = false) => {
|
|
1413
|
-
const addToCurrentFrame = immediate && isProcessing;
|
|
1414
|
-
const queue = addToCurrentFrame ? thisFrame : nextFrame;
|
|
1415
|
-
if (keepAlive)
|
|
1416
|
-
toKeepAlive.add(callback);
|
|
1417
|
-
if (!queue.has(callback))
|
|
1418
|
-
queue.add(callback);
|
|
1419
|
-
return callback;
|
|
1420
|
-
},
|
|
1421
|
-
/**
|
|
1422
|
-
* Cancel the provided callback from running on the next frame.
|
|
1423
|
-
*/
|
|
1424
|
-
cancel: (callback) => {
|
|
1425
|
-
nextFrame.delete(callback);
|
|
1426
|
-
toKeepAlive.delete(callback);
|
|
1427
|
-
},
|
|
1428
|
-
/**
|
|
1429
|
-
* Execute all schedule callbacks.
|
|
1430
|
-
*/
|
|
1431
|
-
process: (frameData) => {
|
|
1432
|
-
latestFrameData = frameData;
|
|
1433
|
-
/**
|
|
1434
|
-
* If we're already processing we've probably been triggered by a flushSync
|
|
1435
|
-
* inside an existing process. Instead of executing, mark flushNextFrame
|
|
1436
|
-
* as true and ensure we flush the following frame at the end of this one.
|
|
1437
|
-
*/
|
|
1438
|
-
if (isProcessing) {
|
|
1439
|
-
flushNextFrame = true;
|
|
1440
|
-
return;
|
|
1441
|
-
}
|
|
1442
|
-
isProcessing = true;
|
|
1443
|
-
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
1444
|
-
// Execute this frame
|
|
1445
|
-
thisFrame.forEach(triggerCallback);
|
|
1446
|
-
/**
|
|
1447
|
-
* If we're recording stats then
|
|
1448
|
-
*/
|
|
1449
|
-
if (stepName && statsBuffer.value) {
|
|
1450
|
-
statsBuffer.value.frameloop[stepName].push(numCalls);
|
|
1451
|
-
}
|
|
1452
|
-
numCalls = 0;
|
|
1453
|
-
// Clear the frame so no callbacks remain. This is to avoid
|
|
1454
|
-
// memory leaks should this render step not run for a while.
|
|
1455
|
-
thisFrame.clear();
|
|
1456
|
-
isProcessing = false;
|
|
1457
|
-
if (flushNextFrame) {
|
|
1458
|
-
flushNextFrame = false;
|
|
1459
|
-
step.process(frameData);
|
|
1454
|
+
else {
|
|
1455
|
+
state.done = t >= duration;
|
|
1460
1456
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
const
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
let useDefaultElapsed = true;
|
|
1470
|
-
const state = {
|
|
1471
|
-
delta: 0.0,
|
|
1472
|
-
timestamp: 0.0,
|
|
1473
|
-
isProcessing: false,
|
|
1474
|
-
};
|
|
1475
|
-
const flagRunNextFrame = () => (runNextFrame = true);
|
|
1476
|
-
const steps = stepsOrder.reduce((acc, key) => {
|
|
1477
|
-
acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : undefined);
|
|
1478
|
-
return acc;
|
|
1479
|
-
}, {});
|
|
1480
|
-
const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
|
|
1481
|
-
const processBatch = () => {
|
|
1482
|
-
const timestamp = performance.now();
|
|
1483
|
-
runNextFrame = false;
|
|
1484
|
-
{
|
|
1485
|
-
state.delta = useDefaultElapsed
|
|
1486
|
-
? 1000 / 60
|
|
1487
|
-
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
|
|
1488
|
-
}
|
|
1489
|
-
state.timestamp = timestamp;
|
|
1490
|
-
state.isProcessing = true;
|
|
1491
|
-
// Unrolled render loop for better per-frame performance
|
|
1492
|
-
read.process(state);
|
|
1493
|
-
resolveKeyframes.process(state);
|
|
1494
|
-
update.process(state);
|
|
1495
|
-
preRender.process(state);
|
|
1496
|
-
render.process(state);
|
|
1497
|
-
postRender.process(state);
|
|
1498
|
-
state.isProcessing = false;
|
|
1499
|
-
if (runNextFrame && allowKeepAlive) {
|
|
1500
|
-
useDefaultElapsed = false;
|
|
1501
|
-
scheduleNextBatch(processBatch);
|
|
1502
|
-
}
|
|
1503
|
-
};
|
|
1504
|
-
const wake = () => {
|
|
1505
|
-
runNextFrame = true;
|
|
1506
|
-
useDefaultElapsed = true;
|
|
1507
|
-
if (!state.isProcessing) {
|
|
1508
|
-
scheduleNextBatch(processBatch);
|
|
1509
|
-
}
|
|
1510
|
-
};
|
|
1511
|
-
const schedule = stepsOrder.reduce((acc, key) => {
|
|
1512
|
-
const step = steps[key];
|
|
1513
|
-
acc[key] = (process, keepAlive = false, immediate = false) => {
|
|
1514
|
-
if (!runNextFrame)
|
|
1515
|
-
wake();
|
|
1516
|
-
return step.schedule(process, keepAlive, immediate);
|
|
1517
|
-
};
|
|
1518
|
-
return acc;
|
|
1519
|
-
}, {});
|
|
1520
|
-
const cancel = (process) => {
|
|
1521
|
-
for (let i = 0; i < stepsOrder.length; i++) {
|
|
1522
|
-
steps[stepsOrder[i]].cancel(process);
|
|
1523
|
-
}
|
|
1457
|
+
state.value = state.done ? target : current;
|
|
1458
|
+
return state;
|
|
1459
|
+
},
|
|
1460
|
+
toString: () => {
|
|
1461
|
+
const calculatedDuration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);
|
|
1462
|
+
const easing = generateLinearEasing((progress) => generator.next(calculatedDuration * progress).value, calculatedDuration, 30);
|
|
1463
|
+
return calculatedDuration + "ms " + easing;
|
|
1464
|
+
},
|
|
1524
1465
|
};
|
|
1525
|
-
return
|
|
1466
|
+
return generator;
|
|
1526
1467
|
}
|
|
1527
1468
|
|
|
1528
|
-
const
|
|
1469
|
+
const wrap = (min, max, v) => {
|
|
1470
|
+
const rangeSize = max - min;
|
|
1471
|
+
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
|
|
1472
|
+
};
|
|
1529
1473
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1474
|
+
const isEasingArray = (ease) => {
|
|
1475
|
+
return Array.isArray(ease) && typeof ease[0] !== "number";
|
|
1476
|
+
};
|
|
1477
|
+
|
|
1478
|
+
function getEasingForSegment(easing, i) {
|
|
1479
|
+
return isEasingArray(easing) ? easing[wrap(0, easing.length, i)] : easing;
|
|
1533
1480
|
}
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1481
|
+
|
|
1482
|
+
/*
|
|
1483
|
+
Value in range from progress
|
|
1484
|
+
|
|
1485
|
+
Given a lower limit and an upper limit, we return the value within
|
|
1486
|
+
that range as expressed by progress (usually a number from 0 to 1)
|
|
1487
|
+
|
|
1488
|
+
So progress = 0.5 would change
|
|
1489
|
+
|
|
1490
|
+
from -------- to
|
|
1491
|
+
|
|
1492
|
+
to
|
|
1493
|
+
|
|
1494
|
+
from ---- to
|
|
1495
|
+
|
|
1496
|
+
E.g. from = 10, to = 20, progress = 0.5 => 15
|
|
1497
|
+
|
|
1498
|
+
@param [number]: Lower limit of range
|
|
1499
|
+
@param [number]: Upper limit of range
|
|
1500
|
+
@param [number]: The progress between lower and upper limits expressed 0-1
|
|
1501
|
+
@return [number]: Value as calculated from progress within range (not limited within range)
|
|
1502
|
+
*/
|
|
1503
|
+
const mixNumber$1 = (from, to, progress) => {
|
|
1504
|
+
return from + (to - from) * progress;
|
|
1555
1505
|
};
|
|
1556
1506
|
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1507
|
+
function fillOffset(offset, remaining) {
|
|
1508
|
+
const min = offset[offset.length - 1];
|
|
1509
|
+
for (let i = 1; i <= remaining; i++) {
|
|
1510
|
+
const offsetProgress = progress(0, remaining, i);
|
|
1511
|
+
offset.push(mixNumber$1(min, 1, offsetProgress));
|
|
1560
1512
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
function defaultOffset$1(arr) {
|
|
1516
|
+
const offset = [0];
|
|
1517
|
+
fillOffset(offset, arr.length - 1);
|
|
1518
|
+
return offset;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
const isMotionValue = (value) => Boolean(value && value.getVelocity);
|
|
1522
|
+
|
|
1523
|
+
function isDOMKeyframes(keyframes) {
|
|
1524
|
+
return typeof keyframes === "object" && !Array.isArray(keyframes);
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
function resolveSubjects(subject, keyframes, scope, selectorCache) {
|
|
1528
|
+
if (typeof subject === "string" && isDOMKeyframes(keyframes)) {
|
|
1529
|
+
return resolveElements(subject, scope, selectorCache);
|
|
1564
1530
|
}
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
if (!numSubscriptions)
|
|
1568
|
-
return;
|
|
1569
|
-
if (numSubscriptions === 1) {
|
|
1570
|
-
/**
|
|
1571
|
-
* If there's only a single handler we can just call it without invoking a loop.
|
|
1572
|
-
*/
|
|
1573
|
-
this.subscriptions[0](a, b, c);
|
|
1574
|
-
}
|
|
1575
|
-
else {
|
|
1576
|
-
for (let i = 0; i < numSubscriptions; i++) {
|
|
1577
|
-
/**
|
|
1578
|
-
* Check whether the handler exists before firing as it's possible
|
|
1579
|
-
* the subscriptions were modified during this loop running.
|
|
1580
|
-
*/
|
|
1581
|
-
const handler = this.subscriptions[i];
|
|
1582
|
-
handler && handler(a, b, c);
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1531
|
+
else if (subject instanceof NodeList) {
|
|
1532
|
+
return Array.from(subject);
|
|
1585
1533
|
}
|
|
1586
|
-
|
|
1587
|
-
return
|
|
1534
|
+
else if (Array.isArray(subject)) {
|
|
1535
|
+
return subject;
|
|
1588
1536
|
}
|
|
1589
|
-
|
|
1590
|
-
|
|
1537
|
+
else {
|
|
1538
|
+
return [subject];
|
|
1591
1539
|
}
|
|
1592
1540
|
}
|
|
1593
1541
|
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
if (condition || warned.has(message))
|
|
1597
|
-
return;
|
|
1598
|
-
console.warn(message);
|
|
1599
|
-
if (element)
|
|
1600
|
-
console.warn(element);
|
|
1601
|
-
warned.add(message);
|
|
1542
|
+
function calculateRepeatDuration(duration, repeat, _repeatDelay) {
|
|
1543
|
+
return duration * (repeat + 1);
|
|
1602
1544
|
}
|
|
1603
1545
|
|
|
1604
1546
|
/**
|
|
1605
|
-
*
|
|
1606
|
-
*
|
|
1607
|
-
*/
|
|
1608
|
-
const MAX_VELOCITY_DELTA = 30;
|
|
1609
|
-
const isFloat = (value) => {
|
|
1610
|
-
return !isNaN(parseFloat(value));
|
|
1611
|
-
};
|
|
1612
|
-
/**
|
|
1613
|
-
* `MotionValue` is used to track the state and velocity of motion values.
|
|
1614
|
-
*
|
|
1615
|
-
* @public
|
|
1547
|
+
* Given a absolute or relative time definition and current/prev time state of the sequence,
|
|
1548
|
+
* calculate an absolute time for the next keyframes.
|
|
1616
1549
|
*/
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
*
|
|
1622
|
-
* - `transformer`: A function to transform incoming values with.
|
|
1623
|
-
*
|
|
1624
|
-
* @internal
|
|
1625
|
-
*/
|
|
1626
|
-
constructor(init, options = {}) {
|
|
1627
|
-
/**
|
|
1628
|
-
* This will be replaced by the build step with the latest version number.
|
|
1629
|
-
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
1630
|
-
*/
|
|
1631
|
-
this.version = "12.4.12";
|
|
1632
|
-
/**
|
|
1633
|
-
* Tracks whether this value can output a velocity. Currently this is only true
|
|
1634
|
-
* if the value is numerical, but we might be able to widen the scope here and support
|
|
1635
|
-
* other value types.
|
|
1636
|
-
*
|
|
1637
|
-
* @internal
|
|
1638
|
-
*/
|
|
1639
|
-
this.canTrackVelocity = null;
|
|
1640
|
-
/**
|
|
1641
|
-
* An object containing a SubscriptionManager for each active event.
|
|
1642
|
-
*/
|
|
1643
|
-
this.events = {};
|
|
1644
|
-
this.updateAndNotify = (v, render = true) => {
|
|
1645
|
-
const currentTime = time.now();
|
|
1646
|
-
/**
|
|
1647
|
-
* If we're updating the value during another frame or eventloop
|
|
1648
|
-
* than the previous frame, then the we set the previous frame value
|
|
1649
|
-
* to current.
|
|
1650
|
-
*/
|
|
1651
|
-
if (this.updatedAt !== currentTime) {
|
|
1652
|
-
this.setPrevFrameValue();
|
|
1653
|
-
}
|
|
1654
|
-
this.prev = this.current;
|
|
1655
|
-
this.setCurrent(v);
|
|
1656
|
-
// Update update subscribers
|
|
1657
|
-
if (this.current !== this.prev && this.events.change) {
|
|
1658
|
-
this.events.change.notify(this.current);
|
|
1659
|
-
}
|
|
1660
|
-
// Update render subscribers
|
|
1661
|
-
if (render && this.events.renderRequest) {
|
|
1662
|
-
this.events.renderRequest.notify(this.current);
|
|
1663
|
-
}
|
|
1664
|
-
};
|
|
1665
|
-
this.hasAnimated = false;
|
|
1666
|
-
this.setCurrent(init);
|
|
1667
|
-
this.owner = options.owner;
|
|
1668
|
-
}
|
|
1669
|
-
setCurrent(current) {
|
|
1670
|
-
this.current = current;
|
|
1671
|
-
this.updatedAt = time.now();
|
|
1672
|
-
if (this.canTrackVelocity === null && current !== undefined) {
|
|
1673
|
-
this.canTrackVelocity = isFloat(this.current);
|
|
1674
|
-
}
|
|
1675
|
-
}
|
|
1676
|
-
setPrevFrameValue(prevFrameValue = this.current) {
|
|
1677
|
-
this.prevFrameValue = prevFrameValue;
|
|
1678
|
-
this.prevUpdatedAt = this.updatedAt;
|
|
1679
|
-
}
|
|
1680
|
-
/**
|
|
1681
|
-
* Adds a function that will be notified when the `MotionValue` is updated.
|
|
1682
|
-
*
|
|
1683
|
-
* It returns a function that, when called, will cancel the subscription.
|
|
1684
|
-
*
|
|
1685
|
-
* When calling `onChange` inside a React component, it should be wrapped with the
|
|
1686
|
-
* `useEffect` hook. As it returns an unsubscribe function, this should be returned
|
|
1687
|
-
* from the `useEffect` function to ensure you don't add duplicate subscribers..
|
|
1688
|
-
*
|
|
1689
|
-
* ```jsx
|
|
1690
|
-
* export const MyComponent = () => {
|
|
1691
|
-
* const x = useMotionValue(0)
|
|
1692
|
-
* const y = useMotionValue(0)
|
|
1693
|
-
* const opacity = useMotionValue(1)
|
|
1694
|
-
*
|
|
1695
|
-
* useEffect(() => {
|
|
1696
|
-
* function updateOpacity() {
|
|
1697
|
-
* const maxXY = Math.max(x.get(), y.get())
|
|
1698
|
-
* const newOpacity = transform(maxXY, [0, 100], [1, 0])
|
|
1699
|
-
* opacity.set(newOpacity)
|
|
1700
|
-
* }
|
|
1701
|
-
*
|
|
1702
|
-
* const unsubscribeX = x.on("change", updateOpacity)
|
|
1703
|
-
* const unsubscribeY = y.on("change", updateOpacity)
|
|
1704
|
-
*
|
|
1705
|
-
* return () => {
|
|
1706
|
-
* unsubscribeX()
|
|
1707
|
-
* unsubscribeY()
|
|
1708
|
-
* }
|
|
1709
|
-
* }, [])
|
|
1710
|
-
*
|
|
1711
|
-
* return <motion.div style={{ x }} />
|
|
1712
|
-
* }
|
|
1713
|
-
* ```
|
|
1714
|
-
*
|
|
1715
|
-
* @param subscriber - A function that receives the latest value.
|
|
1716
|
-
* @returns A function that, when called, will cancel this subscription.
|
|
1717
|
-
*
|
|
1718
|
-
* @deprecated
|
|
1719
|
-
*/
|
|
1720
|
-
onChange(subscription) {
|
|
1721
|
-
if (process.env.NODE_ENV !== "production") {
|
|
1722
|
-
warnOnce(false, `value.onChange(callback) is deprecated. Switch to value.on("change", callback).`);
|
|
1723
|
-
}
|
|
1724
|
-
return this.on("change", subscription);
|
|
1550
|
+
function calcNextTime(current, next, prev, labels) {
|
|
1551
|
+
var _a;
|
|
1552
|
+
if (typeof next === "number") {
|
|
1553
|
+
return next;
|
|
1725
1554
|
}
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
this.events[eventName] = new SubscriptionManager();
|
|
1729
|
-
}
|
|
1730
|
-
const unsubscribe = this.events[eventName].add(callback);
|
|
1731
|
-
if (eventName === "change") {
|
|
1732
|
-
return () => {
|
|
1733
|
-
unsubscribe();
|
|
1734
|
-
/**
|
|
1735
|
-
* If we have no more change listeners by the start
|
|
1736
|
-
* of the next frame, stop active animations.
|
|
1737
|
-
*/
|
|
1738
|
-
frame.read(() => {
|
|
1739
|
-
if (!this.events.change.getSize()) {
|
|
1740
|
-
this.stop();
|
|
1741
|
-
}
|
|
1742
|
-
});
|
|
1743
|
-
};
|
|
1744
|
-
}
|
|
1745
|
-
return unsubscribe;
|
|
1555
|
+
else if (next.startsWith("-") || next.startsWith("+")) {
|
|
1556
|
+
return Math.max(0, current + parseFloat(next));
|
|
1746
1557
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
this.events[eventManagers].clear();
|
|
1750
|
-
}
|
|
1558
|
+
else if (next === "<") {
|
|
1559
|
+
return prev;
|
|
1751
1560
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
*
|
|
1755
|
-
* @internal
|
|
1756
|
-
*/
|
|
1757
|
-
attach(passiveEffect, stopPassiveEffect) {
|
|
1758
|
-
this.passiveEffect = passiveEffect;
|
|
1759
|
-
this.stopPassiveEffect = stopPassiveEffect;
|
|
1561
|
+
else {
|
|
1562
|
+
return (_a = labels.get(next)) !== null && _a !== void 0 ? _a : current;
|
|
1760
1563
|
}
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
*
|
|
1771
|
-
* @param latest - Latest value to set.
|
|
1772
|
-
* @param render - Whether to notify render subscribers. Defaults to `true`
|
|
1773
|
-
*
|
|
1774
|
-
* @public
|
|
1775
|
-
*/
|
|
1776
|
-
set(v, render = true) {
|
|
1777
|
-
if (!render || !this.passiveEffect) {
|
|
1778
|
-
this.updateAndNotify(v, render);
|
|
1779
|
-
}
|
|
1780
|
-
else {
|
|
1781
|
-
this.passiveEffect(v, this.updateAndNotify);
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
function eraseKeyframes(sequence, startTime, endTime) {
|
|
1567
|
+
for (let i = 0; i < sequence.length; i++) {
|
|
1568
|
+
const keyframe = sequence[i];
|
|
1569
|
+
if (keyframe.at > startTime && keyframe.at < endTime) {
|
|
1570
|
+
removeItem(sequence, keyframe);
|
|
1571
|
+
// If we remove this item we have to push the pointer back one
|
|
1572
|
+
i--;
|
|
1782
1573
|
}
|
|
1783
1574
|
}
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
this.prev = undefined;
|
|
1787
|
-
this.prevFrameValue = prev;
|
|
1788
|
-
this.prevUpdatedAt = this.updatedAt - delta;
|
|
1789
|
-
}
|
|
1575
|
+
}
|
|
1576
|
+
function addKeyframes(sequence, keyframes, easing, offset, startTime, endTime) {
|
|
1790
1577
|
/**
|
|
1791
|
-
*
|
|
1792
|
-
*
|
|
1578
|
+
* Erase every existing value between currentTime and targetTime,
|
|
1579
|
+
* this will essentially splice this timeline into any currently
|
|
1580
|
+
* defined ones.
|
|
1793
1581
|
*/
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1582
|
+
eraseKeyframes(sequence, startTime, endTime);
|
|
1583
|
+
for (let i = 0; i < keyframes.length; i++) {
|
|
1584
|
+
sequence.push({
|
|
1585
|
+
value: keyframes[i],
|
|
1586
|
+
at: mixNumber$1(startTime, endTime, offset[i]),
|
|
1587
|
+
easing: getEasingForSegment(easing, i),
|
|
1588
|
+
});
|
|
1801
1589
|
}
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
/**
|
|
1593
|
+
* Take an array of times that represent repeated keyframes. For instance
|
|
1594
|
+
* if we have original times of [0, 0.5, 1] then our repeated times will
|
|
1595
|
+
* be [0, 0.5, 1, 1, 1.5, 2]. Loop over the times and scale them back
|
|
1596
|
+
* down to a 0-1 scale.
|
|
1597
|
+
*/
|
|
1598
|
+
function normalizeTimes(times, repeat) {
|
|
1599
|
+
for (let i = 0; i < times.length; i++) {
|
|
1600
|
+
times[i] = times[i] / (repeat + 1);
|
|
1811
1601
|
}
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
function compareByTime(a, b) {
|
|
1605
|
+
if (a.at === b.at) {
|
|
1606
|
+
if (a.value === null)
|
|
1607
|
+
return 1;
|
|
1608
|
+
if (b.value === null)
|
|
1609
|
+
return -1;
|
|
1610
|
+
return 0;
|
|
1611
|
+
}
|
|
1612
|
+
else {
|
|
1613
|
+
return a.at - b.at;
|
|
1817
1614
|
}
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
const defaultSegmentEasing = "easeInOut";
|
|
1618
|
+
const MAX_REPEAT = 20;
|
|
1619
|
+
function createAnimationsFromSequence(sequence, { defaultTransition = {}, ...sequenceTransition } = {}, scope, generators) {
|
|
1620
|
+
const defaultDuration = defaultTransition.duration || 0.3;
|
|
1621
|
+
const animationDefinitions = new Map();
|
|
1622
|
+
const sequences = new Map();
|
|
1623
|
+
const elementCache = {};
|
|
1624
|
+
const timeLabels = new Map();
|
|
1625
|
+
let prevTime = 0;
|
|
1626
|
+
let currentTime = 0;
|
|
1627
|
+
let totalDuration = 0;
|
|
1818
1628
|
/**
|
|
1819
|
-
*
|
|
1820
|
-
*
|
|
1821
|
-
*
|
|
1822
|
-
*
|
|
1823
|
-
* @public
|
|
1629
|
+
* Build the timeline by mapping over the sequence array and converting
|
|
1630
|
+
* the definitions into keyframes and offsets with absolute time values.
|
|
1631
|
+
* These will later get converted into relative offsets in a second pass.
|
|
1824
1632
|
*/
|
|
1825
|
-
|
|
1826
|
-
const
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1633
|
+
for (let i = 0; i < sequence.length; i++) {
|
|
1634
|
+
const segment = sequence[i];
|
|
1635
|
+
/**
|
|
1636
|
+
* If this is a timeline label, mark it and skip the rest of this iteration.
|
|
1637
|
+
*/
|
|
1638
|
+
if (typeof segment === "string") {
|
|
1639
|
+
timeLabels.set(segment, currentTime);
|
|
1640
|
+
continue;
|
|
1641
|
+
}
|
|
1642
|
+
else if (!Array.isArray(segment)) {
|
|
1643
|
+
timeLabels.set(segment.name, calcNextTime(currentTime, segment.at, prevTime, timeLabels));
|
|
1644
|
+
continue;
|
|
1645
|
+
}
|
|
1646
|
+
let [subject, keyframes, transition = {}] = segment;
|
|
1647
|
+
/**
|
|
1648
|
+
* If a relative or absolute time value has been specified we need to resolve
|
|
1649
|
+
* it in relation to the currentTime.
|
|
1650
|
+
*/
|
|
1651
|
+
if (transition.at !== undefined) {
|
|
1652
|
+
currentTime = calcNextTime(currentTime, transition.at, prevTime, timeLabels);
|
|
1653
|
+
}
|
|
1654
|
+
/**
|
|
1655
|
+
* Keep track of the maximum duration in this definition. This will be
|
|
1656
|
+
* applied to currentTime once the definition has been parsed.
|
|
1657
|
+
*/
|
|
1658
|
+
let maxDuration = 0;
|
|
1659
|
+
const resolveValueSequence = (valueKeyframes, valueTransition, valueSequence, elementIndex = 0, numSubjects = 0) => {
|
|
1660
|
+
const valueKeyframesAsList = keyframesAsList(valueKeyframes);
|
|
1661
|
+
const { delay = 0, times = defaultOffset$1(valueKeyframesAsList), type = "keyframes", repeat, repeatType, repeatDelay = 0, ...remainingTransition } = valueTransition;
|
|
1662
|
+
let { ease = defaultTransition.ease || "easeOut", duration } = valueTransition;
|
|
1663
|
+
/**
|
|
1664
|
+
* Resolve stagger() if defined.
|
|
1665
|
+
*/
|
|
1666
|
+
const calculatedDelay = typeof delay === "function"
|
|
1667
|
+
? delay(elementIndex, numSubjects)
|
|
1668
|
+
: delay;
|
|
1669
|
+
/**
|
|
1670
|
+
* If this animation should and can use a spring, generate a spring easing function.
|
|
1671
|
+
*/
|
|
1672
|
+
const numKeyframes = valueKeyframesAsList.length;
|
|
1673
|
+
const createGenerator = isGenerator(type)
|
|
1674
|
+
? type
|
|
1675
|
+
: generators === null || generators === void 0 ? void 0 : generators[type];
|
|
1676
|
+
if (numKeyframes <= 2 && createGenerator) {
|
|
1677
|
+
/**
|
|
1678
|
+
* As we're creating an easing function from a spring,
|
|
1679
|
+
* ideally we want to generate it using the real distance
|
|
1680
|
+
* between the two keyframes. However this isn't always
|
|
1681
|
+
* possible - in these situations we use 0-100.
|
|
1682
|
+
*/
|
|
1683
|
+
let absoluteDelta = 100;
|
|
1684
|
+
if (numKeyframes === 2 &&
|
|
1685
|
+
isNumberKeyframesArray(valueKeyframesAsList)) {
|
|
1686
|
+
const delta = valueKeyframesAsList[1] - valueKeyframesAsList[0];
|
|
1687
|
+
absoluteDelta = Math.abs(delta);
|
|
1688
|
+
}
|
|
1689
|
+
const springTransition = { ...remainingTransition };
|
|
1690
|
+
if (duration !== undefined) {
|
|
1691
|
+
springTransition.duration = secondsToMilliseconds(duration);
|
|
1692
|
+
}
|
|
1693
|
+
const springEasing = createGeneratorEasing(springTransition, absoluteDelta, createGenerator);
|
|
1694
|
+
ease = springEasing.ease;
|
|
1695
|
+
duration = springEasing.duration;
|
|
1696
|
+
}
|
|
1697
|
+
duration !== null && duration !== void 0 ? duration : (duration = defaultDuration);
|
|
1698
|
+
const startTime = currentTime + calculatedDelay;
|
|
1699
|
+
/**
|
|
1700
|
+
* If there's only one time offset of 0, fill in a second with length 1
|
|
1701
|
+
*/
|
|
1702
|
+
if (times.length === 1 && times[0] === 0) {
|
|
1703
|
+
times[1] = 1;
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Fill out if offset if fewer offsets than keyframes
|
|
1707
|
+
*/
|
|
1708
|
+
const remainder = times.length - valueKeyframesAsList.length;
|
|
1709
|
+
remainder > 0 && fillOffset(times, remainder);
|
|
1710
|
+
/**
|
|
1711
|
+
* If only one value has been set, ie [1], push a null to the start of
|
|
1712
|
+
* the keyframe array. This will let us mark a keyframe at this point
|
|
1713
|
+
* that will later be hydrated with the previous value.
|
|
1714
|
+
*/
|
|
1715
|
+
valueKeyframesAsList.length === 1 &&
|
|
1716
|
+
valueKeyframesAsList.unshift(null);
|
|
1717
|
+
/**
|
|
1718
|
+
* Handle repeat options
|
|
1719
|
+
*/
|
|
1720
|
+
if (repeat) {
|
|
1721
|
+
exports.invariant(repeat < MAX_REPEAT, "Repeat count too high, must be less than 20");
|
|
1722
|
+
duration = calculateRepeatDuration(duration, repeat);
|
|
1723
|
+
const originalKeyframes = [...valueKeyframesAsList];
|
|
1724
|
+
const originalTimes = [...times];
|
|
1725
|
+
ease = Array.isArray(ease) ? [...ease] : [ease];
|
|
1726
|
+
const originalEase = [...ease];
|
|
1727
|
+
for (let repeatIndex = 0; repeatIndex < repeat; repeatIndex++) {
|
|
1728
|
+
valueKeyframesAsList.push(...originalKeyframes);
|
|
1729
|
+
for (let keyframeIndex = 0; keyframeIndex < originalKeyframes.length; keyframeIndex++) {
|
|
1730
|
+
times.push(originalTimes[keyframeIndex] + (repeatIndex + 1));
|
|
1731
|
+
ease.push(keyframeIndex === 0
|
|
1732
|
+
? "linear"
|
|
1733
|
+
: getEasingForSegment(originalEase, keyframeIndex - 1));
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
normalizeTimes(times, repeat);
|
|
1737
|
+
}
|
|
1738
|
+
const targetTime = startTime + duration;
|
|
1739
|
+
/**
|
|
1740
|
+
* Add keyframes, mapping offsets to absolute time.
|
|
1741
|
+
*/
|
|
1742
|
+
addKeyframes(valueSequence, valueKeyframesAsList, ease, times, startTime, targetTime);
|
|
1743
|
+
maxDuration = Math.max(calculatedDelay + duration, maxDuration);
|
|
1744
|
+
totalDuration = Math.max(targetTime, totalDuration);
|
|
1745
|
+
};
|
|
1746
|
+
if (isMotionValue(subject)) {
|
|
1747
|
+
const subjectSequence = getSubjectSequence(subject, sequences);
|
|
1748
|
+
resolveValueSequence(keyframes, transition, getValueSequence("default", subjectSequence));
|
|
1831
1749
|
}
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1750
|
+
else {
|
|
1751
|
+
const subjects = resolveSubjects(subject, keyframes, scope, elementCache);
|
|
1752
|
+
const numSubjects = subjects.length;
|
|
1753
|
+
/**
|
|
1754
|
+
* For every element in this segment, process the defined values.
|
|
1755
|
+
*/
|
|
1756
|
+
for (let subjectIndex = 0; subjectIndex < numSubjects; subjectIndex++) {
|
|
1757
|
+
/**
|
|
1758
|
+
* Cast necessary, but we know these are of this type
|
|
1759
|
+
*/
|
|
1760
|
+
keyframes = keyframes;
|
|
1761
|
+
transition = transition;
|
|
1762
|
+
const thisSubject = subjects[subjectIndex];
|
|
1763
|
+
const subjectSequence = getSubjectSequence(thisSubject, sequences);
|
|
1764
|
+
for (const key in keyframes) {
|
|
1765
|
+
resolveValueSequence(keyframes[key], getValueTransition(transition, key), getValueSequence(key, subjectSequence), subjectIndex, numSubjects);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
prevTime = currentTime;
|
|
1770
|
+
currentTime += maxDuration;
|
|
1836
1771
|
}
|
|
1837
1772
|
/**
|
|
1838
|
-
*
|
|
1839
|
-
* animation can drive a `MotionValue` at one time.
|
|
1840
|
-
*
|
|
1841
|
-
* ```jsx
|
|
1842
|
-
* value.start()
|
|
1843
|
-
* ```
|
|
1844
|
-
*
|
|
1845
|
-
* @param animation - A function that starts the provided animation
|
|
1846
|
-
*
|
|
1847
|
-
* @internal
|
|
1773
|
+
* For every element and value combination create a new animation.
|
|
1848
1774
|
*/
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1775
|
+
sequences.forEach((valueSequences, element) => {
|
|
1776
|
+
for (const key in valueSequences) {
|
|
1777
|
+
const valueSequence = valueSequences[key];
|
|
1778
|
+
/**
|
|
1779
|
+
* Arrange all the keyframes in ascending time order.
|
|
1780
|
+
*/
|
|
1781
|
+
valueSequence.sort(compareByTime);
|
|
1782
|
+
const keyframes = [];
|
|
1783
|
+
const valueOffset = [];
|
|
1784
|
+
const valueEasing = [];
|
|
1785
|
+
/**
|
|
1786
|
+
* For each keyframe, translate absolute times into
|
|
1787
|
+
* relative offsets based on the total duration of the timeline.
|
|
1788
|
+
*/
|
|
1789
|
+
for (let i = 0; i < valueSequence.length; i++) {
|
|
1790
|
+
const { at, value, easing } = valueSequence[i];
|
|
1791
|
+
keyframes.push(value);
|
|
1792
|
+
valueOffset.push(progress(0, totalDuration, at));
|
|
1793
|
+
valueEasing.push(easing || "easeOut");
|
|
1856
1794
|
}
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1795
|
+
/**
|
|
1796
|
+
* If the first keyframe doesn't land on offset: 0
|
|
1797
|
+
* provide one by duplicating the initial keyframe. This ensures
|
|
1798
|
+
* it snaps to the first keyframe when the animation starts.
|
|
1799
|
+
*/
|
|
1800
|
+
if (valueOffset[0] !== 0) {
|
|
1801
|
+
valueOffset.unshift(0);
|
|
1802
|
+
keyframes.unshift(keyframes[0]);
|
|
1803
|
+
valueEasing.unshift(defaultSegmentEasing);
|
|
1860
1804
|
}
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
stop() {
|
|
1870
|
-
if (this.animation) {
|
|
1871
|
-
this.animation.stop();
|
|
1872
|
-
if (this.events.animationCancel) {
|
|
1873
|
-
this.events.animationCancel.notify();
|
|
1805
|
+
/**
|
|
1806
|
+
* If the last keyframe doesn't land on offset: 1
|
|
1807
|
+
* provide one with a null wildcard value. This will ensure it
|
|
1808
|
+
* stays static until the end of the animation.
|
|
1809
|
+
*/
|
|
1810
|
+
if (valueOffset[valueOffset.length - 1] !== 1) {
|
|
1811
|
+
valueOffset.push(1);
|
|
1812
|
+
keyframes.push(null);
|
|
1874
1813
|
}
|
|
1814
|
+
if (!animationDefinitions.has(element)) {
|
|
1815
|
+
animationDefinitions.set(element, {
|
|
1816
|
+
keyframes: {},
|
|
1817
|
+
transition: {},
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
const definition = animationDefinitions.get(element);
|
|
1821
|
+
definition.keyframes[key] = keyframes;
|
|
1822
|
+
definition.transition[key] = {
|
|
1823
|
+
...defaultTransition,
|
|
1824
|
+
duration: totalDuration,
|
|
1825
|
+
ease: valueEasing,
|
|
1826
|
+
times: valueOffset,
|
|
1827
|
+
...sequenceTransition,
|
|
1828
|
+
};
|
|
1875
1829
|
}
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
/**
|
|
1879
|
-
* Returns `true` if this value is currently animating.
|
|
1880
|
-
*
|
|
1881
|
-
* @public
|
|
1882
|
-
*/
|
|
1883
|
-
isAnimating() {
|
|
1884
|
-
return !!this.animation;
|
|
1885
|
-
}
|
|
1886
|
-
clearAnimation() {
|
|
1887
|
-
delete this.animation;
|
|
1888
|
-
}
|
|
1889
|
-
/**
|
|
1890
|
-
* Destroy and clean up subscribers to this `MotionValue`.
|
|
1891
|
-
*
|
|
1892
|
-
* The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically
|
|
1893
|
-
* handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually
|
|
1894
|
-
* created a `MotionValue` via the `motionValue` function.
|
|
1895
|
-
*
|
|
1896
|
-
* @public
|
|
1897
|
-
*/
|
|
1898
|
-
destroy() {
|
|
1899
|
-
this.clearListeners();
|
|
1900
|
-
this.stop();
|
|
1901
|
-
if (this.stopPassiveEffect) {
|
|
1902
|
-
this.stopPassiveEffect();
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1830
|
+
});
|
|
1831
|
+
return animationDefinitions;
|
|
1905
1832
|
}
|
|
1906
|
-
function
|
|
1907
|
-
|
|
1833
|
+
function getSubjectSequence(subject, sequences) {
|
|
1834
|
+
!sequences.has(subject) && sequences.set(subject, {});
|
|
1835
|
+
return sequences.get(subject);
|
|
1836
|
+
}
|
|
1837
|
+
function getValueSequence(name, sequences) {
|
|
1838
|
+
if (!sequences[name])
|
|
1839
|
+
sequences[name] = [];
|
|
1840
|
+
return sequences[name];
|
|
1841
|
+
}
|
|
1842
|
+
function keyframesAsList(keyframes) {
|
|
1843
|
+
return Array.isArray(keyframes) ? keyframes : [keyframes];
|
|
1844
|
+
}
|
|
1845
|
+
function getValueTransition(transition, key) {
|
|
1846
|
+
return transition && transition[key]
|
|
1847
|
+
? {
|
|
1848
|
+
...transition,
|
|
1849
|
+
...transition[key],
|
|
1850
|
+
}
|
|
1851
|
+
: { ...transition };
|
|
1908
1852
|
}
|
|
1853
|
+
const isNumber = (keyframe) => typeof keyframe === "number";
|
|
1854
|
+
const isNumberKeyframesArray = (keyframes) => keyframes.every(isNumber);
|
|
1855
|
+
|
|
1856
|
+
const visualElementStore = new WeakMap();
|
|
1857
|
+
|
|
1858
|
+
/**
|
|
1859
|
+
* Generate a list of every possible transform key.
|
|
1860
|
+
*/
|
|
1861
|
+
const transformPropOrder = [
|
|
1862
|
+
"transformPerspective",
|
|
1863
|
+
"x",
|
|
1864
|
+
"y",
|
|
1865
|
+
"z",
|
|
1866
|
+
"translateX",
|
|
1867
|
+
"translateY",
|
|
1868
|
+
"translateZ",
|
|
1869
|
+
"scale",
|
|
1870
|
+
"scaleX",
|
|
1871
|
+
"scaleY",
|
|
1872
|
+
"rotate",
|
|
1873
|
+
"rotateX",
|
|
1874
|
+
"rotateY",
|
|
1875
|
+
"rotateZ",
|
|
1876
|
+
"skew",
|
|
1877
|
+
"skewX",
|
|
1878
|
+
"skewY",
|
|
1879
|
+
];
|
|
1880
|
+
/**
|
|
1881
|
+
* A quick lookup for transform props.
|
|
1882
|
+
*/
|
|
1883
|
+
const transformProps = new Set(transformPropOrder);
|
|
1884
|
+
|
|
1885
|
+
const positionalKeys = new Set([
|
|
1886
|
+
"width",
|
|
1887
|
+
"height",
|
|
1888
|
+
"top",
|
|
1889
|
+
"left",
|
|
1890
|
+
"right",
|
|
1891
|
+
"bottom",
|
|
1892
|
+
...transformPropOrder,
|
|
1893
|
+
]);
|
|
1894
|
+
|
|
1895
|
+
const isKeyframesTarget = (v) => {
|
|
1896
|
+
return Array.isArray(v);
|
|
1897
|
+
};
|
|
1898
|
+
|
|
1899
|
+
const resolveFinalValueInKeyframes = (v) => {
|
|
1900
|
+
// TODO maybe throw if v.length - 1 is placeholder token?
|
|
1901
|
+
return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
|
|
1902
|
+
};
|
|
1909
1903
|
|
|
1910
1904
|
function getValueState(visualElement) {
|
|
1911
1905
|
const state = [{}, {}];
|
|
@@ -2494,25 +2488,89 @@ function makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, n
|
|
|
2494
2488
|
}
|
|
2495
2489
|
}
|
|
2496
2490
|
|
|
2497
|
-
const
|
|
2498
|
-
const
|
|
2499
|
-
const
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2491
|
+
const radToDeg = (rad) => (rad * 180) / Math.PI;
|
|
2492
|
+
const rotate = (v) => {
|
|
2493
|
+
const angle = radToDeg(Math.atan2(v[1], v[0]));
|
|
2494
|
+
return rebaseAngle(angle);
|
|
2495
|
+
};
|
|
2496
|
+
const matrix2dParsers = {
|
|
2497
|
+
x: 4,
|
|
2498
|
+
y: 5,
|
|
2499
|
+
translateX: 4,
|
|
2500
|
+
translateY: 5,
|
|
2501
|
+
scaleX: 0,
|
|
2502
|
+
scaleY: 3,
|
|
2503
|
+
scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2,
|
|
2504
|
+
rotate,
|
|
2505
|
+
rotateZ: rotate,
|
|
2506
|
+
skewX: (v) => radToDeg(Math.atan(v[1])),
|
|
2507
|
+
skewY: (v) => radToDeg(Math.atan(v[2])),
|
|
2508
|
+
skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2,
|
|
2509
|
+
};
|
|
2510
|
+
const rebaseAngle = (angle) => {
|
|
2511
|
+
angle = angle % 360;
|
|
2512
|
+
if (angle < 0)
|
|
2513
|
+
angle += 360;
|
|
2514
|
+
return angle;
|
|
2515
|
+
};
|
|
2516
|
+
const rotateZ = rotate;
|
|
2517
|
+
const scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
|
2518
|
+
const scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]);
|
|
2519
|
+
const matrix3dParsers = {
|
|
2520
|
+
x: 12,
|
|
2521
|
+
y: 13,
|
|
2522
|
+
z: 14,
|
|
2523
|
+
translateX: 12,
|
|
2524
|
+
translateY: 13,
|
|
2525
|
+
translateZ: 14,
|
|
2526
|
+
scaleX,
|
|
2527
|
+
scaleY,
|
|
2528
|
+
scale: (v) => (scaleX(v) + scaleY(v)) / 2,
|
|
2529
|
+
rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))),
|
|
2530
|
+
rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))),
|
|
2531
|
+
rotateZ,
|
|
2532
|
+
rotate: rotateZ,
|
|
2533
|
+
skewX: (v) => radToDeg(Math.atan(v[4])),
|
|
2534
|
+
skewY: (v) => radToDeg(Math.atan(v[1])),
|
|
2535
|
+
skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2,
|
|
2536
|
+
};
|
|
2537
|
+
function defaultTransformValue(name) {
|
|
2538
|
+
return name.includes("scale") ? 1 : 0;
|
|
2539
|
+
}
|
|
2540
|
+
function parseValueFromTransform(transform, name) {
|
|
2541
|
+
if (!transform || transform === "none") {
|
|
2542
|
+
return defaultTransformValue(name);
|
|
2505
2543
|
}
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
return 0;
|
|
2513
|
-
}
|
|
2544
|
+
const matrix3dMatch = transform.match(/^matrix3d\(([-\d.e\s,]+)\)$/u);
|
|
2545
|
+
let parsers;
|
|
2546
|
+
let match;
|
|
2547
|
+
if (matrix3dMatch) {
|
|
2548
|
+
parsers = matrix3dParsers;
|
|
2549
|
+
match = matrix3dMatch;
|
|
2514
2550
|
}
|
|
2551
|
+
else {
|
|
2552
|
+
const matrix2dMatch = transform.match(/^matrix\(([-\d.e\s,]+)\)$/u);
|
|
2553
|
+
parsers = matrix2dParsers;
|
|
2554
|
+
match = matrix2dMatch;
|
|
2555
|
+
}
|
|
2556
|
+
if (!match) {
|
|
2557
|
+
return defaultTransformValue(name);
|
|
2558
|
+
}
|
|
2559
|
+
const valueParser = parsers[name];
|
|
2560
|
+
const values = match[1].split(",").map(convertTransformToNumber);
|
|
2561
|
+
return typeof valueParser === "function"
|
|
2562
|
+
? valueParser(values)
|
|
2563
|
+
: values[valueParser];
|
|
2564
|
+
}
|
|
2565
|
+
const readTransformValue = (instance, name) => {
|
|
2566
|
+
const { transform = "none" } = getComputedStyle(instance);
|
|
2567
|
+
return parseValueFromTransform(transform, name);
|
|
2515
2568
|
};
|
|
2569
|
+
function convertTransformToNumber(value) {
|
|
2570
|
+
return parseFloat(value.trim());
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2573
|
+
const isNumOrPxType = (v) => v === number || v === px;
|
|
2516
2574
|
const transformKeys = new Set(["x", "y", "z"]);
|
|
2517
2575
|
const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
|
|
2518
2576
|
function removeNonTranslationalTransform(visualElement) {
|
|
@@ -2535,8 +2593,8 @@ const positionalValues = {
|
|
|
2535
2593
|
bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
|
|
2536
2594
|
right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
|
|
2537
2595
|
// Transform
|
|
2538
|
-
x:
|
|
2539
|
-
y:
|
|
2596
|
+
x: (_bbox, { transform }) => parseValueFromTransform(transform, "x"),
|
|
2597
|
+
y: (_bbox, { transform }) => parseValueFromTransform(transform, "y"),
|
|
2540
2598
|
};
|
|
2541
2599
|
// Alias translate longform names
|
|
2542
2600
|
positionalValues.translateX = positionalValues.x;
|
|
@@ -4571,7 +4629,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
4571
4629
|
* and warn against mismatches.
|
|
4572
4630
|
*/
|
|
4573
4631
|
if (process.env.NODE_ENV === "development") {
|
|
4574
|
-
warnOnce(nextValue.version === "12.
|
|
4632
|
+
warnOnce(nextValue.version === "12.5.0", `Attempting to mix Motion versions ${nextValue.version} with 12.5.0 may not work as expected.`);
|
|
4575
4633
|
}
|
|
4576
4634
|
}
|
|
4577
4635
|
else if (isMotionValue(prevValue)) {
|
|
@@ -5511,8 +5569,7 @@ class HTMLVisualElement extends DOMVisualElement {
|
|
|
5511
5569
|
}
|
|
5512
5570
|
readValueFromInstance(instance, key) {
|
|
5513
5571
|
if (transformProps.has(key)) {
|
|
5514
|
-
|
|
5515
|
-
return defaultType ? defaultType.default || 0 : 0;
|
|
5572
|
+
return readTransformValue(instance, key);
|
|
5516
5573
|
}
|
|
5517
5574
|
else {
|
|
5518
5575
|
const computedStyle = getComputedStyle$1(instance);
|
|
@@ -6525,22 +6582,6 @@ function transform(...args) {
|
|
|
6525
6582
|
return useImmediate ? interpolator(inputValue) : interpolator;
|
|
6526
6583
|
}
|
|
6527
6584
|
|
|
6528
|
-
/**
|
|
6529
|
-
* @deprecated
|
|
6530
|
-
*
|
|
6531
|
-
* Import as `frame` instead.
|
|
6532
|
-
*/
|
|
6533
|
-
const sync = frame;
|
|
6534
|
-
/**
|
|
6535
|
-
* @deprecated
|
|
6536
|
-
*
|
|
6537
|
-
* Use cancelFrame(callback) instead.
|
|
6538
|
-
*/
|
|
6539
|
-
const cancelSync = stepsOrder.reduce((acc, key) => {
|
|
6540
|
-
acc[key] = (process) => cancelFrame(process);
|
|
6541
|
-
return acc;
|
|
6542
|
-
}, {});
|
|
6543
|
-
|
|
6544
6585
|
exports.MotionValue = MotionValue;
|
|
6545
6586
|
exports.animate = animate;
|
|
6546
6587
|
exports.animateMini = animateMini;
|
|
@@ -6549,7 +6590,6 @@ exports.backIn = backIn;
|
|
|
6549
6590
|
exports.backInOut = backInOut;
|
|
6550
6591
|
exports.backOut = backOut;
|
|
6551
6592
|
exports.cancelFrame = cancelFrame;
|
|
6552
|
-
exports.cancelSync = cancelSync;
|
|
6553
6593
|
exports.circIn = circIn;
|
|
6554
6594
|
exports.circInOut = circInOut;
|
|
6555
6595
|
exports.circOut = circOut;
|
|
@@ -6564,7 +6604,6 @@ exports.easeInOut = easeInOut;
|
|
|
6564
6604
|
exports.easeOut = easeOut;
|
|
6565
6605
|
exports.frame = frame;
|
|
6566
6606
|
exports.frameData = frameData;
|
|
6567
|
-
exports.frameSteps = frameSteps;
|
|
6568
6607
|
exports.hover = hover;
|
|
6569
6608
|
exports.inView = inView;
|
|
6570
6609
|
exports.inertia = inertia;
|
|
@@ -6584,7 +6623,6 @@ exports.scrollInfo = scrollInfo;
|
|
|
6584
6623
|
exports.spring = spring;
|
|
6585
6624
|
exports.stagger = stagger;
|
|
6586
6625
|
exports.steps = steps;
|
|
6587
|
-
exports.sync = sync;
|
|
6588
6626
|
exports.time = time;
|
|
6589
6627
|
exports.transform = transform;
|
|
6590
6628
|
exports.wrap = wrap;
|