framer-motion 6.1.0 → 6.2.4

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.
@@ -221,6 +221,7 @@
221
221
  var MotionConfigContext = React.createContext({
222
222
  transformPagePoint: function (p) { return p; },
223
223
  isStatic: false,
224
+ reducedMotion: "never",
224
225
  });
225
226
 
226
227
  var MotionContext = React.createContext({});
@@ -237,10 +238,81 @@
237
238
 
238
239
  var useIsomorphicLayoutEffect = isBrowser ? React.useLayoutEffect : React.useEffect;
239
240
 
241
+ // Does this device prefer reduced motion? Returns `null` server-side.
242
+ var prefersReducedMotion = { current: null };
243
+ var hasDetected = false;
244
+ function initPrefersReducedMotion() {
245
+ hasDetected = true;
246
+ if (typeof window === "undefined")
247
+ return;
248
+ if (window.matchMedia) {
249
+ var motionMediaQuery_1 = window.matchMedia("(prefers-reduced-motion)");
250
+ var setReducedMotionPreferences = function () {
251
+ return (prefersReducedMotion.current = motionMediaQuery_1.matches);
252
+ };
253
+ motionMediaQuery_1.addListener(setReducedMotionPreferences);
254
+ setReducedMotionPreferences();
255
+ }
256
+ else {
257
+ prefersReducedMotion.current = false;
258
+ }
259
+ }
260
+ /**
261
+ * A hook that returns `true` if we should be using reduced motion based on the current device's Reduced Motion setting.
262
+ *
263
+ * This can be used to implement changes to your UI based on Reduced Motion. For instance, replacing motion-sickness inducing
264
+ * `x`/`y` animations with `opacity`, disabling the autoplay of background videos, or turning off parallax motion.
265
+ *
266
+ * It will actively respond to changes and re-render your components with the latest setting.
267
+ *
268
+ * ```jsx
269
+ * export function Sidebar({ isOpen }) {
270
+ * const shouldReduceMotion = useReducedMotion()
271
+ * const closedX = shouldReduceMotion ? 0 : "-100%"
272
+ *
273
+ * return (
274
+ * <motion.div animate={{
275
+ * opacity: isOpen ? 1 : 0,
276
+ * x: isOpen ? 0 : closedX
277
+ * }} />
278
+ * )
279
+ * }
280
+ * ```
281
+ *
282
+ * @return boolean
283
+ *
284
+ * @public
285
+ */
286
+ function useReducedMotion() {
287
+ /**
288
+ * Lazy initialisation of prefersReducedMotion
289
+ */
290
+ !hasDetected && initPrefersReducedMotion();
291
+ var _a = __read(React.useState(prefersReducedMotion.current), 1), shouldReduceMotion = _a[0];
292
+ /**
293
+ * TODO See if people miss automatically updating shouldReduceMotion setting
294
+ */
295
+ return shouldReduceMotion;
296
+ }
297
+ function useReducedMotionConfig() {
298
+ var reducedMotionPreference = useReducedMotion();
299
+ var reducedMotion = React.useContext(MotionConfigContext).reducedMotion;
300
+ if (reducedMotion === "never") {
301
+ return false;
302
+ }
303
+ else if (reducedMotion === "always") {
304
+ return true;
305
+ }
306
+ else {
307
+ return reducedMotionPreference;
308
+ }
309
+ }
310
+
240
311
  function useVisualElement(Component, visualState, props, createVisualElement) {
241
312
  var lazyContext = React.useContext(LazyContext);
242
313
  var parent = useVisualElementContext();
243
314
  var presenceContext = React.useContext(PresenceContext);
315
+ var shouldReduceMotion = useReducedMotionConfig();
244
316
  var visualElementRef = React.useRef(undefined);
245
317
  /**
246
318
  * If we haven't preloaded a renderer, check to see if we have one lazy-loaded
@@ -254,6 +326,7 @@
254
326
  props: props,
255
327
  presenceId: presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.id,
256
328
  blockInitialAnimation: (presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.initial) === false,
329
+ shouldReduceMotion: shouldReduceMotion,
257
330
  });
258
331
  }
259
332
  var visualElement = visualElementRef.current;
@@ -3057,9 +3130,6 @@
3057
3130
  };
3058
3131
  this.hasProjected = false;
3059
3132
  this.isVisible = true;
3060
- /**
3061
- * Animation
3062
- */
3063
3133
  this.animationProgress = 0;
3064
3134
  /**
3065
3135
  * Shared layout
@@ -3176,9 +3246,23 @@
3176
3246
  _this.resumingFrom.resumingFrom = undefined;
3177
3247
  }
3178
3248
  _this.setAnimationOrigin(delta, hasOnlyRelativeTargetChanged);
3179
- _this.startAnimation(__assign(__assign({}, getValueTransition(layoutTransition, "layout")), { onComplete: onLayoutAnimationComplete }));
3249
+ var animationOptions = __assign(__assign({}, getValueTransition(layoutTransition, "layout")), { onComplete: onLayoutAnimationComplete });
3250
+ if (visualElement.shouldReduceMotion) {
3251
+ animationOptions.delay = 0;
3252
+ animationOptions.type = false;
3253
+ }
3254
+ _this.startAnimation(animationOptions);
3180
3255
  }
3181
3256
  else {
3257
+ /**
3258
+ * If the layout hasn't changed and we have an animation that hasn't started yet,
3259
+ * finish it immediately. Otherwise it will be animating from a location
3260
+ * that was probably never commited to screen and look like a jumpy box.
3261
+ */
3262
+ if (!hasLayoutChanged &&
3263
+ _this.animationProgress === 0) {
3264
+ _this.finishAnimation();
3265
+ }
3182
3266
  _this.isLead() && ((_f = (_e = _this.options).onExitComplete) === null || _f === void 0 ? void 0 : _f.call(_e));
3183
3267
  }
