framer-motion 7.6.4 → 7.6.6
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/index.js +789 -850
- package/dist/es/animation/use-animated-state.mjs +29 -17
- package/dist/es/gestures/drag/VisualElementDragControls.mjs +14 -10
- package/dist/es/gestures/use-focus-gesture.mjs +1 -1
- package/dist/es/gestures/use-tap-gesture.mjs +1 -1
- package/dist/es/index.mjs +1 -1
- package/dist/es/motion/features/viewport/use-viewport.mjs +2 -2
- package/dist/es/motion/utils/use-visual-element.mjs +3 -3
- package/dist/es/projection/node/create-projection-node.mjs +74 -60
- package/dist/es/render/VisualElement.mjs +480 -0
- package/dist/es/render/dom/DOMVisualElement.mjs +49 -0
- package/dist/es/render/dom/create-visual-element.mjs +4 -4
- package/dist/es/render/dom/utils/css-variables-conversion.mjs +2 -2
- package/dist/es/render/dom/utils/unit-conversion.mjs +4 -4
- package/dist/es/render/html/HTMLVisualElement.mjs +41 -0
- package/dist/es/render/svg/{visual-element.mjs → SVGVisualElement.mjs} +21 -15
- package/dist/es/render/utils/animation.mjs +4 -4
- package/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/render/utils/resolve-dynamic-variants.mjs +2 -2
- package/dist/es/render/utils/setters.mjs +2 -1
- package/dist/es/value/index.mjs +1 -1
- package/dist/framer-motion.dev.js +789 -850
- package/dist/framer-motion.js +1 -1
- package/dist/index.d.ts +2101 -1931
- package/dist/projection.dev.js +1053 -1136
- package/dist/size-rollup-dom-animation-m.js +1 -1
- package/dist/size-rollup-dom-animation.js +1 -1
- package/dist/size-rollup-dom-max-assets.js +1 -1
- package/dist/size-rollup-dom-max.js +1 -1
- package/dist/size-rollup-m.js +1 -1
- package/dist/size-rollup-motion.js +1 -1
- package/dist/size-webpack-dom-animation.js +1 -1
- package/dist/size-webpack-dom-max.js +1 -1
- package/dist/size-webpack-m.js +1 -1
- package/dist/three-entry.d.ts +1956 -1745
- package/package.json +8 -8
- package/dist/es/render/html/visual-element.mjs +0 -109
- package/dist/es/render/index.mjs +0 -515
- package/dist/es/render/utils/lifecycles.mjs +0 -43
package/dist/projection.dev.js
CHANGED
|
@@ -1242,7 +1242,7 @@
|
|
|
1242
1242
|
* This will be replaced by the build step with the latest version number.
|
|
1243
1243
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
1244
1244
|
*/
|
|
1245
|
-
this.version = "7.6.
|
|
1245
|
+
this.version = "7.6.6";
|
|
1246
1246
|
/**
|
|
1247
1247
|
* Duration, in milliseconds, since last updating frame.
|
|
1248
1248
|
*
|
|
@@ -2570,7 +2570,7 @@
|
|
|
2570
2570
|
const animationTarget = 1000;
|
|
2571
2571
|
function createProjectionNode({ attachResizeListener, defaultParent, measureScroll, checkIsScrollRoot, resetTransform, }) {
|
|
2572
2572
|
return class ProjectionNode {
|
|
2573
|
-
constructor(
|
|
2573
|
+
constructor(elementId, latestValues = {}, parent = defaultParent === null || defaultParent === void 0 ? void 0 : defaultParent()) {
|
|
2574
2574
|
/**
|
|
2575
2575
|
* A Set containing all this component's children. This is used to iterate
|
|
2576
2576
|
* through the children.
|
|
@@ -2623,7 +2623,7 @@
|
|
|
2623
2623
|
/**
|
|
2624
2624
|
* An object representing the calculated contextual/accumulated/tree scale.
|
|
2625
2625
|
* This will be used to scale calculcated projection transforms, as these are
|
|
2626
|
-
* calculated in screen-space but need to be scaled for elements to
|
|
2626
|
+
* calculated in screen-space but need to be scaled for elements to layoutly
|
|
2627
2627
|
* make it to their calculated destinations.
|
|
2628
2628
|
*
|
|
2629
2629
|
* TODO: Lazy-init
|
|
@@ -2653,13 +2653,13 @@
|
|
|
2653
2653
|
*/
|
|
2654
2654
|
// TODO Only running on root node
|
|
2655
2655
|
this.sharedNodes = new Map();
|
|
2656
|
-
this.
|
|
2656
|
+
this.elementId = elementId;
|
|
2657
2657
|
this.latestValues = latestValues;
|
|
2658
2658
|
this.root = parent ? parent.root || parent : this;
|
|
2659
2659
|
this.path = parent ? [...parent.path, parent] : [];
|
|
2660
2660
|
this.parent = parent;
|
|
2661
2661
|
this.depth = parent ? parent.depth + 1 : 0;
|
|
2662
|
-
|
|
2662
|
+
elementId && this.root.registerPotentialNode(elementId, this);
|
|
2663
2663
|
for (let i = 0; i < this.path.length; i++) {
|
|
2664
2664
|
this.path[i].shouldResetTransform = true;
|
|
2665
2665
|
}
|
|
@@ -2693,12 +2693,12 @@
|
|
|
2693
2693
|
instance instanceof SVGElement && instance.tagName !== "svg";
|
|
2694
2694
|
this.instance = instance;
|
|
2695
2695
|
const { layoutId, layout, visualElement } = this.options;
|
|
2696
|
-
if (visualElement && !visualElement.
|
|
2696
|
+
if (visualElement && !visualElement.current) {
|
|
2697
2697
|
visualElement.mount(instance);
|
|
2698
2698
|
}
|
|
2699
2699
|
this.root.nodes.add(this);
|
|
2700
2700
|
(_a = this.parent) === null || _a === void 0 ? void 0 : _a.children.add(this);
|
|
2701
|
-
this.
|
|
2701
|
+
this.elementId && this.root.potentialNodes.delete(this.elementId);
|
|
2702
2702
|
if (isLayoutDirty && (layout || layoutId)) {
|
|
2703
2703
|
this.isLayoutDirty = true;
|
|
2704
2704
|
}
|
|
@@ -2914,14 +2914,7 @@
|
|
|
2914
2914
|
updateSnapshot() {
|
|
2915
2915
|
if (this.snapshot || !this.instance)
|
|
2916
2916
|
return;
|
|
2917
|
-
|
|
2918
|
-
const layout = this.removeTransform(this.removeElementScroll(measured));
|
|
2919
|
-
roundBox(layout);
|
|
2920
|
-
this.snapshot = {
|
|
2921
|
-
measured,
|
|
2922
|
-
layout,
|
|
2923
|
-
latestValues: {},
|
|
2924
|
-
};
|
|
2917
|
+
this.snapshot = this.measure();
|
|
2925
2918
|
}
|
|
2926
2919
|
updateLayout() {
|
|
2927
2920
|
var _a;
|
|
@@ -2946,18 +2939,13 @@
|
|
|
2946
2939
|
node.updateScroll();
|
|
2947
2940
|
}
|
|
2948
2941
|
}
|
|
2949
|
-
const measured = this.measure();
|
|
2950
|
-
roundBox(measured);
|
|
2951
2942
|
const prevLayout = this.layout;
|
|
2952
|
-
this.layout =
|
|
2953
|
-
measured,
|
|
2954
|
-
actual: this.removeElementScroll(measured),
|
|
2955
|
-
};
|
|
2943
|
+
this.layout = this.measure(false);
|
|
2956
2944
|
this.layoutCorrected = createBox();
|
|
2957
2945
|
this.isLayoutDirty = false;
|
|
2958
2946
|
this.projectionDelta = undefined;
|
|
2959
|
-
this.notifyListeners("measure", this.layout.
|
|
2960
|
-
(_a = this.options.visualElement) === null || _a === void 0 ? void 0 : _a.
|
|
2947
|
+
this.notifyListeners("measure", this.layout.layoutBox);
|
|
2948
|
+
(_a = this.options.visualElement) === null || _a === void 0 ? void 0 : _a.notify("LayoutMeasure", this.layout.layoutBox, prevLayout === null || prevLayout === void 0 ? void 0 : prevLayout.layoutBox);
|
|
2961
2949
|
}
|
|
2962
2950
|
updateScroll() {
|
|
2963
2951
|
if (this.options.layoutScroll && this.instance) {
|
|
@@ -2983,7 +2971,25 @@
|
|
|
2983
2971
|
this.scheduleRender();
|
|
2984
2972
|
}
|
|
2985
2973
|
}
|
|
2986
|
-
measure() {
|
|
2974
|
+
measure(removeTransform = true) {
|
|
2975
|
+
const pageBox = this.measurePageBox();
|
|
2976
|
+
let layoutBox = this.removeElementScroll(pageBox);
|
|
2977
|
+
/**
|
|
2978
|
+
* Measurements taken during the pre-render stage
|
|
2979
|
+
* still have transforms applied so we remove them
|
|
2980
|
+
* via calculation.
|
|
2981
|
+
*/
|
|
2982
|
+
if (removeTransform) {
|
|
2983
|
+
layoutBox = this.removeTransform(layoutBox);
|
|
2984
|
+
}
|
|
2985
|
+
roundBox(layoutBox);
|
|
2986
|
+
return {
|
|
2987
|
+
measuredBox: pageBox,
|
|
2988
|
+
layoutBox,
|
|
2989
|
+
latestValues: {},
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2992
|
+
measurePageBox() {
|
|
2987
2993
|
const { visualElement } = this.options;
|
|
2988
2994
|
if (!visualElement)
|
|
2989
2995
|
return createBox();
|
|
@@ -3064,9 +3070,9 @@
|
|
|
3064
3070
|
continue;
|
|
3065
3071
|
hasScale(node.latestValues) && node.updateSnapshot();
|
|
3066
3072
|
const sourceBox = createBox();
|
|
3067
|
-
const nodeBox = node.
|
|
3073
|
+
const nodeBox = node.measurePageBox();
|
|
3068
3074
|
copyBoxInto(sourceBox, nodeBox);
|
|
3069
|
-
removeBoxTransforms(boxWithoutTransform, node.latestValues, (_a = node.snapshot) === null || _a === void 0 ? void 0 : _a.
|
|
3075
|
+
removeBoxTransforms(boxWithoutTransform, node.latestValues, (_a = node.snapshot) === null || _a === void 0 ? void 0 : _a.layoutBox, sourceBox);
|
|
3070
3076
|
}
|
|
3071
3077
|
if (hasTransform(this.latestValues)) {
|
|
3072
3078
|
removeBoxTransforms(boxWithoutTransform, this.latestValues);
|
|
@@ -3115,13 +3121,17 @@
|
|
|
3115
3121
|
// TODO If this is unsuccessful this currently happens every frame
|
|
3116
3122
|
if (!this.targetDelta && !this.relativeTarget) {
|
|
3117
3123
|
// TODO: This is a semi-repetition of further down this function, make DRY
|
|
3118
|
-
|
|
3119
|
-
if (
|
|
3124
|
+
const relativeParent = this.getClosestProjectingParent();
|
|
3125
|
+
if (relativeParent && relativeParent.layout) {
|
|
3126
|
+
this.relativeParent = relativeParent;
|
|
3120
3127
|
this.relativeTarget = createBox();
|
|
3121
3128
|
this.relativeTargetOrigin = createBox();
|
|
3122
|
-
calcRelativePosition(this.relativeTargetOrigin, this.layout.
|
|
3129
|
+
calcRelativePosition(this.relativeTargetOrigin, this.layout.layoutBox, relativeParent.layout.layoutBox);
|
|
3123
3130
|
copyBoxInto(this.relativeTarget, this.relativeTargetOrigin);
|
|
3124
3131
|
}
|
|
3132
|
+
else {
|
|
3133
|
+
this.relativeParent = this.relativeTarget = undefined;
|
|
3134
|
+
}
|
|
3125
3135
|
}
|
|
3126
3136
|
/**
|
|
3127
3137
|
* If we have no relative target or no target delta our target isn't valid
|
|
@@ -3150,10 +3160,10 @@
|
|
|
3150
3160
|
else if (this.targetDelta) {
|
|
3151
3161
|
if (Boolean(this.resumingFrom)) {
|
|
3152
3162
|
// TODO: This is creating a new object every frame
|
|
3153
|
-
this.target = this.applyTransform(this.layout.
|
|
3163
|
+
this.target = this.applyTransform(this.layout.layoutBox);
|
|
3154
3164
|
}
|
|
3155
3165
|
else {
|
|
3156
|
-
copyBoxInto(this.target, this.layout.
|
|
3166
|
+
copyBoxInto(this.target, this.layout.layoutBox);
|
|
3157
3167
|
}
|
|
3158
3168
|
applyBoxDelta(this.target, this.targetDelta);
|
|
3159
3169
|
}
|
|
@@ -3161,24 +3171,28 @@
|
|
|
3161
3171
|
/**
|
|
3162
3172
|
* If no target, use own layout as target
|
|
3163
3173
|
*/
|
|
3164
|
-
copyBoxInto(this.target, this.layout.
|
|
3174
|
+
copyBoxInto(this.target, this.layout.layoutBox);
|
|
3165
3175
|
}
|
|
3166
3176
|
/**
|
|
3167
3177
|
* If we've been told to attempt to resolve a relative target, do so.
|
|
3168
3178
|
*/
|
|
3169
3179
|
if (this.attemptToResolveRelativeTarget) {
|
|
3170
3180
|
this.attemptToResolveRelativeTarget = false;
|
|
3171
|
-
|
|
3172
|
-
if (
|
|
3173
|
-
Boolean(
|
|
3181
|
+
const relativeParent = this.getClosestProjectingParent();
|
|
3182
|
+
if (relativeParent &&
|
|
3183
|
+
Boolean(relativeParent.resumingFrom) ===
|
|
3174
3184
|
Boolean(this.resumingFrom) &&
|
|
3175
|
-
!
|
|
3176
|
-
|
|
3185
|
+
!relativeParent.options.layoutScroll &&
|
|
3186
|
+
relativeParent.target) {
|
|
3187
|
+
this.relativeParent = relativeParent;
|
|
3177
3188
|
this.relativeTarget = createBox();
|
|
3178
3189
|
this.relativeTargetOrigin = createBox();
|
|
3179
|
-
calcRelativePosition(this.relativeTargetOrigin, this.target,
|
|
3190
|
+
calcRelativePosition(this.relativeTargetOrigin, this.target, relativeParent.target);
|
|
3180
3191
|
copyBoxInto(this.relativeTarget, this.relativeTargetOrigin);
|
|
3181
3192
|
}
|
|
3193
|
+
else {
|
|
3194
|
+
this.relativeParent = this.relativeTarget = undefined;
|
|
3195
|
+
}
|
|
3182
3196
|
}
|
|
3183
3197
|
}
|
|
3184
3198
|
getClosestProjectingParent() {
|
|
@@ -3214,7 +3228,7 @@
|
|
|
3214
3228
|
* Reset the corrected box with the latest values from box, as we're then going
|
|
3215
3229
|
* to perform mutative operations on it.
|
|
3216
3230
|
*/
|
|
3217
|
-
copyBoxInto(this.layoutCorrected, this.layout.
|
|
3231
|
+
copyBoxInto(this.layoutCorrected, this.layout.layoutBox);
|
|
3218
3232
|
/**
|
|
3219
3233
|
* Apply all the parent deltas to this box to produce the corrected box. This
|
|
3220
3234
|
* is the layout box, as it will appear on screen as a result of the transforms of its parents.
|
|
@@ -3291,7 +3305,7 @@
|
|
|
3291
3305
|
this.relativeTargetOrigin &&
|
|
3292
3306
|
this.layout &&
|
|
3293
3307
|
((_a = this.relativeParent) === null || _a === void 0 ? void 0 : _a.layout)) {
|
|
3294
|
-
calcRelativePosition(relativeLayout, this.layout.
|
|
3308
|
+
calcRelativePosition(relativeLayout, this.layout.layoutBox, this.relativeParent.layout.layoutBox);
|
|
3295
3309
|
mixBox(this.relativeTarget, this.relativeTargetOrigin, relativeLayout, progress);
|
|
3296
3310
|
}
|
|
3297
3311
|
if (isSharedLayoutAnimation) {
|
|
@@ -3375,12 +3389,12 @@
|
|
|
3375
3389
|
if (this !== lead &&
|
|
3376
3390
|
this.layout &&
|
|
3377
3391
|
layout &&
|
|
3378
|
-
shouldAnimatePositionOnly(this.options.animationType, this.layout.
|
|
3392
|
+
shouldAnimatePositionOnly(this.options.animationType, this.layout.layoutBox, layout.layoutBox)) {
|
|
3379
3393
|
target = this.target || createBox();
|
|
3380
|
-
const xLength = calcLength(this.layout.
|
|
3394
|
+
const xLength = calcLength(this.layout.layoutBox.x);
|
|
3381
3395
|
target.x.min = lead.target.x.min;
|
|
3382
3396
|
target.x.max = target.x.min + xLength;
|
|
3383
|
-
const yLength = calcLength(this.layout.
|
|
3397
|
+
const yLength = calcLength(this.layout.layoutBox.y);
|
|
3384
3398
|
target.y.min = lead.target.y.min;
|
|
3385
3399
|
target.y.max = target.y.min + yLength;
|
|
3386
3400
|
}
|
|
@@ -3394,7 +3408,7 @@
|
|
|
3394
3408
|
/**
|
|
3395
3409
|
* Update the delta between the corrected box and the final target box, after
|
|
3396
3410
|
* user-set transforms are applied to it. This will be used by the renderer to
|
|
3397
|
-
* create a transform style that will reproject the element from its
|
|
3411
|
+
* create a transform style that will reproject the element from its layout layout
|
|
3398
3412
|
* into the desired bounding box.
|
|
3399
3413
|
*/
|
|
3400
3414
|
calcBoxDelta(this.projectionDeltaWithTransform, this.layoutCorrected, targetWithTransforms, latestValues);
|
|
@@ -3477,7 +3491,7 @@
|
|
|
3477
3491
|
return;
|
|
3478
3492
|
// Force a render of this element to apply the transform with all rotations
|
|
3479
3493
|
// set to 0.
|
|
3480
|
-
visualElement === null || visualElement === void 0 ? void 0 : visualElement.
|
|
3494
|
+
visualElement === null || visualElement === void 0 ? void 0 : visualElement.render();
|
|
3481
3495
|
// Put back all the values we reset
|
|
3482
3496
|
for (const key in resetValues) {
|
|
3483
3497
|
visualElement.setStaticValue(key, resetValues[key]);
|
|
@@ -3550,7 +3564,7 @@
|
|
|
3550
3564
|
}
|
|
3551
3565
|
else {
|
|
3552
3566
|
/**
|
|
3553
|
-
* Or we're not animating at all, set the lead component to its
|
|
3567
|
+
* Or we're not animating at all, set the lead component to its layout
|
|
3554
3568
|
* opacity and other components to hidden.
|
|
3555
3569
|
*/
|
|
3556
3570
|
styles.opacity =
|
|
@@ -3614,53 +3628,53 @@
|
|
|
3614
3628
|
node.layout &&
|
|
3615
3629
|
snapshot &&
|
|
3616
3630
|
node.hasListeners("didUpdate")) {
|
|
3617
|
-
const {
|
|
3631
|
+
const { layoutBox: layout, measuredBox: measuredLayout } = node.layout;
|
|
3618
3632
|
const { animationType } = node.options;
|
|
3619
3633
|
// TODO Maybe we want to also resize the layout snapshot so we don't trigger
|
|
3620
3634
|
// animations for instance if layout="size" and an element has only changed position
|
|
3621
3635
|
if (animationType === "size") {
|
|
3622
3636
|
eachAxis((axis) => {
|
|
3623
3637
|
const axisSnapshot = snapshot.isShared
|
|
3624
|
-
? snapshot.
|
|
3625
|
-
: snapshot.
|
|
3638
|
+
? snapshot.measuredBox[axis]
|
|
3639
|
+
: snapshot.layoutBox[axis];
|
|
3626
3640
|
const length = calcLength(axisSnapshot);
|
|
3627
3641
|
axisSnapshot.min = layout[axis].min;
|
|
3628
3642
|
axisSnapshot.max = axisSnapshot.min + length;
|
|
3629
3643
|
});
|
|
3630
3644
|
}
|
|
3631
|
-
else if (shouldAnimatePositionOnly(animationType, snapshot.
|
|
3645
|
+
else if (shouldAnimatePositionOnly(animationType, snapshot.layoutBox, layout)) {
|
|
3632
3646
|
eachAxis((axis) => {
|
|
3633
3647
|
const axisSnapshot = snapshot.isShared
|
|
3634
|
-
? snapshot.
|
|
3635
|
-
: snapshot.
|
|
3648
|
+
? snapshot.measuredBox[axis]
|
|
3649
|
+
: snapshot.layoutBox[axis];
|
|
3636
3650
|
const length = calcLength(layout[axis]);
|
|
3637
3651
|
axisSnapshot.max = axisSnapshot.min + length;
|
|
3638
3652
|
});
|
|
3639
3653
|
}
|
|
3640
3654
|
const layoutDelta = createDelta();
|
|
3641
|
-
calcBoxDelta(layoutDelta, layout, snapshot.
|
|
3655
|
+
calcBoxDelta(layoutDelta, layout, snapshot.layoutBox);
|
|
3642
3656
|
const visualDelta = createDelta();
|
|
3643
3657
|
if (snapshot.isShared) {
|
|
3644
|
-
calcBoxDelta(visualDelta, node.applyTransform(measuredLayout, true), snapshot.
|
|
3658
|
+
calcBoxDelta(visualDelta, node.applyTransform(measuredLayout, true), snapshot.measuredBox);
|
|
3645
3659
|
}
|
|
3646
3660
|
else {
|
|
3647
|
-
calcBoxDelta(visualDelta, layout, snapshot.
|
|
3661
|
+
calcBoxDelta(visualDelta, layout, snapshot.layoutBox);
|
|
3648
3662
|
}
|
|
3649
3663
|
const hasLayoutChanged = !isDeltaZero(layoutDelta);
|
|
3650
3664
|
let hasRelativeTargetChanged = false;
|
|
3651
3665
|
if (!node.resumeFrom) {
|
|
3652
|
-
|
|
3666
|
+
const relativeParent = node.getClosestProjectingParent();
|
|
3653
3667
|
/**
|
|
3654
3668
|
* If the relativeParent is itself resuming from a different element then
|
|
3655
3669
|
* the relative snapshot is not relavent
|
|
3656
3670
|
*/
|
|
3657
|
-
if (
|
|
3658
|
-
const { snapshot: parentSnapshot, layout: parentLayout } =
|
|
3671
|
+
if (relativeParent && !relativeParent.resumeFrom) {
|
|
3672
|
+
const { snapshot: parentSnapshot, layout: parentLayout } = relativeParent;
|
|
3659
3673
|
if (parentSnapshot && parentLayout) {
|
|
3660
3674
|
const relativeSnapshot = createBox();
|
|
3661
|
-
calcRelativePosition(relativeSnapshot, snapshot.
|
|
3675
|
+
calcRelativePosition(relativeSnapshot, snapshot.layoutBox, parentSnapshot.layoutBox);
|
|
3662
3676
|
const relativeLayout = createBox();
|
|
3663
|
-
calcRelativePosition(relativeLayout, layout, parentLayout.
|
|
3677
|
+
calcRelativePosition(relativeLayout, layout, parentLayout.layoutBox);
|
|
3664
3678
|
if (!boxEquals(relativeSnapshot, relativeLayout)) {
|
|
3665
3679
|
hasRelativeTargetChanged = true;
|
|
3666
3680
|
}
|
|
@@ -3695,7 +3709,7 @@
|
|
|
3695
3709
|
function resetTransformStyle(node) {
|
|
3696
3710
|
const { visualElement } = node.options;
|
|
3697
3711
|
if (visualElement === null || visualElement === void 0 ? void 0 : visualElement.getProps().onBeforeLayoutMeasure) {
|
|
3698
|
-
visualElement.
|
|
3712
|
+
visualElement.notify("BeforeLayoutMeasure");
|
|
3699
3713
|
}
|
|
3700
3714
|
node.resetTransform();
|
|
3701
3715
|
}
|
|
@@ -3976,7 +3990,7 @@
|
|
|
3976
3990
|
* @internal
|
|
3977
3991
|
*/
|
|
3978
3992
|
function resolveCSSVariables(visualElement, { ...target }, transitionEnd) {
|
|
3979
|
-
const element = visualElement.
|
|
3993
|
+
const element = visualElement.current;
|
|
3980
3994
|
if (!(element instanceof Element))
|
|
3981
3995
|
return { target, transitionEnd };
|
|
3982
3996
|
// If `transitionEnd` isn't `undefined`, clone it. We could clone `target` and `transitionEnd`
|
|
@@ -3985,7 +3999,7 @@
|
|
|
3985
3999
|
transitionEnd = { ...transitionEnd };
|
|
3986
4000
|
}
|
|
3987
4001
|
// Go through existing `MotionValue`s and ensure any existing CSS variables are resolved
|
|
3988
|
-
visualElement.
|
|
4002
|
+
visualElement.values.forEach((value) => {
|
|
3989
4003
|
const current = value.get();
|
|
3990
4004
|
if (!isCSSVariable$1(current))
|
|
3991
4005
|
return;
|
|
@@ -4066,33 +4080,148 @@
|
|
|
4066
4080
|
},
|
|
4067
4081
|
};
|
|
4068
4082
|
|
|
4069
|
-
|
|
4083
|
+
/**
|
|
4084
|
+
* Returns true if the provided key is a CSS variable
|
|
4085
|
+
*/
|
|
4086
|
+
function isCSSVariable(key) {
|
|
4087
|
+
return key.startsWith("--");
|
|
4088
|
+
}
|
|
4070
4089
|
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4090
|
+
/**
|
|
4091
|
+
* Provided a value and a ValueType, returns the value as that value type.
|
|
4092
|
+
*/
|
|
4093
|
+
const getValueAsType = (value, type) => {
|
|
4094
|
+
return type && typeof value === "number"
|
|
4095
|
+
? type.transform(value)
|
|
4096
|
+
: value;
|
|
4097
|
+
};
|
|
4074
4098
|
|
|
4075
|
-
function
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4099
|
+
function buildHTMLStyles(state, latestValues, options, transformTemplate) {
|
|
4100
|
+
const { style, vars, transform, transformKeys, transformOrigin } = state;
|
|
4101
|
+
transformKeys.length = 0;
|
|
4102
|
+
// Track whether we encounter any transform or transformOrigin values.
|
|
4103
|
+
let hasTransform = false;
|
|
4104
|
+
let hasTransformOrigin = false;
|
|
4105
|
+
// Does the calculated transform essentially equal "none"?
|
|
4106
|
+
let transformIsNone = true;
|
|
4107
|
+
/**
|
|
4108
|
+
* Loop over all our latest animated values and decide whether to handle them
|
|
4109
|
+
* as a style or CSS variable.
|
|
4110
|
+
*
|
|
4111
|
+
* Transforms and transform origins are kept seperately for further processing.
|
|
4112
|
+
*/
|
|
4113
|
+
for (const key in latestValues) {
|
|
4114
|
+
const value = latestValues[key];
|
|
4115
|
+
/**
|
|
4116
|
+
* If this is a CSS variable we don't do any further processing.
|
|
4117
|
+
*/
|
|
4118
|
+
if (isCSSVariable(key)) {
|
|
4119
|
+
vars[key] = value;
|
|
4120
|
+
continue;
|
|
4121
|
+
}
|
|
4122
|
+
// Convert the value to its default value type, ie 0 -> "0px"
|
|
4123
|
+
const valueType = numberValueTypes[key];
|
|
4124
|
+
const valueAsType = getValueAsType(value, valueType);
|
|
4125
|
+
if (transformProps.has(key)) {
|
|
4126
|
+
// If this is a transform, flag to enable further transform processing
|
|
4127
|
+
hasTransform = true;
|
|
4128
|
+
transform[key] = valueAsType;
|
|
4129
|
+
transformKeys.push(key);
|
|
4130
|
+
// If we already know we have a non-default transform, early return
|
|
4131
|
+
if (!transformIsNone)
|
|
4132
|
+
continue;
|
|
4133
|
+
// Otherwise check to see if this is a default transform
|
|
4134
|
+
if (value !== (valueType.default || 0))
|
|
4135
|
+
transformIsNone = false;
|
|
4136
|
+
}
|
|
4137
|
+
else if (key.startsWith("origin")) {
|
|
4138
|
+
// If this is a transform origin, flag and enable further transform-origin processing
|
|
4139
|
+
hasTransformOrigin = true;
|
|
4140
|
+
transformOrigin[key] = valueAsType;
|
|
4141
|
+
}
|
|
4142
|
+
else {
|
|
4143
|
+
style[key] = valueAsType;
|
|
4144
|
+
}
|
|
4084
4145
|
}
|
|
4085
|
-
|
|
4086
|
-
|
|
4146
|
+
if (!latestValues.transform) {
|
|
4147
|
+
if (hasTransform || transformTemplate) {
|
|
4148
|
+
style.transform = buildTransform(state, options, transformIsNone, transformTemplate);
|
|
4149
|
+
}
|
|
4150
|
+
else if (style.transform) {
|
|
4151
|
+
/**
|
|
4152
|
+
* If we have previously created a transform but currently don't have any,
|
|
4153
|
+
* reset transform style to none.
|
|
4154
|
+
*/
|
|
4155
|
+
style.transform = "none";
|
|
4156
|
+
}
|
|
4157
|
+
}
|
|
4158
|
+
/**
|
|
4159
|
+
* Build a transformOrigin style. Uses the same defaults as the browser for
|
|
4160
|
+
* undefined origins.
|
|
4161
|
+
*/
|
|
4162
|
+
if (hasTransformOrigin) {
|
|
4163
|
+
const { originX = "50%", originY = "50%", originZ = 0, } = transformOrigin;
|
|
4164
|
+
style.transformOrigin = `${originX} ${originY} ${originZ}`;
|
|
4087
4165
|
}
|
|
4088
4166
|
}
|
|
4089
4167
|
|
|
4090
|
-
function
|
|
4091
|
-
return
|
|
4168
|
+
function isForcedMotionValue(key, { layout, layoutId }) {
|
|
4169
|
+
return (transformProps.has(key) ||
|
|
4170
|
+
key.startsWith("origin") ||
|
|
4171
|
+
((layout || layoutId !== undefined) &&
|
|
4172
|
+
(!!scaleCorrectors[key] || key === "opacity")));
|
|
4092
4173
|
}
|
|
4093
4174
|
|
|
4094
|
-
function
|
|
4095
|
-
|
|
4175
|
+
function scrapeMotionValuesFromProps(props) {
|
|
4176
|
+
const { style } = props;
|
|
4177
|
+
const newValues = {};
|
|
4178
|
+
for (const key in style) {
|
|
4179
|
+
if (isMotionValue(style[key]) || isForcedMotionValue(key, props)) {
|
|
4180
|
+
newValues[key] = style[key];
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
return newValues;
|
|
4184
|
+
}
|
|
4185
|
+
|
|
4186
|
+
function renderHTML(element, { style, vars }, styleProp, projection) {
|
|
4187
|
+
Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));
|
|
4188
|
+
// Loop over any CSS variables and assign those.
|
|
4189
|
+
for (const key in vars) {
|
|
4190
|
+
element.style.setProperty(key, vars[key]);
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
|
|
4194
|
+
/**
|
|
4195
|
+
* Bounding boxes tend to be defined as top, left, right, bottom. For various operations
|
|
4196
|
+
* it's easier to consider each axis individually. This function returns a bounding box
|
|
4197
|
+
* as a map of single-axis min/max values.
|
|
4198
|
+
*/
|
|
4199
|
+
function convertBoundingBoxToBox({ top, left, right, bottom, }) {
|
|
4200
|
+
return {
|
|
4201
|
+
x: { min: left, max: right },
|
|
4202
|
+
y: { min: top, max: bottom },
|
|
4203
|
+
};
|
|
4204
|
+
}
|
|
4205
|
+
/**
|
|
4206
|
+
* Applies a TransformPoint function to a bounding box. TransformPoint is usually a function
|
|
4207
|
+
* provided by Framer to allow measured points to be corrected for device scaling. This is used
|
|
4208
|
+
* when measuring DOM elements and DOM event points.
|
|
4209
|
+
*/
|
|
4210
|
+
function transformBoxPoints(point, transformPoint) {
|
|
4211
|
+
if (!transformPoint)
|
|
4212
|
+
return point;
|
|
4213
|
+
const topLeft = transformPoint({ x: point.left, y: point.top });
|
|
4214
|
+
const bottomRight = transformPoint({ x: point.right, y: point.bottom });
|
|
4215
|
+
return {
|
|
4216
|
+
top: topLeft.y,
|
|
4217
|
+
left: topLeft.x,
|
|
4218
|
+
bottom: bottomRight.y,
|
|
4219
|
+
right: bottomRight.x,
|
|
4220
|
+
};
|
|
4221
|
+
}
|
|
4222
|
+
|
|
4223
|
+
function measureViewportBox(instance, transformPoint) {
|
|
4224
|
+
return convertBoundingBoxToBox(transformBoxPoints(instance.getBoundingClientRect(), transformPoint));
|
|
4096
4225
|
}
|
|
4097
4226
|
|
|
4098
4227
|
/**
|
|
@@ -4204,7 +4333,8 @@
|
|
|
4204
4333
|
if (origin[key] === undefined) {
|
|
4205
4334
|
origin[key] = value;
|
|
4206
4335
|
}
|
|
4207
|
-
|
|
4336
|
+
if (value !== null)
|
|
4337
|
+
visualElement.setBaseTarget(key, value);
|
|
4208
4338
|
}
|
|
4209
4339
|
}
|
|
4210
4340
|
function getOriginFromTransition(key, transition) {
|
|
@@ -4226,141 +4356,345 @@
|
|
|
4226
4356
|
return origin;
|
|
4227
4357
|
}
|
|
4228
4358
|
|
|
4229
|
-
|
|
4230
|
-
* Decides if the supplied variable is variant label
|
|
4231
|
-
*/
|
|
4232
|
-
function isVariantLabel(v) {
|
|
4233
|
-
return typeof v === "string" || Array.isArray(v);
|
|
4234
|
-
}
|
|
4235
|
-
|
|
4236
|
-
var AnimationType;
|
|
4237
|
-
(function (AnimationType) {
|
|
4238
|
-
AnimationType["Animate"] = "animate";
|
|
4239
|
-
AnimationType["Hover"] = "whileHover";
|
|
4240
|
-
AnimationType["Tap"] = "whileTap";
|
|
4241
|
-
AnimationType["Drag"] = "whileDrag";
|
|
4242
|
-
AnimationType["Focus"] = "whileFocus";
|
|
4243
|
-
AnimationType["InView"] = "whileInView";
|
|
4244
|
-
AnimationType["Exit"] = "exit";
|
|
4245
|
-
})(AnimationType || (AnimationType = {}));
|
|
4246
|
-
|
|
4247
|
-
const variantPriorityOrder = [
|
|
4248
|
-
AnimationType.Animate,
|
|
4249
|
-
AnimationType.InView,
|
|
4250
|
-
AnimationType.Focus,
|
|
4251
|
-
AnimationType.Hover,
|
|
4252
|
-
AnimationType.Tap,
|
|
4253
|
-
AnimationType.Drag,
|
|
4254
|
-
AnimationType.Exit,
|
|
4255
|
-
];
|
|
4256
|
-
|
|
4257
|
-
const names = [
|
|
4258
|
-
"LayoutMeasure",
|
|
4259
|
-
"BeforeLayoutMeasure",
|
|
4260
|
-
"LayoutUpdate",
|
|
4261
|
-
"ViewportBoxUpdate",
|
|
4262
|
-
"Update",
|
|
4263
|
-
"Render",
|
|
4264
|
-
"AnimationComplete",
|
|
4265
|
-
"LayoutAnimationComplete",
|
|
4266
|
-
"AnimationStart",
|
|
4267
|
-
"LayoutAnimationStart",
|
|
4268
|
-
"SetAxisTarget",
|
|
4269
|
-
"Unmount",
|
|
4270
|
-
];
|
|
4271
|
-
function createLifecycles() {
|
|
4272
|
-
const managers = names.map(() => new SubscriptionManager());
|
|
4273
|
-
const propSubscriptions = {};
|
|
4274
|
-
const lifecycles = {
|
|
4275
|
-
clearAllListeners: () => managers.forEach((manager) => manager.clear()),
|
|
4276
|
-
updatePropListeners: (props) => {
|
|
4277
|
-
names.forEach((name) => {
|
|
4278
|
-
var _a;
|
|
4279
|
-
const on = "on" + name;
|
|
4280
|
-
const propListener = props[on];
|
|
4281
|
-
// Unsubscribe existing subscription
|
|
4282
|
-
(_a = propSubscriptions[name]) === null || _a === void 0 ? void 0 : _a.call(propSubscriptions);
|
|
4283
|
-
// Add new subscription
|
|
4284
|
-
if (propListener) {
|
|
4285
|
-
propSubscriptions[name] = lifecycles[on](propListener);
|
|
4286
|
-
}
|
|
4287
|
-
});
|
|
4288
|
-
},
|
|
4289
|
-
};
|
|
4290
|
-
managers.forEach((manager, i) => {
|
|
4291
|
-
lifecycles["on" + names[i]] = (handler) => manager.add(handler);
|
|
4292
|
-
lifecycles["notify" + names[i]] = (...args) => manager.notify(...args);
|
|
4293
|
-
});
|
|
4294
|
-
return lifecycles;
|
|
4295
|
-
}
|
|
4296
|
-
|
|
4297
|
-
const warned = new Set();
|
|
4298
|
-
function warnOnce(condition, message, element) {
|
|
4299
|
-
if (condition || warned.has(message))
|
|
4300
|
-
return;
|
|
4301
|
-
console.warn(message);
|
|
4302
|
-
if (element)
|
|
4303
|
-
console.warn(element);
|
|
4304
|
-
warned.add(message);
|
|
4305
|
-
}
|
|
4359
|
+
const isBrowser = typeof document !== "undefined";
|
|
4306
4360
|
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4361
|
+
const positionalKeys = new Set([
|
|
4362
|
+
"width",
|
|
4363
|
+
"height",
|
|
4364
|
+
"top",
|
|
4365
|
+
"left",
|
|
4366
|
+
"right",
|
|
4367
|
+
"bottom",
|
|
4368
|
+
"x",
|
|
4369
|
+
"y",
|
|
4370
|
+
]);
|
|
4371
|
+
const isPositionalKey = (key) => positionalKeys.has(key);
|
|
4372
|
+
const hasPositionalKey = (target) => {
|
|
4373
|
+
return Object.keys(target).some(isPositionalKey);
|
|
4374
|
+
};
|
|
4375
|
+
const setAndResetVelocity = (value, to) => {
|
|
4376
|
+
// Looks odd but setting it twice doesn't render, it'll just
|
|
4377
|
+
// set both prev and current to the latest value
|
|
4378
|
+
value.set(to, false);
|
|
4379
|
+
value.set(to);
|
|
4380
|
+
};
|
|
4381
|
+
const isNumOrPxType = (v) => v === number || v === px;
|
|
4382
|
+
var BoundingBoxDimension;
|
|
4383
|
+
(function (BoundingBoxDimension) {
|
|
4384
|
+
BoundingBoxDimension["width"] = "width";
|
|
4385
|
+
BoundingBoxDimension["height"] = "height";
|
|
4386
|
+
BoundingBoxDimension["left"] = "left";
|
|
4387
|
+
BoundingBoxDimension["right"] = "right";
|
|
4388
|
+
BoundingBoxDimension["top"] = "top";
|
|
4389
|
+
BoundingBoxDimension["bottom"] = "bottom";
|
|
4390
|
+
})(BoundingBoxDimension || (BoundingBoxDimension = {}));
|
|
4391
|
+
const getPosFromMatrix = (matrix, pos) => parseFloat(matrix.split(", ")[pos]);
|
|
4392
|
+
const getTranslateFromMatrix = (pos2, pos3) => (_bbox, { transform }) => {
|
|
4393
|
+
if (transform === "none" || !transform)
|
|
4394
|
+
return 0;
|
|
4395
|
+
const matrix3d = transform.match(/^matrix3d\((.+)\)$/);
|
|
4396
|
+
if (matrix3d) {
|
|
4397
|
+
return getPosFromMatrix(matrix3d[1], pos3);
|
|
4398
|
+
}
|
|
4399
|
+
else {
|
|
4400
|
+
const matrix = transform.match(/^matrix\((.+)\)$/);
|
|
4401
|
+
if (matrix) {
|
|
4402
|
+
return getPosFromMatrix(matrix[1], pos2);
|
|
4403
|
+
}
|
|
4404
|
+
else {
|
|
4405
|
+
return 0;
|
|
4406
|
+
}
|
|
4407
|
+
}
|
|
4408
|
+
};
|
|
4409
|
+
const transformKeys = new Set(["x", "y", "z"]);
|
|
4410
|
+
const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
|
|
4411
|
+
function removeNonTranslationalTransform(visualElement) {
|
|
4412
|
+
const removedTransforms = [];
|
|
4413
|
+
nonTranslationalTransformKeys.forEach((key) => {
|
|
4414
|
+
const value = visualElement.getValue(key);
|
|
4415
|
+
if (value !== undefined) {
|
|
4416
|
+
removedTransforms.push([key, value.get()]);
|
|
4417
|
+
value.set(key.startsWith("scale") ? 1 : 0);
|
|
4418
|
+
}
|
|
4419
|
+
});
|
|
4420
|
+
// Apply changes to element before measurement
|
|
4421
|
+
if (removedTransforms.length)
|
|
4422
|
+
visualElement.render();
|
|
4423
|
+
return removedTransforms;
|
|
4424
|
+
}
|
|
4425
|
+
const positionalValues = {
|
|
4426
|
+
// Dimensions
|
|
4427
|
+
width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
|
|
4428
|
+
height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
|
|
4429
|
+
top: (_bbox, { top }) => parseFloat(top),
|
|
4430
|
+
left: (_bbox, { left }) => parseFloat(left),
|
|
4431
|
+
bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
|
|
4432
|
+
right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
|
|
4433
|
+
// Transform
|
|
4434
|
+
x: getTranslateFromMatrix(4, 13),
|
|
4435
|
+
y: getTranslateFromMatrix(5, 14),
|
|
4436
|
+
};
|
|
4437
|
+
const convertChangedValueTypes = (target, visualElement, changedKeys) => {
|
|
4438
|
+
const originBbox = visualElement.measureViewportBox();
|
|
4439
|
+
const element = visualElement.current;
|
|
4440
|
+
const elementComputedStyle = getComputedStyle(element);
|
|
4441
|
+
const { display } = elementComputedStyle;
|
|
4442
|
+
const origin = {};
|
|
4443
|
+
// If the element is currently set to display: "none", make it visible before
|
|
4444
|
+
// measuring the target bounding box
|
|
4445
|
+
if (display === "none") {
|
|
4446
|
+
visualElement.setStaticValue("display", target.display || "block");
|
|
4447
|
+
}
|
|
4448
|
+
/**
|
|
4449
|
+
* Record origins before we render and update styles
|
|
4450
|
+
*/
|
|
4451
|
+
changedKeys.forEach((key) => {
|
|
4452
|
+
origin[key] = positionalValues[key](originBbox, elementComputedStyle);
|
|
4453
|
+
});
|
|
4454
|
+
// Apply the latest values (as set in checkAndConvertChangedValueTypes)
|
|
4455
|
+
visualElement.render();
|
|
4456
|
+
const targetBbox = visualElement.measureViewportBox();
|
|
4457
|
+
changedKeys.forEach((key) => {
|
|
4458
|
+
// Restore styles to their **calculated computed style**, not their actual
|
|
4459
|
+
// originally set style. This allows us to animate between equivalent pixel units.
|
|
4460
|
+
const value = visualElement.getValue(key);
|
|
4461
|
+
setAndResetVelocity(value, origin[key]);
|
|
4462
|
+
target[key] = positionalValues[key](targetBbox, elementComputedStyle);
|
|
4463
|
+
});
|
|
4464
|
+
return target;
|
|
4465
|
+
};
|
|
4466
|
+
const checkAndConvertChangedValueTypes = (visualElement, target, origin = {}, transitionEnd = {}) => {
|
|
4467
|
+
target = { ...target };
|
|
4468
|
+
transitionEnd = { ...transitionEnd };
|
|
4469
|
+
const targetPositionalKeys = Object.keys(target).filter(isPositionalKey);
|
|
4470
|
+
// We want to remove any transform values that could affect the element's bounding box before
|
|
4471
|
+
// it's measured. We'll reapply these later.
|
|
4472
|
+
let removedTransformValues = [];
|
|
4473
|
+
let hasAttemptedToRemoveTransformValues = false;
|
|
4474
|
+
const changedValueTypeKeys = [];
|
|
4475
|
+
targetPositionalKeys.forEach((key) => {
|
|
4476
|
+
const value = visualElement.getValue(key);
|
|
4477
|
+
if (!visualElement.hasValue(key))
|
|
4478
|
+
return;
|
|
4479
|
+
let from = origin[key];
|
|
4480
|
+
let fromType = findDimensionValueType(from);
|
|
4481
|
+
const to = target[key];
|
|
4482
|
+
let toType;
|
|
4483
|
+
// TODO: The current implementation of this basically throws an error
|
|
4484
|
+
// if you try and do value conversion via keyframes. There's probably
|
|
4485
|
+
// a way of doing this but the performance implications would need greater scrutiny,
|
|
4486
|
+
// as it'd be doing multiple resize-remeasure operations.
|
|
4487
|
+
if (isKeyframesTarget(to)) {
|
|
4488
|
+
const numKeyframes = to.length;
|
|
4489
|
+
const fromIndex = to[0] === null ? 1 : 0;
|
|
4490
|
+
from = to[fromIndex];
|
|
4491
|
+
fromType = findDimensionValueType(from);
|
|
4492
|
+
for (let i = fromIndex; i < numKeyframes; i++) {
|
|
4493
|
+
if (!toType) {
|
|
4494
|
+
toType = findDimensionValueType(to[i]);
|
|
4495
|
+
invariant(toType === fromType ||
|
|
4496
|
+
(isNumOrPxType(fromType) && isNumOrPxType(toType)), "Keyframes must be of the same dimension as the current value");
|
|
4497
|
+
}
|
|
4498
|
+
else {
|
|
4499
|
+
invariant(findDimensionValueType(to[i]) === toType, "All keyframes must be of the same type");
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
else {
|
|
4504
|
+
toType = findDimensionValueType(to);
|
|
4505
|
+
}
|
|
4506
|
+
if (fromType !== toType) {
|
|
4507
|
+
// If they're both just number or px, convert them both to numbers rather than
|
|
4508
|
+
// relying on resize/remeasure to convert (which is wasteful in this situation)
|
|
4509
|
+
if (isNumOrPxType(fromType) && isNumOrPxType(toType)) {
|
|
4510
|
+
const current = value.get();
|
|
4511
|
+
if (typeof current === "string") {
|
|
4512
|
+
value.set(parseFloat(current));
|
|
4513
|
+
}
|
|
4514
|
+
if (typeof to === "string") {
|
|
4515
|
+
target[key] = parseFloat(to);
|
|
4516
|
+
}
|
|
4517
|
+
else if (Array.isArray(to) && toType === px) {
|
|
4518
|
+
target[key] = to.map(parseFloat);
|
|
4519
|
+
}
|
|
4520
|
+
}
|
|
4521
|
+
else if ((fromType === null || fromType === void 0 ? void 0 : fromType.transform) &&
|
|
4522
|
+
(toType === null || toType === void 0 ? void 0 : toType.transform) &&
|
|
4523
|
+
(from === 0 || to === 0)) {
|
|
4524
|
+
// If one or the other value is 0, it's safe to coerce it to the
|
|
4525
|
+
// type of the other without measurement
|
|
4526
|
+
if (from === 0) {
|
|
4527
|
+
value.set(toType.transform(from));
|
|
4528
|
+
}
|
|
4529
|
+
else {
|
|
4530
|
+
target[key] = fromType.transform(to);
|
|
4531
|
+
}
|
|
4349
4532
|
}
|
|
4350
4533
|
else {
|
|
4351
|
-
|
|
4352
|
-
|
|
4534
|
+
// If we're going to do value conversion via DOM measurements, we first
|
|
4535
|
+
// need to remove non-positional transform values that could affect the bbox measurements.
|
|
4536
|
+
if (!hasAttemptedToRemoveTransformValues) {
|
|
4537
|
+
removedTransformValues =
|
|
4538
|
+
removeNonTranslationalTransform(visualElement);
|
|
4539
|
+
hasAttemptedToRemoveTransformValues = true;
|
|
4540
|
+
}
|
|
4541
|
+
changedValueTypeKeys.push(key);
|
|
4542
|
+
transitionEnd[key] =
|
|
4543
|
+
transitionEnd[key] !== undefined
|
|
4544
|
+
? transitionEnd[key]
|
|
4545
|
+
: target[key];
|
|
4546
|
+
setAndResetVelocity(value, to);
|
|
4353
4547
|
}
|
|
4354
4548
|
}
|
|
4549
|
+
});
|
|
4550
|
+
if (changedValueTypeKeys.length) {
|
|
4551
|
+
const scrollY = changedValueTypeKeys.indexOf("height") >= 0
|
|
4552
|
+
? window.pageYOffset
|
|
4553
|
+
: null;
|
|
4554
|
+
const convertedTarget = convertChangedValueTypes(target, visualElement, changedValueTypeKeys);
|
|
4555
|
+
// If we removed transform values, reapply them before the next render
|
|
4556
|
+
if (removedTransformValues.length) {
|
|
4557
|
+
removedTransformValues.forEach(([key, value]) => {
|
|
4558
|
+
visualElement.getValue(key).set(value);
|
|
4559
|
+
});
|
|
4560
|
+
}
|
|
4561
|
+
// Reapply original values
|
|
4562
|
+
visualElement.render();
|
|
4563
|
+
// Restore scroll position
|
|
4564
|
+
if (isBrowser && scrollY !== null) {
|
|
4565
|
+
window.scrollTo({ top: scrollY });
|
|
4566
|
+
}
|
|
4567
|
+
return { target: convertedTarget, transitionEnd };
|
|
4355
4568
|
}
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
if (next[key] === undefined)
|
|
4359
|
-
element.removeValue(key);
|
|
4569
|
+
else {
|
|
4570
|
+
return { target, transitionEnd };
|
|
4360
4571
|
}
|
|
4361
|
-
|
|
4572
|
+
};
|
|
4573
|
+
/**
|
|
4574
|
+
* Convert value types for x/y/width/height/top/left/bottom/right
|
|
4575
|
+
*
|
|
4576
|
+
* Allows animation between `'auto'` -> `'100%'` or `0` -> `'calc(50% - 10vw)'`
|
|
4577
|
+
*
|
|
4578
|
+
* @internal
|
|
4579
|
+
*/
|
|
4580
|
+
function unitConversion(visualElement, target, origin, transitionEnd) {
|
|
4581
|
+
return hasPositionalKey(target)
|
|
4582
|
+
? checkAndConvertChangedValueTypes(visualElement, target, origin, transitionEnd)
|
|
4583
|
+
: { target, transitionEnd };
|
|
4584
|
+
}
|
|
4585
|
+
|
|
4586
|
+
/**
|
|
4587
|
+
* Parse a DOM variant to make it animatable. This involves resolving CSS variables
|
|
4588
|
+
* and ensuring animations like "20%" => "calc(50vw)" are performed in pixels.
|
|
4589
|
+
*/
|
|
4590
|
+
const parseDomVariant = (visualElement, target, origin, transitionEnd) => {
|
|
4591
|
+
const resolved = resolveCSSVariables(visualElement, target, transitionEnd);
|
|
4592
|
+
target = resolved.target;
|
|
4593
|
+
transitionEnd = resolved.transitionEnd;
|
|
4594
|
+
return unitConversion(visualElement, target, origin, transitionEnd);
|
|
4595
|
+
};
|
|
4596
|
+
|
|
4597
|
+
const createDefinition = (propNames) => ({
|
|
4598
|
+
isEnabled: (props) => propNames.some((name) => !!props[name]),
|
|
4599
|
+
});
|
|
4600
|
+
const featureDefinitions = {
|
|
4601
|
+
measureLayout: createDefinition(["layout", "layoutId", "drag"]),
|
|
4602
|
+
animation: createDefinition([
|
|
4603
|
+
"animate",
|
|
4604
|
+
"exit",
|
|
4605
|
+
"variants",
|
|
4606
|
+
"whileHover",
|
|
4607
|
+
"whileTap",
|
|
4608
|
+
"whileFocus",
|
|
4609
|
+
"whileDrag",
|
|
4610
|
+
"whileInView",
|
|
4611
|
+
]),
|
|
4612
|
+
exit: createDefinition(["exit"]),
|
|
4613
|
+
drag: createDefinition(["drag", "dragControls"]),
|
|
4614
|
+
focus: createDefinition(["whileFocus"]),
|
|
4615
|
+
hover: createDefinition(["whileHover", "onHoverStart", "onHoverEnd"]),
|
|
4616
|
+
tap: createDefinition(["whileTap", "onTap", "onTapStart", "onTapCancel"]),
|
|
4617
|
+
pan: createDefinition([
|
|
4618
|
+
"onPan",
|
|
4619
|
+
"onPanStart",
|
|
4620
|
+
"onPanSessionStart",
|
|
4621
|
+
"onPanEnd",
|
|
4622
|
+
]),
|
|
4623
|
+
inView: createDefinition([
|
|
4624
|
+
"whileInView",
|
|
4625
|
+
"onViewportEnter",
|
|
4626
|
+
"onViewportLeave",
|
|
4627
|
+
]),
|
|
4628
|
+
};
|
|
4629
|
+
|
|
4630
|
+
function isRefObject(ref) {
|
|
4631
|
+
return (typeof ref === "object" &&
|
|
4632
|
+
Object.prototype.hasOwnProperty.call(ref, "current"));
|
|
4633
|
+
}
|
|
4634
|
+
|
|
4635
|
+
/**
|
|
4636
|
+
* Browser-safe usage of process
|
|
4637
|
+
*/
|
|
4638
|
+
const defaultEnvironment = "production";
|
|
4639
|
+
const env = typeof process === "undefined" || process.env === undefined
|
|
4640
|
+
? defaultEnvironment
|
|
4641
|
+
: "development" ;
|
|
4642
|
+
|
|
4643
|
+
// Does this device prefer reduced motion? Returns `null` server-side.
|
|
4644
|
+
const prefersReducedMotion = { current: null };
|
|
4645
|
+
const hasReducedMotionListener = { current: false };
|
|
4646
|
+
|
|
4647
|
+
function initPrefersReducedMotion() {
|
|
4648
|
+
hasReducedMotionListener.current = true;
|
|
4649
|
+
if (!isBrowser)
|
|
4650
|
+
return;
|
|
4651
|
+
if (window.matchMedia) {
|
|
4652
|
+
const motionMediaQuery = window.matchMedia("(prefers-reduced-motion)");
|
|
4653
|
+
const setReducedMotionPreferences = () => (prefersReducedMotion.current = motionMediaQuery.matches);
|
|
4654
|
+
motionMediaQuery.addListener(setReducedMotionPreferences);
|
|
4655
|
+
setReducedMotionPreferences();
|
|
4656
|
+
}
|
|
4657
|
+
else {
|
|
4658
|
+
prefersReducedMotion.current = false;
|
|
4659
|
+
}
|
|
4660
|
+
}
|
|
4661
|
+
|
|
4662
|
+
function isWillChangeMotionValue(value) {
|
|
4663
|
+
return Boolean(isMotionValue(value) && value.add);
|
|
4362
4664
|
}
|
|
4363
4665
|
|
|
4666
|
+
function isAnimationControls(v) {
|
|
4667
|
+
return typeof v === "object" && typeof v.start === "function";
|
|
4668
|
+
}
|
|
4669
|
+
|
|
4670
|
+
/**
|
|
4671
|
+
* Decides if the supplied variable is variant label
|
|
4672
|
+
*/
|
|
4673
|
+
function isVariantLabel(v) {
|
|
4674
|
+
return typeof v === "string" || Array.isArray(v);
|
|
4675
|
+
}
|
|
4676
|
+
|
|
4677
|
+
var AnimationType;
|
|
4678
|
+
(function (AnimationType) {
|
|
4679
|
+
AnimationType["Animate"] = "animate";
|
|
4680
|
+
AnimationType["Hover"] = "whileHover";
|
|
4681
|
+
AnimationType["Tap"] = "whileTap";
|
|
4682
|
+
AnimationType["Drag"] = "whileDrag";
|
|
4683
|
+
AnimationType["Focus"] = "whileFocus";
|
|
4684
|
+
AnimationType["InView"] = "whileInView";
|
|
4685
|
+
AnimationType["Exit"] = "exit";
|
|
4686
|
+
})(AnimationType || (AnimationType = {}));
|
|
4687
|
+
|
|
4688
|
+
const variantPriorityOrder = [
|
|
4689
|
+
AnimationType.Animate,
|
|
4690
|
+
AnimationType.InView,
|
|
4691
|
+
AnimationType.Focus,
|
|
4692
|
+
AnimationType.Hover,
|
|
4693
|
+
AnimationType.Tap,
|
|
4694
|
+
AnimationType.Drag,
|
|
4695
|
+
AnimationType.Exit,
|
|
4696
|
+
];
|
|
4697
|
+
|
|
4364
4698
|
const variantProps$1 = [
|
|
4365
4699
|
"initial",
|
|
4366
4700
|
"animate",
|
|
@@ -4379,989 +4713,552 @@
|
|
|
4379
4713
|
return Boolean(isControllingVariants(props) || props.variants);
|
|
4380
4714
|
}
|
|
4381
4715
|
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
const createDefinition = (propNames) => ({
|
|
4391
|
-
isEnabled: (props) => propNames.some((name) => !!props[name]),
|
|
4392
|
-
});
|
|
4393
|
-
const featureDefinitions = {
|
|
4394
|
-
measureLayout: createDefinition(["layout", "layoutId", "drag"]),
|
|
4395
|
-
animation: createDefinition([
|
|
4396
|
-
"animate",
|
|
4397
|
-
"exit",
|
|
4398
|
-
"variants",
|
|
4399
|
-
"whileHover",
|
|
4400
|
-
"whileTap",
|
|
4401
|
-
"whileFocus",
|
|
4402
|
-
"whileDrag",
|
|
4403
|
-
"whileInView",
|
|
4404
|
-
]),
|
|
4405
|
-
exit: createDefinition(["exit"]),
|
|
4406
|
-
drag: createDefinition(["drag", "dragControls"]),
|
|
4407
|
-
focus: createDefinition(["whileFocus"]),
|
|
4408
|
-
hover: createDefinition(["whileHover", "onHoverStart", "onHoverEnd"]),
|
|
4409
|
-
tap: createDefinition(["whileTap", "onTap", "onTapStart", "onTapCancel"]),
|
|
4410
|
-
pan: createDefinition([
|
|
4411
|
-
"onPan",
|
|
4412
|
-
"onPanStart",
|
|
4413
|
-
"onPanSessionStart",
|
|
4414
|
-
"onPanEnd",
|
|
4415
|
-
]),
|
|
4416
|
-
inView: createDefinition([
|
|
4417
|
-
"whileInView",
|
|
4418
|
-
"onViewportEnter",
|
|
4419
|
-
"onViewportLeave",
|
|
4420
|
-
]),
|
|
4421
|
-
};
|
|
4422
|
-
|
|
4423
|
-
function isRefObject(ref) {
|
|
4424
|
-
return (typeof ref === "object" &&
|
|
4425
|
-
Object.prototype.hasOwnProperty.call(ref, "current"));
|
|
4716
|
+
const warned = new Set();
|
|
4717
|
+
function warnOnce(condition, message, element) {
|
|
4718
|
+
if (condition || warned.has(message))
|
|
4719
|
+
return;
|
|
4720
|
+
console.warn(message);
|
|
4721
|
+
if (element)
|
|
4722
|
+
console.warn(element);
|
|
4723
|
+
warned.add(message);
|
|
4426
4724
|
}
|
|
4427
4725
|
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
let instance;
|
|
4440
|
-
/**
|
|
4441
|
-
* Manages the subscriptions for a visual element's lifecycle, for instance
|
|
4442
|
-
* onRender
|
|
4443
|
-
*/
|
|
4444
|
-
const lifecycles = createLifecycles();
|
|
4445
|
-
/**
|
|
4446
|
-
* A map of all motion values attached to this visual element. Motion
|
|
4447
|
-
* values are source of truth for any given animated value. A motion
|
|
4448
|
-
* value might be provided externally by the component via props.
|
|
4449
|
-
*/
|
|
4450
|
-
const values = new Map();
|
|
4451
|
-
/**
|
|
4452
|
-
* A map of every subscription that binds the provided or generated
|
|
4453
|
-
* motion values onChange listeners to this visual element.
|
|
4454
|
-
*/
|
|
4455
|
-
const valueSubscriptions = new Map();
|
|
4456
|
-
/**
|
|
4457
|
-
* A reference to the previously-provided motion values as returned
|
|
4458
|
-
* from scrapeMotionValuesFromProps. We use the keys in here to determine
|
|
4459
|
-
* if any motion values need to be removed after props are updated.
|
|
4460
|
-
*/
|
|
4461
|
-
let prevMotionValues = {};
|
|
4462
|
-
/**
|
|
4463
|
-
* When values are removed from all animation props we need to search
|
|
4464
|
-
* for a fallback value to animate to. These values are tracked in baseTarget.
|
|
4465
|
-
*/
|
|
4466
|
-
const baseTarget = {
|
|
4467
|
-
...latestValues,
|
|
4468
|
-
};
|
|
4469
|
-
/**
|
|
4470
|
-
* Create an object of the values we initially animated from (if initial prop present).
|
|
4471
|
-
*/
|
|
4472
|
-
const initialValues = props.initial ? { ...latestValues } : {};
|
|
4473
|
-
// Internal methods ========================
|
|
4474
|
-
/**
|
|
4475
|
-
* On mount, this will be hydrated with a callback to disconnect
|
|
4476
|
-
* this visual element from its parent on unmount.
|
|
4477
|
-
*/
|
|
4478
|
-
let removeFromVariantTree;
|
|
4479
|
-
/**
|
|
4480
|
-
* Render the element with the latest styles outside of the React
|
|
4481
|
-
* render lifecycle
|
|
4482
|
-
*/
|
|
4483
|
-
function render() {
|
|
4484
|
-
if (!instance || !isMounted)
|
|
4485
|
-
return;
|
|
4486
|
-
triggerBuild();
|
|
4487
|
-
renderInstance(instance, renderState, props.style, element.projection);
|
|
4488
|
-
}
|
|
4489
|
-
function triggerBuild() {
|
|
4490
|
-
build(element, renderState, latestValues, options, props);
|
|
4491
|
-
}
|
|
4492
|
-
function update() {
|
|
4493
|
-
lifecycles.notifyUpdate(latestValues);
|
|
4494
|
-
}
|
|
4495
|
-
/**
|
|
4496
|
-
*
|
|
4497
|
-
*/
|
|
4498
|
-
function bindToMotionValue(key, value) {
|
|
4499
|
-
const removeOnChange = value.onChange((latestValue) => {
|
|
4500
|
-
latestValues[key] = latestValue;
|
|
4501
|
-
props.onUpdate && sync.update(update, false, true);
|
|
4502
|
-
});
|
|
4503
|
-
const removeOnRenderRequest = value.onRenderRequest(element.scheduleRender);
|
|
4504
|
-
valueSubscriptions.set(key, () => {
|
|
4505
|
-
removeOnChange();
|
|
4506
|
-
removeOnRenderRequest();
|
|
4507
|
-
});
|
|
4508
|
-
}
|
|
4509
|
-
/**
|
|
4510
|
-
* Any motion values that are provided to the element when created
|
|
4511
|
-
* aren't yet bound to the element, as this would technically be impure.
|
|
4512
|
-
* However, we iterate through the motion values and set them to the
|
|
4513
|
-
* initial values for this component.
|
|
4514
|
-
*
|
|
4515
|
-
* TODO: This is impure and we should look at changing this to run on mount.
|
|
4516
|
-
* Doing so will break some tests but this isn't neccessarily a breaking change,
|
|
4517
|
-
* more a reflection of the test.
|
|
4518
|
-
*/
|
|
4519
|
-
const { willChange, ...initialMotionValues } = scrapeMotionValuesFromProps(props);
|
|
4520
|
-
for (const key in initialMotionValues) {
|
|
4521
|
-
const value = initialMotionValues[key];
|
|
4522
|
-
if (latestValues[key] !== undefined && isMotionValue(value)) {
|
|
4523
|
-
value.set(latestValues[key], false);
|
|
4726
|
+
function updateMotionValuesFromProps(element, next, prev) {
|
|
4727
|
+
const { willChange } = next;
|
|
4728
|
+
for (const key in next) {
|
|
4729
|
+
const nextValue = next[key];
|
|
4730
|
+
const prevValue = prev[key];
|
|
4731
|
+
if (isMotionValue(nextValue)) {
|
|
4732
|
+
/**
|
|
4733
|
+
* If this is a motion value found in props or style, we want to add it
|
|
4734
|
+
* to our visual element's motion value map.
|
|
4735
|
+
*/
|
|
4736
|
+
element.addValue(key, nextValue);
|
|
4524
4737
|
if (isWillChangeMotionValue(willChange)) {
|
|
4525
4738
|
willChange.add(key);
|
|
4526
4739
|
}
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
for (const key in props.values) {
|
|
4534
|
-
const value = props.values[key];
|
|
4535
|
-
if (latestValues[key] !== undefined && isMotionValue(value)) {
|
|
4536
|
-
value.set(latestValues[key]);
|
|
4740
|
+
/**
|
|
4741
|
+
* Check the version of the incoming motion value with this version
|
|
4742
|
+
* and warn against mismatches.
|
|
4743
|
+
*/
|
|
4744
|
+
{
|
|
4745
|
+
warnOnce(nextValue.version === "7.6.6", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.6.6 may not work as expected.`);
|
|
4537
4746
|
}
|
|
4538
4747
|
}
|
|
4539
|
-
|
|
4540
|
-
/**
|
|
4541
|
-
* Determine what role this visual element should take in the variant tree.
|
|
4542
|
-
*/
|
|
4543
|
-
const isControllingVariants$1 = isControllingVariants(props);
|
|
4544
|
-
const isVariantNode$1 = isVariantNode(props);
|
|
4545
|
-
const element = {
|
|
4546
|
-
treeType,
|
|
4547
|
-
/**
|
|
4548
|
-
* This is a mirror of the internal instance prop, which keeps
|
|
4549
|
-
* VisualElement type-compatible with React's RefObject.
|
|
4550
|
-
*/
|
|
4551
|
-
current: null,
|
|
4552
|
-
/**
|
|
4553
|
-
* The depth of this visual element within the visual element tree.
|
|
4554
|
-
*/
|
|
4555
|
-
depth: parent ? parent.depth + 1 : 0,
|
|
4556
|
-
parent,
|
|
4557
|
-
children: new Set(),
|
|
4558
|
-
/**
|
|
4559
|
-
*
|
|
4560
|
-
*/
|
|
4561
|
-
presenceId,
|
|
4562
|
-
shouldReduceMotion: null,
|
|
4563
|
-
/**
|
|
4564
|
-
* If this component is part of the variant tree, it should track
|
|
4565
|
-
* any children that are also part of the tree. This is essentially
|
|
4566
|
-
* a shadow tree to simplify logic around how to stagger over children.
|
|
4567
|
-
*/
|
|
4568
|
-
variantChildren: isVariantNode$1 ? new Set() : undefined,
|
|
4569
|
-
/**
|
|
4570
|
-
* Whether this instance is visible. This can be changed imperatively
|
|
4571
|
-
* by the projection tree, is analogous to CSS's visibility in that
|
|
4572
|
-
* hidden elements should take up layout, and needs enacting by the configured
|
|
4573
|
-
* render function.
|
|
4574
|
-
*/
|
|
4575
|
-
isVisible: undefined,
|
|
4576
|
-
/**
|
|
4577
|
-
* Normally, if a component is controlled by a parent's variants, it can
|
|
4578
|
-
* rely on that ancestor to trigger animations further down the tree.
|
|
4579
|
-
* However, if a component is created after its parent is mounted, the parent
|
|
4580
|
-
* won't trigger that mount animation so the child needs to.
|
|
4581
|
-
*
|
|
4582
|
-
* TODO: This might be better replaced with a method isParentMounted
|
|
4583
|
-
*/
|
|
4584
|
-
manuallyAnimateOnMount: Boolean(parent === null || parent === void 0 ? void 0 : parent.isMounted()),
|
|
4585
|
-
/**
|
|
4586
|
-
* This can be set by AnimatePresence to force components that mount
|
|
4587
|
-
* at the same time as it to mount as if they have initial={false} set.
|
|
4588
|
-
*/
|
|
4589
|
-
blockInitialAnimation,
|
|
4590
|
-
/**
|
|
4591
|
-
* Determine whether this component has mounted yet. This is mostly used
|
|
4592
|
-
* by variant children to determine whether they need to trigger their
|
|
4593
|
-
* own animations on mount.
|
|
4594
|
-
*/
|
|
4595
|
-
isMounted: () => Boolean(instance),
|
|
4596
|
-
mount(newInstance) {
|
|
4597
|
-
isMounted = true;
|
|
4598
|
-
instance = element.current = newInstance;
|
|
4599
|
-
if (element.projection) {
|
|
4600
|
-
element.projection.mount(newInstance);
|
|
4601
|
-
}
|
|
4602
|
-
if (isVariantNode$1 && parent && !isControllingVariants$1) {
|
|
4603
|
-
removeFromVariantTree = parent === null || parent === void 0 ? void 0 : parent.addVariantChild(element);
|
|
4604
|
-
}
|
|
4605
|
-
values.forEach((value, key) => bindToMotionValue(key, value));
|
|
4606
|
-
if (!hasReducedMotionListener.current) {
|
|
4607
|
-
initPrefersReducedMotion();
|
|
4608
|
-
}
|
|
4609
|
-
element.shouldReduceMotion =
|
|
4610
|
-
reducedMotionConfig === "never"
|
|
4611
|
-
? false
|
|
4612
|
-
: reducedMotionConfig === "always"
|
|
4613
|
-
? true
|
|
4614
|
-
: prefersReducedMotion.current;
|
|
4615
|
-
parent === null || parent === void 0 ? void 0 : parent.children.add(element);
|
|
4616
|
-
element.setProps(props);
|
|
4617
|
-
},
|
|
4618
|
-
/**
|
|
4619
|
-
*
|
|
4620
|
-
*/
|
|
4621
|
-
unmount() {
|
|
4622
|
-
var _a;
|
|
4623
|
-
(_a = element.projection) === null || _a === void 0 ? void 0 : _a.unmount();
|
|
4624
|
-
cancelSync.update(update);
|
|
4625
|
-
cancelSync.render(render);
|
|
4626
|
-
valueSubscriptions.forEach((remove) => remove());
|
|
4627
|
-
removeFromVariantTree === null || removeFromVariantTree === void 0 ? void 0 : removeFromVariantTree();
|
|
4628
|
-
parent === null || parent === void 0 ? void 0 : parent.children.delete(element);
|
|
4629
|
-
lifecycles.clearAllListeners();
|
|
4630
|
-
instance = undefined;
|
|
4631
|
-
isMounted = false;
|
|
4632
|
-
},
|
|
4633
|
-
loadFeatures(renderedProps, isStrict, preloadedFeatures, projectionId, ProjectionNodeConstructor, initialLayoutGroupConfig) {
|
|
4634
|
-
const features = [];
|
|
4748
|
+
else if (isMotionValue(prevValue)) {
|
|
4635
4749
|
/**
|
|
4636
|
-
* If we're
|
|
4637
|
-
*
|
|
4750
|
+
* If we're swapping from a motion value to a static value,
|
|
4751
|
+
* create a new motion value from that
|
|
4638
4752
|
*/
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
for (let i = 0; i < numFeatures; i++) {
|
|
4643
|
-
const name = featureNames[i];
|
|
4644
|
-
const { isEnabled, Component } = featureDefinitions[name];
|
|
4645
|
-
/**
|
|
4646
|
-
* It might be possible in the future to use this moment to
|
|
4647
|
-
* dynamically request functionality. In initial tests this
|
|
4648
|
-
* was producing a lot of duplication amongst bundles.
|
|
4649
|
-
*/
|
|
4650
|
-
if (isEnabled(renderedProps) && Component) {
|
|
4651
|
-
features.push(react.createElement(Component, {
|
|
4652
|
-
key: name,
|
|
4653
|
-
...renderedProps,
|
|
4654
|
-
visualElement: element,
|
|
4655
|
-
}));
|
|
4656
|
-
}
|
|
4657
|
-
}
|
|
4658
|
-
if (!element.projection && ProjectionNodeConstructor) {
|
|
4659
|
-
element.projection = new ProjectionNodeConstructor(projectionId, element.getLatestValues(), parent && parent.projection);
|
|
4660
|
-
const { layoutId, layout, drag, dragConstraints, layoutScroll, } = renderedProps;
|
|
4661
|
-
element.projection.setOptions({
|
|
4662
|
-
layoutId,
|
|
4663
|
-
layout,
|
|
4664
|
-
alwaysMeasureLayout: Boolean(drag) ||
|
|
4665
|
-
(dragConstraints && isRefObject(dragConstraints)),
|
|
4666
|
-
visualElement: element,
|
|
4667
|
-
scheduleRender: () => element.scheduleRender(),
|
|
4668
|
-
/**
|
|
4669
|
-
* TODO: Update options in an effect. This could be tricky as it'll be too late
|
|
4670
|
-
* to update by the time layout animations run.
|
|
4671
|
-
* We also need to fix this safeToRemove by linking it up to the one returned by usePresence,
|
|
4672
|
-
* ensuring it gets called if there's no potential layout animations.
|
|
4673
|
-
*
|
|
4674
|
-
*/
|
|
4675
|
-
animationType: typeof layout === "string" ? layout : "both",
|
|
4676
|
-
initialPromotionConfig: initialLayoutGroupConfig,
|
|
4677
|
-
layoutScroll,
|
|
4678
|
-
});
|
|
4679
|
-
}
|
|
4680
|
-
return features;
|
|
4681
|
-
},
|
|
4682
|
-
/**
|
|
4683
|
-
* Add a child visual element to our set of children.
|
|
4684
|
-
*/
|
|
4685
|
-
addVariantChild(child) {
|
|
4686
|
-
var _a;
|
|
4687
|
-
const closestVariantNode = element.getClosestVariantNode();
|
|
4688
|
-
if (closestVariantNode) {
|
|
4689
|
-
(_a = closestVariantNode.variantChildren) === null || _a === void 0 ? void 0 : _a.add(child);
|
|
4690
|
-
return () => closestVariantNode.variantChildren.delete(child);
|
|
4753
|
+
element.addValue(key, motionValue(nextValue));
|
|
4754
|
+
if (isWillChangeMotionValue(willChange)) {
|
|
4755
|
+
willChange.remove(key);
|
|
4691
4756
|
}
|
|
4692
|
-
}
|
|
4693
|
-
|
|
4757
|
+
}
|
|
4758
|
+
else if (prevValue !== nextValue) {
|
|
4694
4759
|
/**
|
|
4695
|
-
* If
|
|
4760
|
+
* If this is a flat value that has changed, update the motion value
|
|
4761
|
+
* or create one if it doesn't exist. We only want to do this if we're
|
|
4762
|
+
* not handling the value with our animation state.
|
|
4696
4763
|
*/
|
|
4697
|
-
if (
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
/**
|
|
4702
|
-
* Returns the closest variant node in the tree starting from
|
|
4703
|
-
* this visual element.
|
|
4704
|
-
*/
|
|
4705
|
-
getClosestVariantNode: () => isVariantNode$1 ? element : parent === null || parent === void 0 ? void 0 : parent.getClosestVariantNode(),
|
|
4706
|
-
/**
|
|
4707
|
-
* Expose the latest layoutId prop.
|
|
4708
|
-
*/
|
|
4709
|
-
getLayoutId: () => props.layoutId,
|
|
4710
|
-
/**
|
|
4711
|
-
* Returns the current instance.
|
|
4712
|
-
*/
|
|
4713
|
-
getInstance: () => instance,
|
|
4714
|
-
/**
|
|
4715
|
-
* Get/set the latest static values.
|
|
4716
|
-
*/
|
|
4717
|
-
getStaticValue: (key) => latestValues[key],
|
|
4718
|
-
setStaticValue: (key, value) => (latestValues[key] = value),
|
|
4719
|
-
/**
|
|
4720
|
-
* Returns the latest motion value state. Currently only used to take
|
|
4721
|
-
* a snapshot of the visual element - perhaps this can return the whole
|
|
4722
|
-
* visual state
|
|
4723
|
-
*/
|
|
4724
|
-
getLatestValues: () => latestValues,
|
|
4725
|
-
/**
|
|
4726
|
-
* Set the visiblity of the visual element. If it's changed, schedule
|
|
4727
|
-
* a render to reflect these changes.
|
|
4728
|
-
*/
|
|
4729
|
-
setVisibility(visibility) {
|
|
4730
|
-
if (element.isVisible === visibility)
|
|
4731
|
-
return;
|
|
4732
|
-
element.isVisible = visibility;
|
|
4733
|
-
element.scheduleRender();
|
|
4734
|
-
},
|
|
4735
|
-
/**
|
|
4736
|
-
* Make a target animatable by Popmotion. For instance, if we're
|
|
4737
|
-
* trying to animate width from 100px to 100vw we need to measure 100vw
|
|
4738
|
-
* in pixels to determine what we really need to animate to. This is also
|
|
4739
|
-
* pluggable to support Framer's custom value types like Color,
|
|
4740
|
-
* and CSS variables.
|
|
4741
|
-
*/
|
|
4742
|
-
makeTargetAnimatable(target, canMutate = true) {
|
|
4743
|
-
return makeTargetAnimatable(element, target, props, canMutate);
|
|
4744
|
-
},
|
|
4745
|
-
/**
|
|
4746
|
-
* Measure the current viewport box with or without transforms.
|
|
4747
|
-
* Only measures axis-aligned boxes, rotate and skew must be manually
|
|
4748
|
-
* removed with a re-render to work.
|
|
4749
|
-
*/
|
|
4750
|
-
measureViewportBox() {
|
|
4751
|
-
return measureViewportBox(instance, props);
|
|
4752
|
-
},
|
|
4753
|
-
// Motion values ========================
|
|
4754
|
-
/**
|
|
4755
|
-
* Add a motion value and bind it to this visual element.
|
|
4756
|
-
*/
|
|
4757
|
-
addValue(key, value) {
|
|
4758
|
-
// Remove existing value if it exists
|
|
4759
|
-
if (element.hasValue(key))
|
|
4760
|
-
element.removeValue(key);
|
|
4761
|
-
values.set(key, value);
|
|
4762
|
-
latestValues[key] = value.get();
|
|
4763
|
-
bindToMotionValue(key, value);
|
|
4764
|
-
},
|
|
4765
|
-
/**
|
|
4766
|
-
* Remove a motion value and unbind any active subscriptions.
|
|
4767
|
-
*/
|
|
4768
|
-
removeValue(key) {
|
|
4769
|
-
var _a;
|
|
4770
|
-
values.delete(key);
|
|
4771
|
-
(_a = valueSubscriptions.get(key)) === null || _a === void 0 ? void 0 : _a();
|
|
4772
|
-
valueSubscriptions.delete(key);
|
|
4773
|
-
delete latestValues[key];
|
|
4774
|
-
removeValueFromRenderState(key, renderState);
|
|
4775
|
-
},
|
|
4776
|
-
/**
|
|
4777
|
-
* Check whether we have a motion value for this key
|
|
4778
|
-
*/
|
|
4779
|
-
hasValue: (key) => values.has(key),
|
|
4780
|
-
/**
|
|
4781
|
-
* Get a motion value for this key. If called with a default
|
|
4782
|
-
* value, we'll create one if none exists.
|
|
4783
|
-
*/
|
|
4784
|
-
getValue(key, defaultValue) {
|
|
4785
|
-
if (props.values && props.values[key]) {
|
|
4786
|
-
return props.values[key];
|
|
4764
|
+
if (element.hasValue(key)) {
|
|
4765
|
+
const existingValue = element.getValue(key);
|
|
4766
|
+
// TODO: Only update values that aren't being animated or even looked at
|
|
4767
|
+
!existingValue.hasAnimated && existingValue.set(nextValue);
|
|
4787
4768
|
}
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
element.addValue(key, value);
|
|
4769
|
+
else {
|
|
4770
|
+
const latestValue = element.getStaticValue(key);
|
|
4771
|
+
element.addValue(key, motionValue(latestValue !== undefined ? latestValue : nextValue));
|
|
4792
4772
|
}
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4773
|
+
}
|
|
4774
|
+
}
|
|
4775
|
+
// Handle removed values
|
|
4776
|
+
for (const key in prev) {
|
|
4777
|
+
if (next[key] === undefined)
|
|
4778
|
+
element.removeValue(key);
|
|
4779
|
+
}
|
|
4780
|
+
return next;
|
|
4781
|
+
}
|
|
4782
|
+
|
|
4783
|
+
const featureNames = Object.keys(featureDefinitions);
|
|
4784
|
+
const numFeatures = featureNames.length;
|
|
4785
|
+
const propEventHandlers = [
|
|
4786
|
+
"AnimationStart",
|
|
4787
|
+
"AnimationComplete",
|
|
4788
|
+
"Update",
|
|
4789
|
+
"Unmount",
|
|
4790
|
+
"BeforeLayoutMeasure",
|
|
4791
|
+
"LayoutMeasure",
|
|
4792
|
+
"LayoutAnimationStart",
|
|
4793
|
+
"LayoutAnimationComplete",
|
|
4794
|
+
];
|
|
4795
|
+
/**
|
|
4796
|
+
* A VisualElement is an imperative abstraction around UI elements such as
|
|
4797
|
+
* HTMLElement, SVGElement, Three.Object3D etc.
|
|
4798
|
+
*/
|
|
4799
|
+
class VisualElement {
|
|
4800
|
+
constructor({ parent, props, reducedMotionConfig, visualState, }, options = {}) {
|
|
4814
4801
|
/**
|
|
4815
|
-
*
|
|
4816
|
-
*
|
|
4802
|
+
* A reference to the current underlying Instance, e.g. a HTMLElement
|
|
4803
|
+
* or Three.Mesh etc.
|
|
4817
4804
|
*/
|
|
4818
|
-
|
|
4819
|
-
var _a;
|
|
4820
|
-
const { initial } = props;
|
|
4821
|
-
const valueFromInitial = typeof initial === "string" || typeof initial === "object"
|
|
4822
|
-
? (_a = resolveVariantFromProps(props, initial)) === null || _a === void 0 ? void 0 : _a[key]
|
|
4823
|
-
: undefined;
|
|
4824
|
-
/**
|
|
4825
|
-
* If this value still exists in the current initial variant, read that.
|
|
4826
|
-
*/
|
|
4827
|
-
if (initial && valueFromInitial !== undefined) {
|
|
4828
|
-
return valueFromInitial;
|
|
4829
|
-
}
|
|
4830
|
-
/**
|
|
4831
|
-
* Alternatively, if this VisualElement config has defined a getBaseTarget
|
|
4832
|
-
* so we can read the value from an alternative source, try that.
|
|
4833
|
-
*/
|
|
4834
|
-
if (getBaseTarget) {
|
|
4835
|
-
const target = getBaseTarget(props, key);
|
|
4836
|
-
if (target !== undefined && !isMotionValue(target))
|
|
4837
|
-
return target;
|
|
4838
|
-
}
|
|
4839
|
-
/**
|
|
4840
|
-
* If the value was initially defined on initial, but it doesn't any more,
|
|
4841
|
-
* return undefined. Otherwise return the value as initially read from the DOM.
|
|
4842
|
-
*/
|
|
4843
|
-
return initialValues[key] !== undefined &&
|
|
4844
|
-
valueFromInitial === undefined
|
|
4845
|
-
? undefined
|
|
4846
|
-
: baseTarget[key];
|
|
4847
|
-
},
|
|
4848
|
-
// Lifecyles ========================
|
|
4849
|
-
...lifecycles,
|
|
4805
|
+
this.current = null;
|
|
4850
4806
|
/**
|
|
4851
|
-
*
|
|
4807
|
+
* A set containing references to this VisualElement's children.
|
|
4852
4808
|
*/
|
|
4853
|
-
|
|
4854
|
-
triggerBuild();
|
|
4855
|
-
return renderState;
|
|
4856
|
-
},
|
|
4809
|
+
this.children = new Set();
|
|
4857
4810
|
/**
|
|
4858
|
-
*
|
|
4811
|
+
* Determine what role this visual element should take in the variant tree.
|
|
4859
4812
|
*/
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
},
|
|
4813
|
+
this.isVariantNode = false;
|
|
4814
|
+
this.isControllingVariants = false;
|
|
4863
4815
|
/**
|
|
4864
|
-
*
|
|
4865
|
-
*
|
|
4866
|
-
*
|
|
4867
|
-
*
|
|
4816
|
+
* Decides whether this VisualElement should animate in reduced motion
|
|
4817
|
+
* mode.
|
|
4818
|
+
*
|
|
4819
|
+
* TODO: This is currently set on every individual VisualElement but feels
|
|
4820
|
+
* like it could be set globally.
|
|
4868
4821
|
*/
|
|
4869
|
-
|
|
4822
|
+
this.shouldReduceMotion = null;
|
|
4870
4823
|
/**
|
|
4871
|
-
*
|
|
4872
|
-
*
|
|
4824
|
+
* A map of all motion values attached to this visual element. Motion
|
|
4825
|
+
* values are source of truth for any given animated value. A motion
|
|
4826
|
+
* value might be provided externally by the component via props.
|
|
4873
4827
|
*/
|
|
4874
|
-
|
|
4875
|
-
if (newProps.transformTemplate || props.transformTemplate) {
|
|
4876
|
-
element.scheduleRender();
|
|
4877
|
-
}
|
|
4878
|
-
props = newProps;
|
|
4879
|
-
lifecycles.updatePropListeners(newProps);
|
|
4880
|
-
prevMotionValues = updateMotionValuesFromProps(element, scrapeMotionValuesFromProps(props), prevMotionValues);
|
|
4881
|
-
},
|
|
4882
|
-
getProps: () => props,
|
|
4883
|
-
// Variants ==============================
|
|
4828
|
+
this.values = new Map();
|
|
4884
4829
|
/**
|
|
4885
|
-
*
|
|
4830
|
+
* Tracks whether this VisualElement's React component is currently present
|
|
4831
|
+
* within the defined React tree.
|
|
4886
4832
|
*/
|
|
4887
|
-
|
|
4833
|
+
this.isPresent = true;
|
|
4888
4834
|
/**
|
|
4889
|
-
*
|
|
4835
|
+
* A map of every subscription that binds the provided or generated
|
|
4836
|
+
* motion values onChange listeners to this visual element.
|
|
4890
4837
|
*/
|
|
4891
|
-
|
|
4892
|
-
getTransformPagePoint: () => {
|
|
4893
|
-
return props.transformPagePoint;
|
|
4894
|
-
},
|
|
4838
|
+
this.valueSubscriptions = new Map();
|
|
4895
4839
|
/**
|
|
4896
|
-
*
|
|
4840
|
+
* A reference to the previously-provided motion values as returned
|
|
4841
|
+
* from scrapeMotionValuesFromProps. We use the keys in here to determine
|
|
4842
|
+
* if any motion values need to be removed after props are updated.
|
|
4897
4843
|
*/
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4844
|
+
this.prevMotionValues = {};
|
|
4845
|
+
/**
|
|
4846
|
+
* An object containing a SubscriptionManager for each active event.
|
|
4847
|
+
*/
|
|
4848
|
+
this.events = {};
|
|
4849
|
+
/**
|
|
4850
|
+
* An object containing an unsubscribe function for each prop event subscription.
|
|
4851
|
+
* For example, every "Update" event can have multiple subscribers via
|
|
4852
|
+
* VisualElement.on(), but only one of those can be defined via the onUpdate prop.
|
|
4853
|
+
*/
|
|
4854
|
+
this.propEventSubscriptions = {};
|
|
4855
|
+
this.notifyUpdate = () => this.notify("Update", this.latestValues);
|
|
4856
|
+
this.render = () => {
|
|
4857
|
+
if (!this.current)
|
|
4858
|
+
return;
|
|
4859
|
+
this.triggerBuild();
|
|
4860
|
+
this.renderInstance(this.current, this.renderState, this.props.style, this.projection);
|
|
4861
|
+
};
|
|
4862
|
+
this.scheduleRender = () => sync.render(this.render, false, true);
|
|
4863
|
+
const { latestValues, renderState } = visualState;
|
|
4864
|
+
this.latestValues = latestValues;
|
|
4865
|
+
this.baseTarget = { ...latestValues };
|
|
4866
|
+
this.initialValues = props.initial ? { ...latestValues } : {};
|
|
4867
|
+
this.renderState = renderState;
|
|
4868
|
+
this.parent = parent;
|
|
4869
|
+
this.props = props;
|
|
4870
|
+
this.depth = parent ? parent.depth + 1 : 0;
|
|
4871
|
+
this.reducedMotionConfig = reducedMotionConfig;
|
|
4872
|
+
this.options = options;
|
|
4873
|
+
this.isControllingVariants = isControllingVariants(props);
|
|
4874
|
+
this.isVariantNode = isVariantNode(props);
|
|
4875
|
+
if (this.isVariantNode) {
|
|
4876
|
+
this.variantChildren = new Set();
|
|
4877
|
+
}
|
|
4878
|
+
this.manuallyAnimateOnMount = Boolean(parent && parent.current);
|
|
4879
|
+
/**
|
|
4880
|
+
* Any motion values that are provided to the element when created
|
|
4881
|
+
* aren't yet bound to the element, as this would technically be impure.
|
|
4882
|
+
* However, we iterate through the motion values and set them to the
|
|
4883
|
+
* initial values for this component.
|
|
4884
|
+
*
|
|
4885
|
+
* TODO: This is impure and we should look at changing this to run on mount.
|
|
4886
|
+
* Doing so will break some tests but this isn't neccessarily a breaking change,
|
|
4887
|
+
* more a reflection of the test.
|
|
4888
|
+
*/
|
|
4889
|
+
const { willChange, ...initialMotionValues } = this.scrapeMotionValuesFromProps(props);
|
|
4890
|
+
for (const key in initialMotionValues) {
|
|
4891
|
+
const value = initialMotionValues[key];
|
|
4892
|
+
if (latestValues[key] !== undefined && isMotionValue(value)) {
|
|
4893
|
+
value.set(latestValues[key], false);
|
|
4894
|
+
if (isWillChangeMotionValue(willChange)) {
|
|
4895
|
+
willChange.add(key);
|
|
4914
4896
|
}
|
|
4915
4897
|
}
|
|
4916
|
-
|
|
4917
|
-
},
|
|
4918
|
-
};
|
|
4919
|
-
return element;
|
|
4920
|
-
};
|
|
4921
|
-
const variantProps = ["initial", ...variantPriorityOrder];
|
|
4922
|
-
const numVariantProps = variantProps.length;
|
|
4923
|
-
|
|
4924
|
-
/**
|
|
4925
|
-
* Returns true if the provided key is a CSS variable
|
|
4926
|
-
*/
|
|
4927
|
-
function isCSSVariable(key) {
|
|
4928
|
-
return key.startsWith("--");
|
|
4929
|
-
}
|
|
4930
|
-
|
|
4931
|
-
/**
|
|
4932
|
-
* Provided a value and a ValueType, returns the value as that value type.
|
|
4933
|
-
*/
|
|
4934
|
-
const getValueAsType = (value, type) => {
|
|
4935
|
-
return type && typeof value === "number"
|
|
4936
|
-
? type.transform(value)
|
|
4937
|
-
: value;
|
|
4938
|
-
};
|
|
4939
|
-
|
|
4940
|
-
function buildHTMLStyles(state, latestValues, options, transformTemplate) {
|
|
4941
|
-
const { style, vars, transform, transformKeys, transformOrigin } = state;
|
|
4942
|
-
transformKeys.length = 0;
|
|
4943
|
-
// Track whether we encounter any transform or transformOrigin values.
|
|
4944
|
-
let hasTransform = false;
|
|
4945
|
-
let hasTransformOrigin = false;
|
|
4946
|
-
// Does the calculated transform essentially equal "none"?
|
|
4947
|
-
let transformIsNone = true;
|
|
4948
|
-
/**
|
|
4949
|
-
* Loop over all our latest animated values and decide whether to handle them
|
|
4950
|
-
* as a style or CSS variable.
|
|
4951
|
-
*
|
|
4952
|
-
* Transforms and transform origins are kept seperately for further processing.
|
|
4953
|
-
*/
|
|
4954
|
-
for (const key in latestValues) {
|
|
4955
|
-
const value = latestValues[key];
|
|
4898
|
+
}
|
|
4956
4899
|
/**
|
|
4957
|
-
*
|
|
4900
|
+
* Update external values with initial values
|
|
4958
4901
|
*/
|
|
4959
|
-
if (
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
if (transformProps.has(key)) {
|
|
4967
|
-
// If this is a transform, flag to enable further transform processing
|
|
4968
|
-
hasTransform = true;
|
|
4969
|
-
transform[key] = valueAsType;
|
|
4970
|
-
transformKeys.push(key);
|
|
4971
|
-
// If we already know we have a non-default transform, early return
|
|
4972
|
-
if (!transformIsNone)
|
|
4973
|
-
continue;
|
|
4974
|
-
// Otherwise check to see if this is a default transform
|
|
4975
|
-
if (value !== (valueType.default || 0))
|
|
4976
|
-
transformIsNone = false;
|
|
4977
|
-
}
|
|
4978
|
-
else if (key.startsWith("origin")) {
|
|
4979
|
-
// If this is a transform origin, flag and enable further transform-origin processing
|
|
4980
|
-
hasTransformOrigin = true;
|
|
4981
|
-
transformOrigin[key] = valueAsType;
|
|
4982
|
-
}
|
|
4983
|
-
else {
|
|
4984
|
-
style[key] = valueAsType;
|
|
4985
|
-
}
|
|
4986
|
-
}
|
|
4987
|
-
if (!latestValues.transform) {
|
|
4988
|
-
if (hasTransform || transformTemplate) {
|
|
4989
|
-
style.transform = buildTransform(state, options, transformIsNone, transformTemplate);
|
|
4990
|
-
}
|
|
4991
|
-
else if (style.transform) {
|
|
4992
|
-
/**
|
|
4993
|
-
* If we have previously created a transform but currently don't have any,
|
|
4994
|
-
* reset transform style to none.
|
|
4995
|
-
*/
|
|
4996
|
-
style.transform = "none";
|
|
4902
|
+
if (props.values) {
|
|
4903
|
+
for (const key in props.values) {
|
|
4904
|
+
const value = props.values[key];
|
|
4905
|
+
if (latestValues[key] !== undefined && isMotionValue(value)) {
|
|
4906
|
+
value.set(latestValues[key]);
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4997
4909
|
}
|
|
4998
4910
|
}
|
|
4999
4911
|
/**
|
|
5000
|
-
*
|
|
5001
|
-
*
|
|
4912
|
+
* This method takes React props and returns found MotionValues. For example, HTML
|
|
4913
|
+
* MotionValues will be found within the style prop, whereas for Three.js within attribute arrays.
|
|
4914
|
+
*
|
|
4915
|
+
* This isn't an abstract method as it needs calling in the constructor, but it is
|
|
4916
|
+
* intended to be one.
|
|
5002
4917
|
*/
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
style.transformOrigin = `${originX} ${originY} ${originZ}`;
|
|
4918
|
+
scrapeMotionValuesFromProps(_props) {
|
|
4919
|
+
return {};
|
|
5006
4920
|
}
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
4921
|
+
mount(instance) {
|
|
4922
|
+
var _a;
|
|
4923
|
+
this.current = instance;
|
|
4924
|
+
if (this.projection) {
|
|
4925
|
+
this.projection.mount(instance);
|
|
4926
|
+
}
|
|
4927
|
+
if (this.parent && this.isVariantNode && !this.isControllingVariants) {
|
|
4928
|
+
this.removeFromVariantTree = (_a = this.parent) === null || _a === void 0 ? void 0 : _a.addVariantChild(this);
|
|
4929
|
+
}
|
|
4930
|
+
this.values.forEach((value, key) => this.bindToMotionValue(key, value));
|
|
4931
|
+
if (!hasReducedMotionListener.current) {
|
|
4932
|
+
initPrefersReducedMotion();
|
|
4933
|
+
}
|
|
4934
|
+
this.shouldReduceMotion =
|
|
4935
|
+
this.reducedMotionConfig === "never"
|
|
4936
|
+
? false
|
|
4937
|
+
: this.reducedMotionConfig === "always"
|
|
4938
|
+
? true
|
|
4939
|
+
: prefersReducedMotion.current;
|
|
4940
|
+
if (this.parent)
|
|
4941
|
+
this.parent.children.add(this);
|
|
4942
|
+
this.setProps(this.props);
|
|
4943
|
+
}
|
|
4944
|
+
unmount() {
|
|
4945
|
+
var _a, _b, _c;
|
|
4946
|
+
(_a = this.projection) === null || _a === void 0 ? void 0 : _a.unmount();
|
|
4947
|
+
cancelSync.update(this.notifyUpdate);
|
|
4948
|
+
cancelSync.render(this.render);
|
|
4949
|
+
this.valueSubscriptions.forEach((remove) => remove());
|
|
4950
|
+
(_b = this.removeFromVariantTree) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
4951
|
+
(_c = this.parent) === null || _c === void 0 ? void 0 : _c.children.delete(this);
|
|
4952
|
+
for (const key in this.events) {
|
|
4953
|
+
this.events[key].clear();
|
|
4954
|
+
}
|
|
4955
|
+
this.current = null;
|
|
4956
|
+
}
|
|
4957
|
+
bindToMotionValue(key, value) {
|
|
4958
|
+
const removeOnChange = value.onChange((latestValue) => {
|
|
4959
|
+
this.latestValues[key] = latestValue;
|
|
4960
|
+
this.props.onUpdate &&
|
|
4961
|
+
sync.update(this.notifyUpdate, false, true);
|
|
4962
|
+
});
|
|
4963
|
+
const removeOnRenderRequest = value.onRenderRequest(this.scheduleRender);
|
|
4964
|
+
this.valueSubscriptions.set(key, () => {
|
|
4965
|
+
removeOnChange();
|
|
4966
|
+
removeOnRenderRequest();
|
|
4967
|
+
});
|
|
5046
4968
|
}
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
4969
|
+
sortNodePosition(other) {
|
|
4970
|
+
/**
|
|
4971
|
+
* If these nodes aren't even of the same type we can't compare their depth.
|
|
4972
|
+
*/
|
|
4973
|
+
if (!this.current ||
|
|
4974
|
+
!this.sortInstanceNodePosition ||
|
|
4975
|
+
this.type !== other.type)
|
|
5053
4976
|
return 0;
|
|
5054
|
-
|
|
4977
|
+
return this.sortInstanceNodePosition(this.current, other.current);
|
|
5055
4978
|
}
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
removedTransforms.push([key, value.get()]);
|
|
5065
|
-
value.set(key.startsWith("scale") ? 1 : 0);
|
|
4979
|
+
loadFeatures(renderedProps, isStrict, preloadedFeatures, projectionId, ProjectionNodeConstructor, initialLayoutGroupConfig) {
|
|
4980
|
+
const features = [];
|
|
4981
|
+
/**
|
|
4982
|
+
* If we're in development mode, check to make sure we're not rendering a motion component
|
|
4983
|
+
* as a child of LazyMotion, as this will break the file-size benefits of using it.
|
|
4984
|
+
*/
|
|
4985
|
+
if (env !== "production" && preloadedFeatures && isStrict) {
|
|
4986
|
+
invariant(false, "You have rendered a `motion` component within a `LazyMotion` component. This will break tree shaking. Import and render a `m` component instead.");
|
|
5066
4987
|
}
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
// Transform
|
|
5082
|
-
x: getTranslateFromMatrix(4, 13),
|
|
5083
|
-
y: getTranslateFromMatrix(5, 14),
|
|
5084
|
-
};
|
|
5085
|
-
const convertChangedValueTypes = (target, visualElement, changedKeys) => {
|
|
5086
|
-
const originBbox = visualElement.measureViewportBox();
|
|
5087
|
-
const element = visualElement.getInstance();
|
|
5088
|
-
const elementComputedStyle = getComputedStyle(element);
|
|
5089
|
-
const { display } = elementComputedStyle;
|
|
5090
|
-
const origin = {};
|
|
5091
|
-
// If the element is currently set to display: "none", make it visible before
|
|
5092
|
-
// measuring the target bounding box
|
|
5093
|
-
if (display === "none") {
|
|
5094
|
-
visualElement.setStaticValue("display", target.display || "block");
|
|
5095
|
-
}
|
|
5096
|
-
/**
|
|
5097
|
-
* Record origins before we render and update styles
|
|
5098
|
-
*/
|
|
5099
|
-
changedKeys.forEach((key) => {
|
|
5100
|
-
origin[key] = positionalValues[key](originBbox, elementComputedStyle);
|
|
5101
|
-
});
|
|
5102
|
-
// Apply the latest values (as set in checkAndConvertChangedValueTypes)
|
|
5103
|
-
visualElement.syncRender();
|
|
5104
|
-
const targetBbox = visualElement.measureViewportBox();
|
|
5105
|
-
changedKeys.forEach((key) => {
|
|
5106
|
-
// Restore styles to their **calculated computed style**, not their actual
|
|
5107
|
-
// originally set style. This allows us to animate between equivalent pixel units.
|
|
5108
|
-
const value = visualElement.getValue(key);
|
|
5109
|
-
setAndResetVelocity(value, origin[key]);
|
|
5110
|
-
target[key] = positionalValues[key](targetBbox, elementComputedStyle);
|
|
5111
|
-
});
|
|
5112
|
-
return target;
|
|
5113
|
-
};
|
|
5114
|
-
const checkAndConvertChangedValueTypes = (visualElement, target, origin = {}, transitionEnd = {}) => {
|
|
5115
|
-
target = { ...target };
|
|
5116
|
-
transitionEnd = { ...transitionEnd };
|
|
5117
|
-
const targetPositionalKeys = Object.keys(target).filter(isPositionalKey);
|
|
5118
|
-
// We want to remove any transform values that could affect the element's bounding box before
|
|
5119
|
-
// it's measured. We'll reapply these later.
|
|
5120
|
-
let removedTransformValues = [];
|
|
5121
|
-
let hasAttemptedToRemoveTransformValues = false;
|
|
5122
|
-
const changedValueTypeKeys = [];
|
|
5123
|
-
targetPositionalKeys.forEach((key) => {
|
|
5124
|
-
const value = visualElement.getValue(key);
|
|
5125
|
-
if (!visualElement.hasValue(key))
|
|
5126
|
-
return;
|
|
5127
|
-
let from = origin[key];
|
|
5128
|
-
let fromType = findDimensionValueType(from);
|
|
5129
|
-
const to = target[key];
|
|
5130
|
-
let toType;
|
|
5131
|
-
// TODO: The current implementation of this basically throws an error
|
|
5132
|
-
// if you try and do value conversion via keyframes. There's probably
|
|
5133
|
-
// a way of doing this but the performance implications would need greater scrutiny,
|
|
5134
|
-
// as it'd be doing multiple resize-remeasure operations.
|
|
5135
|
-
if (isKeyframesTarget(to)) {
|
|
5136
|
-
const numKeyframes = to.length;
|
|
5137
|
-
const fromIndex = to[0] === null ? 1 : 0;
|
|
5138
|
-
from = to[fromIndex];
|
|
5139
|
-
fromType = findDimensionValueType(from);
|
|
5140
|
-
for (let i = fromIndex; i < numKeyframes; i++) {
|
|
5141
|
-
if (!toType) {
|
|
5142
|
-
toType = findDimensionValueType(to[i]);
|
|
5143
|
-
invariant(toType === fromType ||
|
|
5144
|
-
(isNumOrPxType(fromType) && isNumOrPxType(toType)), "Keyframes must be of the same dimension as the current value");
|
|
5145
|
-
}
|
|
5146
|
-
else {
|
|
5147
|
-
invariant(findDimensionValueType(to[i]) === toType, "All keyframes must be of the same type");
|
|
5148
|
-
}
|
|
4988
|
+
for (let i = 0; i < numFeatures; i++) {
|
|
4989
|
+
const name = featureNames[i];
|
|
4990
|
+
const { isEnabled, Component } = featureDefinitions[name];
|
|
4991
|
+
/**
|
|
4992
|
+
* It might be possible in the future to use this moment to
|
|
4993
|
+
* dynamically request functionality. In initial tests this
|
|
4994
|
+
* was producing a lot of duplication amongst bundles.
|
|
4995
|
+
*/
|
|
4996
|
+
if (isEnabled(renderedProps) && Component) {
|
|
4997
|
+
features.push(react.createElement(Component, {
|
|
4998
|
+
key: name,
|
|
4999
|
+
...renderedProps,
|
|
5000
|
+
visualElement: this,
|
|
5001
|
+
}));
|
|
5149
5002
|
}
|
|
5150
5003
|
}
|
|
5151
|
-
|
|
5152
|
-
|
|
5004
|
+
if (!this.projection && ProjectionNodeConstructor) {
|
|
5005
|
+
this.projection = new ProjectionNodeConstructor(projectionId, this.latestValues, this.parent && this.parent.projection);
|
|
5006
|
+
const { layoutId, layout, drag, dragConstraints, layoutScroll } = renderedProps;
|
|
5007
|
+
this.projection.setOptions({
|
|
5008
|
+
layoutId,
|
|
5009
|
+
layout,
|
|
5010
|
+
alwaysMeasureLayout: Boolean(drag) ||
|
|
5011
|
+
(dragConstraints && isRefObject(dragConstraints)),
|
|
5012
|
+
visualElement: this,
|
|
5013
|
+
scheduleRender: () => this.scheduleRender(),
|
|
5014
|
+
/**
|
|
5015
|
+
* TODO: Update options in an effect. This could be tricky as it'll be too late
|
|
5016
|
+
* to update by the time layout animations run.
|
|
5017
|
+
* We also need to fix this safeToRemove by linking it up to the one returned by usePresence,
|
|
5018
|
+
* ensuring it gets called if there's no potential layout animations.
|
|
5019
|
+
*
|
|
5020
|
+
*/
|
|
5021
|
+
animationType: typeof layout === "string" ? layout : "both",
|
|
5022
|
+
initialPromotionConfig: initialLayoutGroupConfig,
|
|
5023
|
+
layoutScroll,
|
|
5024
|
+
});
|
|
5025
|
+
}
|
|
5026
|
+
return features;
|
|
5027
|
+
}
|
|
5028
|
+
triggerBuild() {
|
|
5029
|
+
this.build(this.renderState, this.latestValues, this.options, this.props);
|
|
5030
|
+
}
|
|
5031
|
+
/**
|
|
5032
|
+
* Measure the current viewport box with or without transforms.
|
|
5033
|
+
* Only measures axis-aligned boxes, rotate and skew must be manually
|
|
5034
|
+
* removed with a re-render to work.
|
|
5035
|
+
*/
|
|
5036
|
+
measureViewportBox() {
|
|
5037
|
+
return this.current
|
|
5038
|
+
? this.measureInstanceViewportBox(this.current, this.props)
|
|
5039
|
+
: createBox();
|
|
5040
|
+
}
|
|
5041
|
+
getStaticValue(key) {
|
|
5042
|
+
return this.latestValues[key];
|
|
5043
|
+
}
|
|
5044
|
+
setStaticValue(key, value) {
|
|
5045
|
+
this.latestValues[key] = value;
|
|
5046
|
+
}
|
|
5047
|
+
/**
|
|
5048
|
+
* Make a target animatable by Popmotion. For instance, if we're
|
|
5049
|
+
* trying to animate width from 100px to 100vw we need to measure 100vw
|
|
5050
|
+
* in pixels to determine what we really need to animate to. This is also
|
|
5051
|
+
* pluggable to support Framer's custom value types like Color,
|
|
5052
|
+
* and CSS variables.
|
|
5053
|
+
*/
|
|
5054
|
+
makeTargetAnimatable(target, canMutate = true) {
|
|
5055
|
+
return this.makeTargetAnimatableFromInstance(target, this.props, canMutate);
|
|
5056
|
+
}
|
|
5057
|
+
/**
|
|
5058
|
+
* Update the provided props. Ensure any newly-added motion values are
|
|
5059
|
+
* added to our map, old ones removed, and listeners updated.
|
|
5060
|
+
*/
|
|
5061
|
+
setProps(props) {
|
|
5062
|
+
if (props.transformTemplate || this.props.transformTemplate) {
|
|
5063
|
+
this.scheduleRender();
|
|
5153
5064
|
}
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
target[key] = parseFloat(to);
|
|
5164
|
-
}
|
|
5165
|
-
else if (Array.isArray(to) && toType === px) {
|
|
5166
|
-
target[key] = to.map(parseFloat);
|
|
5167
|
-
}
|
|
5065
|
+
this.props = props;
|
|
5066
|
+
/**
|
|
5067
|
+
* Update prop event handlers ie onAnimationStart, onAnimationComplete
|
|
5068
|
+
*/
|
|
5069
|
+
for (let i = 0; i < propEventHandlers.length; i++) {
|
|
5070
|
+
const key = propEventHandlers[i];
|
|
5071
|
+
if (this.propEventSubscriptions[key]) {
|
|
5072
|
+
this.propEventSubscriptions[key]();
|
|
5073
|
+
delete this.propEventSubscriptions[key];
|
|
5168
5074
|
}
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
// If one or the other value is 0, it's safe to coerce it to the
|
|
5173
|
-
// type of the other without measurement
|
|
5174
|
-
if (from === 0) {
|
|
5175
|
-
value.set(toType.transform(from));
|
|
5176
|
-
}
|
|
5177
|
-
else {
|
|
5178
|
-
target[key] = fromType.transform(to);
|
|
5179
|
-
}
|
|
5075
|
+
const listener = props["on" + key];
|
|
5076
|
+
if (listener) {
|
|
5077
|
+
this.propEventSubscriptions[key] = this.on(key, listener);
|
|
5180
5078
|
}
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5079
|
+
}
|
|
5080
|
+
this.prevMotionValues = updateMotionValuesFromProps(this, this.scrapeMotionValuesFromProps(props), this.prevMotionValues);
|
|
5081
|
+
}
|
|
5082
|
+
getProps() {
|
|
5083
|
+
return this.props;
|
|
5084
|
+
}
|
|
5085
|
+
/**
|
|
5086
|
+
* Returns the variant definition with a given name.
|
|
5087
|
+
*/
|
|
5088
|
+
getVariant(name) {
|
|
5089
|
+
var _a;
|
|
5090
|
+
return (_a = this.props.variants) === null || _a === void 0 ? void 0 : _a[name];
|
|
5091
|
+
}
|
|
5092
|
+
/**
|
|
5093
|
+
* Returns the defined default transition on this component.
|
|
5094
|
+
*/
|
|
5095
|
+
getDefaultTransition() {
|
|
5096
|
+
return this.props.transition;
|
|
5097
|
+
}
|
|
5098
|
+
getTransformPagePoint() {
|
|
5099
|
+
return this.props.transformPagePoint;
|
|
5100
|
+
}
|
|
5101
|
+
getClosestVariantNode() {
|
|
5102
|
+
var _a;
|
|
5103
|
+
return this.isVariantNode ? this : (_a = this.parent) === null || _a === void 0 ? void 0 : _a.getClosestVariantNode();
|
|
5104
|
+
}
|
|
5105
|
+
getVariantContext(startAtParent = false) {
|
|
5106
|
+
var _a, _b;
|
|
5107
|
+
if (startAtParent)
|
|
5108
|
+
return (_a = this.parent) === null || _a === void 0 ? void 0 : _a.getVariantContext();
|
|
5109
|
+
if (!this.isControllingVariants) {
|
|
5110
|
+
const context = ((_b = this.parent) === null || _b === void 0 ? void 0 : _b.getVariantContext()) || {};
|
|
5111
|
+
if (this.props.initial !== undefined) {
|
|
5112
|
+
context.initial = this.props.initial;
|
|
5195
5113
|
}
|
|
5114
|
+
return context;
|
|
5196
5115
|
}
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
if (removedTransformValues.length) {
|
|
5205
|
-
removedTransformValues.forEach(([key, value]) => {
|
|
5206
|
-
visualElement.getValue(key).set(value);
|
|
5207
|
-
});
|
|
5116
|
+
const context = {};
|
|
5117
|
+
for (let i = 0; i < numVariantProps; i++) {
|
|
5118
|
+
const name = variantProps[i];
|
|
5119
|
+
const prop = this.props[name];
|
|
5120
|
+
if (isVariantLabel(prop) || prop === false) {
|
|
5121
|
+
context[name] = prop;
|
|
5122
|
+
}
|
|
5208
5123
|
}
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5124
|
+
return context;
|
|
5125
|
+
}
|
|
5126
|
+
/**
|
|
5127
|
+
* Add a child visual element to our set of children.
|
|
5128
|
+
*/
|
|
5129
|
+
addVariantChild(child) {
|
|
5130
|
+
var _a;
|
|
5131
|
+
const closestVariantNode = this.getClosestVariantNode();
|
|
5132
|
+
if (closestVariantNode) {
|
|
5133
|
+
(_a = closestVariantNode.variantChildren) === null || _a === void 0 ? void 0 : _a.add(child);
|
|
5134
|
+
return () => closestVariantNode.variantChildren.delete(child);
|
|
5214
5135
|
}
|
|
5215
|
-
return { target: convertedTarget, transitionEnd };
|
|
5216
5136
|
}
|
|
5217
|
-
|
|
5218
|
-
|
|
5137
|
+
/**
|
|
5138
|
+
* Add a motion value and bind it to this visual element.
|
|
5139
|
+
*/
|
|
5140
|
+
addValue(key, value) {
|
|
5141
|
+
// Remove existing value if it exists
|
|
5142
|
+
if (this.hasValue(key))
|
|
5143
|
+
this.removeValue(key);
|
|
5144
|
+
this.values.set(key, value);
|
|
5145
|
+
this.latestValues[key] = value.get();
|
|
5146
|
+
this.bindToMotionValue(key, value);
|
|
5219
5147
|
}
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
(!!scaleCorrectors[key] || key === "opacity")));
|
|
5250
|
-
}
|
|
5251
|
-
|
|
5252
|
-
function scrapeMotionValuesFromProps(props) {
|
|
5253
|
-
const { style } = props;
|
|
5254
|
-
const newValues = {};
|
|
5255
|
-
for (const key in style) {
|
|
5256
|
-
if (isMotionValue(style[key]) || isForcedMotionValue(key, props)) {
|
|
5257
|
-
newValues[key] = style[key];
|
|
5148
|
+
/**
|
|
5149
|
+
* Remove a motion value and unbind any active subscriptions.
|
|
5150
|
+
*/
|
|
5151
|
+
removeValue(key) {
|
|
5152
|
+
var _a;
|
|
5153
|
+
this.values.delete(key);
|
|
5154
|
+
(_a = this.valueSubscriptions.get(key)) === null || _a === void 0 ? void 0 : _a();
|
|
5155
|
+
this.valueSubscriptions.delete(key);
|
|
5156
|
+
delete this.latestValues[key];
|
|
5157
|
+
this.removeValueFromRenderState(key, this.renderState);
|
|
5158
|
+
}
|
|
5159
|
+
/**
|
|
5160
|
+
* Check whether we have a motion value for this key
|
|
5161
|
+
*/
|
|
5162
|
+
hasValue(key) {
|
|
5163
|
+
return this.values.has(key);
|
|
5164
|
+
}
|
|
5165
|
+
/**
|
|
5166
|
+
* Get a motion value for this key. If called with a default
|
|
5167
|
+
* value, we'll create one if none exists.
|
|
5168
|
+
*/
|
|
5169
|
+
getValue(key, defaultValue) {
|
|
5170
|
+
if (this.props.values && this.props.values[key]) {
|
|
5171
|
+
return this.props.values[key];
|
|
5172
|
+
}
|
|
5173
|
+
let value = this.values.get(key);
|
|
5174
|
+
if (value === undefined && defaultValue !== undefined) {
|
|
5175
|
+
value = motionValue(defaultValue);
|
|
5176
|
+
this.addValue(key, value);
|
|
5258
5177
|
}
|
|
5178
|
+
return value;
|
|
5259
5179
|
}
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5180
|
+
/**
|
|
5181
|
+
* If we're trying to animate to a previously unencountered value,
|
|
5182
|
+
* we need to check for it in our state and as a last resort read it
|
|
5183
|
+
* directly from the instance (which might have performance implications).
|
|
5184
|
+
*/
|
|
5185
|
+
readValue(key) {
|
|
5186
|
+
return this.latestValues[key] !== undefined || !this.current
|
|
5187
|
+
? this.latestValues[key]
|
|
5188
|
+
: this.readValueFromInstance(this.current, key, this.options);
|
|
5268
5189
|
}
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
const bottomRight = transformPoint({ x: point.right, y: point.bottom });
|
|
5292
|
-
return {
|
|
5293
|
-
top: topLeft.y,
|
|
5294
|
-
left: topLeft.x,
|
|
5295
|
-
bottom: bottomRight.y,
|
|
5296
|
-
right: bottomRight.x,
|
|
5297
|
-
};
|
|
5298
|
-
}
|
|
5299
|
-
|
|
5300
|
-
function measureViewportBox(instance, transformPoint) {
|
|
5301
|
-
return convertBoundingBoxToBox(transformBoxPoints(instance.getBoundingClientRect(), transformPoint));
|
|
5302
|
-
}
|
|
5303
|
-
|
|
5304
|
-
function getComputedStyle$1(element) {
|
|
5305
|
-
return window.getComputedStyle(element);
|
|
5306
|
-
}
|
|
5307
|
-
const htmlConfig = {
|
|
5308
|
-
treeType: "dom",
|
|
5309
|
-
readValueFromInstance(domElement, key) {
|
|
5310
|
-
if (transformProps.has(key)) {
|
|
5311
|
-
const defaultType = getDefaultValueType(key);
|
|
5312
|
-
return defaultType ? defaultType.default || 0 : 0;
|
|
5190
|
+
/**
|
|
5191
|
+
* Set the base target to later animate back to. This is currently
|
|
5192
|
+
* only hydrated on creation and when we first read a value.
|
|
5193
|
+
*/
|
|
5194
|
+
setBaseTarget(key, value) {
|
|
5195
|
+
this.baseTarget[key] = value;
|
|
5196
|
+
}
|
|
5197
|
+
/**
|
|
5198
|
+
* Find the base target for a value thats been removed from all animation
|
|
5199
|
+
* props.
|
|
5200
|
+
*/
|
|
5201
|
+
getBaseTarget(key) {
|
|
5202
|
+
var _a;
|
|
5203
|
+
const { initial } = this.props;
|
|
5204
|
+
const valueFromInitial = typeof initial === "string" || typeof initial === "object"
|
|
5205
|
+
? (_a = resolveVariantFromProps(this.props, initial)) === null || _a === void 0 ? void 0 : _a[key]
|
|
5206
|
+
: undefined;
|
|
5207
|
+
/**
|
|
5208
|
+
* If this value still exists in the current initial variant, read that.
|
|
5209
|
+
*/
|
|
5210
|
+
if (initial && valueFromInitial !== undefined) {
|
|
5211
|
+
return valueFromInitial;
|
|
5313
5212
|
}
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5213
|
+
/**
|
|
5214
|
+
* Alternatively, if this VisualElement config has defined a getBaseTarget
|
|
5215
|
+
* so we can read the value from an alternative source, try that.
|
|
5216
|
+
*/
|
|
5217
|
+
const target = this.getBaseTargetFromProps(this.props, key);
|
|
5218
|
+
if (target !== undefined && !isMotionValue(target))
|
|
5219
|
+
return target;
|
|
5220
|
+
/**
|
|
5221
|
+
* If the value was initially defined on initial, but it doesn't any more,
|
|
5222
|
+
* return undefined. Otherwise return the value as initially read from the DOM.
|
|
5223
|
+
*/
|
|
5224
|
+
return this.initialValues[key] !== undefined &&
|
|
5225
|
+
valueFromInitial === undefined
|
|
5226
|
+
? undefined
|
|
5227
|
+
: this.baseTarget[key];
|
|
5228
|
+
}
|
|
5229
|
+
on(eventName, callback) {
|
|
5230
|
+
if (!this.events[eventName]) {
|
|
5231
|
+
this.events[eventName] = new SubscriptionManager();
|
|
5320
5232
|
}
|
|
5321
|
-
|
|
5322
|
-
|
|
5233
|
+
return this.events[eventName].add(callback);
|
|
5234
|
+
}
|
|
5235
|
+
notify(eventName, ...args) {
|
|
5236
|
+
var _a;
|
|
5237
|
+
(_a = this.events[eventName]) === null || _a === void 0 ? void 0 : _a.notify(...args);
|
|
5238
|
+
}
|
|
5239
|
+
}
|
|
5240
|
+
const variantProps = ["initial", ...variantPriorityOrder];
|
|
5241
|
+
const numVariantProps = variantProps.length;
|
|
5242
|
+
|
|
5243
|
+
class DOMVisualElement extends VisualElement {
|
|
5244
|
+
sortInstanceNodePosition(a, b) {
|
|
5323
5245
|
/**
|
|
5324
5246
|
* compareDocumentPosition returns a bitmask, by using the bitwise &
|
|
5325
5247
|
* we're returning true if 2 in that bitmask is set to true. 2 is set
|
|
5326
5248
|
* to true if b preceeds a.
|
|
5327
5249
|
*/
|
|
5328
5250
|
return a.compareDocumentPosition(b) & 2 ? 1 : -1;
|
|
5329
|
-
}
|
|
5330
|
-
|
|
5251
|
+
}
|
|
5252
|
+
getBaseTargetFromProps(props, key) {
|
|
5331
5253
|
var _a;
|
|
5332
5254
|
return (_a = props.style) === null || _a === void 0 ? void 0 : _a[key];
|
|
5333
|
-
}
|
|
5334
|
-
measureViewportBox(element, { transformPagePoint }) {
|
|
5335
|
-
return measureViewportBox(element, transformPagePoint);
|
|
5336
|
-
},
|
|
5337
|
-
/**
|
|
5338
|
-
* Reset the transform on the current Element. This is called as part
|
|
5339
|
-
* of a batched process across the entire layout tree. To remove this write
|
|
5340
|
-
* cycle it'd be interesting to see if it's possible to "undo" all the current
|
|
5341
|
-
* layout transforms up the tree in the same way this.getBoundingBoxWithoutTransforms
|
|
5342
|
-
* works
|
|
5343
|
-
*/
|
|
5344
|
-
resetTransform(element, domElement, props) {
|
|
5345
|
-
const { transformTemplate } = props;
|
|
5346
|
-
domElement.style.transform = transformTemplate
|
|
5347
|
-
? transformTemplate({}, "")
|
|
5348
|
-
: "none";
|
|
5349
|
-
// Ensure that whatever happens next, we restore our transform on the next frame
|
|
5350
|
-
element.scheduleRender();
|
|
5351
|
-
},
|
|
5352
|
-
restoreTransform(instance, mutableState) {
|
|
5353
|
-
instance.style.transform = mutableState.style.transform;
|
|
5354
|
-
},
|
|
5255
|
+
}
|
|
5355
5256
|
removeValueFromRenderState(key, { vars, style }) {
|
|
5356
5257
|
delete vars[key];
|
|
5357
5258
|
delete style[key];
|
|
5358
|
-
}
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
* can be animated by Motion.
|
|
5362
|
-
*/
|
|
5363
|
-
makeTargetAnimatable(element, { transition, transitionEnd, ...target }, { transformValues }, isMounted = true) {
|
|
5364
|
-
let origin = getOrigin(target, transition || {}, element);
|
|
5259
|
+
}
|
|
5260
|
+
makeTargetAnimatableFromInstance({ transition, transitionEnd, ...target }, { transformValues }, isMounted) {
|
|
5261
|
+
let origin = getOrigin(target, transition || {}, this);
|
|
5365
5262
|
/**
|
|
5366
5263
|
* If Framer has provided a function to convert `Color` etc value types, convert them
|
|
5367
5264
|
*/
|
|
@@ -5374,8 +5271,8 @@
|
|
|
5374
5271
|
origin = transformValues(origin);
|
|
5375
5272
|
}
|
|
5376
5273
|
if (isMounted) {
|
|
5377
|
-
checkTargetForNewValues(
|
|
5378
|
-
const parsed = parseDomVariant(
|
|
5274
|
+
checkTargetForNewValues(this, target, origin);
|
|
5275
|
+
const parsed = parseDomVariant(this, target, origin, transitionEnd);
|
|
5379
5276
|
transitionEnd = parsed.transitionEnd;
|
|
5380
5277
|
target = parsed.target;
|
|
5381
5278
|
}
|
|
@@ -5384,28 +5281,48 @@
|
|
|
5384
5281
|
transitionEnd,
|
|
5385
5282
|
...target,
|
|
5386
5283
|
};
|
|
5387
|
-
}
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5284
|
+
}
|
|
5285
|
+
}
|
|
5286
|
+
|
|
5287
|
+
function getComputedStyle$1(element) {
|
|
5288
|
+
return window.getComputedStyle(element);
|
|
5289
|
+
}
|
|
5290
|
+
class HTMLVisualElement extends DOMVisualElement {
|
|
5291
|
+
readValueFromInstance(instance, key) {
|
|
5292
|
+
if (transformProps.has(key)) {
|
|
5293
|
+
const defaultType = getDefaultValueType(key);
|
|
5294
|
+
return defaultType ? defaultType.default || 0 : 0;
|
|
5295
|
+
}
|
|
5296
|
+
else {
|
|
5297
|
+
const computedStyle = getComputedStyle$1(instance);
|
|
5298
|
+
const value = (isCSSVariable(key)
|
|
5299
|
+
? computedStyle.getPropertyValue(key)
|
|
5300
|
+
: computedStyle[key]) || 0;
|
|
5301
|
+
return typeof value === "string" ? value.trim() : value;
|
|
5394
5302
|
}
|
|
5303
|
+
}
|
|
5304
|
+
measureInstanceViewportBox(instance, { transformPagePoint }) {
|
|
5305
|
+
return measureViewportBox(instance, transformPagePoint);
|
|
5306
|
+
}
|
|
5307
|
+
build(renderState, latestValues, options, props) {
|
|
5395
5308
|
buildHTMLStyles(renderState, latestValues, options, props.transformTemplate);
|
|
5396
|
-
}
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5309
|
+
}
|
|
5310
|
+
scrapeMotionValuesFromProps(props) {
|
|
5311
|
+
return scrapeMotionValuesFromProps(props);
|
|
5312
|
+
}
|
|
5313
|
+
renderInstance(instance, renderState, styleProp, projection) {
|
|
5314
|
+
renderHTML(instance, renderState, styleProp, projection);
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5400
5317
|
|
|
5401
5318
|
exports.HTMLProjectionNode = HTMLProjectionNode;
|
|
5319
|
+
exports.HTMLVisualElement = HTMLVisualElement;
|
|
5402
5320
|
exports.addScaleCorrector = addScaleCorrector;
|
|
5403
5321
|
exports.animate = animate$1;
|
|
5404
5322
|
exports.buildTransform = buildTransform;
|
|
5405
5323
|
exports.calcBoxDelta = calcBoxDelta;
|
|
5406
5324
|
exports.correctBorderRadius = correctBorderRadius;
|
|
5407
5325
|
exports.correctBoxShadow = correctBoxShadow;
|
|
5408
|
-
exports.htmlVisualElement = htmlVisualElement;
|
|
5409
5326
|
exports.mix = mix;
|
|
5410
5327
|
exports.nodeGroup = nodeGroup;
|
|
5411
5328
|
exports.sync = sync;
|