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.
Files changed (39) hide show
  1. package/dist/cjs/index.js +789 -850
  2. package/dist/es/animation/use-animated-state.mjs +29 -17
  3. package/dist/es/gestures/drag/VisualElementDragControls.mjs +14 -10
  4. package/dist/es/gestures/use-focus-gesture.mjs +1 -1
  5. package/dist/es/gestures/use-tap-gesture.mjs +1 -1
  6. package/dist/es/index.mjs +1 -1
  7. package/dist/es/motion/features/viewport/use-viewport.mjs +2 -2
  8. package/dist/es/motion/utils/use-visual-element.mjs +3 -3
  9. package/dist/es/projection/node/create-projection-node.mjs +74 -60
  10. package/dist/es/render/VisualElement.mjs +480 -0
  11. package/dist/es/render/dom/DOMVisualElement.mjs +49 -0
  12. package/dist/es/render/dom/create-visual-element.mjs +4 -4
  13. package/dist/es/render/dom/utils/css-variables-conversion.mjs +2 -2
  14. package/dist/es/render/dom/utils/unit-conversion.mjs +4 -4
  15. package/dist/es/render/html/HTMLVisualElement.mjs +41 -0
  16. package/dist/es/render/svg/{visual-element.mjs → SVGVisualElement.mjs} +21 -15
  17. package/dist/es/render/utils/animation.mjs +4 -4
  18. package/dist/es/render/utils/motion-values.mjs +1 -1
  19. package/dist/es/render/utils/resolve-dynamic-variants.mjs +2 -2
  20. package/dist/es/render/utils/setters.mjs +2 -1
  21. package/dist/es/value/index.mjs +1 -1
  22. package/dist/framer-motion.dev.js +789 -850
  23. package/dist/framer-motion.js +1 -1
  24. package/dist/index.d.ts +2101 -1931
  25. package/dist/projection.dev.js +1053 -1136
  26. package/dist/size-rollup-dom-animation-m.js +1 -1
  27. package/dist/size-rollup-dom-animation.js +1 -1
  28. package/dist/size-rollup-dom-max-assets.js +1 -1
  29. package/dist/size-rollup-dom-max.js +1 -1
  30. package/dist/size-rollup-m.js +1 -1
  31. package/dist/size-rollup-motion.js +1 -1
  32. package/dist/size-webpack-dom-animation.js +1 -1
  33. package/dist/size-webpack-dom-max.js +1 -1
  34. package/dist/size-webpack-m.js +1 -1
  35. package/dist/three-entry.d.ts +1956 -1745
  36. package/package.json +8 -8
  37. package/dist/es/render/html/visual-element.mjs +0 -109
  38. package/dist/es/render/index.mjs +0 -515
  39. package/dist/es/render/utils/lifecycles.mjs +0 -43
package/dist/cjs/index.js CHANGED
@@ -63,7 +63,7 @@ function useVisualElement(Component, visualState, props, createVisualElement) {
63
63
  const lazyContext = React.useContext(LazyContext);
64
64
  const presenceContext = React.useContext(PresenceContext);
65
65
  const reducedMotionConfig = React.useContext(MotionConfigContext).reducedMotion;
66
- const visualElementRef = React.useRef(undefined);
66
+ const visualElementRef = React.useRef();
67
67
  /**
68
68
  * If we haven't preloaded a renderer, check to see if we have one lazy-loaded
69
69
  */
@@ -82,14 +82,14 @@ function useVisualElement(Component, visualState, props, createVisualElement) {
82
82
  }
83
83
  const visualElement = visualElementRef.current;
84
84
  useIsomorphicLayoutEffect(() => {
85
- visualElement && visualElement.syncRender();
85
+ visualElement && visualElement.render();
86
86
  });
87
87
  React.useEffect(() => {
88
88
  if (visualElement && visualElement.animationState) {
89
89
  visualElement.animationState.animateChanges();
90
90
  }
91
91
  });
92
- useIsomorphicLayoutEffect(() => () => visualElement && visualElement.notifyUnmount(), []);
92
+ useIsomorphicLayoutEffect(() => () => visualElement && visualElement.notify("Unmount"), []);
93
93
  return visualElement;
94
94
  }
95
95
 