3184
3268
  _this.targetLayout = newLayout;
@@ -3668,6 +3752,7 @@
3668
3752
  !isOnlyMember &&
3669
3753
  this.options.crossfade === true &&
3670
3754
  !this.path.some(hasOpacityCrossfade));
3755
+ this.animationProgress = 0;
3671
3756
  this.mixTargetDelta = function (latest) {
3672
3757
  var _a;
3673
3758
  var progress = latest / 1000;
@@ -3687,6 +3772,7 @@
3687
3772
  }
3688
3773
  _this.root.scheduleUpdateProjection();
3689
3774
  _this.scheduleRender();
3775
+ _this.animationProgress = progress;
3690
3776
  };
3691
3777
  this.mixTargetDelta(0);
3692
3778
  };
@@ -4052,6 +4138,10 @@
4052
4138
  node.clearMeasurements();
4053
4139
  }
4054
4140
  function resetTransformStyle(node) {
4141
+ var visualElement = node.options.visualElement;
4142
+ if (visualElement === null || visualElement === void 0 ? void 0 : visualElement.getProps().onBeforeLayoutMeasure) {
4143
+ visualElement.notifyBeforeLayoutMeasure();
4144
+ }
4055
4145
  node.resetTransform();
4056
4146
  }
4057
4147
  function finishAnimation(node) {
@@ -5805,7 +5895,14 @@
5805
5895
  shouldBlockAnimation(animationTypeState, key))) {
5806
5896
  continue;
5807
5897
  }
5808
- var animation = startAnimation(key, value, valueTarget, __assign({ delay: delay }, transition));
5898
+ var valueTransition = __assign({ delay: delay }, transition);
5899
+ /**
5900
+ * Make animation instant if this is a transform prop and we should reduce motion.
5901
+ */
5902
+ if (visualElement.shouldReduceMotion && isTransformProp(key)) {
5903
+ valueTransition = __assign(__assign({}, valueTransition), { type: false, delay: 0 });
5904
+ }
5905
+ var animation = startAnimation(key, value, valueTarget, valueTransition);
5809
5906
  animations.push(animation);
5810
5907
  }
5811
5908
  return Promise.all(animations).then(function () {
@@ -7051,7 +7148,7 @@
7051
7148
  for (var _i = 0; _i < arguments.length; _i++) {
7052
7149
  args[_i] = arguments[_i];
7053
7150
  }
7054
- manager.notify.apply(manager, __spreadArray([], __read(args), false));
7151
+ return manager.notify.apply(manager, __spreadArray([], __read(args), false));
7055
7152
  };
7056
7153
  });
7057
7154
  return lifecycles;
