framer-motion 11.0.0-alpha.1 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/dom-entry.js +1 -1
- package/dist/cjs/{index-legacy-4be91252.js → index-legacy-731c5510.js} +173 -172
- package/dist/cjs/index.js +17 -16
- package/dist/es/frameloop/batcher.mjs +3 -1
- package/dist/es/frameloop/sync-time.mjs +1 -2
- package/dist/es/motion/features/layout/MeasureLayout.mjs +2 -1
- package/dist/es/motion/utils/use-visual-element.mjs +2 -1
- package/dist/es/projection/node/create-projection-node.mjs +2 -3
- package/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/value/index.mjs +1 -1
- package/dist/es/value/use-spring.mjs +7 -11
- package/dist/es/value/use-velocity.mjs +4 -0
- package/dist/framer-motion.dev.js +188 -187
- package/dist/framer-motion.js +1 -1
- package/dist/projection.dev.js +9 -9
- package/package.json +8 -8
package/dist/cjs/dom-entry.js
CHANGED
|
@@ -10,6 +10,175 @@ const camelToDash = (str) => str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase
|
|
|
10
10
|
const optimizedAppearDataId = "framerAppearId";
|
|
11
11
|
const optimizedAppearDataAttribute = "data-" + camelToDash(optimizedAppearDataId);
|
|
12
12
|
|
|
13
|
+
const MotionGlobalConfig = {
|
|
14
|
+
skipAnimations: false,
|
|
15
|
+
useManualTiming: false,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
class Queue {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.order = [];
|
|
21
|
+
this.scheduled = new Set();
|
|
22
|
+
}
|
|
23
|
+
add(process) {
|
|
24
|
+
if (!this.scheduled.has(process)) {
|
|
25
|
+
this.scheduled.add(process);
|
|
26
|
+
this.order.push(process);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
remove(process) {
|
|
31
|
+
const index = this.order.indexOf(process);
|
|
32
|
+
if (index !== -1) {
|
|
33
|
+
this.order.splice(index, 1);
|
|
34
|
+
this.scheduled.delete(process);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
clear() {
|
|
38
|
+
this.order.length = 0;
|
|
39
|
+
this.scheduled.clear();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function createRenderStep(runNextFrame) {
|
|
43
|
+
/**
|
|
44
|
+
* We create and reuse two queues, one to queue jobs for the current frame
|
|
45
|
+
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
46
|
+
*/
|
|
47
|
+
let thisFrame = new Queue();
|
|
48
|
+
let nextFrame = new Queue();
|
|
49
|
+
let numToRun = 0;
|
|
50
|
+
/**
|
|
51
|
+
* Track whether we're currently processing jobs in this step. This way
|
|
52
|
+
* we can decide whether to schedule new jobs for this frame or next.
|
|
53
|
+
*/
|
|
54
|
+
let isProcessing = false;
|
|
55
|
+
let flushNextFrame = false;
|
|
56
|
+
/**
|
|
57
|
+
* A set of processes which were marked keepAlive when scheduled.
|
|
58
|
+
*/
|
|
59
|
+
const toKeepAlive = new WeakSet();
|
|
60
|
+
const step = {
|
|
61
|
+
/**
|
|
62
|
+
* Schedule a process to run on the next frame.
|
|
63
|
+
*/
|
|
64
|
+
schedule: (callback, keepAlive = false, immediate = false) => {
|
|
65
|
+
const addToCurrentFrame = immediate && isProcessing;
|
|
66
|
+
const queue = addToCurrentFrame ? thisFrame : nextFrame;
|
|
67
|
+
if (keepAlive)
|
|
68
|
+
toKeepAlive.add(callback);
|
|
69
|
+
if (queue.add(callback) && addToCurrentFrame && isProcessing) {
|
|
70
|
+
// If we're adding it to the currently running queue, update its measured size
|
|
71
|
+
numToRun = thisFrame.order.length;
|
|
72
|
+
}
|
|
73
|
+
return callback;
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* Cancel the provided callback from running on the next frame.
|
|
77
|
+
*/
|
|
78
|
+
cancel: (callback) => {
|
|
79
|
+
nextFrame.remove(callback);
|
|
80
|
+
toKeepAlive.delete(callback);
|
|
81
|
+
},
|
|
82
|
+
/**
|
|
83
|
+
* Execute all schedule callbacks.
|
|
84
|
+
*/
|
|
85
|
+
process: (frameData) => {
|
|
86
|
+
/**
|
|
87
|
+
* If we're already processing we've probably been triggered by a flushSync
|
|
88
|
+
* inside an existing process. Instead of executing, mark flushNextFrame
|
|
89
|
+
* as true and ensure we flush the following frame at the end of this one.
|
|
90
|
+
*/
|
|
91
|
+
if (isProcessing) {
|
|
92
|
+
flushNextFrame = true;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
isProcessing = true;
|
|
96
|
+
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
97
|
+
// Clear the next frame queue
|
|
98
|
+
nextFrame.clear();
|
|
99
|
+
// Execute this frame
|
|
100
|
+
numToRun = thisFrame.order.length;
|
|
101
|
+
if (numToRun) {
|
|
102
|
+
for (let i = 0; i < numToRun; i++) {
|
|
103
|
+
const callback = thisFrame.order[i];
|
|
104
|
+
if (toKeepAlive.has(callback)) {
|
|
105
|
+
step.schedule(callback);
|
|
106
|
+
runNextFrame();
|
|
107
|
+
}
|
|
108
|
+
callback(frameData);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
isProcessing = false;
|
|
112
|
+
if (flushNextFrame) {
|
|
113
|
+
flushNextFrame = false;
|
|
114
|
+
step.process(frameData);
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
return step;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const stepsOrder = [
|
|
122
|
+
"prepare",
|
|
123
|
+
"read",
|
|
124
|
+
"update",
|
|
125
|
+
"preRender",
|
|
126
|
+
"render",
|
|
127
|
+
"postRender",
|
|
128
|
+
];
|
|
129
|
+
const maxElapsed$1 = 40;
|
|
130
|
+
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
131
|
+
let runNextFrame = false;
|
|
132
|
+
let useDefaultElapsed = true;
|
|
133
|
+
const state = {
|
|
134
|
+
delta: 0,
|
|
135
|
+
timestamp: 0,
|
|
136
|
+
isProcessing: false,
|
|
137
|
+
};
|
|
138
|
+
const steps = stepsOrder.reduce((acc, key) => {
|
|
139
|
+
acc[key] = createRenderStep(() => (runNextFrame = true));
|
|
140
|
+
return acc;
|
|
141
|
+
}, {});
|
|
142
|
+
const processStep = (stepId) => {
|
|
143
|
+
steps[stepId].process(state);
|
|
144
|
+
};
|
|
145
|
+
const processBatch = () => {
|
|
146
|
+
const timestamp = MotionGlobalConfig.useManualTiming
|
|
147
|
+
? state.timestamp
|
|
148
|
+
: performance.now();
|
|
149
|
+
runNextFrame = false;
|
|
150
|
+
state.delta = useDefaultElapsed
|
|
151
|
+
? 1000 / 60
|
|
152
|
+
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
|
|
153
|
+
state.timestamp = timestamp;
|
|
154
|
+
state.isProcessing = true;
|
|
155
|
+
stepsOrder.forEach(processStep);
|
|
156
|
+
state.isProcessing = false;
|
|
157
|
+
if (runNextFrame && allowKeepAlive) {
|
|
158
|
+
useDefaultElapsed = false;
|
|
159
|
+
scheduleNextBatch(processBatch);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const wake = () => {
|
|
163
|
+
runNextFrame = true;
|
|
164
|
+
useDefaultElapsed = true;
|
|
165
|
+
if (!state.isProcessing) {
|
|
166
|
+
scheduleNextBatch(processBatch);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const schedule = stepsOrder.reduce((acc, key) => {
|
|
170
|
+
const step = steps[key];
|
|
171
|
+
acc[key] = (process, keepAlive = false, immediate = false) => {
|
|
172
|
+
if (!runNextFrame)
|
|
173
|
+
wake();
|
|
174
|
+
return step.schedule(process, keepAlive, immediate);
|
|
175
|
+
};
|
|
176
|
+
return acc;
|
|
177
|
+
}, {});
|
|
178
|
+
const cancel = (process) => stepsOrder.forEach((key) => steps[key].cancel(process));
|
|
179
|
+
return { schedule, cancel, state, steps };
|
|
180
|
+
}
|
|
181
|
+
|
|
13
182
|
function isRefObject(ref) {
|
|
14
183
|
return (ref &&
|
|
15
184
|
typeof ref === "object" &&
|
|
@@ -559,173 +728,6 @@ const resolveFinalValueInKeyframes = (v) => {
|
|
|
559
728
|
|
|
560
729
|
const noop = (any) => any;
|
|
561
730
|
|
|
562
|
-
const MotionGlobalConfig = {
|
|
563
|
-
skipAnimations: false,
|
|
564
|
-
useManualTiming: false,
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
class Queue {
|
|
568
|
-
constructor() {
|
|
569
|
-
this.order = [];
|
|
570
|
-
this.scheduled = new Set();
|
|
571
|
-
}
|
|
572
|
-
add(process) {
|
|
573
|
-
if (!this.scheduled.has(process)) {
|
|
574
|
-
this.scheduled.add(process);
|
|
575
|
-
this.order.push(process);
|
|
576
|
-
return true;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
remove(process) {
|
|
580
|
-
const index = this.order.indexOf(process);
|
|
581
|
-
if (index !== -1) {
|
|
582
|
-
this.order.splice(index, 1);
|
|
583
|
-
this.scheduled.delete(process);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
clear() {
|
|
587
|
-
this.order.length = 0;
|
|
588
|
-
this.scheduled.clear();
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
function createRenderStep(runNextFrame) {
|
|
592
|
-
/**
|
|
593
|
-
* We create and reuse two queues, one to queue jobs for the current frame
|
|
594
|
-
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
595
|
-
*/
|
|
596
|
-
let thisFrame = new Queue();
|
|
597
|
-
let nextFrame = new Queue();
|
|
598
|
-
let numToRun = 0;
|
|
599
|
-
/**
|
|
600
|
-
* Track whether we're currently processing jobs in this step. This way
|
|
601
|
-
* we can decide whether to schedule new jobs for this frame or next.
|
|
602
|
-
*/
|
|
603
|
-
let isProcessing = false;
|
|
604
|
-
let flushNextFrame = false;
|
|
605
|
-
/**
|
|
606
|
-
* A set of processes which were marked keepAlive when scheduled.
|
|
607
|
-
*/
|
|
608
|
-
const toKeepAlive = new WeakSet();
|
|
609
|
-
const step = {
|
|
610
|
-
/**
|
|
611
|
-
* Schedule a process to run on the next frame.
|
|
612
|
-
*/
|
|
613
|
-
schedule: (callback, keepAlive = false, immediate = false) => {
|
|
614
|
-
const addToCurrentFrame = immediate && isProcessing;
|
|
615
|
-
const queue = addToCurrentFrame ? thisFrame : nextFrame;
|
|
616
|
-
if (keepAlive)
|
|
617
|
-
toKeepAlive.add(callback);
|
|
618
|
-
if (queue.add(callback) && addToCurrentFrame && isProcessing) {
|
|
619
|
-
// If we're adding it to the currently running queue, update its measured size
|
|
620
|
-
numToRun = thisFrame.order.length;
|
|
621
|
-
}
|
|
622
|
-
return callback;
|
|
623
|
-
},
|
|
624
|
-
/**
|
|
625
|
-
* Cancel the provided callback from running on the next frame.
|
|
626
|
-
*/
|
|
627
|
-
cancel: (callback) => {
|
|
628
|
-
nextFrame.remove(callback);
|
|
629
|
-
toKeepAlive.delete(callback);
|
|
630
|
-
},
|
|
631
|
-
/**
|
|
632
|
-
* Execute all schedule callbacks.
|
|
633
|
-
*/
|
|
634
|
-
process: (frameData) => {
|
|
635
|
-
/**
|
|
636
|
-
* If we're already processing we've probably been triggered by a flushSync
|
|
637
|
-
* inside an existing process. Instead of executing, mark flushNextFrame
|
|
638
|
-
* as true and ensure we flush the following frame at the end of this one.
|
|
639
|
-
*/
|
|
640
|
-
if (isProcessing) {
|
|
641
|
-
flushNextFrame = true;
|
|
642
|
-
return;
|
|
643
|
-
}
|
|
644
|
-
isProcessing = true;
|
|
645
|
-
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
646
|
-
// Clear the next frame queue
|
|
647
|
-
nextFrame.clear();
|
|
648
|
-
// Execute this frame
|
|
649
|
-
numToRun = thisFrame.order.length;
|
|
650
|
-
if (numToRun) {
|
|
651
|
-
for (let i = 0; i < numToRun; i++) {
|
|
652
|
-
const callback = thisFrame.order[i];
|
|
653
|
-
if (toKeepAlive.has(callback)) {
|
|
654
|
-
step.schedule(callback);
|
|
655
|
-
runNextFrame();
|
|
656
|
-
}
|
|
657
|
-
callback(frameData);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
isProcessing = false;
|
|
661
|
-
if (flushNextFrame) {
|
|
662
|
-
flushNextFrame = false;
|
|
663
|
-
step.process(frameData);
|
|
664
|
-
}
|
|
665
|
-
},
|
|
666
|
-
};
|
|
667
|
-
return step;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
const stepsOrder = [
|
|
671
|
-
"prepare",
|
|
672
|
-
"read",
|
|
673
|
-
"update",
|
|
674
|
-
"preRender",
|
|
675
|
-
"render",
|
|
676
|
-
"postRender",
|
|
677
|
-
];
|
|
678
|
-
const maxElapsed$1 = 40;
|
|
679
|
-
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
680
|
-
let runNextFrame = false;
|
|
681
|
-
let useDefaultElapsed = true;
|
|
682
|
-
const state = {
|
|
683
|
-
delta: 0,
|
|
684
|
-
timestamp: 0,
|
|
685
|
-
isProcessing: false,
|
|
686
|
-
};
|
|
687
|
-
const steps = stepsOrder.reduce((acc, key) => {
|
|
688
|
-
acc[key] = createRenderStep(() => (runNextFrame = true));
|
|
689
|
-
return acc;
|
|
690
|
-
}, {});
|
|
691
|
-
const processStep = (stepId) => steps[stepId].process(state);
|
|
692
|
-
const processBatch = () => {
|
|
693
|
-
const timestamp = MotionGlobalConfig.useManualTiming
|
|
694
|
-
? state.timestamp
|
|
695
|
-
: performance.now();
|
|
696
|
-
runNextFrame = false;
|
|
697
|
-
state.delta = useDefaultElapsed
|
|
698
|
-
? 1000 / 60
|
|
699
|
-
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
|
|
700
|
-
state.timestamp = timestamp;
|
|
701
|
-
state.isProcessing = true;
|
|
702
|
-
stepsOrder.forEach(processStep);
|
|
703
|
-
state.isProcessing = false;
|
|
704
|
-
if (runNextFrame && allowKeepAlive) {
|
|
705
|
-
useDefaultElapsed = false;
|
|
706
|
-
scheduleNextBatch(processBatch);
|
|
707
|
-
}
|
|
708
|
-
};
|
|
709
|
-
const wake = () => {
|
|
710
|
-
runNextFrame = true;
|
|
711
|
-
useDefaultElapsed = true;
|
|
712
|
-
if (!state.isProcessing) {
|
|
713
|
-
scheduleNextBatch(processBatch);
|
|
714
|
-
}
|
|
715
|
-
};
|
|
716
|
-
const schedule = stepsOrder.reduce((acc, key) => {
|
|
717
|
-
const step = steps[key];
|
|
718
|
-
acc[key] = (process, keepAlive = false, immediate = false) => {
|
|
719
|
-
if (!runNextFrame)
|
|
720
|
-
wake();
|
|
721
|
-
return step.schedule(process, keepAlive, immediate);
|
|
722
|
-
};
|
|
723
|
-
return acc;
|
|
724
|
-
}, {});
|
|
725
|
-
const cancel = (process) => stepsOrder.forEach((key) => steps[key].cancel(process));
|
|
726
|
-
return { schedule, cancel, state, steps };
|
|
727
|
-
}
|
|
728
|
-
|
|
729
731
|
const { schedule: frame, cancel: cancelFrame, state: frameData, steps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
|
|
730
732
|
|
|
731
733
|
/**
|
|
@@ -1764,8 +1766,6 @@ function inertia({ keyframes, velocity = 0.0, power = 0.8, timeConstant = 325, b
|
|
|
1764
1766
|
};
|
|
1765
1767
|
}
|
|
1766
1768
|
|
|
1767
|
-
const { schedule: microtask, cancel: cancelMicrotask } = createRenderBatcher(queueMicrotask, false);
|
|
1768
|
-
|
|
1769
1769
|
let now;
|
|
1770
1770
|
function clearTime() {
|
|
1771
1771
|
now = undefined;
|
|
@@ -1789,7 +1789,7 @@ const time = {
|
|
|
1789
1789
|
},
|
|
1790
1790
|
set: (newTime) => {
|
|
1791
1791
|
now = newTime;
|
|
1792
|
-
|
|
1792
|
+
queueMicrotask(clearTime);
|
|
1793
1793
|
},
|
|
1794
1794
|
};
|
|
1795
1795
|
|
|
@@ -2750,7 +2750,7 @@ class MotionValue {
|
|
|
2750
2750
|
* This will be replaced by the build step with the latest version number.
|
|
2751
2751
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
2752
2752
|
*/
|
|
2753
|
-
this.version = "11.0.0
|
|
2753
|
+
this.version = "11.0.0";
|
|
2754
2754
|
/**
|
|
2755
2755
|
* Tracks whether this value can output a velocity. Currently this is only true
|
|
2756
2756
|
* if the value is numerical, but we might be able to widen the scope here and support
|
|
@@ -3977,7 +3977,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
3977
3977
|
* and warn against mismatches.
|
|
3978
3978
|
*/
|
|
3979
3979
|
if (process.env.NODE_ENV === "development") {
|
|
3980
|
-
warnOnce(nextValue.version === "11.0.0
|
|
3980
|
+
warnOnce(nextValue.version === "11.0.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.0.0 may not work as expected.`);
|
|
3981
3981
|
}
|
|
3982
3982
|
}
|
|
3983
3983
|
else if (isMotionValue(prevValue)) {
|
|
@@ -5652,6 +5652,7 @@ exports.convertBoundingBoxToBox = convertBoundingBoxToBox;
|
|
|
5652
5652
|
exports.convertBoxToBoundingBox = convertBoxToBoundingBox;
|
|
5653
5653
|
exports.createBox = createBox;
|
|
5654
5654
|
exports.createDelta = createDelta;
|
|
5655
|
+
exports.createRenderBatcher = createRenderBatcher;
|
|
5655
5656
|
exports.createScopedAnimate = createScopedAnimate;
|
|
5656
5657
|
exports.cubicBezier = cubicBezier;
|
|
5657
5658
|
exports.delay = delay;
|
package/dist/cjs/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var React = require('react');
|
|
6
|
-
var indexLegacy = require('./index-legacy-
|
|
6
|
+
var indexLegacy = require('./index-legacy-731c5510.js');
|
|
7
7
|
|
|
8
8
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
9
|
|
|
@@ -48,6 +48,8 @@ const useIsomorphicLayoutEffect = indexLegacy.isBrowser ? React.useLayoutEffect
|
|
|
48
48
|
|
|
49
49
|
const LazyContext = React.createContext({ strict: false });
|
|
50
50
|
|
|
51
|
+
const { schedule: microtask, cancel: cancelMicrotask } = indexLegacy.createRenderBatcher(queueMicrotask, false);
|
|
52
|
+
|
|
51
53
|
function useVisualElement(Component, visualState, props, createVisualElement) {
|
|
52
54
|
const { visualElement: parent } = React.useContext(MotionContext);
|
|
53
55
|
const lazyContext = React.useContext(LazyContext);
|
|
@@ -82,7 +84,7 @@ function useVisualElement(Component, visualState, props, createVisualElement) {
|
|
|
82
84
|
useIsomorphicLayoutEffect(() => {
|
|
83
85
|
if (!visualElement)
|
|
84
86
|
return;
|
|
85
|
-
visualElement.render
|
|
87
|
+
microtask.postRender(visualElement.render);
|
|
86
88
|
/**
|
|
87
89
|
* Ideally this function would always run in a useEffect.
|
|
88
90
|
*
|
|
@@ -3188,7 +3190,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
3188
3190
|
didUpdate() {
|
|
3189
3191
|
if (!this.updateScheduled) {
|
|
3190
3192
|
this.updateScheduled = true;
|
|
3191
|
-
|
|
3193
|
+
microtask.read(() => this.update());
|
|
3192
3194
|
}
|
|
3193
3195
|
}
|
|
3194
3196
|
clearAllSnapshots() {
|
|
@@ -3470,9 +3472,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
3470
3472
|
* a relativeParent. This will allow a component to perform scale correction
|
|
3471
3473
|
* even if no animation has started.
|
|
3472
3474
|
*/
|
|
3473
|
-
// TODO If this is unsuccessful this currently happens every frame
|
|
3474
3475
|
if (!this.targetDelta && !this.relativeTarget) {
|
|
3475
|
-
// TODO: This is a semi-repetition of further down this function, make DRY
|
|
3476
3476
|
const relativeParent = this.getClosestProjectingParent();
|
|
3477
3477
|
if (relativeParent &&
|
|
3478
3478
|
relativeParent.layout &&
|
|
@@ -4536,7 +4536,7 @@ class MeasureLayoutWithContext extends React__default["default"].Component {
|
|
|
4536
4536
|
const { projection } = this.props.visualElement;
|
|
4537
4537
|
if (projection) {
|
|
4538
4538
|
projection.root.didUpdate();
|
|
4539
|
-
|
|
4539
|
+
microtask.postRender(() => {
|
|
4540
4540
|
if (!projection.currentAnimation && projection.isLead()) {
|
|
4541
4541
|
this.safeToRemove();
|
|
4542
4542
|
}
|
|
@@ -5365,6 +5365,13 @@ function useSpring(source, config = {}) {
|
|
|
5365
5365
|
*/
|
|
5366
5366
|
if (isStatic)
|
|
5367
5367
|
return set(v);
|
|
5368
|
+
/**
|
|
5369
|
+
* If the previous animation hasn't had the chance to even render a frame, render it now.
|
|
5370
|
+
*/
|
|
5371
|
+
const animation = activeSpringAnimation.current;
|
|
5372
|
+
if (animation && animation.time === 0) {
|
|
5373
|
+
animation.sample(indexLegacy.frameData.delta);
|
|
5374
|
+
}
|
|
5368
5375
|
stopAnimation();
|
|
5369
5376
|
activeSpringAnimation.current = indexLegacy.animateValue({
|
|
5370
5377
|
keyframes: [value.get(), v],
|
|
@@ -5375,16 +5382,6 @@ function useSpring(source, config = {}) {
|
|
|
5375
5382
|
...config,
|
|
5376
5383
|
onUpdate: set,
|
|
5377
5384
|
});
|
|
5378
|
-
/**
|
|
5379
|
-
* If we're between frames, resync the animation to the frameloop.
|
|
5380
|
-
*/
|
|
5381
|
-
if (!indexLegacy.frameData.isProcessing) {
|
|
5382
|
-
const delta = performance.now() - indexLegacy.frameData.timestamp;
|
|
5383
|
-
if (delta < 30) {
|
|
5384
|
-
activeSpringAnimation.current.time =
|
|
5385
|
-
indexLegacy.millisecondsToSeconds(delta);
|
|
5386
|
-
}
|
|
5387
|
-
}
|
|
5388
5385
|
return value.get();
|
|
5389
5386
|
}, stopAnimation);
|
|
5390
5387
|
}, [JSON.stringify(config)]);
|
|
@@ -5422,6 +5419,10 @@ function useVelocity(value) {
|
|
|
5422
5419
|
const updateVelocity = () => {
|
|
5423
5420
|
const latest = value.getVelocity();
|
|
5424
5421
|
velocity.set(latest);
|
|
5422
|
+
/**
|
|
5423
|
+
* If we still have velocity, schedule an update for the next frame
|
|
5424
|
+
* to keep checking until it is zero.
|
|
5425
|
+
*/
|
|
5425
5426
|
if (latest)
|
|
5426
5427
|
indexLegacy.frame.update(updateVelocity);
|
|
5427
5428
|
};
|
|
@@ -22,7 +22,9 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
|
22
22
|
acc[key] = createRenderStep(() => (runNextFrame = true));
|
|
23
23
|
return acc;
|
|
24
24
|
}, {});
|
|
25
|
-
const processStep = (stepId) =>
|
|
25
|
+
const processStep = (stepId) => {
|
|
26
|
+
steps[stepId].process(state);
|
|
27
|
+
};
|
|
26
28
|
const processBatch = () => {
|
|
27
29
|
const timestamp = MotionGlobalConfig.useManualTiming
|
|
28
30
|
? state.timestamp
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { MotionGlobalConfig } from '../utils/GlobalConfig.mjs';
|
|
2
2
|
import { frameData } from './frame.mjs';
|
|
3
|
-
import { microtask } from './microtask.mjs';
|
|
4
3
|
|
|
5
4
|
let now;
|
|
6
5
|
function clearTime() {
|
|
@@ -25,7 +24,7 @@ const time = {
|
|
|
25
24
|
},
|
|
26
25
|
set: (newTime) => {
|
|
27
26
|
now = newTime;
|
|
28
|
-
|
|
27
|
+
queueMicrotask(clearTime);
|
|
29
28
|
},
|
|
30
29
|
};
|
|
31
30
|
|
|
@@ -6,6 +6,7 @@ import { globalProjectionState } from '../../../projection/node/state.mjs';
|
|
|
6
6
|
import { correctBorderRadius } from '../../../projection/styles/scale-border-radius.mjs';
|
|
7
7
|
import { correctBoxShadow } from '../../../projection/styles/scale-box-shadow.mjs';
|
|
8
8
|
import { addScaleCorrector } from '../../../projection/styles/scale-correction.mjs';
|
|
9
|
+
import { microtask } from '../../../frameloop/microtask.mjs';
|
|
9
10
|
import { frame } from '../../../frameloop/frame.mjs';
|
|
10
11
|
|
|
11
12
|
class MeasureLayoutWithContext extends React__default.Component {
|
|
@@ -80,7 +81,7 @@ class MeasureLayoutWithContext extends React__default.Component {
|
|
|
80
81
|
const { projection } = this.props.visualElement;
|
|
81
82
|
if (projection) {
|
|
82
83
|
projection.root.didUpdate();
|
|
83
|
-
|
|
84
|
+
microtask.postRender(() => {
|
|
84
85
|
if (!projection.currentAnimation && projection.isLead()) {
|
|
85
86
|
this.safeToRemove();
|
|
86
87
|
}
|
|
@@ -5,6 +5,7 @@ import { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs
|
|
|
5
5
|
import { LazyContext } from '../../context/LazyContext.mjs';
|
|
6
6
|
import { MotionConfigContext } from '../../context/MotionConfigContext.mjs';
|
|
7
7
|
import { optimizedAppearDataAttribute } from '../../animation/optimized-appear/data-id.mjs';
|
|
8
|
+
import { microtask } from '../../frameloop/microtask.mjs';
|
|
8
9
|
|
|
9
10
|
function useVisualElement(Component, visualState, props, createVisualElement) {
|
|
10
11
|
const { visualElement: parent } = useContext(MotionContext);
|
|
@@ -40,7 +41,7 @@ function useVisualElement(Component, visualState, props, createVisualElement) {
|
|
|
40
41
|
useIsomorphicLayoutEffect(() => {
|
|
41
42
|
if (!visualElement)
|
|
42
43
|
return;
|
|
43
|
-
visualElement.render
|
|
44
|
+
microtask.postRender(visualElement.render);
|
|
44
45
|
/**
|
|
45
46
|
* Ideally this function would always run in a useEffect.
|
|
46
47
|
*
|
|
@@ -24,6 +24,7 @@ import { clamp } from '../../utils/clamp.mjs';
|
|
|
24
24
|
import { cancelFrame, frameData, steps, frame } from '../../frameloop/frame.mjs';
|
|
25
25
|
import { noop } from '../../utils/noop.mjs';
|
|
26
26
|
import { time } from '../../frameloop/sync-time.mjs';
|
|
27
|
+
import { microtask } from '../../frameloop/microtask.mjs';
|
|
27
28
|
|
|
28
29
|
const transformAxes = ["", "X", "Y", "Z"];
|
|
29
30
|
const hiddenVisibility = { visibility: "hidden" };
|
|
@@ -406,7 +407,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
406
407
|
didUpdate() {
|
|
407
408
|
if (!this.updateScheduled) {
|
|
408
409
|
this.updateScheduled = true;
|
|
409
|
-
|
|
410
|
+
microtask.read(() => this.update());
|
|
410
411
|
}
|
|
411
412
|
}
|
|
412
413
|
clearAllSnapshots() {
|
|
@@ -688,9 +689,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
688
689
|
* a relativeParent. This will allow a component to perform scale correction
|
|
689
690
|
* even if no animation has started.
|
|
690
691
|
*/
|
|
691
|
-
// TODO If this is unsuccessful this currently happens every frame
|
|
692
692
|
if (!this.targetDelta && !this.relativeTarget) {
|
|
693
|
-
// TODO: This is a semi-repetition of further down this function, make DRY
|
|
694
693
|
const relativeParent = this.getClosestProjectingParent();
|
|
695
694
|
if (relativeParent &&
|
|
696
695
|
relativeParent.layout &&
|
|
@@ -22,7 +22,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
22
22
|
* and warn against mismatches.
|
|
23
23
|
*/
|
|
24
24
|
if (process.env.NODE_ENV === "development") {
|
|
25
|
-
warnOnce(nextValue.version === "11.0.0
|
|
25
|
+
warnOnce(nextValue.version === "11.0.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.0.0 may not work as expected.`);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
else if (isMotionValue(prevValue)) {
|
package/dist/es/value/index.mjs
CHANGED
|
@@ -34,7 +34,7 @@ class MotionValue {
|
|
|
34
34
|
* This will be replaced by the build step with the latest version number.
|
|
35
35
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
36
36
|
*/
|
|
37
|
-
this.version = "11.0.0
|
|
37
|
+
this.version = "11.0.0";
|
|
38
38
|
/**
|
|
39
39
|
* Tracks whether this value can output a velocity. Currently this is only true
|
|
40
40
|
* if the value is numerical, but we might be able to widen the scope here and support
|
|
@@ -4,7 +4,6 @@ import { useMotionValue } from './use-motion-value.mjs';
|
|
|
4
4
|
import { MotionConfigContext } from '../context/MotionConfigContext.mjs';
|
|
5
5
|
import { useIsomorphicLayoutEffect } from '../utils/use-isomorphic-effect.mjs';
|
|
6
6
|
import { animateValue } from '../animation/animators/js/index.mjs';
|
|
7
|
-
import { millisecondsToSeconds } from '../utils/time-conversion.mjs';
|
|
8
7
|
import { frameData } from '../frameloop/frame.mjs';
|
|
9
8
|
|
|
10
9
|
/**
|
|
@@ -43,6 +42,13 @@ function useSpring(source, config = {}) {
|
|
|
43
42
|
*/
|
|
44
43
|
if (isStatic)
|
|
45
44
|
return set(v);
|
|
45
|
+
/**
|
|
46
|
+
* If the previous animation hasn't had the chance to even render a frame, render it now.
|
|
47
|
+
*/
|
|
48
|
+
const animation = activeSpringAnimation.current;
|
|
49
|
+
if (animation && animation.time === 0) {
|
|
50
|
+
animation.sample(frameData.delta);
|
|
51
|
+
}
|
|
46
52
|
stopAnimation();
|
|
47
53
|
activeSpringAnimation.current = animateValue({
|
|
48
54
|
keyframes: [value.get(), v],
|
|
@@ -53,16 +59,6 @@ function useSpring(source, config = {}) {
|
|
|
53
59
|
...config,
|
|
54
60
|
onUpdate: set,
|
|
55
61
|
});
|
|
56
|
-
/**
|
|
57
|
-
* If we're between frames, resync the animation to the frameloop.
|
|
58
|
-
*/
|
|
59
|
-
if (!frameData.isProcessing) {
|
|
60
|
-
const delta = performance.now() - frameData.timestamp;
|
|
61
|
-
if (delta < 30) {
|
|
62
|
-
activeSpringAnimation.current.time =
|
|
63
|
-
millisecondsToSeconds(delta);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
62
|
return value.get();
|
|
67
63
|
}, stopAnimation);
|
|
68
64
|
}, [JSON.stringify(config)]);
|
|
@@ -18,6 +18,10 @@ function useVelocity(value) {
|
|
|
18
18
|
const updateVelocity = () => {
|
|
19
19
|
const latest = value.getVelocity();
|
|
20
20
|
velocity.set(latest);
|
|
21
|
+
/**
|
|
22
|
+
* If we still have velocity, schedule an update for the next frame
|
|
23
|
+
* to keep checking until it is zero.
|
|
24
|
+
*/
|
|
21
25
|
if (latest)
|
|
22
26
|
frame.update(updateVelocity);
|
|
23
27
|
};
|