framer-motion 11.5.6 → 11.7.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.
@@ -338,7 +338,7 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
338
338
  return { schedule, cancel, state, steps };
339
339
  }
340
340
 
341
- const { schedule: frame, cancel: cancelFrame, state: frameData, steps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
341
+ const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
342
342
 
343
343
  /**
344
344
  * Check if the value is a zero value string like "0px" or "0%"
@@ -1215,6 +1215,10 @@ function memo(callback) {
1215
1215
  };
1216
1216
  }
1217
1217
 
1218
+ function isGenerator(type) {
1219
+ return typeof type === "function";
1220
+ }
1221
+
1218
1222
  let now;
1219
1223
  function clearTime() {
1220
1224
  now = undefined;
@@ -1302,7 +1306,8 @@ function canAnimate(keyframes, name, type, velocity) {
1302
1306
  if (!isOriginAnimatable || !isTargetAnimatable) {
1303
1307
  return false;
1304
1308
  }
1305
- return hasKeyframesChanged(keyframes) || (type === "spring" && velocity);
1309
+ return (hasKeyframesChanged(keyframes) ||
1310
+ ((type === "spring" || isGenerator(type)) && velocity));
1306
1311
  }
1307
1312
 
1308
1313
  /**
@@ -2284,7 +2289,9 @@ class MainThreadAnimation extends BaseAnimation {
2284
2289
  }
2285
2290
  initPlayback(keyframes$1) {
2286
2291
  const { type = "keyframes", repeat = 0, repeatDelay = 0, repeatType, velocity = 0, } = this.options;
2287
- const generatorFactory = generators[type] || keyframes;
2292
+ const generatorFactory = isGenerator(type)
2293
+ ? type
2294
+ : generators[type] || keyframes;
2288
2295
  /**
2289
2296
  * If our generator doesn't support mixing numbers, we need to replace keyframes with
2290
2297
  * [0, 100] and then make a function that maps that to the actual keyframes.
@@ -2672,7 +2679,9 @@ const maxDuration = 20000;
2672
2679
  * handing off.
2673
2680
  */
2674
2681
  function requiresPregeneratedKeyframes(options) {
2675
- return options.type === "spring" || !isWaapiSupportedEasing(options.ease);
2682
+ return (isGenerator(options.type) ||
2683
+ options.type === "spring" ||
2684
+ !isWaapiSupportedEasing(options.ease));
2676
2685
  }
2677
2686
  function pregenerateKeyframes(keyframes, options) {
2678
2687
  /**
@@ -3032,14 +3041,7 @@ class GroupPlaybackControls {
3032
3041
  }
3033
3042
  }
3034
3043
 
3035
- const animateMotionValue = (name, value, target, transition = {}, element, isHandoff,
3036
- /**
3037
- * Currently used to remove values from will-change when an animation ends.
3038
- * Preferably this would be handled by event listeners on the MotionValue
3039
- * but these aren't consistent enough yet when considering the different ways
3040
- * an animation can be cancelled.
3041
- */
3042
- onEnd) => (onComplete) => {
3044
+ const animateMotionValue = (name, value, target, transition = {}, element, isHandoff) => (onComplete) => {
3043
3045
  const valueTransition = getValueTransition(transition, name) || {};
3044
3046
  /**
3045
3047
  * Most transition values are currently completely overwritten by value-specific
@@ -3066,9 +3068,7 @@ onEnd) => (onComplete) => {
3066
3068
  onComplete: () => {
3067
3069
  onComplete();
3068
3070
  valueTransition.onComplete && valueTransition.onComplete();
3069
- onEnd && onEnd();
3070
3071
  },
3071
- onStop: onEnd,
3072
3072
  name,
3073
3073
  motionValue: value,
3074
3074
  element: isHandoff ? undefined : element,
@@ -3227,7 +3227,7 @@ class MotionValue {
3227
3227
  * This will be replaced by the build step with the latest version number.
3228
3228
  * When MotionValues are provided to motion components, warn if versions are mixed.
3229
3229
  */
3230
- this.version = "11.5.6";
3230
+ this.version = "11.7.0";
3231
3231
  /**
3232
3232
  * Tracks whether this value can output a velocity. Currently this is only true
3233
3233
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -3552,42 +3552,17 @@ function getWillChangeName(name) {
3552
3552
  class WillChangeMotionValue extends MotionValue {
3553
3553
  constructor() {
3554
3554
  super(...arguments);
3555
- this.output = [];
3556
- this.counts = new Map();
3555
+ this.values = [];
3557
3556
  }
3558
3557
  add(name) {
3559
3558
  const styleName = getWillChangeName(name);
3560
- if (!styleName)
3561
- return;
3562
- /**
3563
- * Update counter. Each value has an indepdent counter
3564
- * as multiple sources could be requesting the same value
3565
- * gets added to will-change.
3566
- */
3567
- const prevCount = this.counts.get(styleName) || 0;
3568
- this.counts.set(styleName, prevCount + 1);
3569
- if (prevCount === 0) {
3570
- this.output.push(styleName);
3559
+ if (styleName) {
3560
+ addUniqueItem(this.values, styleName);
3571
3561
  this.update();
3572
3562
  }
3573
- /**
3574
- * Prevents the remove function from being called multiple times.
3575
- */
3576
- let hasRemoved = false;
3577
- return () => {
3578
- if (hasRemoved)
3579
- return;
3580
- hasRemoved = true;
3581
- const newCount = this.counts.get(styleName) - 1;
3582
- this.counts.set(styleName, newCount);
3583
- if (newCount === 0) {
3584
- removeItem(this.output, styleName);
3585
- this.update();
3586
- }
3587
- };
3588
3563
  }
3589
3564
  update() {
3590
- this.set(this.output.length ? this.output.join(", ") : "auto");
3565
+ this.set(this.values.length ? this.values.join(", ") : "auto");
3591
3566
  }
3592
3567
  }
3593
3568
 
@@ -3666,9 +3641,10 @@ function animateTarget(visualElement, targetAndTransition, { delay = 0, transiti
3666
3641
  }
3667
3642
  }
3668
3643
  }
3644
+ addValueToWillChange(visualElement, key);
3669
3645
  value.start(animateMotionValue(key, value, valueTarget, visualElement.shouldReduceMotion && transformProps.has(key)
3670
3646
  ? { type: false }
3671
- : valueTransition, visualElement, isHandoff, addValueToWillChange(visualElement, key)));
3647
+ : valueTransition, visualElement, isHandoff));
3672
3648
  const animation = value.animation;