@@ -7103,7 +7200,7 @@
7103
7200
  var visualElement = function (_a) {
7104
7201
  var _b = _a.treeType, treeType = _b === void 0 ? "" : _b, build = _a.build, getBaseTarget = _a.getBaseTarget, makeTargetAnimatable = _a.makeTargetAnimatable, measureViewportBox = _a.measureViewportBox, renderInstance = _a.render, readValueFromInstance = _a.readValueFromInstance, removeValueFromRenderState = _a.removeValueFromRenderState, sortNodePosition = _a.sortNodePosition, scrapeMotionValuesFromProps = _a.scrapeMotionValuesFromProps;
7105
7202
  return function (_a, options) {
7106
- var parent = _a.parent, props = _a.props, presenceId = _a.presenceId, blockInitialAnimation = _a.blockInitialAnimation, visualState = _a.visualState;
7203
+ var parent = _a.parent, props = _a.props, presenceId = _a.presenceId, blockInitialAnimation = _a.blockInitialAnimation, visualState = _a.visualState, shouldReduceMotion = _a.shouldReduceMotion;
7107
7204
  if (options === void 0) { options = {}; }
7108
7205
  var isMounted = false;
7109
7206
  var latestValues = visualState.latestValues, renderState = visualState.renderState;
@@ -7212,7 +7309,7 @@
7212
7309
  /**
7213
7310
  *
7214
7311
  */
7215
- presenceId: presenceId,
7312
+ presenceId: presenceId, shouldReduceMotion: shouldReduceMotion,
7216
7313
  /**
7217
7314
  * If this component is part of the variant tree, it should track
7218
7315
  * any children that are also part of the tree. This is essentially
@@ -9107,60 +9204,6 @@
9107
9204
  return time;
9108
9205
  }
9109
9206
 
9110
- // Does this device prefer reduced motion? Returns `null` server-side.
9111
- var prefersReducedMotion;
9112
- function initPrefersReducedMotion() {
9113
- prefersReducedMotion = motionValue(null);
9114
- if (typeof window === "undefined")
9115
- return;
9116
- if (window.matchMedia) {
9117
- var motionMediaQuery_1 = window.matchMedia("(prefers-reduced-motion)");
9118
- var setReducedMotionPreferences = function () {
9119
- return prefersReducedMotion.set(motionMediaQuery_1.matches);
9120
- };
9121
- motionMediaQuery_1.addListener(setReducedMotionPreferences);
9122
- setReducedMotionPreferences();
9123
- }
9124
- else {
9125
- prefersReducedMotion.set(false);
9126
- }
9127
- }
9128
- /**
9129
- * A hook that returns `true` if we should be using reduced motion based on the current device's Reduced Motion setting.
9130
- *
9131
- * This can be used to implement changes to your UI based on Reduced Motion. For instance, replacing motion-sickness inducing
9132
- * `x`/`y` animations with `opacity`, disabling the autoplay of background videos, or turning off parallax motion.
9133
- *
9134
- * It will actively respond to changes and re-render your components with the latest setting.
9135
- *
9136
- * ```jsx
9137
- * export function Sidebar({ isOpen }) {
9138
- * const shouldReduceMotion = useReducedMotion()
9139
- * const closedX = shouldReduceMotion ? 0 : "-100%"
9140
- *
9141
- * return (
9142
- * <motion.div animate={{
9143
- * opacity: isOpen ? 1 : 0,
9144
- * x: isOpen ? 0 : closedX
9145
- * }} />
9146
- * )
9147
- * }
9148
- * ```
9149
- *
9150
- * @return boolean
9151
- *
9152
- * @public
9153
- */
9154
- function useReducedMotion() {
9155
- /**
9156
- * Lazy initialisation of prefersReducedMotion
9157
- */
9158
- !prefersReducedMotion && initPrefersReducedMotion();
9159
- var _a = __read(React.useState(prefersReducedMotion.get()), 2), shouldReduceMotion = _a[0], setShouldReduceMotion = _a[1];
9160
- useOnChange(prefersReducedMotion, setShouldReduceMotion);
9161
- return shouldReduceMotion;
9162
- }
9163
-
9164
9207
  /**
9165
9208
  * @public
9166
9209
  */
@@ -9595,6 +9638,7 @@
9595
9638
  exports.useMotionValue = useMotionValue;
9596
9639
  exports.usePresence = usePresence;
9597
9640
  exports.useReducedMotion = useReducedMotion;
9641
+ exports.useReducedMotionConfig = useReducedMotionConfig;
9598
9642
  exports.useResetProjection = useResetProjection;
9599
9643
  exports.useSpring = useSpring;
9600
9644
  exports.useTime = useTime;