framer-motion 10.16.0 → 10.16.2
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-3cb60b07.js → index-legacy-ccd59e4d.js} +83 -42
- package/dist/cjs/index.js +55 -37
- package/dist/es/frameloop/render-step.mjs +37 -21
- package/dist/es/motion/utils/use-visual-element.mjs +32 -18
- package/dist/es/render/dom/scroll/offsets/index.mjs +6 -1
- package/dist/es/render/dom/scroll/offsets/inset.mjs +28 -8
- package/dist/es/render/svg/config-motion.mjs +23 -18
- package/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/value/index.mjs +1 -1
- package/dist/framer-motion.dev.js +254 -195
- package/dist/framer-motion.js +1 -1
- package/dist/projection.dev.js +39 -23
- package/package.json +10 -10
package/dist/cjs/dom-entry.js
CHANGED
|
@@ -551,28 +551,39 @@ const resolveFinalValueInKeyframes = (v) => {
|
|
|
551
551
|
return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
|
|
552
552
|
};
|
|
553
553
|
|
|
554
|
-
/**
|
|
555
|
-
* Pipe
|
|
556
|
-
* Compose other transformers to run linearily
|
|
557
|
-
* pipe(min(20), max(40))
|
|
558
|
-
* @param {...functions} transformers
|
|
559
|
-
* @return {function}
|
|
560
|
-
*/
|
|
561
|
-
const combineFunctions = (a, b) => (v) => b(a(v));
|
|
562
|
-
const pipe = (...transformers) => transformers.reduce(combineFunctions);
|
|
563
|
-
|
|
564
554
|
const noop = (any) => any;
|
|
565
555
|
|
|
556
|
+
class Queue {
|
|
557
|
+
constructor() {
|
|
558
|
+
this.order = [];
|
|
559
|
+
this.scheduled = new Set();
|
|
560
|
+
}
|
|
561
|
+
add(process) {
|
|
562
|
+
if (!this.scheduled.has(process)) {
|
|
563
|
+
this.scheduled.add(process);
|
|
564
|
+
this.order.push(process);
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
remove(process) {
|
|
569
|
+
const index = this.order.indexOf(process);
|
|
570
|
+
if (index !== -1) {
|
|
571
|
+
this.order.splice(index, 1);
|
|
572
|
+
this.scheduled.delete(process);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
clear() {
|
|
576
|
+
this.order.length = 0;
|
|
577
|
+
this.scheduled.clear();
|
|
578
|
+
}
|
|
579
|
+
}
|
|
566
580
|
function createRenderStep(runNextFrame) {
|
|
567
581
|
/**
|
|
568
|
-
* We create and reuse two
|
|
582
|
+
* We create and reuse two queues, one to queue jobs for the current frame
|
|
569
583
|
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
570
584
|
*/
|
|
571
|
-
let
|
|
572
|
-
let
|
|
573
|
-
/**
|
|
574
|
-
*
|
|
575
|
-
*/
|
|
585
|
+
let thisFrame = new Queue();
|
|
586
|
+
let nextFrame = new Queue();
|
|
576
587
|
let numToRun = 0;
|
|
577
588
|
/**
|
|
578
589
|
* Track whether we're currently processing jobs in this step. This way
|
|
@@ -590,15 +601,12 @@ function createRenderStep(runNextFrame) {
|
|
|
590
601
|
*/
|
|
591
602
|
schedule: (callback, keepAlive = false, immediate = false) => {
|
|
592
603
|
const addToCurrentFrame = immediate && isProcessing;
|
|
593
|
-
const
|
|
604
|
+
const queue = addToCurrentFrame ? thisFrame : nextFrame;
|
|
594
605
|
if (keepAlive)
|
|
595
606
|
toKeepAlive.add(callback);
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
// If we're adding it to the currently running buffer, update its measured size
|
|
600
|
-
if (addToCurrentFrame && isProcessing)
|
|
601
|
-
numToRun = toRun.length;
|
|
607
|
+
if (queue.add(callback) && addToCurrentFrame && isProcessing) {
|
|
608
|
+
// If we're adding it to the currently running queue, update its measured size
|
|
609
|
+
numToRun = thisFrame.order.length;
|
|
602
610
|
}
|
|
603
611
|
return callback;
|
|
604
612
|
},
|
|
@@ -606,9 +614,7 @@ function createRenderStep(runNextFrame) {
|
|
|
606
614
|
* Cancel the provided callback from running on the next frame.
|
|
607
615
|
*/
|
|
608
616
|
cancel: (callback) => {
|
|
609
|
-
|
|
610
|
-
if (index !== -1)
|
|
611
|
-
toRunNextFrame.splice(index, 1);
|
|
617
|
+
nextFrame.remove(callback);
|
|
612
618
|
toKeepAlive.delete(callback);
|
|
613
619
|
},
|
|
614
620
|
/**
|
|
@@ -625,14 +631,14 @@ function createRenderStep(runNextFrame) {
|
|
|
625
631
|
return;
|
|
626
632
|
}
|
|
627
633
|
isProcessing = true;
|
|
628
|
-
[
|
|
629
|
-
// Clear the next frame
|
|
630
|
-
|
|
634
|
+
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
635
|
+
// Clear the next frame queue
|
|
636
|
+
nextFrame.clear();
|
|
631
637
|
// Execute this frame
|
|
632
|
-
numToRun =
|
|
638
|
+
numToRun = thisFrame.order.length;
|
|
633
639
|
if (numToRun) {
|
|
634
640
|
for (let i = 0; i < numToRun; i++) {
|
|
635
|
-
const callback =
|
|
641
|
+
const callback = thisFrame.order[i];
|
|
636
642
|
callback(frameData);
|
|
637
643
|
if (toKeepAlive.has(callback)) {
|
|
638
644
|
step.schedule(callback);
|
|
@@ -709,6 +715,16 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
|
709
715
|
|
|
710
716
|
const { schedule: frame, cancel: cancelFrame, state: frameData, steps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
|
|
711
717
|
|
|
718
|
+
/**
|
|
719
|
+
* Pipe
|
|
720
|
+
* Compose other transformers to run linearily
|
|
721
|
+
* pipe(min(20), max(40))
|
|
722
|
+
* @param {...functions} transformers
|
|
723
|
+
* @return {function}
|
|
724
|
+
*/
|
|
725
|
+
const combineFunctions = (a, b) => (v) => b(a(v));
|
|
726
|
+
const pipe = (...transformers) => transformers.reduce(combineFunctions);
|
|
727
|
+
|
|
712
728
|
/**
|
|
713
729
|
* Creates an object containing the latest state of every MotionValue on a VisualElement
|
|
714
730
|
*/
|
|
@@ -2662,7 +2678,7 @@ class MotionValue {
|
|
|
2662
2678
|
* This will be replaced by the build step with the latest version number.
|
|
2663
2679
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
2664
2680
|
*/
|
|
2665
|
-
this.version = "10.16.
|
|
2681
|
+
this.version = "10.16.2";
|
|
2666
2682
|
/**
|
|
2667
2683
|
* Duration, in milliseconds, since last updating frame.
|
|
2668
2684
|
*
|
|
@@ -3880,7 +3896,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
3880
3896
|
* and warn against mismatches.
|
|
3881
3897
|
*/
|
|
3882
3898
|
if (process.env.NODE_ENV === "development") {
|
|
3883
|
-
warnOnce(nextValue.version === "10.16.
|
|
3899
|
+
warnOnce(nextValue.version === "10.16.2", `Attempting to mix Framer Motion versions ${nextValue.version} with 10.16.2 may not work as expected.`);
|
|
3884
3900
|
}
|
|
3885
3901
|
}
|
|
3886
3902
|
else if (isMotionValue(prevValue)) {
|
|
@@ -5071,7 +5087,7 @@ function updateScrollInfo(element, info, time) {
|
|
|
5071
5087
|
}
|
|
5072
5088
|
|
|
5073
5089
|
function calcInset(element, container) {
|
|
5074
|
-
|
|
5090
|
+
const inset = { x: 0, y: 0 };
|
|
5075
5091
|
let current = element;
|
|
5076
5092
|
while (current && current !== container) {
|
|
5077
5093
|
if (current instanceof HTMLElement) {
|
|
@@ -5079,16 +5095,36 @@ function calcInset(element, container) {
|
|
|
5079
5095
|
inset.y += current.offsetTop;
|
|
5080
5096
|
current = current.offsetParent;
|
|
5081
5097
|
}
|
|
5082
|
-
else if (current
|
|
5083
|
-
const { top, left } = current.getBBox();
|
|
5084
|
-
inset.x += left;
|
|
5085
|
-
inset.y += top;
|
|
5098
|
+
else if (current.tagName === "svg") {
|
|
5086
5099
|
/**
|
|
5087
|
-
*
|
|
5100
|
+
* This isn't an ideal approach to measuring the offset of <svg /> tags.
|
|
5101
|
+
* It would be preferable, given they behave like HTMLElements in most ways
|
|
5102
|
+
* to use offsetLeft/Top. But these don't exist on <svg />. Likewise we
|
|
5103
|
+
* can't use .getBBox() like most SVG elements as these provide the offset
|
|
5104
|
+
* relative to the SVG itself, which for <svg /> is usually 0x0.
|
|
5088
5105
|
*/
|
|
5089
|
-
|
|
5090
|
-
|
|
5106
|
+
const svgBoundingBox = current.getBoundingClientRect();
|
|
5107
|
+
current = current.parentElement;
|
|
5108
|
+
const parentBoundingBox = current.getBoundingClientRect();
|
|
5109
|
+
inset.x += svgBoundingBox.left - parentBoundingBox.left;
|
|
5110
|
+
inset.y += svgBoundingBox.top - parentBoundingBox.top;
|
|
5111
|
+
}
|
|
5112
|
+
else if (current instanceof SVGGraphicsElement) {
|
|
5113
|
+
const { x, y } = current.getBBox();
|
|
5114
|
+
inset.x += x;
|
|
5115
|
+
inset.y += y;
|
|
5116
|
+
let svg = null;
|
|
5117
|
+
let parent = current.parentNode;
|
|
5118
|
+
while (!svg) {
|
|
5119
|
+
if (parent.tagName === "svg") {
|
|
5120
|
+
svg = parent;
|
|
5121
|
+
}
|
|
5122
|
+
parent = current.parentNode;
|
|
5091
5123
|
}
|
|
5124
|
+
current = svg;
|
|
5125
|
+
}
|
|
5126
|
+
else {
|
|
5127
|
+
break;
|
|
5092
5128
|
}
|
|
5093
5129
|
}
|
|
5094
5130
|
return inset;
|
|
@@ -5190,6 +5226,11 @@ function resolveOffset(offset, containerLength, targetLength, targetInset) {
|
|
|
5190
5226
|
}
|
|
5191
5227
|
|
|
5192
5228
|
const point = { x: 0, y: 0 };
|
|
5229
|
+
function getTargetSize(target) {
|
|
5230
|
+
return "getBBox" in target && target.tagName !== "svg"
|
|
5231
|
+
? target.getBBox()
|
|
5232
|
+
: { width: target.clientWidth, height: target.clientHeight };
|
|
5233
|
+
}
|
|
5193
5234
|
function resolveOffsets(container, info, options) {
|
|
5194
5235
|
let { offset: offsetDefinition = ScrollOffset.All } = options;
|
|
5195
5236
|
const { target = container, axis = "y" } = options;
|
|
@@ -5202,7 +5243,7 @@ function resolveOffsets(container, info, options) {
|
|
|
5202
5243
|
*/
|
|
5203
5244
|
const targetSize = target === container
|
|
5204
5245
|
? { width: container.scrollWidth, height: container.scrollHeight }
|
|
5205
|
-
:
|
|
5246
|
+
: getTargetSize(target);
|
|
5206
5247
|
const containerSize = {
|
|
5207
5248
|
width: container.clientWidth,
|
|
5208
5249
|
height: container.clientHeight,
|
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-ccd59e4d.js');
|
|
7
7
|
|
|
8
8
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
9
|
|
|
@@ -74,29 +74,43 @@ function useVisualElement(Component, visualState, props, createVisualElement) {
|
|
|
74
74
|
React.useInsertionEffect(() => {
|
|
75
75
|
visualElement && visualElement.update(props, presenceContext);
|
|
76
76
|
});
|
|
77
|
+
/**
|
|
78
|
+
* Cache this value as we want to know whether HandoffAppearAnimations
|
|
79
|
+
* was present on initial render - it will be deleted after this.
|
|
80
|
+
*/
|
|
81
|
+
const canHandoff = React.useRef(Boolean(window.HandoffAppearAnimations));
|
|
77
82
|
useIsomorphicLayoutEffect(() => {
|
|
78
|
-
|
|
83
|
+
if (!visualElement)
|
|
84
|
+
return;
|
|
85
|
+
visualElement.render();
|
|
86
|
+
/**
|
|
87
|
+
* Ideally this function would always run in a useEffect.
|
|
88
|
+
*
|
|
89
|
+
* However, if we have optimised appear animations to handoff from,
|
|
90
|
+
* it needs to happen synchronously to ensure there's no flash of
|
|
91
|
+
* incorrect styles in the event of a hydration error.
|
|
92
|
+
*
|
|
93
|
+
* So if we detect a situtation where optimised appear animations
|
|
94
|
+
* are running, we use useLayoutEffect to trigger animations.
|
|
95
|
+
*/
|
|
96
|
+
if (canHandoff.current && visualElement.animationState) {
|
|
97
|
+
visualElement.animationState.animateChanges();
|
|
98
|
+
}
|
|
79
99
|
});
|
|
80
100
|
React.useEffect(() => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
*
|
|
86
|
-
* However, if we have optimised appear animations to handoff from,
|
|
87
|
-
* it needs to happen synchronously to ensure there's no flash of
|
|
88
|
-
* incorrect styles in the event of a hydration error.
|
|
89
|
-
*
|
|
90
|
-
* So if we detect a situtation where optimised appear animations
|
|
91
|
-
* are running, we use useLayoutEffect to trigger animations.
|
|
92
|
-
*/
|
|
93
|
-
const useAnimateChangesEffect = window.HandoffAppearAnimations
|
|
94
|
-
? useIsomorphicLayoutEffect
|
|
95
|
-
: React.useEffect;
|
|
96
|
-
useAnimateChangesEffect(() => {
|
|
97
|
-
if (visualElement && visualElement.animationState) {
|
|
101
|
+
if (!visualElement)
|
|
102
|
+
return;
|
|
103
|
+
visualElement.updateFeatures();
|
|
104
|
+
if (!canHandoff.current && visualElement.animationState) {
|
|
98
105
|
visualElement.animationState.animateChanges();
|
|
99
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Once we've handed off animations we can delete HandoffAppearAnimations
|
|
109
|
+
* so components added after the initial render can animate changes
|
|
110
|
+
* in useEffect vs useLayoutEffect.
|
|
111
|
+
*/
|
|
112
|
+
window.HandoffAppearAnimations = undefined;
|
|
113
|
+
canHandoff.current = false;
|
|
100
114
|
});
|
|
101
115
|
return visualElement;
|
|
102
116
|
}
|
|
@@ -657,24 +671,28 @@ const svgMotionConfig = {
|
|
|
657
671
|
scrapeMotionValuesFromProps: indexLegacy.scrapeMotionValuesFromProps,
|
|
658
672
|
createRenderState: createSvgRenderState,
|
|
659
673
|
onMount: (props, instance, { renderState, latestValues }) => {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
674
|
+
indexLegacy.frame.read(() => {
|
|
675
|
+
try {
|
|
676
|
+
renderState.dimensions =
|
|
677
|
+
typeof instance.getBBox ===
|
|
678
|
+
"function"
|
|
679
|
+
? instance.getBBox()
|
|
680
|
+
: instance.getBoundingClientRect();
|
|
681
|
+
}
|
|
682
|
+
catch (e) {
|
|
683
|
+
// Most likely trying to measure an unrendered element under Firefox
|
|
684
|
+
renderState.dimensions = {
|
|
685
|
+
x: 0,
|
|
686
|
+
y: 0,
|
|
687
|
+
width: 0,
|
|
688
|
+
height: 0,
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
indexLegacy.frame.render(() => {
|
|
693
|
+
indexLegacy.buildSVGAttrs(renderState, latestValues, { enableHardwareAcceleration: false }, indexLegacy.isSVGTag(instance.tagName), props.transformTemplate);
|
|
694
|
+
indexLegacy.renderSVG(instance, renderState);
|
|
695
|
+
});
|
|
678
696
|
},
|
|
679
697
|
}),
|
|
680
698
|
};
|
|
@@ -1,13 +1,34 @@
|
|
|
1
|
+
class Queue {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.order = [];
|
|
4
|
+
this.scheduled = new Set();
|
|
5
|
+
}
|
|
6
|
+
add(process) {
|
|
7
|
+
if (!this.scheduled.has(process)) {
|
|
8
|
+
this.scheduled.add(process);
|
|
9
|
+
this.order.push(process);
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
remove(process) {
|
|
14
|
+
const index = this.order.indexOf(process);
|
|
15
|
+
if (index !== -1) {
|
|
16
|
+
this.order.splice(index, 1);
|
|
17
|
+
this.scheduled.delete(process);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
clear() {
|
|
21
|
+
this.order.length = 0;
|
|
22
|
+
this.scheduled.clear();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
1
25
|
function createRenderStep(runNextFrame) {
|
|
2
26
|
/**
|
|
3
|
-
* We create and reuse two
|
|
27
|
+
* We create and reuse two queues, one to queue jobs for the current frame
|
|
4
28
|
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
5
29
|
*/
|
|
6
|
-
let
|
|
7
|
-
let
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
*/
|
|
30
|
+
let thisFrame = new Queue();
|
|
31
|
+
let nextFrame = new Queue();
|
|
11
32
|
let numToRun = 0;
|
|
12
33
|
/**
|
|
13
34
|
* Track whether we're currently processing jobs in this step. This way
|
|
@@ -25,15 +46,12 @@ function createRenderStep(runNextFrame) {
|
|
|
25
46
|
*/
|
|
26
47
|
schedule: (callback, keepAlive = false, immediate = false) => {
|
|
27
48
|
const addToCurrentFrame = immediate && isProcessing;
|
|
28
|
-
const
|
|
49
|
+
const queue = addToCurrentFrame ? thisFrame : nextFrame;
|
|
29
50
|
if (keepAlive)
|
|
30
51
|
toKeepAlive.add(callback);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// If we're adding it to the currently running buffer, update its measured size
|
|
35
|
-
if (addToCurrentFrame && isProcessing)
|
|
36
|
-
numToRun = toRun.length;
|
|
52
|
+
if (queue.add(callback) && addToCurrentFrame && isProcessing) {
|
|
53
|
+
// If we're adding it to the currently running queue, update its measured size
|
|
54
|
+
numToRun = thisFrame.order.length;
|
|
37
55
|
}
|
|
38
56
|
return callback;
|
|
39
57
|
},
|
|
@@ -41,9 +59,7 @@ function createRenderStep(runNextFrame) {
|
|
|
41
59
|
* Cancel the provided callback from running on the next frame.
|
|
42
60
|
*/
|
|
43
61
|
cancel: (callback) => {
|
|
44
|
-
|
|
45
|
-
if (index !== -1)
|
|
46
|
-
toRunNextFrame.splice(index, 1);
|
|
62
|
+
nextFrame.remove(callback);
|
|
47
63
|
toKeepAlive.delete(callback);
|
|
48
64
|
},
|
|
49
65
|
/**
|
|
@@ -60,14 +76,14 @@ function createRenderStep(runNextFrame) {
|
|
|
60
76
|
return;
|
|
61
77
|
}
|
|
62
78
|
isProcessing = true;
|
|
63
|
-
[
|
|
64
|
-
// Clear the next frame
|
|
65
|
-
|
|
79
|
+
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
80
|
+
// Clear the next frame queue
|
|
81
|
+
nextFrame.clear();
|
|
66
82
|
// Execute this frame
|
|
67
|
-
numToRun =
|
|
83
|
+
numToRun = thisFrame.order.length;
|
|
68
84
|
if (numToRun) {
|
|
69
85
|
for (let i = 0; i < numToRun; i++) {
|
|
70
|
-
const callback =
|
|
86
|
+
const callback = thisFrame.order[i];
|
|
71
87
|
callback(frameData);
|
|
72
88
|
if (toKeepAlive.has(callback)) {
|
|
73
89
|
step.schedule(callback);
|
|
@@ -31,29 +31,43 @@ function useVisualElement(Component, visualState, props, createVisualElement) {
|
|
|
31
31
|
useInsertionEffect(() => {
|
|
32
32
|
visualElement && visualElement.update(props, presenceContext);
|
|
33
33
|
});
|
|
34
|
+
/**
|
|
35
|
+
* Cache this value as we want to know whether HandoffAppearAnimations
|
|
36
|
+
* was present on initial render - it will be deleted after this.
|
|
37
|
+
*/
|
|
38
|
+
const canHandoff = useRef(Boolean(window.HandoffAppearAnimations));
|
|
34
39
|
useIsomorphicLayoutEffect(() => {
|
|
35
|
-
|
|
40
|
+
if (!visualElement)
|
|
41
|
+
return;
|
|
42
|
+
visualElement.render();
|
|
43
|
+
/**
|
|
44
|
+
* Ideally this function would always run in a useEffect.
|
|
45
|
+
*
|
|
46
|
+
* However, if we have optimised appear animations to handoff from,
|
|
47
|
+
* it needs to happen synchronously to ensure there's no flash of
|
|
48
|
+
* incorrect styles in the event of a hydration error.
|
|
49
|
+
*
|
|
50
|
+
* So if we detect a situtation where optimised appear animations
|
|
51
|
+
* are running, we use useLayoutEffect to trigger animations.
|
|
52
|
+
*/
|
|
53
|
+
if (canHandoff.current && visualElement.animationState) {
|
|
54
|
+
visualElement.animationState.animateChanges();
|
|
55
|
+
}
|
|
36
56
|
});
|
|
37
57
|
useEffect(() => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
*
|
|
43
|
-
* However, if we have optimised appear animations to handoff from,
|
|
44
|
-
* it needs to happen synchronously to ensure there's no flash of
|
|
45
|
-
* incorrect styles in the event of a hydration error.
|
|
46
|
-
*
|
|
47
|
-
* So if we detect a situtation where optimised appear animations
|
|
48
|
-
* are running, we use useLayoutEffect to trigger animations.
|
|
49
|
-
*/
|
|
50
|
-
const useAnimateChangesEffect = window.HandoffAppearAnimations
|
|
51
|
-
? useIsomorphicLayoutEffect
|
|
52
|
-
: useEffect;
|
|
53
|
-
useAnimateChangesEffect(() => {
|
|
54
|
-
if (visualElement && visualElement.animationState) {
|
|
58
|
+
if (!visualElement)
|
|
59
|
+
return;
|
|
60
|
+
visualElement.updateFeatures();
|
|
61
|
+
if (!canHandoff.current && visualElement.animationState) {
|
|
55
62
|
visualElement.animationState.animateChanges();
|
|
56
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Once we've handed off animations we can delete HandoffAppearAnimations
|
|
66
|
+
* so components added after the initial render can animate changes
|
|
67
|
+
* in useEffect vs useLayoutEffect.
|
|
68
|
+
*/
|
|
69
|
+
window.HandoffAppearAnimations = undefined;
|
|
70
|
+
canHandoff.current = false;
|
|
57
71
|
});
|
|
58
72
|
return visualElement;
|
|
59
73
|
}
|
|
@@ -5,6 +5,11 @@ import { interpolate } from '../../../../utils/interpolate.mjs';
|
|
|
5
5
|
import { defaultOffset } from '../../../../utils/offsets/default.mjs';
|
|
6
6
|
|
|
7
7
|
const point = { x: 0, y: 0 };
|
|
8
|
+
function getTargetSize(target) {
|
|
9
|
+
return "getBBox" in target && target.tagName !== "svg"
|
|
10
|
+
? target.getBBox()
|
|
11
|
+
: { width: target.clientWidth, height: target.clientHeight };
|
|
12
|
+
}
|
|
8
13
|
function resolveOffsets(container, info, options) {
|
|
9
14
|
let { offset: offsetDefinition = ScrollOffset.All } = options;
|
|
10
15
|
const { target = container, axis = "y" } = options;
|
|
@@ -17,7 +22,7 @@ function resolveOffsets(container, info, options) {
|
|
|
17
22
|
*/
|
|
18
23
|
const targetSize = target === container
|
|
19
24
|
? { width: container.scrollWidth, height: container.scrollHeight }
|
|
20
|
-
:
|
|
25
|
+
: getTargetSize(target);
|
|
21
26
|
const containerSize = {
|
|
22
27
|
width: container.clientWidth,
|
|
23
28
|
height: container.clientHeight,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function calcInset(element, container) {
|
|
2
|
-
|
|
2
|
+
const inset = { x: 0, y: 0 };
|
|
3
3
|
let current = element;
|
|
4
4
|
while (current && current !== container) {
|
|
5
5
|
if (current instanceof HTMLElement) {
|
|
@@ -7,16 +7,36 @@ function calcInset(element, container) {
|
|
|
7
7
|
inset.y += current.offsetTop;
|
|
8
8
|
current = current.offsetParent;
|
|
9
9
|
}
|
|
10
|
-
else if (current
|
|
11
|
-
const { top, left } = current.getBBox();
|
|
12
|
-
inset.x += left;
|
|
13
|
-
inset.y += top;
|
|
10
|
+
else if (current.tagName === "svg") {
|
|
14
11
|
/**
|
|
15
|
-
*
|
|
12
|
+
* This isn't an ideal approach to measuring the offset of <svg /> tags.
|
|
13
|
+
* It would be preferable, given they behave like HTMLElements in most ways
|
|
14
|
+
* to use offsetLeft/Top. But these don't exist on <svg />. Likewise we
|
|
15
|
+
* can't use .getBBox() like most SVG elements as these provide the offset
|
|
16
|
+
* relative to the SVG itself, which for <svg /> is usually 0x0.
|
|
16
17
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
const svgBoundingBox = current.getBoundingClientRect();
|
|
19
|
+
current = current.parentElement;
|
|
20
|
+
const parentBoundingBox = current.getBoundingClientRect();
|
|
21
|
+
inset.x += svgBoundingBox.left - parentBoundingBox.left;
|
|
22
|
+
inset.y += svgBoundingBox.top - parentBoundingBox.top;
|
|
23
|
+
}
|
|
24
|
+
else if (current instanceof SVGGraphicsElement) {
|
|
25
|
+
const { x, y } = current.getBBox();
|
|
26
|
+
inset.x += x;
|
|
27
|
+
inset.y += y;
|
|
28
|
+
let svg = null;
|
|
29
|
+
let parent = current.parentNode;
|
|
30
|
+
while (!svg) {
|
|
31
|
+
if (parent.tagName === "svg") {
|
|
32
|
+
svg = parent;
|
|
33
|
+
}
|
|
34
|
+
parent = current.parentNode;
|
|
19
35
|
}
|
|
36
|
+
current = svg;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
break;
|
|
20
40
|
}
|
|
21
41
|
}
|
|
22
42
|
return inset;
|
|
@@ -4,30 +4,35 @@ import { makeUseVisualState } from '../../motion/utils/use-visual-state.mjs';
|
|
|
4
4
|
import { createSvgRenderState } from './utils/create-render-state.mjs';
|
|
5
5
|
import { buildSVGAttrs } from './utils/build-attrs.mjs';
|
|
6
6
|
import { isSVGTag } from './utils/is-svg-tag.mjs';
|
|
7
|
+
import { frame } from '../../frameloop/frame.mjs';
|
|
7
8
|
|
|
8
9
|
const svgMotionConfig = {
|
|
9
10
|
useVisualState: makeUseVisualState({
|
|
10
11
|
scrapeMotionValuesFromProps: scrapeMotionValuesFromProps,
|
|
11
12
|
createRenderState: createSvgRenderState,
|
|
12
13
|
onMount: (props, instance, { renderState, latestValues }) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
14
|
+
frame.read(() => {
|
|
15
|
+
try {
|
|
16
|
+
renderState.dimensions =
|
|
17
|
+
typeof instance.getBBox ===
|
|
18
|
+
"function"
|
|
19
|
+
? instance.getBBox()
|
|
20
|
+
: instance.getBoundingClientRect();
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
// Most likely trying to measure an unrendered element under Firefox
|
|
24
|
+
renderState.dimensions = {
|
|
25
|
+
x: 0,
|
|
26
|
+
y: 0,
|
|
27
|
+
width: 0,
|
|
28
|
+
height: 0,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
frame.render(() => {
|
|
33
|
+
buildSVGAttrs(renderState, latestValues, { enableHardwareAcceleration: false }, isSVGTag(instance.tagName), props.transformTemplate);
|
|
34
|
+
renderSVG(instance, renderState);
|
|
35
|
+
});
|
|
31
36
|
},
|
|
32
37
|
}),
|
|
33
38
|
};
|
|
@@ -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 === "10.16.
|
|
25
|
+
warnOnce(nextValue.version === "10.16.2", `Attempting to mix Framer Motion versions ${nextValue.version} with 10.16.2 may not work as expected.`);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
else if (isMotionValue(prevValue)) {
|
package/dist/es/value/index.mjs
CHANGED
|
@@ -28,7 +28,7 @@ class MotionValue {
|
|
|
28
28
|
* This will be replaced by the build step with the latest version number.
|
|
29
29
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
30
30
|
*/
|
|
31
|
-
this.version = "10.16.
|
|
31
|
+
this.version = "10.16.2";
|
|
32
32
|
/**
|
|
33
33
|
* Duration, in milliseconds, since last updating frame.
|
|
34
34
|
*
|