@@ -1294,7 +1294,7 @@ function useDomEvent(ref, eventName, handler, options) {
1294
1294
  * @param ref
1295
1295
  * @internal
1296
1296
  */
1297
- function useFocusGesture({ whileFocus, visualElement }) {
1297
+ function useFocusGesture({ whileFocus, visualElement, }) {
1298
1298
  const { animationState } = visualElement;
1299
1299
  const onFocus = () => {
1300
1300
  animationState && animationState.setActive(exports.AnimationType.Focus, true);
@@ -1530,7 +1530,7 @@ function useTapGesture({ onTap, onTapStart, onTapCancel, whileTap, visualElement
1530
1530
  * We only count this as a tap gesture if the event.target is the same
1531
1531
  * as, or a child of, this component's element
1532
1532
  */
1533
- !isNodeOrChild(visualElement.getInstance(), event.target)
1533
+ !isNodeOrChild(visualElement.current, event.target)
1534
1534
  ? onTapCancel && onTapCancel(event, info)
1535
1535
  : onTap && onTap(event, info);
1536
1536
  }
@@ -1641,7 +1641,7 @@ const thresholdNames = {
1641
1641
  };
1642
1642
  function useIntersectionObserver(shouldObserve, state, visualElement, { root, margin: rootMargin, amount = "some", once }) {
1643
1643
  React.useEffect(() => {
1644
- if (!shouldObserve)
1644
+ if (!shouldObserve || !visualElement.current)
1645
1645
  return;
1646
1646
  const options = {
1647
1647
  root: root === null || root === void 0 ? void 0 : root.current,
@@ -1679,7 +1679,7 @@ function useIntersectionObserver(shouldObserve, state, visualElement, { root, ma
1679
1679
  : props.onViewportLeave;
1680
1680
  callback && callback(entry);
1681
1681
  };
1682
- return observeIntersection(visualElement.getInstance(), options, intersectionCallback);
1682
+ return observeIntersection(visualElement.current, options, intersectionCallback);
1683
1683
  }, [shouldObserve, root, rootMargin, amount]);
1684
1684
  }
1685
1685
  /**
@@ -2258,7 +2258,7 @@ class MotionValue {
2258
2258
  * This will be replaced by the build step with the latest version number.
2259
2259
  * When MotionValues are provided to motion components, warn if versions are mixed.
2260
2260
  */
2261
- this.version = "7.6.4";
2261
+ this.version = "7.6.6";
2262
2262
  /**
2263
2263
  * Duration, in milliseconds, since last updating frame.
2264
2264
  *
@@ -2572,7 +2572,7 @@ const findValueType = (v) => valueTypes.find(testValueType(v));
2572
2572
  */
2573
2573
  function getCurrent(visualElement) {
2574
2574
  const current = {};
2575
- visualElement.forEachValue((value, key) => (current[key] = value.get()));
2575
+ visualElement.values.forEach((value, key) => (current[key] = value.get()));
2576
2576
  return current;
2577
2577
  }
2578
2578
  /**
@@ -2580,7 +2580,7 @@ function getCurrent(visualElement) {
2580
2580
  */
2581
2581
  function getVelocity$1(visualElement) {
2582
2582
  const velocity = {};
2583
- visualElement.forEachValue((value, key) => (velocity[key] = value.getVelocity()));
2583
+ visualElement.values.forEach((value, key) => (velocity[key] = value.getVelocity()));
2584
2584
  return velocity;
2585
2585
  }
2586
2586
  function resolveVariant(visualElement, definition, custom) {
@@ -2674,7 +2674,8 @@ function checkTargetForNewValues(visualElement, target, origin) {
2674
2674
  if (origin[key] === undefined) {
2675
2675
  origin[key] = value;
2676
2676
  }
2677
- visualElement.setBaseTarget(key, value);
2677
+ if (value !== null)
2678
+ visualElement.setBaseTarget(key, value);
2678
2679
  }
2679
2680
  }
2680
2681
  function getOriginFromTransition(key, transition) {
@@ -2701,7 +2702,7 @@ function isWillChangeMotionValue(value) {
2701
2702
  }
2702
2703
 
2703
2704
  function animateVisualElement(visualElement, definition, options = {}) {
2704
- visualElement.notifyAnimationStart(definition);
2705
+ visualElement.notify("AnimationStart", definition);
2705
2706
  let animation;
2706
2707
  if (Array.isArray(definition)) {
2707
2708
  const animations = definition.map((variant) => animateVariant(visualElement, variant, options));
@@ -2716,7 +2717,7 @@ function animateVisualElement(visualElement, definition, options = {}) {
2716
2717
  : definition;
2717
2718
  animation = animateTarget(visualElement, resolvedDefinition, options);
2718
2719
  }
2719
- return animation.then(() => visualElement.notifyAnimationComplete(definition));
2720
+ return animation.then(() => visualElement.notify("AnimationComplete", definition));
2720
2721
  }
2721
2722
  function animateVariant(visualElement, variant, options = {}) {
2722
2723
  var _a;
@@ -2811,12 +2812,12 @@ function animateChildren(visualElement, variant, delayChildren = 0, staggerChild
2811
2812
  animations.push(animateVariant(child, variant, {
2812
2813
  ...options,
2813
2814
  delay: delayChildren + generateStaggerDuration(i),
2814
- }).then(() => child.notifyAnimationComplete(variant)));
2815
+ }).then(() => child.notify("AnimationComplete", variant)));
2815
2816
  });
2816
2817
  return Promise.all(animations);
2817
2818
  }
2818
2819
  function stopAnimation(visualElement) {
2819
- visualElement.forEachValue((value) => value.stop());
2820
+ visualElement.values.forEach((value) => value.stop());
2820
2821
  }
2821
2822
  function sortByTreeOrder(a, b) {
2822
2823
  return a.sortNodePosition(b);
@@ -3737,7 +3738,7 @@ class VisualElementDragControls {
3737
3738
  * If the MotionValue is a percentage value convert to px
3738
3739
  */
3739
3740
  if (styleValueTypes.percent.test(current)) {
3740
- const measuredAxis = (_b = (_a = this.visualElement.projection) === null || _a === void 0 ? void 0 : _a.layout) === null || _b === void 0 ? void 0 : _b.actual[axis];
3741
+ const measuredAxis = (_b = (_a = this.visualElement.projection) === null || _a === void 0 ? void 0 : _a.layout) === null || _b === void 0 ? void 0 : _b.layoutBox[axis];
3741
3742
  if (measuredAxis) {
3742
3743
  const length = calcLength(measuredAxis);
3743
3744
  current = length * (parseFloat(current) / 100);
@@ -3774,9 +3775,9 @@ class VisualElementDragControls {
3774
3775
  * of a re-render we want to ensure the browser can read the latest
3775
3776
  * bounding box to ensure the pointer and element don't fall out of sync.
3776
3777
  */
3777
- this.visualElement.syncRender();
3778
+ this.visualElement.render();
3778
3779
  /**
3779
- * This must fire after the syncRender call as it might trigger a state
3780
+ * This must fire after the render call as it might trigger a state
3780
3781
  * change which itself might trigger a layout update.
3781
3782
  */
3782
3783
  onDrag === null || onDrag === void 0 ? void 0 : onDrag(event, info);
@@ -3838,7 +3839,7 @@ class VisualElementDragControls {
3838
3839
  }
3839
3840
  else {
3840
3841
  if (dragConstraints && layout) {
3841
- this.constraints = calcRelativeConstraints(layout.actual, dragConstraints);
3842
+ this.constraints = calcRelativeConstraints(layout.layoutBox, dragConstraints);
3842
3843
  }
3843
3844
  else {
3844
3845
  this.constraints = false;
@@ -3855,7 +3856,7 @@ class VisualElementDragControls {
3855
3856
  !this.hasMutatedConstraints) {
3856
3857
  eachAxis((axis) => {
3857
3858
  if (this.getAxisMotionValue(axis)) {
3858
- this.constraints[axis] = rebaseAxisConstraints(layout.actual[axis], this.constraints[axis]);
3859
+ this.constraints[axis] = rebaseAxisConstraints(layout.layoutBox[axis], this.constraints[axis]);
3859
3860
  }
3860
3861
  });
3861
3862
  }
@@ -3871,7 +3872,7 @@ class VisualElementDragControls {
3871
3872
  if (!projection || !projection.layout)
3872
3873
  return false;
3873
3874
  const constraintsBox = measurePageBox(constraintsElement, projection.root, this.visualElement.getTransformPagePoint());
3874
- let measuredConstraints = calcViewportConstraints(projection.layout.actual, constraintsBox);
3875
+ let measuredConstraints = calcViewportConstraints(projection.layout.layoutBox, constraintsBox);
3875
3876
  /**
3876
3877
  * If there's an onMeasureDragConstraints listener we call it and
3877
3878
  * if different constraints are returned, set constraints to that
@@ -3953,7 +3954,7 @@ class VisualElementDragControls {
3953
3954
  const { projection } = this.visualElement;
3954
3955
  const axisValue = this.getAxisMotionValue(axis);
3955
3956
  if (projection && projection.layout) {
3956
- const { min, max } = projection.layout.actual[axis];
3957
+ const { min, max } = projection.layout.layoutBox[axis];
3957
3958
  axisValue.set(point[axis] - popmotion.mix(min, max, 0.5));
3958
3959
  }
3959
3960
  });
@@ -3965,6 +3966,8 @@ class VisualElementDragControls {
3965
3966
  */
3966
3967
  scalePositionWithinConstraints() {
3967
3968
  var _a;
3969
+ if (!this.visualElement.current)
3970
+ return;
3968
3971
  const { drag, dragConstraints } = this.getProps();
3969
3972
  const { projection } = this.visualElement;
3970
3973
  if (!isRefObject(dragConstraints) || !projection || !this.constraints)
@@ -3990,7 +3993,7 @@ class VisualElementDragControls {
3990
3993
  * Update the layout of this element and resolve the latest drag constraints
3991
3994
  */
3992
3995
  const { transformTemplate } = this.visualElement.getProps();
3993
- this.visualElement.getInstance().style.transform = transformTemplate
3996
+ this.visualElement.current.style.transform = transformTemplate
3994
3997
  ? transformTemplate({}, "")
3995
3998
  : "none";
3996
3999
  (_a = projection.root) === null || _a === void 0 ? void 0 : _a.updateScroll();
@@ -4013,8 +4016,10 @@ class VisualElementDragControls {
4013
4016
  }
4014
4017
  addListeners() {
4015
4018
  var _a;
4019
+ if (!this.visualElement.current)
4020
+ return;
4016
4021
  elementDragControls.set(this.visualElement, this);
4017
- const element = this.visualElement.getInstance();
4022
+ const element = this.visualElement.current;
4018
4023
  /**
4019
4024
  * Attach a pointerdown event listener on this DOM element to initiate drag tracking.
4020
4025
  */
@@ -4053,7 +4058,7 @@ class VisualElementDragControls {
4053
4058
  this.originPoint[axis] += delta[axis].translate;
4054
4059
  motionValue.set(motionValue.get() + delta[axis].translate);
4055
4060
  });
4056
- this.visualElement.syncRender();
4061
+ this.visualElement.render();
4057
4062
  }
4058
4063
  }));
4059
4064
  return () => {
@@ -4158,618 +4163,6 @@ const drag = {
4158
4163
  drag: makeRenderlessComponent(useDrag),
4159
4164
  };
4160
4165
 
4161
- // Does this device prefer reduced motion? Returns `null` server-side.
4162
- const prefersReducedMotion = { current: null };
4163
- const hasReducedMotionListener = { current: false };
4164
-
4165
- function initPrefersReducedMotion() {
4166
- hasReducedMotionListener.current = true;
4167
- if (!isBrowser)
4168
- return;
4169
- if (window.matchMedia) {
4170
- const motionMediaQuery = window.matchMedia("(prefers-reduced-motion)");
4171
- const setReducedMotionPreferences = () => (prefersReducedMotion.current = motionMediaQuery.matches);
4172
- motionMediaQuery.addListener(setReducedMotionPreferences);
4173
- setReducedMotionPreferences();
4174
- }
4175
- else {
4176
- prefersReducedMotion.current = false;
4177
- }
4178
- }
4179
-
4180
- const names = [
4181
- "LayoutMeasure",
4182
- "BeforeLayoutMeasure",
4183
- "LayoutUpdate",
4184
- "ViewportBoxUpdate",
4185
- "Update",
4186
- "Render",
4187
- "AnimationComplete",
4188
- "LayoutAnimationComplete",
4189
- "AnimationStart",
4190
- "LayoutAnimationStart",
4191
- "SetAxisTarget",
4192
- "Unmount",
4193
- ];
4194
- function createLifecycles() {
4195
- const managers = names.map(() => new SubscriptionManager());
4196
- const propSubscriptions = {};
4197
- const lifecycles = {
4198
- clearAllListeners: () => managers.forEach((manager) => manager.clear()),
4199
- updatePropListeners: (props) => {
4200
- names.forEach((name) => {
4201
- var _a;
4202
- const on = "on" + name;
4203
- const propListener = props[on];
4204
- // Unsubscribe existing subscription
4205
- (_a = propSubscriptions[name]) === null || _a === void 0 ? void 0 : _a.call(propSubscriptions);
4206
- // Add new subscription
4207
- if (propListener) {
4208
- propSubscriptions[name] = lifecycles[on](propListener);
4209
- }
4210
- });
4211
- },
4212
- };
4213
- managers.forEach((manager, i) => {
4214
- lifecycles["on" + names[i]] = (handler) => manager.add(handler);
4215
- lifecycles["notify" + names[i]] = (...args) => manager.notify(...args);
4216
- });
4217
- return lifecycles;
4218
- }
4219
-
4220
- function updateMotionValuesFromProps(element, next, prev) {
4221
- const { willChange } = next;
4222
- for (const key in next) {
4223
- const nextValue = next[key];
4224
- const prevValue = prev[key];
4225
- if (isMotionValue(nextValue)) {
4226
- /**
4227
- * If this is a motion value found in props or style, we want to add it
4228
- * to our visual element's motion value map.
4229
- */
4230
- element.addValue(key, nextValue);
4231
- if (isWillChangeMotionValue(willChange)) {
4232
- willChange.add(key);
4233
- }
4234
- /**
4235
- * Check the version of the incoming motion value with this version
4236
- * and warn against mismatches.
4237
- */
4238
- if (process.env.NODE_ENV === "development") {
4239
- warnOnce(nextValue.version === "7.6.4", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.6.4 may not work as expected.`);
4240
- }
4241
- }
4242
- else if (isMotionValue(prevValue)) {
4243
- /**
4244
- * If we're swapping from a motion value to a static value,
4245
- * create a new motion value from that
4246
- */
4247
- element.addValue(key, motionValue(nextValue));
4248
- if (isWillChangeMotionValue(willChange)) {
4249
- willChange.remove(key);
4250
- }
4251
- }
4252
- else if (prevValue !== nextValue) {
4253
- /**
4254
- * If this is a flat value that has changed, update the motion value
4255
- * or create one if it doesn't exist. We only want to do this if we're
4256
- * not handling the value with our animation state.
4257
- */
4258
- if (element.hasValue(key)) {
4259
- const existingValue = element.getValue(key);
4260
- // TODO: Only update values that aren't being animated or even looked at
4261
- !existingValue.hasAnimated && existingValue.set(nextValue);
4262
- }
4263
- else {
4264
- const latestValue = element.getStaticValue(key);
4265
- element.addValue(key, motionValue(latestValue !== undefined ? latestValue : nextValue));
4266
- }
4267
- }
4268
- }
4269
- // Handle removed values
4270
- for (const key in prev) {
4271
- if (next[key] === undefined)
4272
- element.removeValue(key);
4273
- }
4274
- return next;
4275
- }
4276
-
4277
- const featureNames = Object.keys(featureDefinitions);
4278
- const numFeatures = featureNames.length;
4279
- const visualElement = ({ treeType = "", build, getBaseTarget, makeTargetAnimatable, measureViewportBox, render: renderInstance, readValueFromInstance, removeValueFromRenderState, sortNodePosition, scrapeMotionValuesFromProps, }) => ({ parent, props, presenceId, blockInitialAnimation, visualState, reducedMotionConfig, }, options = {}) => {
4280
- let isMounted = false;
4281
- const { latestValues, renderState } = visualState;
4282
- /**
4283
- * The instance of the render-specific node that will be hydrated by the
4284
- * exposed React ref. So for example, this visual element can host a
4285
- * HTMLElement, plain object, or Three.js object. The functions provided
4286
- * in VisualElementConfig allow us to interface with this instance.
4287
- */
4288
- let instance;
4289
- /**
4290
- * Manages the subscriptions for a visual element's lifecycle, for instance
4291
- * onRender
4292
- */
4293
- const lifecycles = createLifecycles();
4294
- /**
4295
- * A map of all motion values attached to this visual element. Motion
4296
- * values are source of truth for any given animated value. A motion
4297
- * value might be provided externally by the component via props.
4298
- */
4299
- const values = new Map();
4300
- /**
4301
- * A map of every subscription that binds the provided or generated
4302
- * motion values onChange listeners to this visual element.
4303
- */
4304
- const valueSubscriptions = new Map();
4305
- /**
4306
- * A reference to the previously-provided motion values as returned
4307
- * from scrapeMotionValuesFromProps. We use the keys in here to determine
4308
- * if any motion values need to be removed after props are updated.
4309
- */
4310
- let prevMotionValues = {};
4311
- /**
4312
- * When values are removed from all animation props we need to search
4313
- * for a fallback value to animate to. These values are tracked in baseTarget.
4314
- */
4315
- const baseTarget = {
4316
- ...latestValues,
4317
- };
4318
- /**
4319
- * Create an object of the values we initially animated from (if initial prop present).
4320
- */
4321
- const initialValues = props.initial ? { ...latestValues } : {};
4322
- // Internal methods ========================
4323
- /**
4324
- * On mount, this will be hydrated with a callback to disconnect
4325
- * this visual element from its parent on unmount.
4326
- */
4327
- let removeFromVariantTree;
4328
- /**
4329
- * Render the element with the latest styles outside of the React
4330
- * render lifecycle
4331
- */
4332
- function render() {
4333
- if (!instance || !isMounted)
4334
- return;
4335
- triggerBuild();
4336
- renderInstance(instance, renderState, props.style, element.projection);
4337
- }
4338
- function triggerBuild() {
4339
- build(element, renderState, latestValues, options, props);
4340
- }
4341
- function update() {
4342
- lifecycles.notifyUpdate(latestValues);
4343
- }
4344
- /**
4345
- *
4346
- */
4347
- function bindToMotionValue(key, value) {
4348
- const removeOnChange = value.onChange((latestValue) => {
4349
- latestValues[key] = latestValue;
4350
- props.onUpdate && sync__default["default"].update(update, false, true);
4351
- });
4352
- const removeOnRenderRequest = value.onRenderRequest(element.scheduleRender);
4353
- valueSubscriptions.set(key, () => {
4354
- removeOnChange();
4355
- removeOnRenderRequest();
4356
- });
4357
- }
4358
- /**
4359
- * Any motion values that are provided to the element when created
4360
- * aren't yet bound to the element, as this would technically be impure.
4361
- * However, we iterate through the motion values and set them to the
4362
- * initial values for this component.
4363
- *
4364
- * TODO: This is impure and we should look at changing this to run on mount.
4365
- * Doing so will break some tests but this isn't neccessarily a breaking change,
4366
- * more a reflection of the test.
4367
- */
4368
- const { willChange, ...initialMotionValues } = scrapeMotionValuesFromProps(props);
4369
- for (const key in initialMotionValues) {
4370
- const value = initialMotionValues[key];
4371
- if (latestValues[key] !== undefined && isMotionValue(value)) {
4372
- value.set(latestValues[key], false);
4373
- if (isWillChangeMotionValue(willChange)) {
4374
- willChange.add(key);
4375
- }
4376
- }
4377
- }
4378
- /**
4379
- * Update external values with initial values
4380
- */
4381
- if (props.values) {
4382
- for (const key in props.values) {
4383
- const value = props.values[key];
4384
- if (latestValues[key] !== undefined && isMotionValue(value)) {
4385
- value.set(latestValues[key]);
4386
- }
4387
- }
4388
- }
4389
- /**
4390
- * Determine what role this visual element should take in the variant tree.
4391
- */
4392
- const isControllingVariants$1 = isControllingVariants(props);
4393
- const isVariantNode$1 = isVariantNode(props);
4394
- const element = {
4395
- treeType,
4396
- /**
4397
- * This is a mirror of the internal instance prop, which keeps
4398
- * VisualElement type-compatible with React's RefObject.
4399
- */
4400
- current: null,
4401
- /**
4402
- * The depth of this visual element within the visual element tree.
4403
- */
4404
- depth: parent ? parent.depth + 1 : 0,
4405
- parent,
4406
- children: new Set(),
4407
- /**
4408
- *
4409
- */
4410
- presenceId,
4411
- shouldReduceMotion: null,
4412
- /**
4413
- * If this component is part of the variant tree, it should track
4414
- * any children that are also part of the tree. This is essentially
4415
- * a shadow tree to simplify logic around how to stagger over children.
4416
- */
4417
- variantChildren: isVariantNode$1 ? new Set() : undefined,
4418
- /**
4419
- * Whether this instance is visible. This can be changed imperatively
4420
- * by the projection tree, is analogous to CSS's visibility in that
4421
- * hidden elements should take up layout, and needs enacting by the configured
4422
- * render function.
4423
- */
4424
- isVisible: undefined,
4425
- /**
4426
- * Normally, if a component is controlled by a parent's variants, it can
4427
- * rely on that ancestor to trigger animations further down the tree.
4428
- * However, if a component is created after its parent is mounted, the parent
4429
- * won't trigger that mount animation so the child needs to.
4430
- *
4431
- * TODO: This might be better replaced with a method isParentMounted
4432
- */
4433
- manuallyAnimateOnMount: Boolean(parent === null || parent === void 0 ? void 0 : parent.isMounted()),
4434
- /**
4435
- * This can be set by AnimatePresence to force components that mount
4436
- * at the same time as it to mount as if they have initial={false} set.
4437
- */
4438
- blockInitialAnimation,
4439
- /**
4440
- * Determine whether this component has mounted yet. This is mostly used
4441
- * by variant children to determine whether they need to trigger their
4442
- * own animations on mount.
4443
- */
4444
- isMounted: () => Boolean(instance),
4445
- mount(newInstance) {
4446
- isMounted = true;
4447
- instance = element.current = newInstance;
4448
- if (element.projection) {
4449
- element.projection.mount(newInstance);
4450
- }
4451
- if (isVariantNode$1 && parent && !isControllingVariants$1) {
4452
- removeFromVariantTree = parent === null || parent === void 0 ? void 0 : parent.addVariantChild(element);
4453
- }
4454
- values.forEach((value, key) => bindToMotionValue(key, value));
4455
- if (!hasReducedMotionListener.current) {
4456
- initPrefersReducedMotion();
4457
- }
4458
- element.shouldReduceMotion =
4459
- reducedMotionConfig === "never"
4460
- ? false
4461
- : reducedMotionConfig === "always"
4462
- ? true
4463
- : prefersReducedMotion.current;
4464
- parent === null || parent === void 0 ? void 0 : parent.children.add(element);
4465
- element.setProps(props);
4466
- },
4467
- /**
4468
- *
4469
- */
4470
- unmount() {
4471
- var _a;
4472
- (_a = element.projection) === null || _a === void 0 ? void 0 : _a.unmount();
4473
- sync.cancelSync.update(update);
4474
- sync.cancelSync.render(render);
4475
- valueSubscriptions.forEach((remove) => remove());
4476
- removeFromVariantTree === null || removeFromVariantTree === void 0 ? void 0 : removeFromVariantTree();
4477
- parent === null || parent === void 0 ? void 0 : parent.children.delete(element);
4478
- lifecycles.clearAllListeners();
4479
- instance = undefined;
4480
- isMounted = false;
4481
- },
4482
- loadFeatures(renderedProps, isStrict, preloadedFeatures, projectionId, ProjectionNodeConstructor, initialLayoutGroupConfig) {
4483
- const features = [];
4484
- /**
4485
- * If we're in development mode, check to make sure we're not rendering a motion component
4486
- * as a child of LazyMotion, as this will break the file-size benefits of using it.
4487
- */
4488
- if (env !== "production" && preloadedFeatures && isStrict) {
4489
- heyListen.invariant(false, "You have rendered a `motion` component within a `LazyMotion` component. This will break tree shaking. Import and render a `m` component instead.");
4490
- }
4491
- for (let i = 0; i < numFeatures; i++) {
4492
- const name = featureNames[i];
4493
- const { isEnabled, Component } = featureDefinitions[name];
4494
- /**
4495
- * It might be possible in the future to use this moment to
4496
- * dynamically request functionality. In initial tests this
4497
- * was producing a lot of duplication amongst bundles.
4498
- */
4499
- if (isEnabled(renderedProps) && Component) {
4500
- features.push(React.createElement(Component, {
4501
- key: name,
4502
- ...renderedProps,
4503
- visualElement: element,
4504
- }));
4505
- }
4506
- }
4507
- if (!element.projection && ProjectionNodeConstructor) {
4508
- element.projection = new ProjectionNodeConstructor(projectionId, element.getLatestValues(), parent && parent.projection);
4509
- const { layoutId, layout, drag, dragConstraints, layoutScroll, } = renderedProps;
4510
- element.projection.setOptions({
4511
- layoutId,
4512
- layout,
4513
- alwaysMeasureLayout: Boolean(drag) ||
4514
- (dragConstraints && isRefObject(dragConstraints)),
4515
- visualElement: element,
4516
- scheduleRender: () => element.scheduleRender(),
4517
- /**
4518
- * TODO: Update options in an effect. This could be tricky as it'll be too late
4519
- * to update by the time layout animations run.
4520
- * We also need to fix this safeToRemove by linking it up to the one returned by usePresence,
4521
- * ensuring it gets called if there's no potential layout animations.
4522
- *
4523
- */
4524
- animationType: typeof layout === "string" ? layout : "both",
4525
- initialPromotionConfig: initialLayoutGroupConfig,
4526
- layoutScroll,
4527
- });
4528
- }
4529
- return features;
4530
- },
4531
- /**
4532
- * Add a child visual element to our set of children.
4533
- */
4534
- addVariantChild(child) {
4535
- var _a;
4536
- const closestVariantNode = element.getClosestVariantNode();
4537
- if (closestVariantNode) {
4538
- (_a = closestVariantNode.variantChildren) === null || _a === void 0 ? void 0 : _a.add(child);
4539
- return () => closestVariantNode.variantChildren.delete(child);
4540
- }
4541
- },
4542
- sortNodePosition(other) {
4543
- /**
4544
- * If these nodes aren't even of the same type we can't compare their depth.
4545
- */
4546
- if (!sortNodePosition || treeType !== other.treeType)
4547
- return 0;
4548
- return sortNodePosition(element.getInstance(), other.getInstance());
4549
- },
4550
- /**
4551
- * Returns the closest variant node in the tree starting from
4552
- * this visual element.
4553
- */
4554
- getClosestVariantNode: () => isVariantNode$1 ? element : parent === null || parent === void 0 ? void 0 : parent.getClosestVariantNode(),
4555
- /**
4556
- * Expose the latest layoutId prop.
4557
- */
4558
- getLayoutId: () => props.layoutId,
4559
- /**
4560
- * Returns the current instance.
4561
- */
4562
- getInstance: () => instance,
4563
- /**
4564
- * Get/set the latest static values.
4565
- */
4566
- getStaticValue: (key) => latestValues[key],
4567
- setStaticValue: (key, value) => (latestValues[key] = value),
4568
- /**
4569
- * Returns the latest motion value state. Currently only used to take
4570
- * a snapshot of the visual element - perhaps this can return the whole
4571
- * visual state
4572
- */
4573
- getLatestValues: () => latestValues,
4574
- /**
4575
- * Set the visiblity of the visual element. If it's changed, schedule
4576
- * a render to reflect these changes.
4577
- */
4578
- setVisibility(visibility) {
4579
- if (element.isVisible === visibility)
4580
- return;
4581
- element.isVisible = visibility;
4582
- element.scheduleRender();
4583
- },
4584
- /**
4585
- * Make a target animatable by Popmotion. For instance, if we're
4586
- * trying to animate width from 100px to 100vw we need to measure 100vw
4587
- * in pixels to determine what we really need to animate to. This is also
4588
- * pluggable to support Framer's custom value types like Color,
4589
- * and CSS variables.
4590
- */
4591
- makeTargetAnimatable(target, canMutate = true) {
4592
- return makeTargetAnimatable(element, target, props, canMutate);
4593
- },
4594
- /**
4595
- * Measure the current viewport box with or without transforms.
4596
- * Only measures axis-aligned boxes, rotate and skew must be manually
4597
- * removed with a re-render to work.
4598
- */
4599
- measureViewportBox() {
4600
- return measureViewportBox(instance, props);
4601
- },
4602
- // Motion values ========================
4603
- /**
4604
- * Add a motion value and bind it to this visual element.
4605
- */
4606
- addValue(key, value) {
4607
- // Remove existing value if it exists
4608
- if (element.hasValue(key))
4609
- element.removeValue(key);
4610
- values.set(key, value);
4611
- latestValues[key] = value.get();
4612
- bindToMotionValue(key, value);
4613
- },
4614
- /**
4615
- * Remove a motion value and unbind any active subscriptions.
4616
- */
4617
- removeValue(key) {
4618
- var _a;
4619
- values.delete(key);
4620
- (_a = valueSubscriptions.get(key)) === null || _a === void 0 ? void 0 : _a();
4621
- valueSubscriptions.delete(key);
4622
- delete latestValues[key];
4623
- removeValueFromRenderState(key, renderState);
4624
- },
4625
- /**
4626
- * Check whether we have a motion value for this key
4627
- */
4628
- hasValue: (key) => values.has(key),
4629
- /**
4630
- * Get a motion value for this key. If called with a default
4631
- * value, we'll create one if none exists.
4632
- */
4633
- getValue(key, defaultValue) {
4634
- if (props.values && props.values[key]) {
4635
- return props.values[key];
4636
- }
4637
- let value = values.get(key);
4638
- if (value === undefined && defaultValue !== undefined) {
4639
- value = motionValue(defaultValue);
4640
- element.addValue(key, value);
4641
- }
4642
- return value;
4643
- },
4644
- /**
4645
- * Iterate over our motion values.
4646
- */
4647
- forEachValue: (callback) => values.forEach(callback),
4648
- /**
4649
- * If we're trying to animate to a previously unencountered value,
4650
- * we need to check for it in our state and as a last resort read it
4651
- * directly from the instance (which might have performance implications).
4652
- */
4653
- readValue: (key) => latestValues[key] !== undefined
4654
- ? latestValues[key]
4655
- : readValueFromInstance(instance, key, options),
4656
- /**
4657
- * Set the base target to later animate back to. This is currently
4658
- * only hydrated on creation and when we first read a value.
4659
- */
4660
- setBaseTarget(key, value) {
4661
- baseTarget[key] = value;
4662
- },
4663
- /**
4664
- * Find the base target for a value thats been removed from all animation
4665
- * props.
4666
- */
4667
- getBaseTarget(key) {
4668
- var _a;
4669
- const { initial } = props;
4670
- const valueFromInitial = typeof initial === "string" || typeof initial === "object"
4671
- ? (_a = resolveVariantFromProps(props, initial)) === null || _a === void 0 ? void 0 : _a[key]
4672
- : undefined;
4673
- /**
4674
- * If this value still exists in the current initial variant, read that.
4675
- */
4676
- if (initial && valueFromInitial !== undefined) {
4677
- return valueFromInitial;
4678
- }
4679
- /**
4680
- * Alternatively, if this VisualElement config has defined a getBaseTarget
4681
- * so we can read the value from an alternative source, try that.
4682
- */
4683
- if (getBaseTarget) {
4684
- const target = getBaseTarget(props, key);
4685
- if (target !== undefined && !isMotionValue(target))
4686
- return target;
4687
- }
4688
- /**
4689
- * If the value was initially defined on initial, but it doesn't any more,
4690
- * return undefined. Otherwise return the value as initially read from the DOM.
4691
- */
4692
- return initialValues[key] !== undefined &&
4693
- valueFromInitial === undefined
4694
- ? undefined
4695
- : baseTarget[key];
4696
- },
4697
- // Lifecyles ========================
4698
- ...lifecycles,
4699
- /**
4700
- * Build the renderer state based on the latest visual state.
4701
- */
4702
- build() {
4703
- triggerBuild();
4704
- return renderState;
4705
- },
4706
- /**
4707
- * Schedule a render on the next animation frame.
4708
- */
4709
- scheduleRender() {
4710
- sync__default["default"].render(render, false, true);
4711
- },
4712
- /**
4713
- * Synchronously fire render. It's prefered that we batch renders but
4714
- * in many circumstances, like layout measurement, we need to run this
4715
- * synchronously. However in those instances other measures should be taken
4716
- * to batch reads/writes.
4717
- */
4718
- syncRender: render,
4719
- /**
4720
- * Update the provided props. Ensure any newly-added motion values are
4721
- * added to our map, old ones removed, and listeners updated.
4722
- */
4723
- setProps(newProps) {
4724
- if (newProps.transformTemplate || props.transformTemplate) {
4725
- element.scheduleRender();
4726
- }
4727
- props = newProps;
4728
- lifecycles.updatePropListeners(newProps);
4729
- prevMotionValues = updateMotionValuesFromProps(element, scrapeMotionValuesFromProps(props), prevMotionValues);
4730
- },
4731
- getProps: () => props,
4732
- // Variants ==============================
4733
- /**
4734
- * Returns the variant definition with a given name.
4735
- */
4736
- getVariant: (name) => { var _a; return (_a = props.variants) === null || _a === void 0 ? void 0 : _a[name]; },
4737
- /**
4738
- * Returns the defined default transition on this component.
4739
- */
4740
- getDefaultTransition: () => props.transition,
4741
- getTransformPagePoint: () => {
4742
- return props.transformPagePoint;
4743
- },
4744
- /**
4745
- * Used by child variant nodes to get the closest ancestor variant props.
4746
- */
4747
- getVariantContext(startAtParent = false) {
4748
- if (startAtParent)
4749
- return parent === null || parent === void 0 ? void 0 : parent.getVariantContext();
4750
- if (!isControllingVariants$1) {
4751
- const context = (parent === null || parent === void 0 ? void 0 : parent.getVariantContext()) || {};
4752
- if (props.initial !== undefined) {
4753
- context.initial = props.initial;
4754
- }
4755
- return context;
4756
- }
4757
- const context = {};
4758
- for (let i = 0; i < numVariantProps; i++) {
4759
- const name = variantProps[i];
4760
- const prop = props[name];
4761
- if (isVariantLabel(prop) || prop === false) {
4762
- context[name] = prop;
4763
- }
4764
- }
4765
- return context;
4766
- },
4767
- };
4768
- return element;
4769
- };
4770
- const variantProps = ["initial", ...variantPriorityOrder];
4771
- const numVariantProps = variantProps.length;
4772
-
4773
4166
  function isCSSVariable(value) {
4774
4167
  return typeof value === "string" && value.startsWith("var(--");
4775
4168
  }
@@ -4816,7 +4209,7 @@ function getVariableValue(current, element, depth = 1) {
4816
4209
  * @internal
4817
4210
  */
4818
4211
  function resolveCSSVariables(visualElement, { ...target }, transitionEnd) {
4819
- const element = visualElement.getInstance();
4212
+ const element = visualElement.current;
4820
4213
  if (!(element instanceof Element))
4821
4214
  return { target, transitionEnd };
4822
4215
  // If `transitionEnd` isn't `undefined`, clone it. We could clone `target` and `transitionEnd`
@@ -4825,7 +4218,7 @@ function resolveCSSVariables(visualElement, { ...target }, transitionEnd) {
4825
4218
  transitionEnd = { ...transitionEnd };
4826
4219
  }
4827
4220
  // Go through existing `MotionValue`s and ensure any existing CSS variables are resolved
4828
- visualElement.forEachValue((value) => {
4221
+ visualElement.values.forEach((value) => {
4829
4222
  const current = value.get();
4830
4223
  if (!isCSSVariable(current))
4831
4224
  return;
@@ -4915,7 +4308,7 @@ function removeNonTranslationalTransform(visualElement) {
4915
4308
  });
4916
4309
  // Apply changes to element before measurement
4917
4310
  if (removedTransforms.length)
4918
- visualElement.syncRender();
4311
+ visualElement.render();
4919
4312
  return removedTransforms;
4920
4313
  }
4921
4314
  const positionalValues = {
@@ -4932,7 +4325,7 @@ const positionalValues = {
4932
4325
  };
4933
4326
  const convertChangedValueTypes = (target, visualElement, changedKeys) => {
4934
4327
  const originBbox = visualElement.measureViewportBox();
4935
- const element = visualElement.getInstance();
4328
+ const element = visualElement.current;
4936
4329
  const elementComputedStyle = getComputedStyle(element);
4937
4330
  const { display } = elementComputedStyle;
4938
4331
  const origin = {};
@@ -4948,7 +4341,7 @@ const convertChangedValueTypes = (target, visualElement, changedKeys) => {
4948
4341
  origin[key] = positionalValues[key](originBbox, elementComputedStyle);
4949
4342
  });
4950
4343
  // Apply the latest values (as set in checkAndConvertChangedValueTypes)
4951
- visualElement.syncRender();
4344
+ visualElement.render();
4952
4345
  const targetBbox = visualElement.measureViewportBox();
4953
4346
  changedKeys.forEach((key) => {
4954
4347
  // Restore styles to their **calculated computed style**, not their actual
@@ -5026,131 +4419,625 @@ const checkAndConvertChangedValueTypes = (visualElement, target, origin = {}, tr
5026
4419
  target[key] = fromType.transform(to);
5027
4420
  }
5028
4421
  }
5029
- else {
5030
- // If we're going to do value conversion via DOM measurements, we first
5031
- // need to remove non-positional transform values that could affect the bbox measurements.
5032
- if (!hasAttemptedToRemoveTransformValues) {
5033
- removedTransformValues =
5034
- removeNonTranslationalTransform(visualElement);
5035
- hasAttemptedToRemoveTransformValues = true;
4422
+ else {
4423
+ // If we're going to do value conversion via DOM measurements, we first
4424
+ // need to remove non-positional transform values that could affect the bbox measurements.
4425
+ if (!hasAttemptedToRemoveTransformValues) {
4426
+ removedTransformValues =
4427
+ removeNonTranslationalTransform(visualElement);
4428
+ hasAttemptedToRemoveTransformValues = true;
4429
+ }
4430
+ changedValueTypeKeys.push(key);
4431
+ transitionEnd[key] =
4432
+ transitionEnd[key] !== undefined
4433
+ ? transitionEnd[key]
4434
+ : target[key];
4435
+ setAndResetVelocity(value, to);
4436
+ }
4437
+ }
4438
+ });
4439
+ if (changedValueTypeKeys.length) {
4440
+ const scrollY = changedValueTypeKeys.indexOf("height") >= 0
4441
+ ? window.pageYOffset
4442
+ : null;
4443
+ const convertedTarget = convertChangedValueTypes(target, visualElement, changedValueTypeKeys);
4444
+ // If we removed transform values, reapply them before the next render
4445
+ if (removedTransformValues.length) {
4446
+ removedTransformValues.forEach(([key, value]) => {
4447
+ visualElement.getValue(key).set(value);
4448
+ });
4449
+ }
4450
+ // Reapply original values
4451
+ visualElement.render();
4452
+ // Restore scroll position
4453
+ if (isBrowser && scrollY !== null) {
4454
+ window.scrollTo({ top: scrollY });
4455
+ }
4456
+ return { target: convertedTarget, transitionEnd };
4457
+ }
4458
+ else {
4459
+ return { target, transitionEnd };
4460
+ }
4461
+ };
4462
+ /**
4463
+ * Convert value types for x/y/width/height/top/left/bottom/right
4464
+ *
4465
+ * Allows animation between `'auto'` -> `'100%'` or `0` -> `'calc(50% - 10vw)'`
4466
+ *
4467
+ * @internal
4468
+ */
4469
+ function unitConversion(visualElement, target, origin, transitionEnd) {
4470
+ return hasPositionalKey(target)
4471
+ ? checkAndConvertChangedValueTypes(visualElement, target, origin, transitionEnd)
4472
+ : { target, transitionEnd };
4473
+ }
4474
+
4475
+ /**
4476
+ * Parse a DOM variant to make it animatable. This involves resolving CSS variables
4477
+ * and ensuring animations like "20%" => "calc(50vw)" are performed in pixels.
4478
+ */
4479
+ const parseDomVariant = (visualElement, target, origin, transitionEnd) => {
4480
+ const resolved = resolveCSSVariables(visualElement, target, transitionEnd);
4481
+ target = resolved.target;
4482
+ transitionEnd = resolved.transitionEnd;
4483
+ return unitConversion(visualElement, target, origin, transitionEnd);
4484
+ };
4485
+
4486
+ // Does this device prefer reduced motion? Returns `null` server-side.
4487
+ const prefersReducedMotion = { current: null };
4488
+ const hasReducedMotionListener = { current: false };
4489
+
4490
+ function initPrefersReducedMotion() {
4491
+ hasReducedMotionListener.current = true;
4492
+ if (!isBrowser)
4493
+ return;
4494
+ if (window.matchMedia) {
4495
+ const motionMediaQuery = window.matchMedia("(prefers-reduced-motion)");
4496
+ const setReducedMotionPreferences = () => (prefersReducedMotion.current = motionMediaQuery.matches);
4497
+ motionMediaQuery.addListener(setReducedMotionPreferences);
4498
+ setReducedMotionPreferences();
4499
+ }
4500
+ else {
4501
+ prefersReducedMotion.current = false;
4502
+ }
4503
+ }
4504
+
4505
+ function updateMotionValuesFromProps(element, next, prev) {
4506
+ const { willChange } = next;
4507
+ for (const key in next) {
4508
+ const nextValue = next[key];
4509
+ const prevValue = prev[key];
4510
+ if (isMotionValue(nextValue)) {
4511
+ /**
4512
+ * If this is a motion value found in props or style, we want to add it
4513
+ * to our visual element's motion value map.
4514
+ */
4515
+ element.addValue(key, nextValue);
4516
+ if (isWillChangeMotionValue(willChange)) {
4517
+ willChange.add(key);
4518
+ }
4519
+ /**
4520
+ * Check the version of the incoming motion value with this version
4521
+ * and warn against mismatches.
4522
+ */
4523
+ if (process.env.NODE_ENV === "development") {
4524
+ warnOnce(nextValue.version === "7.6.6", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.6.6 may not work as expected.`);
4525
+ }
4526
+ }
4527
+ else if (isMotionValue(prevValue)) {
4528
+ /**
4529
+ * If we're swapping from a motion value to a static value,
4530
+ * create a new motion value from that
4531
+ */
4532
+ element.addValue(key, motionValue(nextValue));
4533
+ if (isWillChangeMotionValue(willChange)) {
4534
+ willChange.remove(key);
4535
+ }
4536
+ }
4537
+ else if (prevValue !== nextValue) {
4538
+ /**
4539
+ * If this is a flat value that has changed, update the motion value
4540
+ * or create one if it doesn't exist. We only want to do this if we're
4541
+ * not handling the value with our animation state.
4542
+ */
4543
+ if (element.hasValue(key)) {
4544
+ const existingValue = element.getValue(key);
4545
+ // TODO: Only update values that aren't being animated or even looked at
4546
+ !existingValue.hasAnimated && existingValue.set(nextValue);
4547
+ }
4548
+ else {
4549
+ const latestValue = element.getStaticValue(key);
4550
+ element.addValue(key, motionValue(latestValue !== undefined ? latestValue : nextValue));
4551
+ }
4552
+ }
4553
+ }
4554
+ // Handle removed values
4555
+ for (const key in prev) {
4556
+ if (next[key] === undefined)
4557
+ element.removeValue(key);
4558
+ }
4559
+ return next;
4560
+ }
4561
+
4562
+ const featureNames = Object.keys(featureDefinitions);
4563
+ const numFeatures = featureNames.length;
4564
+ const propEventHandlers = [
4565
+ "AnimationStart",
4566
+ "AnimationComplete",
4567
+ "Update",
4568
+ "Unmount",
4569
+ "BeforeLayoutMeasure",
4570
+ "LayoutMeasure",
4571
+ "LayoutAnimationStart",
4572
+ "LayoutAnimationComplete",
4573
+ ];
4574
+ /**
4575
+ * A VisualElement is an imperative abstraction around UI elements such as
4576
+ * HTMLElement, SVGElement, Three.Object3D etc.
4577
+ */
4578
+ class VisualElement {
4579
+ constructor({ parent, props, reducedMotionConfig, visualState, }, options = {}) {
4580
+ /**
4581
+ * A reference to the current underlying Instance, e.g. a HTMLElement
4582
+ * or Three.Mesh etc.
4583
+ */
4584
+ this.current = null;
4585
+ /**
4586
+ * A set containing references to this VisualElement's children.
4587
+ */
4588
+ this.children = new Set();
4589
+ /**
4590
+ * Determine what role this visual element should take in the variant tree.
4591
+ */
4592
+ this.isVariantNode = false;
4593
+ this.isControllingVariants = false;
4594
+ /**
4595
+ * Decides whether this VisualElement should animate in reduced motion
4596
+ * mode.
4597
+ *
4598
+ * TODO: This is currently set on every individual VisualElement but feels
4599
+ * like it could be set globally.
4600
+ */
4601
+ this.shouldReduceMotion = null;
4602
+ /**
4603
+ * A map of all motion values attached to this visual element. Motion
4604
+ * values are source of truth for any given animated value. A motion
4605
+ * value might be provided externally by the component via props.
4606
+ */
4607
+ this.values = new Map();
4608
+ /**
4609
+ * Tracks whether this VisualElement's React component is currently present
4610
+ * within the defined React tree.
4611
+ */
4612
+ this.isPresent = true;
4613
+ /**
4614
+ * A map of every subscription that binds the provided or generated
4615
+ * motion values onChange listeners to this visual element.
4616
+ */
4617
+ this.valueSubscriptions = new Map();
4618
+ /**
4619
+ * A reference to the previously-provided motion values as returned
4620
+ * from scrapeMotionValuesFromProps. We use the keys in here to determine
4621
+ * if any motion values need to be removed after props are updated.
4622
+ */
4623
+ this.prevMotionValues = {};
4624
+ /**
4625
+ * An object containing a SubscriptionManager for each active event.
4626
+ */
4627
+ this.events = {};
4628
+ /**
4629
+ * An object containing an unsubscribe function for each prop event subscription.
4630
+ * For example, every "Update" event can have multiple subscribers via
4631
+ * VisualElement.on(), but only one of those can be defined via the onUpdate prop.
4632
+ */
4633
+ this.propEventSubscriptions = {};
4634
+ this.notifyUpdate = () => this.notify("Update", this.latestValues);
4635
+ this.render = () => {
4636
+ if (!this.current)
4637
+ return;
4638
+ this.triggerBuild();
4639
+ this.renderInstance(this.current, this.renderState, this.props.style, this.projection);
4640
+ };
4641
+ this.scheduleRender = () => sync__default["default"].render(this.render, false, true);
4642
+ const { latestValues, renderState } = visualState;
4643
+ this.latestValues = latestValues;
4644
+ this.baseTarget = { ...latestValues };
4645
+ this.initialValues = props.initial ? { ...latestValues } : {};
4646
+ this.renderState = renderState;
4647
+ this.parent = parent;
4648
+ this.props = props;
4649
+ this.depth = parent ? parent.depth + 1 : 0;
4650
+ this.reducedMotionConfig = reducedMotionConfig;
4651
+ this.options = options;
4652
+ this.isControllingVariants = isControllingVariants(props);
4653
+ this.isVariantNode = isVariantNode(props);
4654
+ if (this.isVariantNode) {
4655
+ this.variantChildren = new Set();
4656
+ }
4657
+ this.manuallyAnimateOnMount = Boolean(parent && parent.current);
4658
+ /**
4659
+ * Any motion values that are provided to the element when created
4660
+ * aren't yet bound to the element, as this would technically be impure.
4661
+ * However, we iterate through the motion values and set them to the
4662
+ * initial values for this component.
4663
+ *
4664
+ * TODO: This is impure and we should look at changing this to run on mount.
4665
+ * Doing so will break some tests but this isn't neccessarily a breaking change,
4666
+ * more a reflection of the test.
4667
+ */
4668
+ const { willChange, ...initialMotionValues } = this.scrapeMotionValuesFromProps(props);
4669
+ for (const key in initialMotionValues) {
4670
+ const value = initialMotionValues[key];
4671
+ if (latestValues[key] !== undefined && isMotionValue(value)) {
4672
+ value.set(latestValues[key], false);
4673
+ if (isWillChangeMotionValue(willChange)) {
4674
+ willChange.add(key);
4675
+ }
4676
+ }
4677
+ }
4678
+ /**
4679
+ * Update external values with initial values
4680
+ */
4681
+ if (props.values) {
4682
+ for (const key in props.values) {
4683
+ const value = props.values[key];
4684
+ if (latestValues[key] !== undefined && isMotionValue(value)) {
4685
+ value.set(latestValues[key]);
5036
4686
  }
5037
- changedValueTypeKeys.push(key);
5038
- transitionEnd[key] =
5039
- transitionEnd[key] !== undefined
5040
- ? transitionEnd[key]
5041
- : target[key];
5042
- setAndResetVelocity(value, to);
5043
4687
  }
5044
4688
  }
5045
- });
5046
- if (changedValueTypeKeys.length) {
5047
- const scrollY = changedValueTypeKeys.indexOf("height") >= 0
5048
- ? window.pageYOffset
5049
- : null;
5050
- const convertedTarget = convertChangedValueTypes(target, visualElement, changedValueTypeKeys);
5051
- // If we removed transform values, reapply them before the next render
5052
- if (removedTransformValues.length) {
5053
- removedTransformValues.forEach(([key, value]) => {
5054
- visualElement.getValue(key).set(value);
4689
+ }
4690
+ /**
4691
+ * This method takes React props and returns found MotionValues. For example, HTML
4692
+ * MotionValues will be found within the style prop, whereas for Three.js within attribute arrays.
4693
+ *
4694
+ * This isn't an abstract method as it needs calling in the constructor, but it is
4695
+ * intended to be one.
4696
+ */
4697
+ scrapeMotionValuesFromProps(_props) {
4698
+ return {};
4699
+ }
4700
+ mount(instance) {
4701
+ var _a;
4702
+ this.current = instance;
4703
+ if (this.projection) {
4704
+ this.projection.mount(instance);
4705
+ }
4706
+ if (this.parent && this.isVariantNode && !this.isControllingVariants) {
4707
+ this.removeFromVariantTree = (_a = this.parent) === null || _a === void 0 ? void 0 : _a.addVariantChild(this);
4708
+ }
4709
+ this.values.forEach((value, key) => this.bindToMotionValue(key, value));
4710
+ if (!hasReducedMotionListener.current) {
4711
+ initPrefersReducedMotion();
4712
+ }
4713
+ this.shouldReduceMotion =
4714
+ this.reducedMotionConfig === "never"
4715
+ ? false
4716
+ : this.reducedMotionConfig === "always"
4717
+ ? true
4718
+ : prefersReducedMotion.current;
4719
+ if (this.parent)
4720
+ this.parent.children.add(this);
4721
+ this.setProps(this.props);
4722
+ }
4723
+ unmount() {
4724
+ var _a, _b, _c;
4725
+ (_a = this.projection) === null || _a === void 0 ? void 0 : _a.unmount();
4726
+ sync.cancelSync.update(this.notifyUpdate);
4727
+ sync.cancelSync.render(this.render);
4728
+ this.valueSubscriptions.forEach((remove) => remove());
4729
+ (_b = this.removeFromVariantTree) === null || _b === void 0 ? void 0 : _b.call(this);
4730
+ (_c = this.parent) === null || _c === void 0 ? void 0 : _c.children.delete(this);
4731
+ for (const key in this.events) {
4732
+ this.events[key].clear();
4733
+ }
4734
+ this.current = null;
4735
+ }
4736
+ bindToMotionValue(key, value) {
4737
+ const removeOnChange = value.onChange((latestValue) => {
4738
+ this.latestValues[key] = latestValue;
4739
+ this.props.onUpdate &&
4740
+ sync__default["default"].update(this.notifyUpdate, false, true);
4741
+ });
4742
+ const removeOnRenderRequest = value.onRenderRequest(this.scheduleRender);
4743
+ this.valueSubscriptions.set(key, () => {
4744
+ removeOnChange();
4745
+ removeOnRenderRequest();
4746
+ });
4747
+ }
4748
+ sortNodePosition(other) {
4749
+ /**
4750
+ * If these nodes aren't even of the same type we can't compare their depth.
4751
+ */
4752
+ if (!this.current ||
4753
+ !this.sortInstanceNodePosition ||
4754
+ this.type !== other.type)
4755
+ return 0;
4756
+ return this.sortInstanceNodePosition(this.current, other.current);
4757
+ }
4758
+ loadFeatures(renderedProps, isStrict, preloadedFeatures, projectionId, ProjectionNodeConstructor, initialLayoutGroupConfig) {
4759
+ const features = [];
4760
+ /**
4761
+ * If we're in development mode, check to make sure we're not rendering a motion component
4762
+ * as a child of LazyMotion, as this will break the file-size benefits of using it.
4763
+ */
4764
+ if (env !== "production" && preloadedFeatures && isStrict) {
4765
+ heyListen.invariant(false, "You have rendered a `motion` component within a `LazyMotion` component. This will break tree shaking. Import and render a `m` component instead.");
4766
+ }
4767
+ for (let i = 0; i < numFeatures; i++) {
4768
+ const name = featureNames[i];
4769
+ const { isEnabled, Component } = featureDefinitions[name];
4770
+ /**
4771
+ * It might be possible in the future to use this moment to
4772
+ * dynamically request functionality. In initial tests this
4773
+ * was producing a lot of duplication amongst bundles.
4774
+ */
4775
+ if (isEnabled(renderedProps) && Component) {
4776
+ features.push(React.createElement(Component, {
4777
+ key: name,
4778
+ ...renderedProps,
4779
+ visualElement: this,
4780
+ }));
4781
+ }
4782
+ }
4783
+ if (!this.projection && ProjectionNodeConstructor) {
4784
+ this.projection = new ProjectionNodeConstructor(projectionId, this.latestValues, this.parent && this.parent.projection);
4785
+ const { layoutId, layout, drag, dragConstraints, layoutScroll } = renderedProps;
4786
+ this.projection.setOptions({
4787
+ layoutId,
4788
+ layout,
4789
+ alwaysMeasureLayout: Boolean(drag) ||
4790
+ (dragConstraints && isRefObject(dragConstraints)),
4791
+ visualElement: this,
4792
+ scheduleRender: () => this.scheduleRender(),
4793
+ /**
4794
+ * TODO: Update options in an effect. This could be tricky as it'll be too late
4795
+ * to update by the time layout animations run.
4796
+ * We also need to fix this safeToRemove by linking it up to the one returned by usePresence,
4797
+ * ensuring it gets called if there's no potential layout animations.
4798
+ *
4799
+ */
4800
+ animationType: typeof layout === "string" ? layout : "both",
4801
+ initialPromotionConfig: initialLayoutGroupConfig,
4802
+ layoutScroll,
5055
4803
  });
5056
4804
  }
5057
- // Reapply original values
5058
- visualElement.syncRender();
5059
- // Restore scroll position
5060
- if (isBrowser && scrollY !== null) {
5061
- window.scrollTo({ top: scrollY });
4805
+ return features;
4806
+ }
4807
+ triggerBuild() {
4808
+ this.build(this.renderState, this.latestValues, this.options, this.props);
4809
+ }
4810
+ /**
4811
+ * Measure the current viewport box with or without transforms.
4812
+ * Only measures axis-aligned boxes, rotate and skew must be manually
4813
+ * removed with a re-render to work.
4814
+ */
4815
+ measureViewportBox() {
4816
+ return this.current
4817
+ ? this.measureInstanceViewportBox(this.current, this.props)
4818
+ : createBox();
4819
+ }
4820
+ getStaticValue(key) {
4821
+ return this.latestValues[key];
4822
+ }
4823
+ setStaticValue(key, value) {
4824
+ this.latestValues[key] = value;
4825
+ }
4826
+ /**
4827
+ * Make a target animatable by Popmotion. For instance, if we're
4828
+ * trying to animate width from 100px to 100vw we need to measure 100vw
4829
+ * in pixels to determine what we really need to animate to. This is also
4830
+ * pluggable to support Framer's custom value types like Color,
4831
+ * and CSS variables.
4832
+ */
4833
+ makeTargetAnimatable(target, canMutate = true) {
4834
+ return this.makeTargetAnimatableFromInstance(target, this.props, canMutate);
4835
+ }
4836
+ /**
4837
+ * Update the provided props. Ensure any newly-added motion values are
4838
+ * added to our map, old ones removed, and listeners updated.
4839
+ */
4840
+ setProps(props) {
4841
+ if (props.transformTemplate || this.props.transformTemplate) {
4842
+ this.scheduleRender();
5062
4843
  }
5063
- return { target: convertedTarget, transitionEnd };
4844
+ this.props = props;
4845
+ /**
4846
+ * Update prop event handlers ie onAnimationStart, onAnimationComplete
4847
+ */
4848
+ for (let i = 0; i < propEventHandlers.length; i++) {
4849
+ const key = propEventHandlers[i];
4850
+ if (this.propEventSubscriptions[key]) {
4851
+ this.propEventSubscriptions[key]();
4852
+ delete this.propEventSubscriptions[key];
4853
+ }
4854
+ const listener = props["on" + key];
4855
+ if (listener) {
4856
+ this.propEventSubscriptions[key] = this.on(key, listener);
4857
+ }
4858
+ }
4859
+ this.prevMotionValues = updateMotionValuesFromProps(this, this.scrapeMotionValuesFromProps(props), this.prevMotionValues);
5064
4860
  }
5065
- else {
5066
- return { target, transitionEnd };
4861
+ getProps() {
4862
+ return this.props;
5067
4863
  }
5068
- };
5069
- /**
5070
- * Convert value types for x/y/width/height/top/left/bottom/right
5071
- *
5072
- * Allows animation between `'auto'` -> `'100%'` or `0` -> `'calc(50% - 10vw)'`
5073
- *
5074
- * @internal
5075
- */
5076
- function unitConversion(visualElement, target, origin, transitionEnd) {
5077
- return hasPositionalKey(target)
5078
- ? checkAndConvertChangedValueTypes(visualElement, target, origin, transitionEnd)
5079
- : { target, transitionEnd };
5080
- }
5081
-
5082
- /**
5083
- * Parse a DOM variant to make it animatable. This involves resolving CSS variables
5084
- * and ensuring animations like "20%" => "calc(50vw)" are performed in pixels.
5085
- */
5086
- const parseDomVariant = (visualElement, target, origin, transitionEnd) => {
5087
- const resolved = resolveCSSVariables(visualElement, target, transitionEnd);
5088
- target = resolved.target;
5089
- transitionEnd = resolved.transitionEnd;
5090
- return unitConversion(visualElement, target, origin, transitionEnd);
5091
- };
5092
-
5093
- function getComputedStyle$1(element) {
5094
- return window.getComputedStyle(element);
5095
- }
5096
- const htmlConfig = {
5097
- treeType: "dom",
5098
- readValueFromInstance(domElement, key) {
5099
- if (transformProps.has(key)) {
5100
- const defaultType = getDefaultValueType(key);
5101
- return defaultType ? defaultType.default || 0 : 0;
4864
+ /**
4865
+ * Returns the variant definition with a given name.
4866
+ */
4867
+ getVariant(name) {
4868
+ var _a;
4869
+ return (_a = this.props.variants) === null || _a === void 0 ? void 0 : _a[name];
4870
+ }
4871
+ /**
4872
+ * Returns the defined default transition on this component.
4873
+ */
4874
+ getDefaultTransition() {
4875
+ return this.props.transition;
4876
+ }
4877
+ getTransformPagePoint() {
4878
+ return this.props.transformPagePoint;
4879
+ }
4880
+ getClosestVariantNode() {
4881
+ var _a;
4882
+ return this.isVariantNode ? this : (_a = this.parent) === null || _a === void 0 ? void 0 : _a.getClosestVariantNode();
4883
+ }
4884
+ getVariantContext(startAtParent = false) {
4885
+ var _a, _b;
4886
+ if (startAtParent)
4887
+ return (_a = this.parent) === null || _a === void 0 ? void 0 : _a.getVariantContext();
4888
+ if (!this.isControllingVariants) {
4889
+ const context = ((_b = this.parent) === null || _b === void 0 ? void 0 : _b.getVariantContext()) || {};
4890
+ if (this.props.initial !== undefined) {
4891
+ context.initial = this.props.initial;
4892
+ }
4893
+ return context;
5102
4894
  }
5103
- else {
5104
- const computedStyle = getComputedStyle$1(domElement);
5105
- const value = (isCSSVariable$1(key)
5106
- ? computedStyle.getPropertyValue(key)
5107
- : computedStyle[key]) || 0;
5108
- return typeof value === "string" ? value.trim() : value;
4895
+ const context = {};
4896
+ for (let i = 0; i < numVariantProps; i++) {
4897
+ const name = variantProps[i];
4898
+ const prop = this.props[name];
4899
+ if (isVariantLabel(prop) || prop === false) {
4900
+ context[name] = prop;
4901
+ }
5109
4902
  }
5110
- },
5111
- sortNodePosition(a, b) {
4903
+ return context;
4904
+ }
4905
+ /**
4906
+ * Add a child visual element to our set of children.
4907
+ */
4908
+ addVariantChild(child) {
4909
+ var _a;
4910
+ const closestVariantNode = this.getClosestVariantNode();
4911
+ if (closestVariantNode) {
4912
+ (_a = closestVariantNode.variantChildren) === null || _a === void 0 ? void 0 : _a.add(child);
4913
+ return () => closestVariantNode.variantChildren.delete(child);
4914
+ }
4915
+ }
4916
+ /**
4917
+ * Add a motion value and bind it to this visual element.
4918
+ */
4919
+ addValue(key, value) {
4920
+ // Remove existing value if it exists
4921
+ if (this.hasValue(key))
4922
+ this.removeValue(key);
4923
+ this.values.set(key, value);
4924
+ this.latestValues[key] = value.get();
4925
+ this.bindToMotionValue(key, value);
4926
+ }
4927
+ /**
4928
+ * Remove a motion value and unbind any active subscriptions.
4929
+ */
4930
+ removeValue(key) {
4931
+ var _a;
4932
+ this.values.delete(key);
4933
+ (_a = this.valueSubscriptions.get(key)) === null || _a === void 0 ? void 0 : _a();
4934
+ this.valueSubscriptions.delete(key);
4935
+ delete this.latestValues[key];
4936
+ this.removeValueFromRenderState(key, this.renderState);
4937
+ }
4938
+ /**
4939
+ * Check whether we have a motion value for this key
4940
+ */
4941
+ hasValue(key) {
4942
+ return this.values.has(key);
4943
+ }
4944
+ /**
4945
+ * Get a motion value for this key. If called with a default
4946
+ * value, we'll create one if none exists.
4947
+ */
4948
+ getValue(key, defaultValue) {
4949
+ if (this.props.values && this.props.values[key]) {
4950
+ return this.props.values[key];
4951
+ }
4952
+ let value = this.values.get(key);
4953
+ if (value === undefined && defaultValue !== undefined) {
4954
+ value = motionValue(defaultValue);
4955
+ this.addValue(key, value);
4956
+ }
4957
+ return value;
4958
+ }
4959
+ /**
4960
+ * If we're trying to animate to a previously unencountered value,
4961
+ * we need to check for it in our state and as a last resort read it
4962
+ * directly from the instance (which might have performance implications).
4963
+ */
4964
+ readValue(key) {
4965
+ return this.latestValues[key] !== undefined || !this.current
4966
+ ? this.latestValues[key]
4967
+ : this.readValueFromInstance(this.current, key, this.options);
4968
+ }
4969
+ /**
4970
+ * Set the base target to later animate back to. This is currently
4971
+ * only hydrated on creation and when we first read a value.
4972
+ */
4973
+ setBaseTarget(key, value) {
4974
+ this.baseTarget[key] = value;
4975
+ }
4976
+ /**
4977
+ * Find the base target for a value thats been removed from all animation
4978
+ * props.
4979
+ */
4980
+ getBaseTarget(key) {
4981
+ var _a;
4982
+ const { initial } = this.props;
4983
+ const valueFromInitial = typeof initial === "string" || typeof initial === "object"
4984
+ ? (_a = resolveVariantFromProps(this.props, initial)) === null || _a === void 0 ? void 0 : _a[key]
4985
+ : undefined;
4986
+ /**
4987
+ * If this value still exists in the current initial variant, read that.
4988
+ */
4989
+ if (initial && valueFromInitial !== undefined) {
4990
+ return valueFromInitial;
4991
+ }
4992
+ /**
4993
+ * Alternatively, if this VisualElement config has defined a getBaseTarget
4994
+ * so we can read the value from an alternative source, try that.
4995
+ */
4996
+ const target = this.getBaseTargetFromProps(this.props, key);
4997
+ if (target !== undefined && !isMotionValue(target))
4998
+ return target;
4999
+ /**
5000
+ * If the value was initially defined on initial, but it doesn't any more,
5001
+ * return undefined. Otherwise return the value as initially read from the DOM.
5002
+ */
5003
+ return this.initialValues[key] !== undefined &&
5004
+ valueFromInitial === undefined
5005
+ ? undefined
5006
+ : this.baseTarget[key];
5007
+ }
5008
+ on(eventName, callback) {
5009
+ if (!this.events[eventName]) {
5010
+ this.events[eventName] = new SubscriptionManager();
5011
+ }
5012
+ return this.events[eventName].add(callback);
5013
+ }
5014
+ notify(eventName, ...args) {
5015
+ var _a;
5016
+ (_a = this.events[eventName]) === null || _a === void 0 ? void 0 : _a.notify(...args);
5017
+ }
5018
+ }
5019
+ const variantProps = ["initial", ...variantPriorityOrder];
5020
+ const numVariantProps = variantProps.length;
5021
+
5022
+ class DOMVisualElement extends VisualElement {
5023
+ sortInstanceNodePosition(a, b) {
5112
5024
  /**
5113
5025
  * compareDocumentPosition returns a bitmask, by using the bitwise &
5114
5026
  * we're returning true if 2 in that bitmask is set to true. 2 is set
5115
5027
  * to true if b preceeds a.
5116
5028
  */
5117
5029
  return a.compareDocumentPosition(b) & 2 ? 1 : -1;
5118
- },
5119
- getBaseTarget(props, key) {
5030
+ }
5031
+ getBaseTargetFromProps(props, key) {
5120
5032
  var _a;
5121
5033
  return (_a = props.style) === null || _a === void 0 ? void 0 : _a[key];
5122
- },
5123
- measureViewportBox(element, { transformPagePoint }) {
5124
- return measureViewportBox(element, transformPagePoint);
5125
- },
5126
- /**
5127
- * Reset the transform on the current Element. This is called as part
5128
- * of a batched process across the entire layout tree. To remove this write
5129
- * cycle it'd be interesting to see if it's possible to "undo" all the current
5130
- * layout transforms up the tree in the same way this.getBoundingBoxWithoutTransforms
5131
- * works
5132
- */
5133
- resetTransform(element, domElement, props) {
5134
- const { transformTemplate } = props;
5135
- domElement.style.transform = transformTemplate
5136
- ? transformTemplate({}, "")
5137
- : "none";
5138
- // Ensure that whatever happens next, we restore our transform on the next frame
5139
- element.scheduleRender();
5140
- },
5141
- restoreTransform(instance, mutableState) {
5142
- instance.style.transform = mutableState.style.transform;
5143
- },
5034
+ }
5144
5035
  removeValueFromRenderState(key, { vars, style }) {
5145
5036
  delete vars[key];
5146
5037
  delete style[key];
5147
- },
5148
- /**
5149
- * Ensure that HTML and Framer-specific value types like `px`->`%` and `Color`
5150
- * can be animated by Motion.
5151
- */
5152
- makeTargetAnimatable(element, { transition, transitionEnd, ...target }, { transformValues }, isMounted = true) {
5153
- let origin = getOrigin(target, transition || {}, element);
5038
+ }
5039
+ makeTargetAnimatableFromInstance({ transition, transitionEnd, ...target }, { transformValues }, isMounted) {
5040
+ let origin = getOrigin(target, transition || {}, this);
5154
5041
  /**
5155
5042
  * If Framer has provided a function to convert `Color` etc value types, convert them
5156
5043
  */
@@ -5163,8 +5050,8 @@ const htmlConfig = {
5163
5050
  origin = transformValues(origin);
5164
5051
  }
5165
5052
  if (isMounted) {
5166
- checkTargetForNewValues(element, target, origin);
5167
- const parsed = parseDomVariant(element, target, origin, transitionEnd);
5053
+ checkTargetForNewValues(this, target, origin);
5054
+ const parsed = parseDomVariant(this, target, origin, transitionEnd);
5168
5055
  transitionEnd = parsed.transitionEnd;
5169
5056
  target = parsed.target;
5170
5057
  }
@@ -5173,44 +5060,70 @@ const htmlConfig = {
5173
5060
  transitionEnd,
5174
5061
  ...target,
5175
5062
  };
5176
- },
5177
- scrapeMotionValuesFromProps: scrapeMotionValuesFromProps$1,
5178
- build(element, renderState, latestValues, options, props) {
5179
- if (element.isVisible !== undefined) {
5180
- renderState.style.visibility = element.isVisible
5181
- ? "visible"
5182
- : "hidden";
5063
+ }
5064
+ }
5065
+
5066
+ function getComputedStyle$1(element) {
5067
+ return window.getComputedStyle(element);
5068
+ }
5069
+ class HTMLVisualElement extends DOMVisualElement {
5070
+ readValueFromInstance(instance, key) {
5071
+ if (transformProps.has(key)) {
5072
+ const defaultType = getDefaultValueType(key);
5073
+ return defaultType ? defaultType.default || 0 : 0;
5074
+ }
5075
+ else {
5076
+ const computedStyle = getComputedStyle$1(instance);
5077
+ const value = (isCSSVariable$1(key)
5078
+ ? computedStyle.getPropertyValue(key)
5079
+ : computedStyle[key]) || 0;
5080
+ return typeof value === "string" ? value.trim() : value;
5183
5081
  }
5082
+ }
5083
+ measureInstanceViewportBox(instance, { transformPagePoint }) {
5084
+ return measureViewportBox(instance, transformPagePoint);
5085
+ }
5086
+ build(renderState, latestValues, options, props) {
5184
5087
  buildHTMLStyles(renderState, latestValues, options, props.transformTemplate);
5185
- },
5186
- render: renderHTML,
5187
- };
5188
- const htmlVisualElement = visualElement(htmlConfig);
5088
+ }
5089
+ scrapeMotionValuesFromProps(props) {
5090
+ return scrapeMotionValuesFromProps$1(props);
5091
+ }
5092
+ renderInstance(instance, renderState, styleProp, projection) {
5093
+ renderHTML(instance, renderState, styleProp, projection);
5094
+ }
5095
+ }
5189
5096
 
5190
- const svgVisualElement = visualElement({
5191
- ...htmlConfig,
5192
- getBaseTarget(props, key) {
5097
+ class SVGVisualElement extends DOMVisualElement {
5098
+ getBaseTargetFromProps(props, key) {
5193
5099
  return props[key];
5194
- },
5195
- readValueFromInstance(domElement, key) {
5100
+ }
5101
+ readValueFromInstance(instance, key) {
5196
5102
  var _a;
5197
5103
  if (transformProps.has(key)) {
5198
5104
  return ((_a = getDefaultValueType(key)) === null || _a === void 0 ? void 0 : _a.default) || 0;
5199
5105
  }
5200
5106
  key = !camelCaseAttributes.has(key) ? camelToDash(key) : key;
5201
- return domElement.getAttribute(key);
5202
- },
5203
- scrapeMotionValuesFromProps,
5204
- build(_element, renderState, latestValues, options, props) {
5107
+ return instance.getAttribute(key);
5108
+ }
5109
+ measureInstanceViewportBox() {
5110
+ return createBox();
5111
+ }
5112
+ scrapeMotionValuesFromProps(props) {
5113
+ return scrapeMotionValuesFromProps(props);
5114
+ }
5115
+ build(renderState, latestValues, options, props) {
5205
5116
  buildSVGAttrs(renderState, latestValues, options, props.transformTemplate);
5206
- },
5207
- render: renderSVG,
5208
- });
5117
+ }
5118
+ renderInstance(instance, renderState, styleProp, projection) {
5119
+ renderSVG(instance, renderState, styleProp, projection);
5120
+ }
5121
+ }
5209
5122
 
5210
5123
  const createDomVisualElement = (Component, options) => {
5211
5124
  return isSVGComponent(Component)
5212
- ? svgVisualElement(options, { enableHardwareAcceleration: false })
5213
- : htmlVisualElement(options, { enableHardwareAcceleration: true });
5125
+ ? new SVGVisualElement(options, { enableHardwareAcceleration: false })
5126
+ : new HTMLVisualElement(options, { enableHardwareAcceleration: true });
5214
5127
  };
5215
5128
 
5216
5129
  function pixelsToPercent(pixels, axis) {
@@ -5808,7 +5721,7 @@ const transformAxes = ["", "X", "Y", "Z"];
5808
5721
  const animationTarget = 1000;
5809
5722
  function createProjectionNode({ attachResizeListener, defaultParent, measureScroll, checkIsScrollRoot, resetTransform, }) {
5810
5723
  return class ProjectionNode {
5811
- constructor(id, latestValues = {}, parent = defaultParent === null || defaultParent === void 0 ? void 0 : defaultParent()) {
5724
+ constructor(elementId, latestValues = {}, parent = defaultParent === null || defaultParent === void 0 ? void 0 : defaultParent()) {
5812
5725
  /**
5813
5726
  * A Set containing all this component's children. This is used to iterate
5814
5727
  * through the children.
@@ -5861,7 +5774,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
5861
5774
  /**
5862
5775
  * An object representing the calculated contextual/accumulated/tree scale.
5863
5776
  * This will be used to scale calculcated projection transforms, as these are
5864
- * calculated in screen-space but need to be scaled for elements to actually
5777
+ * calculated in screen-space but need to be scaled for elements to layoutly
5865
5778
  * make it to their calculated destinations.
5866
5779
  *
5867
5780
  * TODO: Lazy-init
@@ -5891,13 +5804,13 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
5891
5804
  */
5892
5805
  // TODO Only running on root node
5893
5806
  this.sharedNodes = new Map();
5894
- this.id = id;
5807
+ this.elementId = elementId;
5895
5808
  this.latestValues = latestValues;
5896
5809
  this.root = parent ? parent.root || parent : this;
5897
5810
  this.path = parent ? [...parent.path, parent] : [];
5898
5811
  this.parent = parent;
5899
5812
  this.depth = parent ? parent.depth + 1 : 0;
5900
- id && this.root.registerPotentialNode(id, this);
5813
+ elementId && this.root.registerPotentialNode(elementId, this);
5901
5814
  for (let i = 0; i < this.path.length; i++) {
5902
5815
  this.path[i].shouldResetTransform = true;
5903
5816
  }
@@ -5931,12 +5844,12 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
5931
5844
  instance instanceof SVGElement && instance.tagName !== "svg";
5932
5845
  this.instance = instance;
5933
5846
  const { layoutId, layout, visualElement } = this.options;
5934
- if (visualElement && !visualElement.getInstance()) {
5847
+ if (visualElement && !visualElement.current) {
5935
5848
  visualElement.mount(instance);
5936
5849
  }
5937
5850
  this.root.nodes.add(this);
5938
5851
  (_a = this.parent) === null || _a === void 0 ? void 0 : _a.children.add(this);
5939
- this.id && this.root.potentialNodes.delete(this.id);
5852
+ this.elementId && this.root.potentialNodes.delete(this.elementId);
5940
5853
  if (isLayoutDirty && (layout || layoutId)) {
5941
5854
  this.isLayoutDirty = true;
5942
5855
  }
@@ -6152,14 +6065,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6152
6065
  updateSnapshot() {
6153
6066
  if (this.snapshot || !this.instance)
6154
6067
  return;
6155
- const measured = this.measure();
6156
- const layout = this.removeTransform(this.removeElementScroll(measured));
6157
- roundBox(layout);
6158
- this.snapshot = {
6159
- measured,
6160
- layout,
6161
- latestValues: {},
6162
- };
6068
+ this.snapshot = this.measure();
6163
6069
  }
6164
6070
  updateLayout() {
6165
6071
  var _a;
@@ -6184,18 +6090,13 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6184
6090
  node.updateScroll();
6185
6091
  }
6186
6092
  }
6187
- const measured = this.measure();
6188
- roundBox(measured);
6189
6093
  const prevLayout = this.layout;
6190
- this.layout = {
6191
- measured,
6192
- actual: this.removeElementScroll(measured),
6193
- };
6094
+ this.layout = this.measure(false);
6194
6095
  this.layoutCorrected = createBox();
6195
6096
  this.isLayoutDirty = false;
6196
6097
  this.projectionDelta = undefined;
6197
- this.notifyListeners("measure", this.layout.actual);
6198
- (_a = this.options.visualElement) === null || _a === void 0 ? void 0 : _a.notifyLayoutMeasure(this.layout.actual, prevLayout === null || prevLayout === void 0 ? void 0 : prevLayout.actual);
6098
+ this.notifyListeners("measure", this.layout.layoutBox);
6099
+ (_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);
6199
6100
  }
6200
6101
  updateScroll() {
6201
6102
  if (this.options.layoutScroll && this.instance) {
@@ -6221,7 +6122,25 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6221
6122
  this.scheduleRender();
6222
6123
  }
6223
6124
  }
6224
- measure() {
6125
+ measure(removeTransform = true) {
6126
+ const pageBox = this.measurePageBox();
6127
+ let layoutBox = this.removeElementScroll(pageBox);
6128
+ /**
6129
+ * Measurements taken during the pre-render stage
6130
+ * still have transforms applied so we remove them
6131
+ * via calculation.
6132
+ */
6133
+ if (removeTransform) {
6134
+ layoutBox = this.removeTransform(layoutBox);
6135
+ }
6136
+ roundBox(layoutBox);
6137
+ return {
6138
+ measuredBox: pageBox,
6139
+ layoutBox,
6140
+ latestValues: {},
6141
+ };
6142
+ }
6143
+ measurePageBox() {
6225
6144
  const { visualElement } = this.options;
6226
6145
  if (!visualElement)
6227
6146
  return createBox();
@@ -6302,9 +6221,9 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6302
6221
  continue;
6303
6222
  hasScale(node.latestValues) && node.updateSnapshot();
6304
6223
  const sourceBox = createBox();
6305
- const nodeBox = node.measure();
6224
+ const nodeBox = node.measurePageBox();
6306
6225
  copyBoxInto(sourceBox, nodeBox);
6307
- removeBoxTransforms(boxWithoutTransform, node.latestValues, (_a = node.snapshot) === null || _a === void 0 ? void 0 : _a.layout, sourceBox);
6226
+ removeBoxTransforms(boxWithoutTransform, node.latestValues, (_a = node.snapshot) === null || _a === void 0 ? void 0 : _a.layoutBox, sourceBox);
6308
6227
  }
6309
6228
  if (hasTransform(this.latestValues)) {
6310
6229
  removeBoxTransforms(boxWithoutTransform, this.latestValues);
@@ -6353,13 +6272,17 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6353
6272
  // TODO If this is unsuccessful this currently happens every frame
6354
6273
  if (!this.targetDelta && !this.relativeTarget) {
6355
6274
  // TODO: This is a semi-repetition of further down this function, make DRY
6356
- this.relativeParent = this.getClosestProjectingParent();
6357
- if (this.relativeParent && this.relativeParent.layout) {
6275
+ const relativeParent = this.getClosestProjectingParent();
6276
+ if (relativeParent && relativeParent.layout) {
6277
+ this.relativeParent = relativeParent;
6358
6278
  this.relativeTarget = createBox();
6359
6279
  this.relativeTargetOrigin = createBox();
6360
- calcRelativePosition(this.relativeTargetOrigin, this.layout.actual, this.relativeParent.layout.actual);
6280
+ calcRelativePosition(this.relativeTargetOrigin, this.layout.layoutBox, relativeParent.layout.layoutBox);
6361
6281
  copyBoxInto(this.relativeTarget, this.relativeTargetOrigin);
6362
6282
  }
6283
+ else {
6284
+ this.relativeParent = this.relativeTarget = undefined;
6285
+ }
6363
6286
  }
6364
6287
  /**
6365
6288
  * If we have no relative target or no target delta our target isn't valid
@@ -6388,10 +6311,10 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6388
6311
  else if (this.targetDelta) {
6389
6312
  if (Boolean(this.resumingFrom)) {
6390
6313
  // TODO: This is creating a new object every frame
6391
- this.target = this.applyTransform(this.layout.actual);
6314
+ this.target = this.applyTransform(this.layout.layoutBox);
6392
6315
  }
6393
6316
  else {
6394
- copyBoxInto(this.target, this.layout.actual);
6317
+ copyBoxInto(this.target, this.layout.layoutBox);
6395
6318
  }
6396
6319
  applyBoxDelta(this.target, this.targetDelta);
6397
6320
  }
@@ -6399,24 +6322,28 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6399
6322
  /**
6400
6323
  * If no target, use own layout as target
6401
6324
  */
6402
- copyBoxInto(this.target, this.layout.actual);
6325
+ copyBoxInto(this.target, this.layout.layoutBox);
6403
6326
  }
6404
6327
  /**
6405
6328
  * If we've been told to attempt to resolve a relative target, do so.
6406
6329
  */
6407
6330
  if (this.attemptToResolveRelativeTarget) {
6408
6331
  this.attemptToResolveRelativeTarget = false;
6409
- this.relativeParent = this.getClosestProjectingParent();
6410
- if (this.relativeParent &&
6411
- Boolean(this.relativeParent.resumingFrom) ===
6332
+ const relativeParent = this.getClosestProjectingParent();
6333
+ if (relativeParent &&
6334
+ Boolean(relativeParent.resumingFrom) ===
6412
6335
  Boolean(this.resumingFrom) &&
6413
- !this.relativeParent.options.layoutScroll &&
6414
- this.relativeParent.target) {
6336
+ !relativeParent.options.layoutScroll &&
6337
+ relativeParent.target) {
6338
+ this.relativeParent = relativeParent;
6415
6339
  this.relativeTarget = createBox();
6416
6340
  this.relativeTargetOrigin = createBox();
6417
- calcRelativePosition(this.relativeTargetOrigin, this.target, this.relativeParent.target);
6341
+ calcRelativePosition(this.relativeTargetOrigin, this.target, relativeParent.target);
6418
6342
  copyBoxInto(this.relativeTarget, this.relativeTargetOrigin);
6419
6343
  }
6344
+ else {
6345
+ this.relativeParent = this.relativeTarget = undefined;
6346
+ }
6420
6347
  }
6421
6348
  }
6422
6349
  getClosestProjectingParent() {
@@ -6452,7 +6379,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6452
6379
  * Reset the corrected box with the latest values from box, as we're then going
6453
6380
  * to perform mutative operations on it.
6454
6381
  */
6455
- copyBoxInto(this.layoutCorrected, this.layout.actual);
6382
+ copyBoxInto(this.layoutCorrected, this.layout.layoutBox);
6456
6383
  /**
6457
6384
  * Apply all the parent deltas to this box to produce the corrected box. This
6458
6385
  * is the layout box, as it will appear on screen as a result of the transforms of its parents.
@@ -6529,7 +6456,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6529
6456
  this.relativeTargetOrigin &&
6530
6457
  this.layout &&
6531
6458
  ((_a = this.relativeParent) === null || _a === void 0 ? void 0 : _a.layout)) {
6532
- calcRelativePosition(relativeLayout, this.layout.actual, this.relativeParent.layout.actual);
6459
+ calcRelativePosition(relativeLayout, this.layout.layoutBox, this.relativeParent.layout.layoutBox);
6533
6460
  mixBox(this.relativeTarget, this.relativeTargetOrigin, relativeLayout, progress);
6534
6461
  }
6535
6462
  if (isSharedLayoutAnimation) {
@@ -6613,12 +6540,12 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6613
6540
  if (this !== lead &&
6614
6541
  this.layout &&
6615
6542
  layout &&
6616
- shouldAnimatePositionOnly(this.options.animationType, this.layout.actual, layout.actual)) {
6543
+ shouldAnimatePositionOnly(this.options.animationType, this.layout.layoutBox, layout.layoutBox)) {
6617
6544
  target = this.target || createBox();
6618
- const xLength = calcLength(this.layout.actual.x);
6545
+ const xLength = calcLength(this.layout.layoutBox.x);
6619
6546
  target.x.min = lead.target.x.min;
6620
6547
  target.x.max = target.x.min + xLength;
6621
- const yLength = calcLength(this.layout.actual.y);
6548
+ const yLength = calcLength(this.layout.layoutBox.y);
6622
6549
  target.y.min = lead.target.y.min;
6623
6550
  target.y.max = target.y.min + yLength;
6624
6551
  }
@@ -6632,7 +6559,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6632
6559
  /**
6633
6560
  * Update the delta between the corrected box and the final target box, after
6634
6561
  * user-set transforms are applied to it. This will be used by the renderer to
6635
- * create a transform style that will reproject the element from its actual layout
6562
+ * create a transform style that will reproject the element from its layout layout
6636
6563
  * into the desired bounding box.
6637
6564
  */
6638
6565
  calcBoxDelta(this.projectionDeltaWithTransform, this.layoutCorrected, targetWithTransforms, latestValues);
@@ -6715,7 +6642,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6715
6642
  return;
6716
6643
  // Force a render of this element to apply the transform with all rotations
6717
6644
  // set to 0.
6718
- visualElement === null || visualElement === void 0 ? void 0 : visualElement.syncRender();
6645
+ visualElement === null || visualElement === void 0 ? void 0 : visualElement.render();
6719
6646
  // Put back all the values we reset
6720
6647
  for (const key in resetValues) {
6721
6648
  visualElement.setStaticValue(key, resetValues[key]);
@@ -6788,7 +6715,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6788
6715
  }
6789
6716
  else {
6790
6717
  /**
6791
- * Or we're not animating at all, set the lead component to its actual
6718
+ * Or we're not animating at all, set the lead component to its layout
6792
6719
  * opacity and other components to hidden.
6793
6720
  */
6794
6721
  styles.opacity =
@@ -6852,53 +6779,53 @@ function notifyLayoutUpdate(node) {
6852
6779
  node.layout &&
6853
6780
  snapshot &&
6854
6781
  node.hasListeners("didUpdate")) {
6855
- const { actual: layout, measured: measuredLayout } = node.layout;
6782
+ const { layoutBox: layout, measuredBox: measuredLayout } = node.layout;
6856
6783
  const { animationType } = node.options;
6857
6784
  // TODO Maybe we want to also resize the layout snapshot so we don't trigger
6858
6785
  // animations for instance if layout="size" and an element has only changed position
6859
6786
  if (animationType === "size") {
6860
6787
  eachAxis((axis) => {
6861
6788
  const axisSnapshot = snapshot.isShared
6862
- ? snapshot.measured[axis]
6863
- : snapshot.layout[axis];
6789
+ ? snapshot.measuredBox[axis]
6790
+ : snapshot.layoutBox[axis];
6864
6791
  const length = calcLength(axisSnapshot);
6865
6792
  axisSnapshot.min = layout[axis].min;
6866
6793
  axisSnapshot.max = axisSnapshot.min + length;
6867
6794
  });
6868
6795
  }
6869
- else if (shouldAnimatePositionOnly(animationType, snapshot.layout, layout)) {
6796
+ else if (shouldAnimatePositionOnly(animationType, snapshot.layoutBox, layout)) {
6870
6797
  eachAxis((axis) => {
6871
6798
  const axisSnapshot = snapshot.isShared
6872
- ? snapshot.measured[axis]
6873
- : snapshot.layout[axis];
6799
+ ? snapshot.measuredBox[axis]
6800
+ : snapshot.layoutBox[axis];
6874
6801
  const length = calcLength(layout[axis]);
6875
6802
  axisSnapshot.max = axisSnapshot.min + length;
6876
6803
  });
6877
6804
  }
6878
6805
  const layoutDelta = createDelta();
6879
- calcBoxDelta(layoutDelta, layout, snapshot.layout);
6806
+ calcBoxDelta(layoutDelta, layout, snapshot.layoutBox);
6880
6807
  const visualDelta = createDelta();
6881
6808
  if (snapshot.isShared) {
6882
- calcBoxDelta(visualDelta, node.applyTransform(measuredLayout, true), snapshot.measured);
6809
+ calcBoxDelta(visualDelta, node.applyTransform(measuredLayout, true), snapshot.measuredBox);
6883
6810
  }
6884
6811
  else {
6885
- calcBoxDelta(visualDelta, layout, snapshot.layout);
6812
+ calcBoxDelta(visualDelta, layout, snapshot.layoutBox);
6886
6813
  }
6887
6814
  const hasLayoutChanged = !isDeltaZero(layoutDelta);
6888
6815
  let hasRelativeTargetChanged = false;
6889
6816
  if (!node.resumeFrom) {
6890
- node.relativeParent = node.getClosestProjectingParent();
6817
+ const relativeParent = node.getClosestProjectingParent();
6891
6818
  /**
6892
6819
  * If the relativeParent is itself resuming from a different element then
6893
6820
  * the relative snapshot is not relavent
6894
6821
  */
6895
- if (node.relativeParent && !node.relativeParent.resumeFrom) {
6896
- const { snapshot: parentSnapshot, layout: parentLayout } = node.relativeParent;
6822
+ if (relativeParent && !relativeParent.resumeFrom) {
6823
+ const { snapshot: parentSnapshot, layout: parentLayout } = relativeParent;
6897
6824
  if (parentSnapshot && parentLayout) {
6898
6825
  const relativeSnapshot = createBox();
6899
- calcRelativePosition(relativeSnapshot, snapshot.layout, parentSnapshot.layout);
6826
+ calcRelativePosition(relativeSnapshot, snapshot.layoutBox, parentSnapshot.layoutBox);
6900
6827
  const relativeLayout = createBox();
6901
- calcRelativePosition(relativeLayout, layout, parentLayout.actual);
6828
+ calcRelativePosition(relativeLayout, layout, parentLayout.layoutBox);
6902
6829
  if (!boxEquals(relativeSnapshot, relativeLayout)) {
6903
6830
  hasRelativeTargetChanged = true;
6904
6831
  }
@@ -6933,7 +6860,7 @@ function clearMeasurements(node) {
6933
6860
  function resetTransformStyle(node) {
6934
6861
  const { visualElement } = node.options;
6935
6862
  if (visualElement === null || visualElement === void 0 ? void 0 : visualElement.getProps().onBeforeLayoutMeasure) {
6936
- visualElement.notifyBeforeLayoutMeasure();
6863
+ visualElement.notify("BeforeLayoutMeasure");
6937
6864
  }
6938
6865
  node.resetTransform();
6939
6866
  }
@@ -8333,23 +8260,33 @@ function useResetProjection() {
8333
8260
  }
8334
8261
 
8335
8262
  const createObject = () => ({});
8336
- const stateVisualElement = visualElement({
8337
- build() { },
8338
- measureViewportBox: createBox,
8339
- resetTransform() { },
8340
- restoreTransform() { },
8341
- removeValueFromRenderState() { },
8342
- render() { },
8343
- scrapeMotionValuesFromProps: createObject,
8263
+ class StateVisualElement extends VisualElement {
8264
+ build() { }
8265
+ measureInstanceViewportBox() {
8266
+ return createBox();
8267
+ }
8268
+ resetTransform() { }
8269
+ restoreTransform() { }
8270
+ removeValueFromRenderState() { }
8271
+ renderInstance() { }
8272
+ scrapeMotionValuesFromProps() {
8273
+ return createObject();
8274
+ }
8275
+ getBaseTargetFromProps() {
8276
+ return undefined;
8277
+ }
8344
8278
  readValueFromInstance(_state, key, options) {
8345
8279
  return options.initialState[key] || 0;
8346
- },
8347
- makeTargetAnimatable(element, { transition, transitionEnd, ...target }) {
8348
- const origin = getOrigin(target, transition || {}, element);
8349
- checkTargetForNewValues(element, target, origin);
8280
+ }
8281
+ sortInstanceNodePosition() {
8282
+ return 0;
8283
+ }
8284
+ makeTargetAnimatableFromInstance({ transition, transitionEnd, ...target }) {
8285
+ const origin = getOrigin(target, transition || {}, this);
8286
+ checkTargetForNewValues(this, target, origin);
8350
8287
  return { transition, transitionEnd, ...target };
8351
- },
8352
- });
8288
+ }
8289
+ }
8353
8290
  const useVisualState = makeUseVisualState({
8354
8291
  scrapeMotionValuesFromProps: createObject,
8355
8292
  createRenderState: createObject,
@@ -8361,10 +8298,12 @@ const useVisualState = makeUseVisualState({
8361
8298
  function useAnimatedState(initialState) {
8362
8299
  const [animationState, setAnimationState] = React.useState(initialState);
8363
8300
  const visualState = useVisualState({}, false);
8364
- const element = useConstant(() => stateVisualElement({ props: {}, visualState }, { initialState }));
8301
+ const element = useConstant(() => {
8302
+ return new StateVisualElement({ props: {}, visualState }, { initialState });
8303
+ });
8365
8304
  React.useEffect(() => {
8366
8305
  element.mount({});
8367
- return element.unmount;
8306
+ return () => element.unmount();
8368
8307
  }, [element]);
8369
8308
  React.useEffect(() => {
8370
8309
  element.setProps({
@@ -8439,6 +8378,7 @@ exports.MotionValue = MotionValue;
8439
8378
  exports.PresenceContext = PresenceContext;
8440
8379
  exports.Reorder = Reorder;
8441
8380
  exports.SwitchLayoutGroupContext = SwitchLayoutGroupContext;
8381
+ exports.VisualElement = VisualElement;
8442
8382
  exports.addPointerEvent = addPointerEvent;
8443
8383
  exports.addScaleCorrector = addScaleCorrector;
8444
8384
  exports.animate = animate;
@@ -8497,5 +8437,4 @@ exports.useVelocity = useVelocity;
8497
8437
  exports.useViewportScroll = useViewportScroll;
8498
8438
  exports.useVisualElementContext = useVisualElementContext;
8499
8439
  exports.useWillChange = useWillChange;
8500
- exports.visualElement = visualElement;
8501
8440
  exports.wrapHandler = wrapHandler;