framer-motion 10.12.8-alpha.2 → 10.12.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/dom-entry.js +1 -1
- package/dist/cjs/{index-legacy-bcb6edf0.js → index-legacy-9f6d433e.js} +5 -5
- package/dist/cjs/index.js +57 -115
- package/dist/es/motion/features/layout/MeasureLayout.mjs +5 -3
- package/dist/es/motion/index.mjs +2 -15
- package/dist/es/projection/node/HTMLProjectionNode.mjs +1 -1
- package/dist/es/projection/node/create-projection-node.mjs +14 -50
- package/dist/es/render/VisualElement.mjs +3 -3
- package/dist/es/render/dom/use-render.mjs +1 -4
- package/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/value/index.mjs +1 -1
- package/dist/framer-motion.dev.js +61 -119
- package/dist/framer-motion.js +1 -1
- package/dist/index.d.ts +3 -5
- package/dist/projection.dev.js +20 -56
- package/dist/three-entry.d.ts +2 -4
- package/package.json +5 -5
- package/dist/es/projection/node/id.mjs +0 -13
package/dist/cjs/dom-entry.js
CHANGED
|
@@ -2645,7 +2645,7 @@ class MotionValue {
|
|
|
2645
2645
|
* This will be replaced by the build step with the latest version number.
|
|
2646
2646
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
2647
2647
|
*/
|
|
2648
|
-
this.version = "10.12.8
|
|
2648
|
+
this.version = "10.12.8";
|
|
2649
2649
|
/**
|
|
2650
2650
|
* Duration, in milliseconds, since last updating frame.
|
|
2651
2651
|
*
|
|
@@ -3817,7 +3817,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
3817
3817
|
* and warn against mismatches.
|
|
3818
3818
|
*/
|
|
3819
3819
|
if (process.env.NODE_ENV === "development") {
|
|
3820
|
-
warnOnce(nextValue.version === "10.12.8
|
|
3820
|
+
warnOnce(nextValue.version === "10.12.8", `Attempting to mix Framer Motion versions ${nextValue.version} with 10.12.8 may not work as expected.`);
|
|
3821
3821
|
}
|
|
3822
3822
|
}
|
|
3823
3823
|
else if (isMotionValue(prevValue)) {
|
|
@@ -3985,7 +3985,7 @@ class VisualElement {
|
|
|
3985
3985
|
mount(instance) {
|
|
3986
3986
|
this.current = instance;
|
|
3987
3987
|
visualElementStore.set(instance, this);
|
|
3988
|
-
if (this.projection) {
|
|
3988
|
+
if (this.projection && !this.projection.instance) {
|
|
3989
3989
|
this.projection.mount(instance);
|
|
3990
3990
|
}
|
|
3991
3991
|
if (this.parent && this.isVariantNode && !this.isControllingVariants) {
|
|
@@ -4051,7 +4051,7 @@ class VisualElement {
|
|
|
4051
4051
|
}
|
|
4052
4052
|
return this.sortInstanceNodePosition(this.current, other.current);
|
|
4053
4053
|
}
|
|
4054
|
-
loadFeatures({ children, ...renderedProps }, isStrict, preloadedFeatures,
|
|
4054
|
+
loadFeatures({ children, ...renderedProps }, isStrict, preloadedFeatures, initialLayoutGroupConfig) {
|
|
4055
4055
|
let ProjectionNodeConstructor;
|
|
4056
4056
|
let MeasureLayout;
|
|
4057
4057
|
/**
|
|
@@ -4081,7 +4081,7 @@ class VisualElement {
|
|
|
4081
4081
|
}
|
|
4082
4082
|
}
|
|
4083
4083
|
if (!this.projection && ProjectionNodeConstructor) {
|
|
4084
|
-
this.projection = new ProjectionNodeConstructor(
|
|
4084
|
+
this.projection = new ProjectionNodeConstructor(this.latestValues, this.parent && this.parent.projection);
|
|
4085
4085
|
const { layoutId, layout, drag, dragConstraints, layoutScroll, layoutRoot, } = renderedProps;
|
|
4086
4086
|
this.projection.setOptions({
|
|
4087
4087
|
layoutId,
|
package/dist/cjs/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var React = require('react');
|
|
6
|
-
var indexLegacy = require('./index-legacy-
|
|
6
|
+
var indexLegacy = require('./index-legacy-9f6d433e.js');
|
|
7
7
|
|
|
8
8
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
9
|
|
|
@@ -160,48 +160,6 @@ function loadFeatures(features) {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
/**
|
|
164
|
-
* Creates a constant value over the lifecycle of a component.
|
|
165
|
-
*
|
|
166
|
-
* Even if `useMemo` is provided an empty array as its final argument, it doesn't offer
|
|
167
|
-
* a guarantee that it won't re-run for performance reasons later on. By using `useConstant`
|
|
168
|
-
* you can ensure that initialisers don't execute twice or more.
|
|
169
|
-
*/
|
|
170
|
-
function useConstant(init) {
|
|
171
|
-
const ref = React.useRef(null);
|
|
172
|
-
if (ref.current === null) {
|
|
173
|
-
ref.current = init();
|
|
174
|
-
}
|
|
175
|
-
return ref.current;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* This should only ever be modified on the client otherwise it'll
|
|
180
|
-
* persist through server requests. If we need instanced states we
|
|
181
|
-
* could lazy-init via root.
|
|
182
|
-
*/
|
|
183
|
-
const globalProjectionState = {
|
|
184
|
-
/**
|
|
185
|
-
* Global flag as to whether the tree has animated since the last time
|
|
186
|
-
* we resized the window
|
|
187
|
-
*/
|
|
188
|
-
hasAnimatedSinceResize: true,
|
|
189
|
-
/**
|
|
190
|
-
* We set this to true once, on the first update. Any nodes added to the tree beyond that
|
|
191
|
-
* update will be given a `data-projection-id` attribute.
|
|
192
|
-
*/
|
|
193
|
-
hasEverUpdated: false,
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
let id$3 = 1;
|
|
197
|
-
function useProjectionId() {
|
|
198
|
-
return useConstant(() => {
|
|
199
|
-
if (globalProjectionState.hasEverUpdated) {
|
|
200
|
-
return id$3++;
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
163
|
const LayoutGroupContext = React.createContext({});
|
|
206
164
|
|
|
207
165
|
/**
|
|
@@ -235,18 +193,6 @@ function createMotionComponent({ preloadedFeatures, createVisualElement, useRend
|
|
|
235
193
|
};
|
|
236
194
|
const { isStatic } = configAndProps;
|
|
237
195
|
const context = useCreateMotionContext(props);
|
|
238
|
-
/**
|
|
239
|
-
* Create a unique projection ID for this component. If a new component is added
|
|
240
|
-
* during a layout animation we'll use this to query the DOM and hydrate its ref early, allowing
|
|
241
|
-
* us to measure it as soon as any layout effect flushes pending layout animations.
|
|
242
|
-
*
|
|
243
|
-
* Performance note: It'd be better not to have to search the DOM for these elements.
|
|
244
|
-
* For newly-entering components it could be enough to only correct treeScale, in which
|
|
245
|
-
* case we could mount in a scale-correction mode. This wouldn't be enough for
|
|
246
|
-
* shared element transitions however. Perhaps for those we could revert to a root node
|
|
247
|
-
* that gets forceRendered and layout animations are triggered on its layout effect.
|
|
248
|
-
*/
|
|
249
|
-
const projectionId = isStatic ? undefined : useProjectionId();
|
|
250
196
|
const visualState = useVisualState(props, isStatic);
|
|
251
197
|
if (!isStatic && indexLegacy.isBrowser) {
|
|
252
198
|
/**
|
|
@@ -265,7 +211,7 @@ function createMotionComponent({ preloadedFeatures, createVisualElement, useRend
|
|
|
265
211
|
if (context.visualElement) {
|
|
266
212
|
MeasureLayout = context.visualElement.loadFeatures(
|
|
267
213
|
// Note: Pass the full new combined props to correctly re-render dynamic feature components.
|
|
268
|
-
configAndProps, isStrict, preloadedFeatures,
|
|
214
|
+
configAndProps, isStrict, preloadedFeatures, initialLayoutGroupConfig);
|
|
269
215
|
}
|
|
270
216
|
}
|
|
271
217
|
/**
|
|
@@ -274,7 +220,7 @@ function createMotionComponent({ preloadedFeatures, createVisualElement, useRend
|
|
|
274
220
|
*/
|
|
275
221
|
return (React__namespace.createElement(MotionContext.Provider, { value: context },
|
|
276
222
|
MeasureLayout && context.visualElement ? (React__namespace.createElement(MeasureLayout, { visualElement: context.visualElement, ...configAndProps })) : null,
|
|
277
|
-
useRender(Component, props,
|
|
223
|
+
useRender(Component, props, useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, context.visualElement)));
|
|
278
224
|
}
|
|
279
225
|
const ForwardRefComponent = React.forwardRef(MotionComponent);
|
|
280
226
|
ForwardRefComponent[motionComponentSymbol] = Component;
|
|
@@ -582,7 +528,7 @@ function useSVGProps(props, visualState, _isStatic, Component) {
|
|
|
582
528
|
}
|
|
583
529
|
|
|
584
530
|
function createUseRender(forwardMotionProps = false) {
|
|
585
|
-
const useRender = (Component, props,
|
|
531
|
+
const useRender = (Component, props, ref, { latestValues }, isStatic) => {
|
|
586
532
|
const useVisualProps = isSVGComponent(Component)
|
|
587
533
|
? useSVGProps
|
|
588
534
|
: useHTMLProps;
|
|
@@ -600,9 +546,6 @@ function createUseRender(forwardMotionProps = false) {
|
|
|
600
546
|
*/
|
|
601
547
|
const { children } = props;
|
|
602
548
|
const renderedChildren = React.useMemo(() => (indexLegacy.isMotionValue(children) ? children.get() : children), [children]);
|
|
603
|
-
if (projectionId) {
|
|
604
|
-
elementProps["data-projection-id"] = projectionId;
|
|
605
|
-
}
|
|
606
549
|
return React.createElement(Component, {
|
|
607
550
|
...elementProps,
|
|
608
551
|
children: renderedChildren,
|
|
@@ -611,6 +554,21 @@ function createUseRender(forwardMotionProps = false) {
|
|
|
611
554
|
return useRender;
|
|
612
555
|
}
|
|
613
556
|
|
|
557
|
+
/**
|
|
558
|
+
* Creates a constant value over the lifecycle of a component.
|
|
559
|
+
*
|
|
560
|
+
* Even if `useMemo` is provided an empty array as its final argument, it doesn't offer
|
|
561
|
+
* a guarantee that it won't re-run for performance reasons later on. By using `useConstant`
|
|
562
|
+
* you can ensure that initialisers don't execute twice or more.
|
|
563
|
+
*/
|
|
564
|
+
function useConstant(init) {
|
|
565
|
+
const ref = React.useRef(null);
|
|
566
|
+
if (ref.current === null) {
|
|
567
|
+
ref.current = init();
|
|
568
|
+
}
|
|
569
|
+
return ref.current;
|
|
570
|
+
}
|
|
571
|
+
|
|
614
572
|
/**
|
|
615
573
|
* If the provided value is a MotionValue, this returns the actual value, otherwise just the value itself
|
|
616
574
|
*
|
|
@@ -2771,6 +2729,24 @@ class FlatTree {
|
|
|
2771
2729
|
}
|
|
2772
2730
|
}
|
|
2773
2731
|
|
|
2732
|
+
/**
|
|
2733
|
+
* This should only ever be modified on the client otherwise it'll
|
|
2734
|
+
* persist through server requests. If we need instanced states we
|
|
2735
|
+
* could lazy-init via root.
|
|
2736
|
+
*/
|
|
2737
|
+
const globalProjectionState = {
|
|
2738
|
+
/**
|
|
2739
|
+
* Global flag as to whether the tree has animated since the last time
|
|
2740
|
+
* we resized the window
|
|
2741
|
+
*/
|
|
2742
|
+
hasAnimatedSinceResize: true,
|
|
2743
|
+
/**
|
|
2744
|
+
* We set this to true once, on the first update. Any nodes added to the tree beyond that
|
|
2745
|
+
* update will be given a `data-projection-id` attribute.
|
|
2746
|
+
*/
|
|
2747
|
+
hasEverUpdated: false,
|
|
2748
|
+
};
|
|
2749
|
+
|
|
2774
2750
|
function record(data) {
|
|
2775
2751
|
if (window.MotionDebug) {
|
|
2776
2752
|
window.MotionDebug.record(data);
|
|
@@ -2796,7 +2772,7 @@ const projectionFrameData = {
|
|
|
2796
2772
|
};
|
|
2797
2773
|
function createProjectionNode({ attachResizeListener, defaultParent, measureScroll, checkIsScrollRoot, resetTransform, }) {
|
|
2798
2774
|
return class ProjectionNode {
|
|
2799
|
-
constructor(
|
|
2775
|
+
constructor(latestValues = {}, parent = defaultParent === null || defaultParent === void 0 ? void 0 : defaultParent()) {
|
|
2800
2776
|
/**
|
|
2801
2777
|
* A unique ID generated for every projection node.
|
|
2802
2778
|
*/
|
|
@@ -2882,8 +2858,9 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
2882
2858
|
*
|
|
2883
2859
|
*/
|
|
2884
2860
|
this.eventHandlers = new Map();
|
|
2861
|
+
this.hasTreeAnimated = false;
|
|
2885
2862
|
// Note: Currently only running on root node
|
|
2886
|
-
this.
|
|
2863
|
+
this.updateScheduled = false;
|
|
2887
2864
|
this.checkUpdateFailed = () => {
|
|
2888
2865
|
if (this.isUpdating) {
|
|
2889
2866
|
this.isUpdating = false;
|
|
@@ -2918,13 +2895,11 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
2918
2895
|
*/
|
|
2919
2896
|
// TODO Only running on root node
|
|
2920
2897
|
this.sharedNodes = new Map();
|
|
2921
|
-
this.elementId = elementId;
|
|
2922
2898
|
this.latestValues = latestValues;
|
|
2923
2899
|
this.root = parent ? parent.root || parent : this;
|
|
2924
2900
|
this.path = parent ? [...parent.path, parent] : [];
|
|
2925
2901
|
this.parent = parent;
|
|
2926
2902
|
this.depth = parent ? parent.depth + 1 : 0;
|
|
2927
|
-
elementId && this.root.registerPotentialNode(elementId, this);
|
|
2928
2903
|
for (let i = 0; i < this.path.length; i++) {
|
|
2929
2904
|
this.path[i].shouldResetTransform = true;
|
|
2930
2905
|
}
|
|
@@ -2944,13 +2919,10 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
2944
2919
|
hasListeners(name) {
|
|
2945
2920
|
return this.eventHandlers.has(name);
|
|
2946
2921
|
}
|
|
2947
|
-
registerPotentialNode(elementId, node) {
|
|
2948
|
-
this.potentialNodes.set(elementId, node);
|
|
2949
|
-
}
|
|
2950
2922
|
/**
|
|
2951
2923
|
* Lifecycles
|
|
2952
2924
|
*/
|
|
2953
|
-
mount(instance, isLayoutDirty =
|
|
2925
|
+
mount(instance, isLayoutDirty = this.root.hasTreeAnimated) {
|
|
2954
2926
|
if (this.instance)
|
|
2955
2927
|
return;
|
|
2956
2928
|
this.isSVG = indexLegacy.isSVGElement(instance);
|
|
@@ -2961,7 +2933,6 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
2961
2933
|
}
|
|
2962
2934
|
this.root.nodes.add(this);
|
|
2963
2935
|
this.parent && this.parent.children.add(this);
|
|
2964
|
-
this.elementId && this.root.potentialNodes.delete(this.elementId);
|
|
2965
2936
|
if (isLayoutDirty && (layout || layoutId)) {
|
|
2966
2937
|
this.isLayoutDirty = true;
|
|
2967
2938
|
}
|
|
@@ -3086,6 +3057,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
3086
3057
|
return visualElement && visualElement.getProps().transformTemplate;
|
|
3087
3058
|
}
|
|
3088
3059
|
willUpdate(shouldNotifyListeners = true) {
|
|
3060
|
+
this.root.hasTreeAnimated = true;
|
|
3089
3061
|
if (this.root.isUpdateBlocked()) {
|
|
3090
3062
|
this.options.onExitComplete && this.options.onExitComplete();
|
|
3091
3063
|
return;
|
|
@@ -3112,8 +3084,8 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
3112
3084
|
this.updateSnapshot();
|
|
3113
3085
|
shouldNotifyListeners && this.notifyListeners("willUpdate");
|
|
3114
3086
|
}
|
|
3115
|
-
|
|
3116
|
-
|
|
3087
|
+
update() {
|
|
3088
|
+
this.updateScheduled = false;
|
|
3117
3089
|
const updateWasBlocked = this.isUpdateBlocked();
|
|
3118
3090
|
// When doing an instant transition, we skip the layout update,
|
|
3119
3091
|
// but should still clean up the measurements so that the next
|
|
@@ -3127,16 +3099,6 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
3127
3099
|
if (!this.isUpdating)
|
|
3128
3100
|
return;
|
|
3129
3101
|
this.isUpdating = false;
|
|
3130
|
-
/**
|
|
3131
|
-
* Search for and mount newly-added projection elements.
|
|
3132
|
-
*
|
|
3133
|
-
* TODO: Every time a new component is rendered we could search up the tree for
|
|
3134
|
-
* the closest mounted node and query from there rather than document.
|
|
3135
|
-
*/
|
|
3136
|
-
if (this.potentialNodes.size) {
|
|
3137
|
-
this.potentialNodes.forEach(mountNodeEarly);
|
|
3138
|
-
this.potentialNodes.clear();
|
|
3139
|
-
}
|
|
3140
3102
|
/**
|
|
3141
3103
|
* Write
|
|
3142
3104
|
*/
|
|
@@ -3157,6 +3119,12 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
3157
3119
|
indexLegacy.steps.preRender.process(indexLegacy.frameData);
|
|
3158
3120
|
indexLegacy.steps.render.process(indexLegacy.frameData);
|
|
3159
3121
|
}
|
|
3122
|
+
didUpdate() {
|
|
3123
|
+
if (!this.updateScheduled) {
|
|
3124
|
+
this.updateScheduled = true;
|
|
3125
|
+
queueMicrotask(() => this.update());
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3160
3128
|
clearAllSnapshots() {
|
|
3161
3129
|
this.nodes.forEach(clearSnapshot);
|
|
3162
3130
|
this.sharedNodes.forEach(removeLeadSnapshots);
|
|
@@ -3183,16 +3151,11 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
3183
3151
|
* Update measurements
|
|
3184
3152
|
*/
|
|
3185
3153
|
updateSnapshot() {
|
|
3186
|
-
var _a, _b;
|
|
3187
3154
|
if (this.snapshot || !this.instance)
|
|
3188
3155
|
return;
|
|
3189
3156
|
this.snapshot = this.measure();
|
|
3190
|
-
if (((_b = (_a = this.instance) === null || _a === void 0 ? void 0 : _a.dataset) === null || _b === void 0 ? void 0 : _b.framerName) === "Top") {
|
|
3191
|
-
console.log("Update snapshot", this.snapshot.measuredBox.y);
|
|
3192
|
-
}
|
|
3193
3157
|
}
|
|
3194
3158
|
updateLayout() {
|
|
3195
|
-
var _a, _b;
|
|
3196
3159
|
if (!this.instance)
|
|
3197
3160
|
return;
|
|
3198
3161
|
// TODO: Incorporate into a forwarded scroll offset
|
|
@@ -3216,9 +3179,6 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
3216
3179
|
}
|
|
3217
3180
|
const prevLayout = this.layout;
|
|
3218
3181
|
this.layout = this.measure(false);
|
|
3219
|
-
if (((_b = (_a = this.instance) === null || _a === void 0 ? void 0 : _a.dataset) === null || _b === void 0 ? void 0 : _b.framerName) === "Top") {
|
|
3220
|
-
console.log("Update layout", this.layout.measuredBox.y);
|
|
3221
|
-
}
|
|
3222
3182
|
this.layoutCorrected = indexLegacy.createBox();
|
|
3223
3183
|
this.isLayoutDirty = false;
|
|
3224
3184
|
this.projectionDelta = undefined;
|
|
@@ -3549,7 +3509,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
3549
3509
|
this.layout);
|
|
3550
3510
|
}
|
|
3551
3511
|
calcProjection() {
|
|
3552
|
-
var _a
|
|
3512
|
+
var _a;
|
|
3553
3513
|
const lead = this.getLead();
|
|
3554
3514
|
const isShared = Boolean(this.resumingFrom) || this !== lead;
|
|
3555
3515
|
let canSkip = true;
|
|
@@ -3575,9 +3535,6 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
3575
3535
|
if (this.resolvedRelativeTargetAt === indexLegacy.frameData.timestamp) {
|
|
3576
3536
|
canSkip = false;
|
|
3577
3537
|
}
|
|
3578
|
-
if (((_c = (_b = this.instance) === null || _b === void 0 ? void 0 : _b.dataset) === null || _c === void 0 ? void 0 : _c.framerName) === "Top") {
|
|
3579
|
-
console.log("Calc projection", canSkip, (_d = this.target) === null || _d === void 0 ? void 0 : _d.y);
|
|
3580
|
-
}
|
|
3581
3538
|
if (canSkip)
|
|
3582
3539
|
return;
|
|
3583
3540
|
const { layout, layoutId } = this.options;
|
|
@@ -4202,23 +4159,6 @@ const defaultLayoutTransition = {
|
|
|
4202
4159
|
duration: 0.45,
|
|
4203
4160
|
ease: [0.4, 0, 0.1, 1],
|
|
4204
4161
|
};
|
|
4205
|
-
function mountNodeEarly(node, elementId) {
|
|
4206
|
-
/**
|
|
4207
|
-
* Rather than searching the DOM from document we can search the
|
|
4208
|
-
* path for the deepest mounted ancestor and search from there
|
|
4209
|
-
*/
|
|
4210
|
-
let searchNode = node.root;
|
|
4211
|
-
for (let i = node.path.length - 1; i >= 0; i--) {
|
|
4212
|
-
if (Boolean(node.path[i].instance)) {
|
|
4213
|
-
searchNode = node.path[i];
|
|
4214
|
-
break;
|
|
4215
|
-
}
|
|
4216
|
-
}
|
|
4217
|
-
const searchElement = searchNode && searchNode !== node.root ? searchNode.instance : document;
|
|
4218
|
-
const element = searchElement.querySelector(`[data-projection-id="${elementId}"]`);
|
|
4219
|
-
if (element)
|
|
4220
|
-
node.mount(element, true);
|
|
4221
|
-
}
|
|
4222
4162
|
function roundAxis(axis) {
|
|
4223
4163
|
axis.min = Math.round(axis.min);
|
|
4224
4164
|
axis.max = Math.round(axis.max);
|
|
@@ -4252,7 +4192,7 @@ const HTMLProjectionNode = createProjectionNode({
|
|
|
4252
4192
|
}),
|
|
4253
4193
|
defaultParent: () => {
|
|
4254
4194
|
if (!rootProjectionNode.current) {
|
|
4255
|
-
const documentNode = new DocumentProjectionNode(
|
|
4195
|
+
const documentNode = new DocumentProjectionNode({});
|
|
4256
4196
|
documentNode.mount(window);
|
|
4257
4197
|
documentNode.setOptions({ layoutScroll: true });
|
|
4258
4198
|
rootProjectionNode.current = documentNode;
|
|
@@ -4491,9 +4431,11 @@ class MeasureLayoutWithContext extends React__default["default"].Component {
|
|
|
4491
4431
|
const { projection } = this.props.visualElement;
|
|
4492
4432
|
if (projection) {
|
|
4493
4433
|
projection.root.didUpdate();
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4434
|
+
queueMicrotask(() => {
|
|
4435
|
+
if (!projection.currentAnimation && projection.isLead()) {
|
|
4436
|
+
this.safeToRemove();
|
|
4437
|
+
}
|
|
4438
|
+
});
|
|
4497
4439
|
}
|
|
4498
4440
|
}
|
|
4499
4441
|
componentWillUnmount() {
|
|
@@ -80,9 +80,11 @@ class MeasureLayoutWithContext extends React__default.Component {
|
|
|
80
80
|
const { projection } = this.props.visualElement;
|
|
81
81
|
if (projection) {
|
|
82
82
|
projection.root.didUpdate();
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
queueMicrotask(() => {
|
|
84
|
+
if (!projection.currentAnimation && projection.isLead()) {
|
|
85
|
+
this.safeToRemove();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
componentWillUnmount() {
|
package/dist/es/motion/index.mjs
CHANGED
|
@@ -7,7 +7,6 @@ import { useMotionRef } from './utils/use-motion-ref.mjs';
|
|
|
7
7
|
import { useCreateMotionContext } from '../context/MotionContext/create.mjs';
|
|
8
8
|
import { loadFeatures } from './features/load-features.mjs';
|
|
9
9
|
import { isBrowser } from '../utils/is-browser.mjs';
|
|
10
|
-
import { useProjectionId } from '../projection/node/id.mjs';
|
|
11
10
|
import { LayoutGroupContext } from '../context/LayoutGroupContext.mjs';
|
|
12
11
|
import { LazyContext } from '../context/LazyContext.mjs';
|
|
13
12
|
import { SwitchLayoutGroupContext } from '../context/SwitchLayoutGroupContext.mjs';
|
|
@@ -37,18 +36,6 @@ function createMotionComponent({ preloadedFeatures, createVisualElement, useRend
|
|
|
37
36
|
};
|
|
38
37
|
const { isStatic } = configAndProps;
|
|
39
38
|
const context = useCreateMotionContext(props);
|
|
40
|
-
/**
|
|
41
|
-
* Create a unique projection ID for this component. If a new component is added
|
|
42
|
-
* during a layout animation we'll use this to query the DOM and hydrate its ref early, allowing
|
|
43
|
-
* us to measure it as soon as any layout effect flushes pending layout animations.
|
|
44
|
-
*
|
|
45
|
-
* Performance note: It'd be better not to have to search the DOM for these elements.
|
|
46
|
-
* For newly-entering components it could be enough to only correct treeScale, in which
|
|
47
|
-
* case we could mount in a scale-correction mode. This wouldn't be enough for
|
|
48
|
-
* shared element transitions however. Perhaps for those we could revert to a root node
|
|
49
|
-
* that gets forceRendered and layout animations are triggered on its layout effect.
|
|
50
|
-
*/
|
|
51
|
-
const projectionId = isStatic ? undefined : useProjectionId();
|
|
52
39
|
const visualState = useVisualState(props, isStatic);
|
|
53
40
|
if (!isStatic && isBrowser) {
|
|
54
41
|
/**
|
|
@@ -67,7 +54,7 @@ function createMotionComponent({ preloadedFeatures, createVisualElement, useRend
|
|
|
67
54
|
if (context.visualElement) {
|
|
68
55
|
MeasureLayout = context.visualElement.loadFeatures(
|
|
69
56
|
// Note: Pass the full new combined props to correctly re-render dynamic feature components.
|
|
70
|
-
configAndProps, isStrict, preloadedFeatures,
|
|
57
|
+
configAndProps, isStrict, preloadedFeatures, initialLayoutGroupConfig);
|
|
71
58
|
}
|
|
72
59
|
}
|
|
73
60
|
/**
|
|
@@ -76,7 +63,7 @@ function createMotionComponent({ preloadedFeatures, createVisualElement, useRend
|
|
|
76
63
|
*/
|
|
77
64
|
return (React.createElement(MotionContext.Provider, { value: context },
|
|
78
65
|
MeasureLayout && context.visualElement ? (React.createElement(MeasureLayout, { visualElement: context.visualElement, ...configAndProps })) : null,
|
|
79
|
-
useRender(Component, props,
|
|
66
|
+
useRender(Component, props, useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, context.visualElement)));
|
|
80
67
|
}
|
|
81
68
|
const ForwardRefComponent = forwardRef(MotionComponent);
|
|
82
69
|
ForwardRefComponent[motionComponentSymbol] = Component;
|
|
@@ -11,7 +11,7 @@ const HTMLProjectionNode = createProjectionNode({
|
|
|
11
11
|
}),
|
|
12
12
|
defaultParent: () => {
|
|
13
13
|
if (!rootProjectionNode.current) {
|
|
14
|
-
const documentNode = new DocumentProjectionNode(
|
|
14
|
+
const documentNode = new DocumentProjectionNode({});
|
|
15
15
|
documentNode.mount(window);
|
|
16
16
|
documentNode.setOptions({ layoutScroll: true });
|
|
17
17
|
rootProjectionNode.current = documentNode;
|
|
@@ -42,7 +42,7 @@ const projectionFrameData = {
|
|
|
42
42
|
};
|
|
43
43
|
function createProjectionNode({ attachResizeListener, defaultParent, measureScroll, checkIsScrollRoot, resetTransform, }) {
|
|
44
44
|
return class ProjectionNode {
|
|
45
|
-
constructor(
|
|
45
|
+
constructor(latestValues = {}, parent = defaultParent === null || defaultParent === void 0 ? void 0 : defaultParent()) {
|
|
46
46
|
/**
|
|
47
47
|
* A unique ID generated for every projection node.
|
|
48
48
|
*/
|
|
@@ -128,8 +128,9 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
128
128
|
*
|
|
129
129
|
*/
|
|
130
130
|
this.eventHandlers = new Map();
|
|
131
|
+
this.hasTreeAnimated = false;
|
|
131
132
|
// Note: Currently only running on root node
|
|
132
|
-
this.
|
|
133
|
+
this.updateScheduled = false;
|
|
133
134
|
this.checkUpdateFailed = () => {
|
|
134
135
|
if (this.isUpdating) {
|
|
135
136
|
this.isUpdating = false;
|
|
@@ -164,13 +165,11 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
164
165
|
*/
|
|
165
166
|
// TODO Only running on root node
|
|
166
167
|
this.sharedNodes = new Map();
|
|
167
|
-
this.elementId = elementId;
|
|
168
168
|
this.latestValues = latestValues;
|
|
169
169
|
this.root = parent ? parent.root || parent : this;
|
|
170
170
|
this.path = parent ? [...parent.path, parent] : [];
|
|
171
171
|
this.parent = parent;
|
|
172
172
|
this.depth = parent ? parent.depth + 1 : 0;
|
|
173
|
-
elementId && this.root.registerPotentialNode(elementId, this);
|
|
174
173
|
for (let i = 0; i < this.path.length; i++) {
|
|
175
174
|
this.path[i].shouldResetTransform = true;
|
|
176
175
|
}
|
|
@@ -190,13 +189,10 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
190
189
|
hasListeners(name) {
|
|
191
190
|
return this.eventHandlers.has(name);
|
|
192
191
|
}
|
|
193
|
-
registerPotentialNode(elementId, node) {
|
|
194
|
-
this.potentialNodes.set(elementId, node);
|
|
195
|
-
}
|
|
196
192
|
/**
|
|
197
193
|
* Lifecycles
|
|
198
194
|
*/
|
|
199
|
-
mount(instance, isLayoutDirty =
|
|
195
|
+
mount(instance, isLayoutDirty = this.root.hasTreeAnimated) {
|
|
200
196
|
if (this.instance)
|
|
201
197
|
return;
|
|
202
198
|
this.isSVG = isSVGElement(instance);
|
|
@@ -207,7 +203,6 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
207
203
|
}
|
|
208
204
|
this.root.nodes.add(this);
|
|
209
205
|
this.parent && this.parent.children.add(this);
|
|
210
|
-
this.elementId && this.root.potentialNodes.delete(this.elementId);
|
|
211
206
|
if (isLayoutDirty && (layout || layoutId)) {
|
|
212
207
|
this.isLayoutDirty = true;
|
|
213
208
|
}
|
|
@@ -332,6 +327,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
332
327
|
return visualElement && visualElement.getProps().transformTemplate;
|
|
333
328
|
}
|
|
334
329
|
willUpdate(shouldNotifyListeners = true) {
|
|
330
|
+
this.root.hasTreeAnimated = true;
|
|
335
331
|
if (this.root.isUpdateBlocked()) {
|
|
336
332
|
this.options.onExitComplete && this.options.onExitComplete();
|
|
337
333
|
return;
|
|
@@ -358,8 +354,8 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
358
354
|
this.updateSnapshot();
|
|
359
355
|
shouldNotifyListeners && this.notifyListeners("willUpdate");
|
|
360
356
|
}
|
|
361
|
-
|
|
362
|
-
|
|
357
|
+
update() {
|
|
358
|
+
this.updateScheduled = false;
|
|
363
359
|
const updateWasBlocked = this.isUpdateBlocked();
|
|
364
360
|
// When doing an instant transition, we skip the layout update,
|
|
365
361
|
// but should still clean up the measurements so that the next
|
|
@@ -373,16 +369,6 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
373
369
|
if (!this.isUpdating)
|
|
374
370
|
return;
|
|
375
371
|
this.isUpdating = false;
|
|
376
|
-
/**
|
|
377
|
-
* Search for and mount newly-added projection elements.
|
|
378
|
-
*
|
|
379
|
-
* TODO: Every time a new component is rendered we could search up the tree for
|
|
380
|
-
* the closest mounted node and query from there rather than document.
|
|
381
|
-
*/
|
|
382
|
-
if (this.potentialNodes.size) {
|
|
383
|
-
this.potentialNodes.forEach(mountNodeEarly);
|
|
384
|
-
this.potentialNodes.clear();
|
|
385
|
-
}
|
|
386
372
|
/**
|
|
387
373
|
* Write
|
|
388
374
|
*/
|
|
@@ -403,6 +389,12 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
403
389
|
steps.preRender.process(frameData);
|
|
404
390
|
steps.render.process(frameData);
|
|
405
391
|
}
|
|
392
|
+
didUpdate() {
|
|
393
|
+
if (!this.updateScheduled) {
|
|
394
|
+
this.updateScheduled = true;
|
|
395
|
+
queueMicrotask(() => this.update());
|
|
396
|
+
}
|
|
397
|
+
}
|
|
406
398
|
clearAllSnapshots() {
|
|
407
399
|
this.nodes.forEach(clearSnapshot);
|
|
408
400
|
this.sharedNodes.forEach(removeLeadSnapshots);
|
|
@@ -429,16 +421,11 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
429
421
|
* Update measurements
|
|
430
422
|
*/
|
|
431
423
|
updateSnapshot() {
|
|
432
|
-
var _a, _b;
|
|
433
424
|
if (this.snapshot || !this.instance)
|
|
434
425
|
return;
|
|
435
426
|
this.snapshot = this.measure();
|
|
436
|
-
if (((_b = (_a = this.instance) === null || _a === void 0 ? void 0 : _a.dataset) === null || _b === void 0 ? void 0 : _b.framerName) === "Top") {
|
|
437
|
-
console.log("Update snapshot", this.snapshot.measuredBox.y);
|
|
438
|
-
}
|
|
439
427
|
}
|
|
440
428
|
updateLayout() {
|
|
441
|
-
var _a, _b;
|
|
442
429
|
if (!this.instance)
|
|
443
430
|
return;
|
|
444
431
|
// TODO: Incorporate into a forwarded scroll offset
|
|
@@ -462,9 +449,6 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
462
449
|
}
|
|
463
450
|
const prevLayout = this.layout;
|
|
464
451
|
this.layout = this.measure(false);
|
|
465
|
-
if (((_b = (_a = this.instance) === null || _a === void 0 ? void 0 : _a.dataset) === null || _b === void 0 ? void 0 : _b.framerName) === "Top") {
|
|
466
|
-
console.log("Update layout", this.layout.measuredBox.y);
|
|
467
|
-
}
|
|
468
452
|
this.layoutCorrected = createBox();
|
|
469
453
|
this.isLayoutDirty = false;
|
|
470
454
|
this.projectionDelta = undefined;
|
|
@@ -795,7 +779,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
795
779
|
this.layout);
|
|
796
780
|
}
|
|
797
781
|
calcProjection() {
|
|
798
|
-
var _a
|
|
782
|
+
var _a;
|
|
799
783
|
const lead = this.getLead();
|
|
800
784
|
const isShared = Boolean(this.resumingFrom) || this !== lead;
|
|
801
785
|
let canSkip = true;
|
|
@@ -821,9 +805,6 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
821
805
|
if (this.resolvedRelativeTargetAt === frameData.timestamp) {
|
|
822
806
|
canSkip = false;
|
|
823
807
|
}
|
|
824
|
-
if (((_c = (_b = this.instance) === null || _b === void 0 ? void 0 : _b.dataset) === null || _c === void 0 ? void 0 : _c.framerName) === "Top") {
|
|
825
|
-
console.log("Calc projection", canSkip, (_d = this.target) === null || _d === void 0 ? void 0 : _d.y);
|
|
826
|
-
}
|
|
827
808
|
if (canSkip)
|
|
828
809
|
return;
|
|
829
810
|
const { layout, layoutId } = this.options;
|
|
@@ -1448,23 +1429,6 @@ const defaultLayoutTransition = {
|
|
|
1448
1429
|
duration: 0.45,
|
|
1449
1430
|
ease: [0.4, 0, 0.1, 1],
|
|
1450
1431
|
};
|
|
1451
|
-
function mountNodeEarly(node, elementId) {
|
|
1452
|
-
/**
|
|
1453
|
-
* Rather than searching the DOM from document we can search the
|
|
1454
|
-
* path for the deepest mounted ancestor and search from there
|
|
1455
|
-
*/
|
|
1456
|
-
let searchNode = node.root;
|
|
1457
|
-
for (let i = node.path.length - 1; i >= 0; i--) {
|
|
1458
|
-
if (Boolean(node.path[i].instance)) {
|
|
1459
|
-
searchNode = node.path[i];
|
|
1460
|
-
break;
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1463
|
-
const searchElement = searchNode && searchNode !== node.root ? searchNode.instance : document;
|
|
1464
|
-
const element = searchElement.querySelector(`[data-projection-id="${elementId}"]`);
|
|
1465
|
-
if (element)
|
|
1466
|
-
node.mount(element, true);
|
|
1467
|
-
}
|
|
1468
1432
|
function roundAxis(axis) {
|
|
1469
1433
|
axis.min = Math.round(axis.min);
|
|
1470
1434
|
axis.max = Math.round(axis.max);
|