framer-motion 11.0.0-alpha.1 → 11.0.0

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var indexLegacy = require('./index-legacy-4be91252.js');
5
+ var indexLegacy = require('./index-legacy-731c5510.js');
6
6
 
7
7
 
8
8
 
@@ -10,6 +10,175 @@ const camelToDash = (str) => str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase
10
10
  const optimizedAppearDataId = "framerAppearId";
11
11
  const optimizedAppearDataAttribute = "data-" + camelToDash(optimizedAppearDataId);
12
12
 
13
+ const MotionGlobalConfig = {
14
+ skipAnimations: false,
15
+ useManualTiming: false,
16
+ };
17
+
18
+ class Queue {
19
+ constructor() {
20
+ this.order = [];
21
+ this.scheduled = new Set();
22
+ }
23
+ add(process) {
24
+ if (!this.scheduled.has(process)) {
25
+ this.scheduled.add(process);
26
+ this.order.push(process);
27
+ return true;
28
+ }
29
+ }
30
+ remove(process) {
31
+ const index = this.order.indexOf(process);
32
+ if (index !== -1) {
33
+ this.order.splice(index, 1);
34
+ this.scheduled.delete(process);
35
+ }
36
+ }
37
+ clear() {
38
+ this.order.length = 0;
39
+ this.scheduled.clear();
40
+ }
41
+ }
42
+ function createRenderStep(runNextFrame) {
43
+ /**
44
+ * We create and reuse two queues, one to queue jobs for the current frame
45
+ * and one for the next. We reuse to avoid triggering GC after x frames.
46
+ */
47
+ let thisFrame = new Queue();
48
+ let nextFrame = new Queue();
49
+ let numToRun = 0;
50
+ /**
51
+ * Track whether we're currently processing jobs in this step. This way
52
+ * we can decide whether to schedule new jobs for this frame or next.
53
+ */
54
+ let isProcessing = false;
55
+ let flushNextFrame = false;
56
+ /**
57
+ * A set of processes which were marked keepAlive when scheduled.
58
+ */
59
+ const toKeepAlive = new WeakSet();
60
+ const step = {
61
+ /**
62
+ * Schedule a process to run on the next frame.
63
+ */
64
+ schedule: (callback, keepAlive = false, immediate = false) => {
65
+ const addToCurrentFrame = immediate && isProcessing;
66
+ const queue = addToCurrentFrame ? thisFrame : nextFrame;
67
+ if (keepAlive)
68
+ toKeepAlive.add(callback);
69
+ if (queue.add(callback) && addToCurrentFrame && isProcessing) {
70
+ // If we're adding it to the currently running queue, update its measured size
71
+ numToRun = thisFrame.order.length;
72
+ }
73
+ return callback;
74
+ },
75
+ /**
76
+ * Cancel the provided callback from running on the next frame.
77
+ */
78
+ cancel: (callback) => {
79
+ nextFrame.remove(callback);
80
+ toKeepAlive.delete(callback);
81
+ },
82
+ /**
83
+ * Execute all schedule callbacks.
84
+ */
85
+ process: (frameData) => {
86
+ /**
87
+ * If we're already processing we've probably been triggered by a flushSync
88
+ * inside an existing process. Instead of executing, mark flushNextFrame
89
+ * as true and ensure we flush the following frame at the end of this one.
90
+ */
91
+ if (isProcessing) {
92
+ flushNextFrame = true;
93
+ return;
94
+ }
95
+ isProcessing = true;
96
+ [thisFrame, nextFrame] = [nextFrame, thisFrame];
97
+ // Clear the next frame queue
98
+ nextFrame.clear();
99
+ // Execute this frame
100
+ numToRun = thisFrame.order.length;
101
+ if (numToRun) {
102
+ for (let i = 0; i < numToRun; i++) {
103
+ const callback = thisFrame.order[i];
104
+ if (toKeepAlive.has(callback)) {
105
+ step.schedule(callback);
106
+ runNextFrame();
107
+ }
108
+ callback(frameData);
109
+ }
110
+ }
111
+ isProcessing = false;
112
+ if (flushNextFrame) {
113
+ flushNextFrame = false;
114
+ step.process(frameData);
115
+ }
116
+ },
117
+ };
118
+ return step;
119
+ }
120
+
121
+ const stepsOrder = [
122
+ "prepare",
123
+ "read",
124
+ "update",
125
+ "preRender",
126
+ "render",
127
+ "postRender",
128
+ ];
129
+ const maxElapsed$1 = 40;
130
+ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
131
+ let runNextFrame = false;
132
+ let useDefaultElapsed = true;
133
+ const state = {
134
+ delta: 0,
135
+ timestamp: 0,
136
+ isProcessing: false,
137
+ };
138
+ const steps = stepsOrder.reduce((acc, key) => {
139
+ acc[key] = createRenderStep(() => (runNextFrame = true));
140
+ return acc;
141
+ }, {});
142
+ const processStep = (stepId) => {
143
+ steps[stepId].process(state);
144
+ };
145
+ const processBatch = () => {
146
+ const timestamp = MotionGlobalConfig.useManualTiming
147
+ ? state.timestamp
148
+ : performance.now();
149
+ runNextFrame = false;
150
+ state.delta = useDefaultElapsed
151
+ ? 1000 / 60
152
+ : Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
153
+ state.timestamp = timestamp;
154
+ state.isProcessing = true;
155
+ stepsOrder.forEach(processStep);
156
+ state.isProcessing = false;
157
+ if (runNextFrame && allowKeepAlive) {
158
+ useDefaultElapsed = false;
159
+ scheduleNextBatch(processBatch);
160
+ }
161
+ };
162
+ const wake = () => {
163
+ runNextFrame = true;
164
+ useDefaultElapsed = true;
165
+ if (!state.isProcessing) {
166
+ scheduleNextBatch(processBatch);
167
+ }
168
+ };
169
+ const schedule = stepsOrder.reduce((acc, key) => {
170
+ const step = steps[key];
171
+ acc[key] = (process, keepAlive = false, immediate = false) => {
172
+ if (!runNextFrame)
173
+ wake();
174
+ return step.schedule(process, keepAlive, immediate);
175
+ };
176
+ return acc;
177
+ }, {});
178
+ const cancel = (process) => stepsOrder.forEach((key) => steps[key].cancel(process));
179
+ return { schedule, cancel, state, steps };
180
+ }
181
+
13
182
  function isRefObject(ref) {
14
183
  return (ref &&
15
184
  typeof ref === "object" &&
@@ -559,173 +728,6 @@ const resolveFinalValueInKeyframes = (v) => {
559
728
 
560
729
  const noop = (any) => any;
561
730
 
562
- const MotionGlobalConfig = {
563
- skipAnimations: false,
564
- useManualTiming: false,
565
- };
566
-
567
- class Queue {
568
- constructor() {
569
- this.order = [];
570
- this.scheduled = new Set();
571
- }
572
- add(process) {
573
- if (!this.scheduled.has(process)) {
574
- this.scheduled.add(process);
575
- this.order.push(process);
576
- return true;
577
- }
578
- }
579
- remove(process) {
580
- const index = this.order.indexOf(process);
581
- if (index !== -1) {
582
- this.order.splice(index, 1);
583
- this.scheduled.delete(process);
584
- }
585
- }
586
- clear() {
587
- this.order.length = 0;
588
- this.scheduled.clear();
589
- }
590
- }
591
- function createRenderStep(runNextFrame) {
592
- /**
593
- * We create and reuse two queues, one to queue jobs for the current frame
594
- * and one for the next. We reuse to avoid triggering GC after x frames.
595
- */
596
- let thisFrame = new Queue();
597
- let nextFrame = new Queue();
598
- let numToRun = 0;
599
- /**
600
- * Track whether we're currently processing jobs in this step. This way
601
- * we can decide whether to schedule new jobs for this frame or next.
602
- */
603
- let isProcessing = false;
604
- let flushNextFrame = false;
605
- /**
606
- * A set of processes which were marked keepAlive when scheduled.
607
- */
608
- const toKeepAlive = new WeakSet();
609
- const step = {
610
- /**
611
- * Schedule a process to run on the next frame.
612
- */
613
- schedule: (callback, keepAlive = false, immediate = false) => {
614
- const addToCurrentFrame = immediate && isProcessing;
615
- const queue = addToCurrentFrame ? thisFrame : nextFrame;
616
- if (keepAlive)
617
- toKeepAlive.add(callback);
618
- if (queue.add(callback) && addToCurrentFrame && isProcessing) {
619
- // If we're adding it to the currently running queue, update its measured size
620
- numToRun = thisFrame.order.length;
621
- }
622
- return callback;
623
- },
624
- /**
625
- * Cancel the provided callback from running on the next frame.
626
- */
627
- cancel: (callback) => {
628
- nextFrame.remove(callback);
629
- toKeepAlive.delete(callback);
630
- },
631
- /**
632
- * Execute all schedule callbacks.
633
- */
634
- process: (frameData) => {
635
- /**
636
- * If we're already processing we've probably been triggered by a flushSync
637
- * inside an existing process. Instead of executing, mark flushNextFrame
638
- * as true and ensure we flush the following frame at the end of this one.
639
- */
640
- if (isProcessing) {
641
- flushNextFrame = true;
642
- return;
643
- }
644
- isProcessing = true;
645
- [thisFrame, nextFrame] = [nextFrame, thisFrame];
646
- // Clear the next frame queue
647
- nextFrame.clear();
648
- // Execute this frame
649
- numToRun = thisFrame.order.length;
650
- if (numToRun) {
651
- for (let i = 0; i < numToRun; i++) {
652
- const callback = thisFrame.order[i];
653
- if (toKeepAlive.has(callback)) {
654
- step.schedule(callback);
655
- runNextFrame();
656
- }
657
- callback(frameData);
658
- }
659
- }
660
- isProcessing = false;
661
- if (flushNextFrame) {
662
- flushNextFrame = false;
663
- step.process(frameData);
664
- }
665
- },
666
- };
667
- return step;
668
- }
669
-
670
- const stepsOrder = [
671
- "prepare",
672
- "read",
673
- "update",
674
- "preRender",
675
- "render",
676
- "postRender",
677
- ];
678
- const maxElapsed$1 = 40;
679
- function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
680
- let runNextFrame = false;
681
- let useDefaultElapsed = true;
682
- const state = {
683
- delta: 0,
684
- timestamp: 0,
685
- isProcessing: false,
686
- };
687
- const steps = stepsOrder.reduce((acc, key) => {
688
- acc[key] = createRenderStep(() => (runNextFrame = true));
689
- return acc;
690
- }, {});
691
- const processStep = (stepId) => steps[stepId].process(state);
692
- const processBatch = () => {
693
- const timestamp = MotionGlobalConfig.useManualTiming
694
- ? state.timestamp
695
- : performance.now();
696
- runNextFrame = false;
697
- state.delta = useDefaultElapsed
698
- ? 1000 / 60
699
- : Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
700
- state.timestamp = timestamp;
701
- state.isProcessing = true;
702
- stepsOrder.forEach(processStep);
703
- state.isProcessing = false;
704
- if (runNextFrame && allowKeepAlive) {
705
- useDefaultElapsed = false;
706
- scheduleNextBatch(processBatch);
707
- }
708
- };
709
- const wake = () => {
710
- runNextFrame = true;
711
- useDefaultElapsed = true;
712
- if (!state.isProcessing) {
713
- scheduleNextBatch(processBatch);
714
- }
715
- };
716
- const schedule = stepsOrder.reduce((acc, key) => {
717
- const step = steps[key];
718
- acc[key] = (process, keepAlive = false, immediate = false) => {
719
- if (!runNextFrame)
720
- wake();
721
- return step.schedule(process, keepAlive, immediate);
722
- };
723
- return acc;
724
- }, {});
725
- const cancel = (process) => stepsOrder.forEach((key) => steps[key].cancel(process));
726
- return { schedule, cancel, state, steps };
727
- }
728
-
729
731
  const { schedule: frame, cancel: cancelFrame, state: frameData, steps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
730
732
 
731
733
  /**
@@ -1764,8 +1766,6 @@ function inertia({ keyframes, velocity = 0.0, power = 0.8, timeConstant = 325, b
1764
1766
  };
1765
1767
  }
1766
1768
 
1767
- const { schedule: microtask, cancel: cancelMicrotask } = createRenderBatcher(queueMicrotask, false);
1768
-
1769
1769
  let now;
1770
1770
  function clearTime() {
1771
1771
  now = undefined;
@@ -1789,7 +1789,7 @@ const time = {
1789
1789
  },
1790
1790
  set: (newTime) => {
1791
1791
  now = newTime;
1792
- microtask.postRender(clearTime);
1792
+ queueMicrotask(clearTime);
1793
1793
  },
1794
1794
  };
1795
1795
 
@@ -2750,7 +2750,7 @@ class MotionValue {
2750
2750
  * This will be replaced by the build step with the latest version number.
2751
2751
  * When MotionValues are provided to motion components, warn if versions are mixed.
2752
2752
  */
2753
- this.version = "11.0.0-alpha.1";
2753
+ this.version = "11.0.0";
2754
2754
  /**
2755
2755
  * Tracks whether this value can output a velocity. Currently this is only true
2756
2756
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -3977,7 +3977,7 @@ function updateMotionValuesFromProps(element, next, prev) {
3977
3977
  * and warn against mismatches.
3978
3978
  */
3979
3979
  if (process.env.NODE_ENV === "development") {
3980
- warnOnce(nextValue.version === "11.0.0-alpha.1", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.0.0-alpha.1 may not work as expected.`);
3980
+ warnOnce(nextValue.version === "11.0.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.0.0 may not work as expected.`);
3981
3981
  }
3982
3982
  }
3983
3983
  else if (isMotionValue(prevValue)) {
@@ -5652,6 +5652,7 @@ exports.convertBoundingBoxToBox = convertBoundingBoxToBox;
5652
5652
  exports.convertBoxToBoundingBox = convertBoxToBoundingBox;
5653
5653
  exports.createBox = createBox;
5654
5654
  exports.createDelta = createDelta;
5655
+ exports.createRenderBatcher = createRenderBatcher;
5655
5656
  exports.createScopedAnimate = createScopedAnimate;
5656
5657
  exports.cubicBezier = cubicBezier;
5657
5658
  exports.delay = delay;
package/dist/cjs/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var React = require('react');
6
- var indexLegacy = require('./index-legacy-4be91252.js');
6
+ var indexLegacy = require('./index-legacy-731c5510.js');
7
7
 
8
8
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
9
 
@@ -48,6 +48,8 @@ const useIsomorphicLayoutEffect = indexLegacy.isBrowser ? React.useLayoutEffect
48
48
 
49
49
  const LazyContext = React.createContext({ strict: false });
50
50
 
51
+ const { schedule: microtask, cancel: cancelMicrotask } = indexLegacy.createRenderBatcher(queueMicrotask, false);
52
+
51
53
  function useVisualElement(Component, visualState, props, createVisualElement) {
52
54
  const { visualElement: parent } = React.useContext(MotionContext);
53
55
  const lazyContext = React.useContext(LazyContext);
@@ -82,7 +84,7 @@ function useVisualElement(Component, visualState, props, createVisualElement) {
82
84
  useIsomorphicLayoutEffect(() => {
83
85
  if (!visualElement)
84
86
  return;
85
- visualElement.render();
87
+ microtask.postRender(visualElement.render);
86
88
  /**
87
89
  * Ideally this function would always run in a useEffect.
88
90
  *
@@ -3188,7 +3190,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
3188
3190
  didUpdate() {
3189
3191
  if (!this.updateScheduled) {
3190
3192
  this.updateScheduled = true;
3191
- queueMicrotask(() => this.update());
3193
+ microtask.read(() => this.update());
3192
3194
  }
3193
3195
  }
3194
3196
  clearAllSnapshots() {
@@ -3470,9 +3472,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
3470
3472
  * a relativeParent. This will allow a component to perform scale correction
3471
3473
  * even if no animation has started.
3472
3474
  */
3473
- // TODO If this is unsuccessful this currently happens every frame
3474
3475
  if (!this.targetDelta && !this.relativeTarget) {
3475
- // TODO: This is a semi-repetition of further down this function, make DRY
3476
3476
  const relativeParent = this.getClosestProjectingParent();
3477
3477
  if (relativeParent &&
3478
3478
  relativeParent.layout &&
@@ -4536,7 +4536,7 @@ class MeasureLayoutWithContext extends React__default["default"].Component {
4536
4536
  const { projection } = this.props.visualElement;
4537
4537
  if (projection) {
4538
4538
  projection.root.didUpdate();
4539
- queueMicrotask(() => {
4539
+ microtask.postRender(() => {
4540
4540
  if (!projection.currentAnimation && projection.isLead()) {
4541
4541
  this.safeToRemove();
4542
4542
  }
@@ -5365,6 +5365,13 @@ function useSpring(source, config = {}) {
5365
5365
  */
5366
5366
  if (isStatic)
5367
5367
  return set(v);
5368
+ /**
5369
+ * If the previous animation hasn't had the chance to even render a frame, render it now.
5370
+ */
5371
+ const animation = activeSpringAnimation.current;
5372
+ if (animation && animation.time === 0) {
5373
+ animation.sample(indexLegacy.frameData.delta);
5374
+ }
5368
5375
  stopAnimation();
5369
5376
  activeSpringAnimation.current = indexLegacy.animateValue({
5370
5377
  keyframes: [value.get(), v],
@@ -5375,16 +5382,6 @@ function useSpring(source, config = {}) {
5375
5382
  ...config,
5376
5383
  onUpdate: set,
5377
5384
  });
5378
- /**
5379
- * If we're between frames, resync the animation to the frameloop.
5380
- */
5381
- if (!indexLegacy.frameData.isProcessing) {
5382
- const delta = performance.now() - indexLegacy.frameData.timestamp;
5383
- if (delta < 30) {
5384
- activeSpringAnimation.current.time =
5385
- indexLegacy.millisecondsToSeconds(delta);
5386
- }
5387
- }
5388
5385
  return value.get();
5389
5386
  }, stopAnimation);
5390
5387
  }, [JSON.stringify(config)]);
@@ -5422,6 +5419,10 @@ function useVelocity(value) {
5422
5419
  const updateVelocity = () => {
5423
5420
  const latest = value.getVelocity();
5424
5421
  velocity.set(latest);
5422
+ /**
5423
+ * If we still have velocity, schedule an update for the next frame
5424
+ * to keep checking until it is zero.
5425
+ */
5425
5426
  if (latest)
5426
5427
  indexLegacy.frame.update(updateVelocity);
5427
5428
  };
@@ -22,7 +22,9 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
22
22
  acc[key] = createRenderStep(() => (runNextFrame = true));
23
23
  return acc;
24
24
  }, {});
25
- const processStep = (stepId) => steps[stepId].process(state);
25
+ const processStep = (stepId) => {
26
+ steps[stepId].process(state);
27
+ };
26
28
  const processBatch = () => {
27
29
  const timestamp = MotionGlobalConfig.useManualTiming
28
30
  ? state.timestamp
@@ -1,6 +1,5 @@
1
1
  import { MotionGlobalConfig } from '../utils/GlobalConfig.mjs';
2
2
  import { frameData } from './frame.mjs';
3
- import { microtask } from './microtask.mjs';
4
3
 
5
4
  let now;
6
5
  function clearTime() {
@@ -25,7 +24,7 @@ const time = {
25
24
  },
26
25
  set: (newTime) => {
27
26
  now = newTime;
28
- microtask.postRender(clearTime);
27
+ queueMicrotask(clearTime);
29
28
  },
30
29
  };
31
30
 
@@ -6,6 +6,7 @@ import { globalProjectionState } from '../../../projection/node/state.mjs';
6
6
  import { correctBorderRadius } from '../../../projection/styles/scale-border-radius.mjs';
7
7
  import { correctBoxShadow } from '../../../projection/styles/scale-box-shadow.mjs';
8
8
  import { addScaleCorrector } from '../../../projection/styles/scale-correction.mjs';
9
+ import { microtask } from '../../../frameloop/microtask.mjs';
9
10
  import { frame } from '../../../frameloop/frame.mjs';
10
11
 
11
12
  class MeasureLayoutWithContext extends React__default.Component {
@@ -80,7 +81,7 @@ class MeasureLayoutWithContext extends React__default.Component {
80
81
  const { projection } = this.props.visualElement;
81
82
  if (projection) {
82
83
  projection.root.didUpdate();
83
- queueMicrotask(() => {
84
+ microtask.postRender(() => {
84
85
  if (!projection.currentAnimation && projection.isLead()) {
85
86
  this.safeToRemove();
86
87
  }
@@ -5,6 +5,7 @@ import { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs
5
5
  import { LazyContext } from '../../context/LazyContext.mjs';
6
6
  import { MotionConfigContext } from '../../context/MotionConfigContext.mjs';
7
7
  import { optimizedAppearDataAttribute } from '../../animation/optimized-appear/data-id.mjs';
8
+ import { microtask } from '../../frameloop/microtask.mjs';
8
9
 
9
10
  function useVisualElement(Component, visualState, props, createVisualElement) {
10
11
  const { visualElement: parent } = useContext(MotionContext);
@@ -40,7 +41,7 @@ function useVisualElement(Component, visualState, props, createVisualElement) {
40
41
  useIsomorphicLayoutEffect(() => {
41
42
  if (!visualElement)
42
43
  return;
43
- visualElement.render();
44
+ microtask.postRender(visualElement.render);
44
45
  /**
45
46
  * Ideally this function would always run in a useEffect.
46
47
  *
@@ -24,6 +24,7 @@ import { clamp } from '../../utils/clamp.mjs';
24
24
  import { cancelFrame, frameData, steps, frame } from '../../frameloop/frame.mjs';
25
25
  import { noop } from '../../utils/noop.mjs';
26
26
  import { time } from '../../frameloop/sync-time.mjs';
27
+ import { microtask } from '../../frameloop/microtask.mjs';
27
28
 
28
29
  const transformAxes = ["", "X", "Y", "Z"];
29
30
  const hiddenVisibility = { visibility: "hidden" };
@@ -406,7 +407,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
406
407
  didUpdate() {
407
408
  if (!this.updateScheduled) {
408
409
  this.updateScheduled = true;
409
- queueMicrotask(() => this.update());
410
+ microtask.read(() => this.update());
410
411
  }
411
412
  }
412
413
  clearAllSnapshots() {
@@ -688,9 +689,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
688
689
  * a relativeParent. This will allow a component to perform scale correction
689
690
  * even if no animation has started.
690
691
  */
691
- // TODO If this is unsuccessful this currently happens every frame
692
692
  if (!this.targetDelta && !this.relativeTarget) {
693
- // TODO: This is a semi-repetition of further down this function, make DRY
694
693
  const relativeParent = this.getClosestProjectingParent();
695
694
  if (relativeParent &&
696
695
  relativeParent.layout &&
@@ -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 === "11.0.0-alpha.1", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.0.0-alpha.1 may not work as expected.`);
25
+ warnOnce(nextValue.version === "11.0.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.0.0 may not work as expected.`);
26
26
  }
27
27
  }
28
28
  else if (isMotionValue(prevValue)) {
@@ -34,7 +34,7 @@ class MotionValue {
34
34
  * This will be replaced by the build step with the latest version number.
35
35
  * When MotionValues are provided to motion components, warn if versions are mixed.
36
36
  */
37
- this.version = "11.0.0-alpha.1";
37
+ this.version = "11.0.0";
38
38
  /**
39
39
  * Tracks whether this value can output a velocity. Currently this is only true
40
40
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -4,7 +4,6 @@ import { useMotionValue } from './use-motion-value.mjs';
4
4
  import { MotionConfigContext } from '../context/MotionConfigContext.mjs';
5
5
  import { useIsomorphicLayoutEffect } from '../utils/use-isomorphic-effect.mjs';
6
6
  import { animateValue } from '../animation/animators/js/index.mjs';
7
- import { millisecondsToSeconds } from '../utils/time-conversion.mjs';
8
7
  import { frameData } from '../frameloop/frame.mjs';
9
8
 
10
9
  /**
@@ -43,6 +42,13 @@ function useSpring(source, config = {}) {
43
42
  */
44
43
  if (isStatic)
45
44
  return set(v);
45
+ /**
46
+ * If the previous animation hasn't had the chance to even render a frame, render it now.
47
+ */
48
+ const animation = activeSpringAnimation.current;
49
+ if (animation && animation.time === 0) {
50
+ animation.sample(frameData.delta);
51
+ }
46
52
  stopAnimation();
47
53
  activeSpringAnimation.current = animateValue({
48
54
  keyframes: [value.get(), v],
@@ -53,16 +59,6 @@ function useSpring(source, config = {}) {
53
59
  ...config,
54
60
  onUpdate: set,
55
61
  });
56
- /**
57
- * If we're between frames, resync the animation to the frameloop.
58
- */
59
- if (!frameData.isProcessing) {
60
- const delta = performance.now() - frameData.timestamp;
61
- if (delta < 30) {
62
- activeSpringAnimation.current.time =
63
- millisecondsToSeconds(delta);
64
- }
65
- }
66
62
  return value.get();
67
63
  }, stopAnimation);
68
64
  }, [JSON.stringify(config)]);
@@ -18,6 +18,10 @@ function useVelocity(value) {
18
18
  const updateVelocity = () => {
19
19
  const latest = value.getVelocity();
20
20
  velocity.set(latest);
21
+ /**
22
+ * If we still have velocity, schedule an update for the next frame
23
+ * to keep checking until it is zero.
24
+ */
21
25
  if (latest)
22
26
  frame.update(updateVelocity);
23
27
  };