framer-motion 7.6.4 → 7.6.5

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 +734 -801
  2. package/dist/es/animation/use-animated-state.mjs +29 -17
  3. package/dist/es/gestures/drag/VisualElementDragControls.mjs +9 -5
  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 +24 -16
  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 +734 -801
  23. package/dist/framer-motion.js +1 -1
  24. package/dist/index.d.ts +2100 -1927
  25. package/dist/projection.dev.js +983 -1072
  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 +1946 -1732
  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.5";
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);
@@ -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);
@@ -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.5", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.6.5 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
+ }
4902
+ }
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;
5109
4991
  }
5110
- },
5111
- sortNodePosition(a, b) {
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) {
@@ -5931,7 +5844,7 @@ 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);
@@ -6195,7 +6108,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6195
6108
  this.isLayoutDirty = false;
6196
6109
  this.projectionDelta = undefined;
6197
6110
  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);
6111
+ (_a = this.options.visualElement) === null || _a === void 0 ? void 0 : _a.notify("LayoutMeasure", this.layout.actual, prevLayout === null || prevLayout === void 0 ? void 0 : prevLayout.actual);
6199
6112
  }
6200
6113
  updateScroll() {
6201
6114
  if (this.options.layoutScroll && this.instance) {
@@ -6353,13 +6266,17 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6353
6266
  // TODO If this is unsuccessful this currently happens every frame
6354
6267
  if (!this.targetDelta && !this.relativeTarget) {
6355
6268
  // 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) {
6269
+ const relativeParent = this.getClosestProjectingParent();
6270
+ if (relativeParent && relativeParent.layout) {
6271
+ this.relativeParent = relativeParent;
6358
6272
  this.relativeTarget = createBox();
6359
6273
  this.relativeTargetOrigin = createBox();
6360
- calcRelativePosition(this.relativeTargetOrigin, this.layout.actual, this.relativeParent.layout.actual);
6274
+ calcRelativePosition(this.relativeTargetOrigin, this.layout.actual, relativeParent.layout.actual);
6361
6275
  copyBoxInto(this.relativeTarget, this.relativeTargetOrigin);
6362
6276
  }
6277
+ else {
6278
+ this.relativeParent = this.relativeTarget = undefined;
6279
+ }
6363
6280
  }
6364
6281
  /**
6365
6282
  * If we have no relative target or no target delta our target isn't valid
@@ -6406,17 +6323,21 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6406
6323
  */
6407
6324
  if (this.attemptToResolveRelativeTarget) {
6408
6325
  this.attemptToResolveRelativeTarget = false;
6409
- this.relativeParent = this.getClosestProjectingParent();
6410
- if (this.relativeParent &&
6411
- Boolean(this.relativeParent.resumingFrom) ===
6326
+ const relativeParent = this.getClosestProjectingParent();
6327
+ if (relativeParent &&
6328
+ Boolean(relativeParent.resumingFrom) ===
6412
6329
  Boolean(this.resumingFrom) &&
6413
- !this.relativeParent.options.layoutScroll &&
6414
- this.relativeParent.target) {
6330
+ !relativeParent.options.layoutScroll &&
6331
+ relativeParent.target) {
6332
+ this.relativeParent = relativeParent;
6415
6333
  this.relativeTarget = createBox();
6416
6334
  this.relativeTargetOrigin = createBox();
6417
- calcRelativePosition(this.relativeTargetOrigin, this.target, this.relativeParent.target);
6335
+ calcRelativePosition(this.relativeTargetOrigin, this.target, relativeParent.target);
6418
6336
  copyBoxInto(this.relativeTarget, this.relativeTargetOrigin);
6419
6337
  }
6338
+ else {
6339
+ this.relativeParent = this.relativeTarget = undefined;
6340
+ }
6420
6341
  }
6421
6342
  }
6422
6343
  getClosestProjectingParent() {
@@ -6715,7 +6636,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6715
6636
  return;
6716
6637
  // Force a render of this element to apply the transform with all rotations
6717
6638
  // set to 0.
6718
- visualElement === null || visualElement === void 0 ? void 0 : visualElement.syncRender();
6639
+ visualElement === null || visualElement === void 0 ? void 0 : visualElement.render();
6719
6640
  // Put back all the values we reset
6720
6641
  for (const key in resetValues) {
6721
6642
  visualElement.setStaticValue(key, resetValues[key]);
@@ -6887,13 +6808,13 @@ function notifyLayoutUpdate(node) {
6887
6808
  const hasLayoutChanged = !isDeltaZero(layoutDelta);
6888
6809
  let hasRelativeTargetChanged = false;
6889
6810
  if (!node.resumeFrom) {
6890
- node.relativeParent = node.getClosestProjectingParent();
6811
+ const relativeParent = node.getClosestProjectingParent();
6891
6812
  /**
6892
6813
  * If the relativeParent is itself resuming from a different element then
6893
6814
  * the relative snapshot is not relavent
6894
6815
  */
6895
- if (node.relativeParent && !node.relativeParent.resumeFrom) {
6896
- const { snapshot: parentSnapshot, layout: parentLayout } = node.relativeParent;
6816
+ if (relativeParent && !relativeParent.resumeFrom) {
6817
+ const { snapshot: parentSnapshot, layout: parentLayout } = relativeParent;
6897
6818
  if (parentSnapshot && parentLayout) {
6898
6819
  const relativeSnapshot = createBox();
6899
6820
  calcRelativePosition(relativeSnapshot, snapshot.layout, parentSnapshot.layout);
@@ -6933,7 +6854,7 @@ function clearMeasurements(node) {
6933
6854
  function resetTransformStyle(node) {
6934
6855
  const { visualElement } = node.options;
6935
6856
  if (visualElement === null || visualElement === void 0 ? void 0 : visualElement.getProps().onBeforeLayoutMeasure) {
6936
- visualElement.notifyBeforeLayoutMeasure();
6857
+ visualElement.notify("BeforeLayoutMeasure");
6937
6858
  }
6938
6859
  node.resetTransform();
6939
6860
  }
@@ -8333,23 +8254,33 @@ function useResetProjection() {
8333
8254
  }
8334
8255
 
8335
8256
  const createObject = () => ({});
8336
- const stateVisualElement = visualElement({
8337
- build() { },
8338
- measureViewportBox: createBox,
8339
- resetTransform() { },
8340
- restoreTransform() { },
8341
- removeValueFromRenderState() { },
8342
- render() { },
8343
- scrapeMotionValuesFromProps: createObject,
8257
+ class StateVisualElement extends VisualElement {
8258
+ build() { }
8259
+ measureInstanceViewportBox() {
8260
+ return createBox();
8261
+ }
8262
+ resetTransform() { }
8263
+ restoreTransform() { }
8264
+ removeValueFromRenderState() { }
8265
+ renderInstance() { }
8266
+ scrapeMotionValuesFromProps() {
8267
+ return createObject();
8268
+ }
8269
+ getBaseTargetFromProps() {
8270
+ return undefined;
8271
+ }
8344
8272
  readValueFromInstance(_state, key, options) {
8345
8273
  return options.initialState[key] || 0;
8346
- },
8347
- makeTargetAnimatable(element, { transition, transitionEnd, ...target }) {
8348
- const origin = getOrigin(target, transition || {}, element);
8349
- checkTargetForNewValues(element, target, origin);
8274
+ }
8275
+ sortInstanceNodePosition() {
8276
+ return 0;
8277
+ }
8278
+ makeTargetAnimatableFromInstance({ transition, transitionEnd, ...target }) {
8279
+ const origin = getOrigin(target, transition || {}, this);
8280
+ checkTargetForNewValues(this, target, origin);
8350
8281
  return { transition, transitionEnd, ...target };
8351
- },
8352
- });
8282
+ }
8283
+ }
8353
8284
  const useVisualState = makeUseVisualState({
8354
8285
  scrapeMotionValuesFromProps: createObject,
8355
8286
  createRenderState: createObject,
@@ -8361,10 +8292,12 @@ const useVisualState = makeUseVisualState({
8361
8292
  function useAnimatedState(initialState) {
8362
8293
  const [animationState, setAnimationState] = React.useState(initialState);
8363
8294
  const visualState = useVisualState({}, false);
8364
- const element = useConstant(() => stateVisualElement({ props: {}, visualState }, { initialState }));
8295
+ const element = useConstant(() => {
8296
+ return new StateVisualElement({ props: {}, visualState }, { initialState });
8297
+ });
8365
8298
  React.useEffect(() => {
8366
8299
  element.mount({});
8367
- return element.unmount;
8300
+ return () => element.unmount();
8368
8301
  }, [element]);
8369
8302
  React.useEffect(() => {
8370
8303
  element.setProps({
@@ -8439,6 +8372,7 @@ exports.MotionValue = MotionValue;
8439
8372
  exports.PresenceContext = PresenceContext;
8440
8373
  exports.Reorder = Reorder;
8441
8374
  exports.SwitchLayoutGroupContext = SwitchLayoutGroupContext;
8375
+ exports.VisualElement = VisualElement;
8442
8376
  exports.addPointerEvent = addPointerEvent;
8443
8377
  exports.addScaleCorrector = addScaleCorrector;
8444
8378
  exports.animate = animate;
@@ -8497,5 +8431,4 @@ exports.useVelocity = useVelocity;
8497
8431
  exports.useViewportScroll = useViewportScroll;
8498
8432
  exports.useVisualElementContext = useVisualElementContext;
8499
8433
  exports.useWillChange = useWillChange;
8500
- exports.visualElement = visualElement;
8501
8434
  exports.wrapHandler = wrapHandler;