3673
3649
  if (animation) {
3674
3650
  animations.push(animation);
@@ -4869,7 +4845,6 @@ class VisualElementDragControls {
4869
4845
  }
4870
4846
  };
4871
4847
  const onStart = (event, info) => {
4872
- var _a;
4873
4848
  // Attempt to grab the global drag gesture lock - maybe make this part of PanSession
4874
4849
  const { drag, dragPropagation, onDragStart } = this.getProps();
4875
4850
  if (drag && !dragPropagation) {
@@ -4911,8 +4886,7 @@ class VisualElementDragControls {
4911
4886
  if (onDragStart) {
4912
4887
  frame.postRender(() => onDragStart(event, info));
4913
4888
  }
4914
- (_a = this.removeWillChange) === null || _a === void 0 ? void 0 : _a.call(this);
4915
- this.removeWillChange = addValueToWillChange(this.visualElement, "transform");
4889
+ addValueToWillChange(this.visualElement, "transform");
4916
4890
  const { animationState } = this.visualElement;
4917
4891
  animationState && animationState.setActive("whileDrag", true);
4918
4892
  };
@@ -4968,8 +4942,6 @@ class VisualElementDragControls {
4968
4942
  });
4969
4943
  }
4970
4944
  stop(event, info) {
4971
- var _a;
4972
- (_a = this.removeWillChange) === null || _a === void 0 ? void 0 : _a.call(this);
4973
4945
  const isDragging = this.isDragging;
4974
4946
  this.cancel();
4975
4947
  if (!isDragging)
@@ -5111,7 +5083,8 @@ class VisualElementDragControls {
5111
5083
  }
5112
5084
  startAxisValueAnimation(axis, transition) {
5113
5085
  const axisValue = this.getAxisMotionValue(axis);
5114
- return axisValue.start(animateMotionValue(axis, axisValue, 0, transition, this.visualElement, false, addValueToWillChange(this.visualElement, axis)));
5086
+ addValueToWillChange(this.visualElement, axis);
5087
+ return axisValue.start(animateMotionValue(axis, axisValue, 0, transition, this.visualElement, false));
5115
5088
  }
5116
5089
  stopAnimation() {
5117
5090
  eachAxis((axis) => this.getAxisMotionValue(axis).stop());
@@ -5877,7 +5850,7 @@ function updateMotionValuesFromProps(element, next, prev) {
5877
5850
  * and warn against mismatches.
5878
5851
  */
5879
5852
  if (process.env.NODE_ENV === "development") {
5880
- warnOnce(nextValue.version === "11.5.6", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.5.6 may not work as expected.`);
5853
+ warnOnce(nextValue.version === "11.7.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.7.0 may not work as expected.`);
5881
5854
  }
5882
5855
  }
5883
5856
  else if (isMotionValue(prevValue)) {
@@ -7214,9 +7187,9 @@ function createProjectionNode$1({ attachResizeListener, defaultParent, measureSc
7214
7187
  frameData.delta = clamp(0, 1000 / 60, now - frameData.timestamp);
7215
7188
  frameData.timestamp = now;
7216
7189
  frameData.isProcessing = true;
7217
- steps.update.process(frameData);
7218
- steps.preRender.process(frameData);
7219
- steps.render.process(frameData);
7190
+ frameSteps.update.process(frameData);
7191
+ frameSteps.preRender.process(frameData);
7192
+ frameSteps.render.process(frameData);
7220
7193
  frameData.isProcessing = false;
7221
7194
  }
7222
7195
  didUpdate() {
@@ -156,7 +156,7 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
156
156
  return { schedule, cancel, state, steps };
157
157
  }
158
158
 
159
- const { schedule: frame, cancel: cancelFrame, state: frameData, steps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
159
+ const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
160
160
 
161
161
  function addUniqueItem(arr, item) {
162
162
  if (arr.indexOf(item) === -1)
@@ -279,7 +279,7 @@ class MotionValue {
279
279
  * This will be replaced by the build step with the latest version number.
280
280
  * When MotionValues are provided to motion components, warn if versions are mixed.
281
281
  */
282
- this.version = "11.5.6";
282
+ this.version = "11.7.0";
283
283
  /**
284
284
  * Tracks whether this value can output a velocity. Currently this is only true
285
285
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -1658,6 +1658,10 @@ class DOMKeyframesResolver extends KeyframeResolver {
1658
1658
  }
1659
1659
  }
1660
1660
 
1661
+ function isGenerator(type) {
1662
+ return typeof type === "function";
1663
+ }
1664
+
1661
1665
  /**
1662
1666
  * Check if a value is animatable. Examples:
1663
1667
  *
@@ -1718,7 +1722,8 @@ function canAnimate(keyframes, name, type, velocity) {
1718
1722
  if (!isOriginAnimatable || !isTargetAnimatable) {
1719
1723
  return false;
1720
1724
  }
1721
- return hasKeyframesChanged(keyframes) || (type === "spring" && velocity);
1725
+ return (hasKeyframesChanged(keyframes) ||
1726
+ ((type === "spring" || isGenerator(type)) && velocity));
1722
1727
  }
1723
1728
 
1724
1729
  /**
@@ -2690,7 +2695,9 @@ class MainThreadAnimation extends BaseAnimation {
2690
2695
  }
2691
2696
  initPlayback(keyframes$1) {
2692
2697
  const { type = "keyframes", repeat = 0, repeatDelay = 0, repeatType, velocity = 0, } = this.options;
2693
- const generatorFactory = generators[type] || keyframes;
2698
+ const generatorFactory = isGenerator(type)
2699
+ ? type
2700
+ : generators[type] || keyframes;
2694
2701
  /**
2695
2702
  * If our generator doesn't support mixing numbers, we need to replace keyframes with
2696
2703
  * [0, 100] and then make a function that maps that to the actual keyframes.
@@ -3078,7 +3085,9 @@ const maxDuration = 20000;
3078
3085
  * handing off.
3079
3086
  */
3080
3087
  function requiresPregeneratedKeyframes(options) {
3081
- return options.type === "spring" || !isWaapiSupportedEasing(options.ease);
3088
+ return (isGenerator(options.type) ||
3089
+ options.type === "spring" ||
3090
+ !isWaapiSupportedEasing(options.ease));
3082
3091
  }
3083
3092
  function pregenerateKeyframes(keyframes, options) {
3084
3093
  /**
@@ -3342,14 +3351,7 @@ class AcceleratedAnimation extends BaseAnimation {
3342
3351
  }
3343
3352
  }
3344
3353
 
3345
- const animateMotionValue = (name, value, target, transition = {}, element, isHandoff,
3346
- /**
3347
- * Currently used to remove values from will-change when an animation ends.
3348
- * Preferably this would be handled by event listeners on the MotionValue
3349
- * but these aren't consistent enough yet when considering the different ways
3350
- * an animation can be cancelled.
3351
- */
3352
- onEnd) => (onComplete) => {
3354
+ const animateMotionValue = (name, value, target, transition = {}, element, isHandoff) => (onComplete) => {
3353
3355
  const valueTransition = getValueTransition$1(transition, name) || {};
3354
3356
  /**
3355
3357
  * Most transition values are currently completely overwritten by value-specific
@@ -3376,9 +3378,7 @@ onEnd) => (onComplete) => {
3376
3378
  onComplete: () => {
3377
3379
  onComplete();
3378
3380
  valueTransition.onComplete && valueTransition.onComplete();
3379
- onEnd && onEnd();
3380
3381
  },
3381
- onStop: onEnd,
3382
3382
  name,
3383
3383
  motionValue: value,
3384
3384
  element: isHandoff ? undefined : element,
@@ -3540,42 +3540,17 @@ function getWillChangeName(name) {
3540
3540
  class WillChangeMotionValue extends MotionValue {
3541
3541
  constructor() {
3542
3542
  super(...arguments);
3543
- this.output = [];
3544
- this.counts = new Map();
3543
+ this.values = [];
3545
3544
  }
3546
3545
  add(name) {
3547
3546
  const styleName = getWillChangeName(name);
3548
- if (!styleName)
3549
- return;
3550
- /**
3551
- * Update counter. Each value has an indepdent counter
3552
- * as multiple sources could be requesting the same value
3553
- * gets added to will-change.
3554
- */
3555
- const prevCount = this.counts.get(styleName) || 0;
3556
- this.counts.set(styleName, prevCount + 1);
3557
- if (prevCount === 0) {
3558
- this.output.push(styleName);
3547
+ if (styleName) {
3548
+ addUniqueItem(this.values, styleName);
3559
3549
  this.update();
3560
3550
  }
3561
- /**
3562
- * Prevents the remove function from being called multiple times.
3563
- */
3564
- let hasRemoved = false;
3565
- return () => {
3566
- if (hasRemoved)
3567
- return;
3568
- hasRemoved = true;
3569
- const newCount = this.counts.get(styleName) - 1;
3570
- this.counts.set(styleName, newCount);
3571
- if (newCount === 0) {
3572
- removeItem(this.output, styleName);
3573
- this.update();
3574
- }
3575
- };
3576
3551
  }
3577
3552
  update() {
3578
- this.set(this.output.length ? this.output.join(", ") : "auto");
3553
+ this.set(this.values.length ? this.values.join(", ") : "auto");
3579
3554
  }
3580
3555
  }
3581
3556
 
@@ -3654,9 +3629,10 @@ function animateTarget(visualElement, targetAndTransition, { delay = 0, transiti
3654
3629
  }
3655
3630
  }
3656
3631
  }
3632
+ addValueToWillChange(visualElement, key);
3657
3633
  value.start(animateMotionValue(key, value, valueTarget, visualElement.shouldReduceMotion && transformProps.has(key)
3658
3634
  ? { type: false }
3659
- : valueTransition, visualElement, isHandoff, addValueToWillChange(visualElement, key)));
3635
+ : valueTransition, visualElement, isHandoff));
3660
3636
  const animation = value.animation;
3661
3637
  if (animation) {
3662
3638
  animations.push(animation);
@@ -3790,7 +3766,7 @@ function updateMotionValuesFromProps(element, next, prev) {
3790
3766
  * and warn against mismatches.
3791
3767
  */
3792
3768
  if (process.env.NODE_ENV === "development") {
3793
- warnOnce(nextValue.version === "11.5.6", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.5.6 may not work as expected.`);
3769
+ warnOnce(nextValue.version === "11.7.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.7.0 may not work as expected.`);
3794
3770
  }
3795
3771
  }
3796
3772
  else if (isMotionValue(prevValue)) {
@@ -4892,7 +4868,7 @@ function createAnimationsFromSequence(sequence, { defaultTransition = {}, ...seq
4892
4868
  * If this animation should and can use a spring, generate a spring easing function.
4893
4869
  */
4894
4870
  const numKeyframes = valueKeyframesAsList.length;
4895
- if (numKeyframes <= 2 && type === "spring") {
4871
+ if ((numKeyframes <= 2 && type === "spring") || isGenerator(type)) {
4896
4872
  /**
4897
4873
  * As we're creating an easing function from a spring,
4898
4874
  * ideally we want to generate it using the real distance
@@ -5584,34 +5560,71 @@ function scrollInfo(onScroll, { container = document.documentElement, ...options
5584
5560
  };
5585
5561
  }
5586
5562
 
5587
- function scrollTimelineFallback({ source, axis = "y" }) {
5563
+ function scrollTimelineFallback({ source, container, axis = "y", }) {
5564
+ // Support legacy source argument. Deprecate later.
5565
+ if (source)
5566
+ container = source;
5588
5567
  // ScrollTimeline records progress as a percentage CSSUnitValue
5589
5568
  const currentTime = { value: 0 };
5590
5569
  const cancel = scrollInfo((info) => {
5591
5570
  currentTime.value = info[axis].progress * 100;
5592
- }, { container: source, axis });
5571
+ }, { container, axis });
5593
5572
  return { currentTime, cancel };
5594
5573
  }
5595
5574
  const timelineCache = new Map();
5596
- function getTimeline({ source = document.documentElement, axis = "y", } = {}) {
5597
- if (!timelineCache.has(source)) {
5598
- timelineCache.set(source, {});
5599
- }
5600
- const elementCache = timelineCache.get(source);
5575
+ function getTimeline({ source, container = document.documentElement, axis = "y", } = {}) {
5576
+ // Support legacy source argument. Deprecate later.
5577
+ if (source)
5578
+ container = source;
5579
+ if (!timelineCache.has(container)) {
5580
+ timelineCache.set(container, {});
5581
+ }
5582
+ const elementCache = timelineCache.get(container);
5601
5583
  if (!elementCache[axis]) {
5602
5584
  elementCache[axis] = supportsScrollTimeline()
5603
- ? new ScrollTimeline({ source, axis })
5604
- : scrollTimelineFallback({ source, axis });
5585
+ ? new ScrollTimeline({ source: container, axis })
5586
+ : scrollTimelineFallback({ source: container, axis });
5605
5587
  }
5606
5588
  return elementCache[axis];
5607
5589
  }
5590
+ function isOnScrollWithInfo(onScroll) {
5591
+ return onScroll.length === 2;
5592
+ }
5593
+ function needsMainThreadScrollTracking(options) {
5594
+ return options && (options.target || options.offset);
5595
+ }
5608
5596
  function scroll(onScroll, options) {
5609
- const timeline = getTimeline(options);
5597
+ const axis = (options === null || options === void 0 ? void 0 : options.axis) || "y";
5610
5598
  if (typeof onScroll === "function") {
5611
- return observeTimeline(onScroll, timeline);
5599
+ /**
5600
+ * If the onScroll function has two arguments, it's expecting
5601
+ * more specific information about the scroll from scrollInfo.
5602
+ */
5603
+ if (isOnScrollWithInfo(onScroll) ||
5604
+ needsMainThreadScrollTracking(options)) {
5605
+ return scrollInfo((info) => {
5606
+ onScroll(info[axis].progress, info);
5607
+ }, options);
5608
+ }
5609
+ else {
5610
+ return observeTimeline(onScroll, getTimeline(options));
5611
+ }
5612
5612
  }
5613
5613
  else {
5614
- return onScroll.attachTimeline(timeline);
5614
+ /**
5615
+ * If we need main thread scroll tracking because we're tracking
5616
+ * a target or defined offsets, we need to create a scrollInfo timeline.
5617
+ * Over time the number of sitauations where this is true
5618
+ */
5619
+ if (needsMainThreadScrollTracking(options)) {
5620
+ onScroll.pause();
5621
+ return scrollInfo((info) => {
5622
+ onScroll.time = onScroll.duration * info[axis].progress;
5623
+ }, options);
5624
+ }
5625
+ else {
5626
+ return onScroll.attachTimeline(getTimeline(options));
5627
+ }
5615
5628
  }
5616
5629
  }
5617
5630
 
@@ -5655,6 +5668,18 @@ function inView(elementOrSelector, onStart, { root, margin: rootMargin, amount =
5655
5668
  return () => observer.disconnect();
5656
5669
  }
5657
5670
 
5671
+ function steps(numSteps, direction = "end") {
5672
+ return (progress) => {
5673
+ progress =
5674
+ direction === "end"
5675
+ ? Math.min(progress, 0.999)
5676
+ : Math.max(progress, 0.001);
5677
+ const expanded = progress * numSteps;
5678
+ const rounded = direction === "end" ? Math.floor(expanded) : Math.ceil(expanded);
5679
+ return clamp(0, 1, rounded / numSteps);
5680
+ };
5681
+ }
5682
+
5658
5683
  function getOriginIndex(from, total) {
5659
5684
  if (from === "first") {
5660
5685
  return 0;
@@ -5758,6 +5783,7 @@ exports.easeInOut = easeInOut;
5758
5783
  exports.easeOut = easeOut;
5759
5784
  exports.frame = frame;
5760
5785
  exports.frameData = frameData;
5786
+ exports.frameSteps = frameSteps;
5761
5787
  exports.inView = inView;
5762
5788
  exports.interpolate = interpolate;
5763
5789
  exports.mirrorEasing = mirrorEasing;