framer-motion 9.1.2 → 9.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -2000,7 +2000,7 @@ class MotionValue {
2000
2000
  * This will be replaced by the build step with the latest version number.
2001
2001
  * When MotionValues are provided to motion components, warn if versions are mixed.
2002
2002
  */
2003
- this.version = "9.1.2";
2003
+ this.version = "9.1.3";
2004
2004
  /**
2005
2005
  * Duration, in milliseconds, since last updating frame.
2006
2006
  *
@@ -5944,6 +5944,12 @@ class FlatTree {
5944
5944
  }
5945
5945
  }
5946
5946
 
5947
+ function record(data) {
5948
+ if (window.MotionDebug) {
5949
+ window.MotionDebug.record(data);
5950
+ }
5951
+ }
5952
+
5947
5953
  const transformAxes = ["", "X", "Y", "Z"];
5948
5954
  /**
5949
5955
  * We use 1000 as the animation target as 0-1000 maps better to pixels than 0-1
@@ -5951,6 +5957,16 @@ const transformAxes = ["", "X", "Y", "Z"];
5951
5957
  */
5952
5958
  const animationTarget = 1000;
5953
5959
  let id$1 = 0;
5960
+ /**
5961
+ * Use a mutable data object for debug data so as to not create a new
5962
+ * object every frame.
5963
+ */
5964
+ const projectionFrameData = {
5965
+ type: "projectionFrame",
5966
+ totalNodes: 0,
5967
+ resolvedTargetDeltas: 0,
5968
+ recalculatedProjection: 0,
5969
+ };
5954
5970
  function createProjectionNode({ attachResizeListener, defaultParent, measureScroll, checkIsScrollRoot, resetTransform, }) {
5955
5971
  return class ProjectionNode {
5956
5972
  constructor(elementId, latestValues = {}, parent = defaultParent === null || defaultParent === void 0 ? void 0 : defaultParent()) {
@@ -5988,12 +6004,21 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
5988
6004
  * and if one node is dirtied, they all are.
5989
6005
  */
5990
6006
  this.isLayoutDirty = false;
5991
- this.isTransformDirty = false;
5992
6007
  /**
5993
- * Flag to true if we think the projection calculations for this or any
5994
- * child might need recalculating as a result of an updated transform or layout animation.
6008
+ * Flag to true if we think the projection calculations for this node needs
6009
+ * recalculating as a result of an updated transform or layout animation.
5995
6010
  */
5996
6011
  this.isProjectionDirty = false;
6012
+ /**
6013
+ * Flag to true if the layout *or* transform has changed. This then gets propagated
6014
+ * throughout the projection tree, forcing any element below to recalculate on the next frame.
6015
+ */
6016
+ this.isSharedProjectionDirty = false;
6017
+ /**
6018
+ * Flag transform dirty. This gets propagated throughout the whole tree but is only
6019
+ * respected by shared nodes.
6020
+ */
6021
+ this.isTransformDirty = false;
5997
6022
  /**
5998
6023
  * Block layout updates for instant layout transitions throughout the tree.
5999
6024
  */
@@ -6044,9 +6069,19 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6044
6069
  * the next step.
6045
6070
  */
6046
6071
  this.updateProjection = () => {
6072
+ /**
6073
+ * Reset debug counts. Manually resetting rather than creating a new
6074
+ * object each frame.
6075
+ */
6076
+ projectionFrameData.totalNodes =
6077
+ projectionFrameData.resolvedTargetDeltas =
6078
+ projectionFrameData.recalculatedProjection =
6079
+ 0;
6047
6080
  this.nodes.forEach(propagateDirtyNodes);
6048
6081
  this.nodes.forEach(resolveTargetDelta);
6049
6082
  this.nodes.forEach(calcProjection);
6083
+ this.nodes.forEach(cleanDirtyNodes);
6084
+ record(projectionFrameData);
6050
6085
  };
6051
6086
  this.hasProjected = false;
6052
6087
  this.isVisible = true;
@@ -6502,13 +6537,10 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6502
6537
  }
6503
6538
  return boxWithoutTransform;
6504
6539
  }
6505
- /**
6506
- *
6507
- */
6508
6540
  setTargetDelta(delta) {
6509
6541
  this.targetDelta = delta;
6510
- this.isProjectionDirty = true;
6511
6542
  this.root.scheduleUpdateProjection();
6543
+ this.isProjectionDirty = true;
6512
6544
  }
6513
6545
  setOptions(options) {
6514
6546
  this.options = {
@@ -6530,6 +6562,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6530
6562
  * Frame calculations
6531
6563
  */
6532
6564
  resolveTargetDelta() {
6565
+ var _a;
6533
6566
  /**
6534
6567
  * Once the dirty status of nodes has been spread through the tree, we also
6535
6568
  * need to check if we have a shared node of a different depth that has itself
@@ -6538,11 +6571,17 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6538
6571
  const lead = this.getLead();
6539
6572
  this.isProjectionDirty || (this.isProjectionDirty = lead.isProjectionDirty);
6540
6573
  this.isTransformDirty || (this.isTransformDirty = lead.isTransformDirty);
6574
+ this.isSharedProjectionDirty || (this.isSharedProjectionDirty = lead.isSharedProjectionDirty);
6575
+ const isShared = Boolean(this.resumingFrom) || this !== lead;
6541
6576
  /**
6542
6577
  * We don't use transform for this step of processing so we don't
6543
6578
  * need to check whether any nodes have changed transform.
6544
6579
  */
6545
- if (!this.isProjectionDirty && !this.attemptToResolveRelativeTarget)
6580
+ const canSkip = !((isShared && this.isSharedProjectionDirty) ||
6581
+ this.isProjectionDirty ||
6582
+ ((_a = this.parent) === null || _a === void 0 ? void 0 : _a.isProjectionDirty) ||
6583
+ this.attemptToResolveRelativeTarget);
6584
+ if (canSkip)
6546
6585
  return;
6547
6586
  const { layout, layoutId } = this.options;
6548
6587
  /**
@@ -6632,6 +6671,10 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6632
6671
  this.relativeParent = this.relativeTarget = undefined;
6633
6672
  }
6634
6673
  }
6674
+ /**
6675
+ * Increase debug counter for resolved target deltas
6676
+ */
6677
+ projectionFrameData.resolvedTargetDeltas++;
6635
6678
  }
6636
6679
  getClosestProjectingParent() {
6637
6680
  if (!this.parent ||
@@ -6639,26 +6682,39 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6639
6682
  has2DTranslate(this.parent.latestValues)) {
6640
6683
  return undefined;
6641
6684
  }
6642
- if ((this.parent.relativeTarget ||
6643
- this.parent.targetDelta ||
6644
- this.parent.options.layoutRoot) &&
6645
- this.parent.layout) {
6685
+ if (this.parent.isProjecting()) {
6646
6686
  return this.parent;
6647
6687
  }
6648
6688
  else {
6649
6689
  return this.parent.getClosestProjectingParent();
6650
6690
  }
6651
6691
  }
6692
+ isProjecting() {
6693
+ return Boolean((this.relativeTarget ||
6694
+ this.targetDelta ||
6695
+ this.options.layoutRoot) &&
6696
+ this.layout);
6697
+ }
6652
6698
  calcProjection() {
6653
- const { isProjectionDirty, isTransformDirty } = this;
6654
- this.isProjectionDirty = this.isTransformDirty = false;
6699
+ var _a;
6655
6700
  const lead = this.getLead();
6656
6701
  const isShared = Boolean(this.resumingFrom) || this !== lead;
6657
6702
  let canSkip = true;
6658
- if (isProjectionDirty)
6703
+ /**
6704
+ * If this is a normal layout animation and neither this node nor its nearest projecting
6705
+ * is dirty then we can't skip.
6706
+ */
6707
+ if (this.isProjectionDirty || ((_a = this.parent) === null || _a === void 0 ? void 0 : _a.isProjectionDirty)) {
6659
6708
  canSkip = false;
6660
- if (isShared && isTransformDirty)
6709
+ }
6710
+ /**
6711
+ * If this is a shared layout animation and this node's shared projection is dirty then
6712
+ * we can't skip.
6713
+ */
6714
+ if (isShared &&
6715
+ (this.isSharedProjectionDirty || this.isTransformDirty)) {
6661
6716
  canSkip = false;
6717
+ }
6662
6718
  if (canSkip)
6663
6719
  return;
6664
6720
  const { layout, layoutId } = this.options;
@@ -6712,6 +6768,10 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6712
6768
  this.scheduleRender();
6713
6769
  this.notifyListeners("projectionUpdate", target);
6714
6770
  }
6771
+ /**
6772
+ * Increase debug counter for recalculated projections
6773
+ */
6774
+ projectionFrameData.recalculatedProjection++;
6715
6775
  }
6716
6776
  hide() {
6717
6777
  this.isVisible = false;
@@ -6754,6 +6814,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6754
6814
  this.options.crossfade === true &&
6755
6815
  !this.path.some(hasOpacityCrossfade));
6756
6816
  this.animationProgress = 0;
6817
+ let prevRelativeTarget;
6757
6818
  this.mixTargetDelta = (latest) => {
6758
6819
  const progress = latest / 1000;
6759
6820
  mixAxisDelta(targetDelta.x, delta.x, progress);
@@ -6766,6 +6827,17 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
6766
6827
  this.relativeParent.layout) {
6767
6828
  calcRelativePosition(relativeLayout, this.layout.layoutBox, this.relativeParent.layout.layoutBox);
6768
6829
  mixBox(this.relativeTarget, this.relativeTargetOrigin, relativeLayout, progress);
6830
+ /**
6831
+ * If this is an unchanged relative target we can consider the
6832
+ * projection not dirty.
6833
+ */
6834
+ if (prevRelativeTarget &&
6835
+ boxEquals(this.relativeTarget, prevRelativeTarget)) {
6836
+ this.isProjectionDirty = false;
6837
+ }
6838
+ if (!prevRelativeTarget)
6839
+ prevRelativeTarget = createBox();
6840
+ copyBoxInto(prevRelativeTarget, this.relativeTarget);
6769
6841
  }
6770
6842
  if (isSharedLayoutAnimation) {
6771
6843
  this.animationValues = mixedValues;
@@ -7179,14 +7251,35 @@ function notifyLayoutUpdate(node) {
7179
7251
  }
7180
7252
  function propagateDirtyNodes(node) {
7181
7253
  /**
7182
- * Propagate isProjectionDirty. Nodes are ordered by depth, so if the parent here
7183
- * is dirty we can simply pass this forward.
7254
+ * Increase debug counter for nodes encountered this frame
7184
7255
  */
7185
- node.isProjectionDirty || (node.isProjectionDirty = Boolean(node.parent && node.parent.isProjectionDirty));
7256
+ projectionFrameData.totalNodes++;
7257
+ if (!node.parent)
7258
+ return;
7186
7259
  /**
7187
- * Propagate isTransformDirty.
7260
+ * If this node isn't projecting, propagate isProjectionDirty. It will have
7261
+ * no performance impact but it will allow the next child that *is* projecting
7262
+ * but *isn't* dirty to just check its parent to see if *any* ancestor needs
7263
+ * correcting.
7188
7264
  */
7189
- node.isTransformDirty || (node.isTransformDirty = Boolean(node.parent && node.parent.isTransformDirty));
7265
+ if (!node.isProjecting()) {
7266
+ node.isProjectionDirty = node.parent.isProjectionDirty;
7267
+ }
7268
+ /**
7269
+ * Propagate isSharedProjectionDirty and isTransformDirty
7270
+ * throughout the whole tree. A future revision can take another look at
7271
+ * this but for safety we still recalcualte shared nodes.
7272
+ */
7273
+ node.isSharedProjectionDirty || (node.isSharedProjectionDirty = Boolean(node.isProjectionDirty ||
7274
+ node.parent.isProjectionDirty ||
7275
+ node.parent.isSharedProjectionDirty));
7276
+ node.isTransformDirty || (node.isTransformDirty = node.parent.isTransformDirty);
7277
+ }
7278
+ function cleanDirtyNodes(node) {
7279
+ node.isProjectionDirty =
7280
+ node.isSharedProjectionDirty =
7281
+ node.isTransformDirty =
7282
+ false;
7190
7283
  }
7191
7284
  function clearSnapshot(node) {
7192
7285
  node.clearSnapshot();
@@ -7764,7 +7857,7 @@ function updateMotionValuesFromProps(element, next, prev) {
7764
7857
  * and warn against mismatches.
7765
7858
  */
7766
7859
  if (process.env.NODE_ENV === "development") {
7767
- warnOnce(nextValue.version === "9.1.2", `Attempting to mix Framer Motion versions ${nextValue.version} with 9.1.2 may not work as expected.`);
7860
+ warnOnce(nextValue.version === "9.1.3", `Attempting to mix Framer Motion versions ${nextValue.version} with 9.1.3 may not work as expected.`);
7768
7861
  }
7769
7862
  }
7770
7863
  else if (isMotionValue(prevValue)) {
@@ -0,0 +1,7 @@
1
+ function record(data) {
2
+ if (window.MotionDebug) {
3
+ window.MotionDebug.record(data);
4
+ }
5
+ }
6
+
7
+ export { record };
@@ -19,6 +19,7 @@ import { resolveMotionValue } from '../../value/utils/resolve-motion-value.mjs';
19
19
  import { globalProjectionState } from './state.mjs';
20
20
  import { delay } from '../../utils/delay.mjs';
21
21
  import { mix } from '../../utils/mix.mjs';
22
+ import { record } from '../../debug/record.mjs';
22
23
 
23
24
  const transformAxes = ["", "X", "Y", "Z"];
24
25
  /**
@@ -27,6 +28,16 @@ const transformAxes = ["", "X", "Y", "Z"];
27
28
  */
28
29
  const animationTarget = 1000;
29
30
  let id = 0;
31
+ /**
32
+ * Use a mutable data object for debug data so as to not create a new
33
+ * object every frame.
34
+ */
35
+ const projectionFrameData = {
36
+ type: "projectionFrame",
37
+ totalNodes: 0,
38
+ resolvedTargetDeltas: 0,
39
+ recalculatedProjection: 0,
40
+ };
30
41
  function createProjectionNode({ attachResizeListener, defaultParent, measureScroll, checkIsScrollRoot, resetTransform, }) {
31
42
  return class ProjectionNode {
32
43
  constructor(elementId, latestValues = {}, parent = defaultParent === null || defaultParent === void 0 ? void 0 : defaultParent()) {
@@ -64,12 +75,21 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
64
75
  * and if one node is dirtied, they all are.
65
76
  */
66
77
  this.isLayoutDirty = false;
67
- this.isTransformDirty = false;
68
78
  /**
69
- * Flag to true if we think the projection calculations for this or any
70
- * child might need recalculating as a result of an updated transform or layout animation.
79
+ * Flag to true if we think the projection calculations for this node needs
80
+ * recalculating as a result of an updated transform or layout animation.
71
81
  */
72
82
  this.isProjectionDirty = false;
83
+ /**
84
+ * Flag to true if the layout *or* transform has changed. This then gets propagated
85
+ * throughout the projection tree, forcing any element below to recalculate on the next frame.
86
+ */
87
+ this.isSharedProjectionDirty = false;
88
+ /**
89
+ * Flag transform dirty. This gets propagated throughout the whole tree but is only
90
+ * respected by shared nodes.
91
+ */
92
+ this.isTransformDirty = false;
73
93
  /**
74
94
  * Block layout updates for instant layout transitions throughout the tree.
75
95
  */
@@ -120,9 +140,19 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
120
140
  * the next step.
121
141
  */
122
142
  this.updateProjection = () => {
143
+ /**
144
+ * Reset debug counts. Manually resetting rather than creating a new
145
+ * object each frame.
146
+ */
147
+ projectionFrameData.totalNodes =
148
+ projectionFrameData.resolvedTargetDeltas =
149
+ projectionFrameData.recalculatedProjection =
150
+ 0;
123
151
  this.nodes.forEach(propagateDirtyNodes);
124
152
  this.nodes.forEach(resolveTargetDelta);
125
153
  this.nodes.forEach(calcProjection);
154
+ this.nodes.forEach(cleanDirtyNodes);
155
+ record(projectionFrameData);
126
156
  };
127
157
  this.hasProjected = false;
128
158
  this.isVisible = true;
@@ -578,13 +608,10 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
578
608
  }
579
609
  return boxWithoutTransform;
580
610
  }
581
- /**
582
- *
583
- */
584
611
  setTargetDelta(delta) {
585
612
  this.targetDelta = delta;
586
- this.isProjectionDirty = true;
587
613
  this.root.scheduleUpdateProjection();
614
+ this.isProjectionDirty = true;
588
615
  }
589
616
  setOptions(options) {
590
617
  this.options = {
@@ -606,6 +633,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
606
633
  * Frame calculations
607
634
  */
608
635
  resolveTargetDelta() {
636
+ var _a;
609
637
  /**
610
638
  * Once the dirty status of nodes has been spread through the tree, we also
611
639
  * need to check if we have a shared node of a different depth that has itself
@@ -614,11 +642,17 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
614
642
  const lead = this.getLead();
615
643
  this.isProjectionDirty || (this.isProjectionDirty = lead.isProjectionDirty);
616
644
  this.isTransformDirty || (this.isTransformDirty = lead.isTransformDirty);
645
+ this.isSharedProjectionDirty || (this.isSharedProjectionDirty = lead.isSharedProjectionDirty);
646
+ const isShared = Boolean(this.resumingFrom) || this !== lead;
617
647
  /**
618
648
  * We don't use transform for this step of processing so we don't
619
649
  * need to check whether any nodes have changed transform.
620
650
  */
621
- if (!this.isProjectionDirty && !this.attemptToResolveRelativeTarget)
651
+ const canSkip = !((isShared && this.isSharedProjectionDirty) ||
652
+ this.isProjectionDirty ||
653
+ ((_a = this.parent) === null || _a === void 0 ? void 0 : _a.isProjectionDirty) ||
654
+ this.attemptToResolveRelativeTarget);
655
+ if (canSkip)
622
656
  return;
623
657
  const { layout, layoutId } = this.options;
624
658
  /**
@@ -708,6 +742,10 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
708
742
  this.relativeParent = this.relativeTarget = undefined;
709
743
  }
710
744
  }
745
+ /**
746
+ * Increase debug counter for resolved target deltas
747
+ */
748
+ projectionFrameData.resolvedTargetDeltas++;
711
749
  }
712
750
  getClosestProjectingParent() {
713
751
  if (!this.parent ||
@@ -715,26 +753,39 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
715
753
  has2DTranslate(this.parent.latestValues)) {
716
754
  return undefined;
717
755
  }
718
- if ((this.parent.relativeTarget ||
719
- this.parent.targetDelta ||
720
- this.parent.options.layoutRoot) &&
721
- this.parent.layout) {
756
+ if (this.parent.isProjecting()) {
722
757
  return this.parent;
723
758
  }
724
759
  else {
725
760
  return this.parent.getClosestProjectingParent();
726
761
  }
727
762
  }
763
+ isProjecting() {
764
+ return Boolean((this.relativeTarget ||
765
+ this.targetDelta ||
766
+ this.options.layoutRoot) &&
767
+ this.layout);
768
+ }
728
769
  calcProjection() {
729
- const { isProjectionDirty, isTransformDirty } = this;
730
- this.isProjectionDirty = this.isTransformDirty = false;
770
+ var _a;
731
771
  const lead = this.getLead();
732
772
  const isShared = Boolean(this.resumingFrom) || this !== lead;
733
773
  let canSkip = true;
734
- if (isProjectionDirty)
774
+ /**
775
+ * If this is a normal layout animation and neither this node nor its nearest projecting
776
+ * is dirty then we can't skip.
777
+ */
778
+ if (this.isProjectionDirty || ((_a = this.parent) === null || _a === void 0 ? void 0 : _a.isProjectionDirty)) {
735
779
  canSkip = false;
736
- if (isShared && isTransformDirty)
780
+ }
781
+ /**
782
+ * If this is a shared layout animation and this node's shared projection is dirty then
783
+ * we can't skip.
784
+ */
785
+ if (isShared &&
786
+ (this.isSharedProjectionDirty || this.isTransformDirty)) {
737
787
  canSkip = false;
788
+ }
738
789
  if (canSkip)
739
790
  return;
740
791
  const { layout, layoutId } = this.options;
@@ -788,6 +839,10 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
788
839
  this.scheduleRender();
789
840
  this.notifyListeners("projectionUpdate", target);
790
841
  }
842
+ /**
843
+ * Increase debug counter for recalculated projections
844
+ */
845
+ projectionFrameData.recalculatedProjection++;
791
846
  }
792
847
  hide() {
793
848
  this.isVisible = false;
@@ -830,6 +885,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
830
885
  this.options.crossfade === true &&
831
886
  !this.path.some(hasOpacityCrossfade));
832
887
  this.animationProgress = 0;
888
+ let prevRelativeTarget;
833
889
  this.mixTargetDelta = (latest) => {
834
890
  const progress = latest / 1000;
835
891
  mixAxisDelta(targetDelta.x, delta.x, progress);
@@ -842,6 +898,17 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
842
898
  this.relativeParent.layout) {
843
899
  calcRelativePosition(relativeLayout, this.layout.layoutBox, this.relativeParent.layout.layoutBox);
844
900
  mixBox(this.relativeTarget, this.relativeTargetOrigin, relativeLayout, progress);
901
+ /**
902
+ * If this is an unchanged relative target we can consider the
903
+ * projection not dirty.
904
+ */
905
+ if (prevRelativeTarget &&
906
+ boxEquals(this.relativeTarget, prevRelativeTarget)) {
907
+ this.isProjectionDirty = false;
908
+ }
909
+ if (!prevRelativeTarget)
910
+ prevRelativeTarget = createBox();
911
+ copyBoxInto(prevRelativeTarget, this.relativeTarget);
845
912
  }
846
913
  if (isSharedLayoutAnimation) {
847
914
  this.animationValues = mixedValues;
@@ -1255,14 +1322,35 @@ function notifyLayoutUpdate(node) {
1255
1322
  }
1256
1323
  function propagateDirtyNodes(node) {
1257
1324
  /**
1258
- * Propagate isProjectionDirty. Nodes are ordered by depth, so if the parent here
1259
- * is dirty we can simply pass this forward.
1325
+ * Increase debug counter for nodes encountered this frame
1260
1326
  */
1261
- node.isProjectionDirty || (node.isProjectionDirty = Boolean(node.parent && node.parent.isProjectionDirty));
1327
+ projectionFrameData.totalNodes++;
1328
+ if (!node.parent)
1329
+ return;
1262
1330
  /**
1263
- * Propagate isTransformDirty.
1331
+ * If this node isn't projecting, propagate isProjectionDirty. It will have
1332
+ * no performance impact but it will allow the next child that *is* projecting
1333
+ * but *isn't* dirty to just check its parent to see if *any* ancestor needs
1334
+ * correcting.
1264
1335
  */
1265
- node.isTransformDirty || (node.isTransformDirty = Boolean(node.parent && node.parent.isTransformDirty));
1336
+ if (!node.isProjecting()) {
1337
+ node.isProjectionDirty = node.parent.isProjectionDirty;
1338
+ }
1339
+ /**
1340
+ * Propagate isSharedProjectionDirty and isTransformDirty
1341
+ * throughout the whole tree. A future revision can take another look at
1342
+ * this but for safety we still recalcualte shared nodes.
1343
+ */
1344
+ node.isSharedProjectionDirty || (node.isSharedProjectionDirty = Boolean(node.isProjectionDirty ||
1345
+ node.parent.isProjectionDirty ||
1346
+ node.parent.isSharedProjectionDirty));
1347
+ node.isTransformDirty || (node.isTransformDirty = node.parent.isTransformDirty);
1348
+ }
1349
+ function cleanDirtyNodes(node) {
1350
+ node.isProjectionDirty =
1351
+ node.isSharedProjectionDirty =
1352
+ node.isTransformDirty =
1353
+ false;
1266
1354
  }
1267
1355
  function clearSnapshot(node) {
1268
1356
  node.clearSnapshot();
@@ -1345,4 +1433,4 @@ function shouldAnimatePositionOnly(animationType, snapshot, layout) {
1345
1433
  !isNear(aspectRatio(snapshot), aspectRatio(layout), 0.2)));
1346
1434
  }
1347
1435
 
1348
- export { createProjectionNode, mixAxis, mixAxisDelta, mixBox, propagateDirtyNodes };
1436
+ export { cleanDirtyNodes, createProjectionNode, mixAxis, mixAxisDelta, mixBox, propagateDirtyNodes };
@@ -22,7 +22,7 @@ function updateMotionValuesFromProps(element, next, prev) {
22
22
  * and warn against mismatches.
23
23
  */
24
24
  if (process.env.NODE_ENV === "development") {
25
- warnOnce(nextValue.version === "9.1.2", `Attempting to mix Framer Motion versions ${nextValue.version} with 9.1.2 may not work as expected.`);
25
+ warnOnce(nextValue.version === "9.1.3", `Attempting to mix Framer Motion versions ${nextValue.version} with 9.1.3 may not work as expected.`);
26
26
  }
27
27
  }
28
28
  else if (isMotionValue(prevValue)) {
@@ -25,7 +25,7 @@ class MotionValue {
25
25
  * This will be replaced by the build step with the latest version number.
26
26
  * When MotionValues are provided to motion components, warn if versions are mixed.
27
27
  */
28
- this.version = "9.1.2";
28
+ this.version = "9.1.3";
29
29
  /**
30
30
  * Duration, in milliseconds, since last updating frame.
31
31
  *