framer-motion 8.0.2 → 8.0.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.
package/dist/cjs/index.js CHANGED
@@ -90,7 +90,6 @@ function useVisualElement(Component, visualState, props, createVisualElement) {
90
90
  visualElement.animationState.animateChanges();
91
91
  }
92
92
  });
93
- useIsomorphicLayoutEffect(() => () => visualElement && visualElement.notify("Unmount"), []);
94
93
  return visualElement;
95
94
  }
96
95
 
@@ -1382,18 +1381,15 @@ function extractEventInfo(event, pointType = "page") {
1382
1381
  },
1383
1382
  };
1384
1383
  }
1385
- const wrapHandler = (handler, shouldFilterPrimaryPointer = false) => {
1386
- const listener = (event) => handler(event, extractEventInfo(event));
1387
- return shouldFilterPrimaryPointer
1388
- ? (event) => isPrimaryPointer(event) && listener(event)
1389
- : listener;
1384
+ const addPointerInfo = (handler) => {
1385
+ return (event) => isPrimaryPointer(event) && handler(event, extractEventInfo(event));
1390
1386
  };
1391
1387
 
1392
1388
  function addPointerEvent(target, eventName, handler, options) {
1393
- return addDomEvent(target, eventName, wrapHandler(handler, eventName === "pointerdown"), options);
1389
+ return addDomEvent(target, eventName, addPointerInfo(handler), options);
1394
1390
  }
1395
1391
  function usePointerEvent(ref, eventName, handler, options) {
1396
- return useDomEvent(ref, eventName, handler && wrapHandler(handler, eventName === "pointerdown"), options);
1392
+ return useDomEvent(ref, eventName, handler && addPointerInfo(handler), options);
1397
1393
  }
1398
1394
 
1399
1395
  function createLock(name) {
@@ -2065,7 +2061,7 @@ class MotionValue {
2065
2061
  * This will be replaced by the build step with the latest version number.
2066
2062
  * When MotionValues are provided to motion components, warn if versions are mixed.
2067
2063
  */
2068
- this.version = "8.0.2";
2064
+ this.version = "8.0.4";
2069
2065
  /**
2070
2066
  * Duration, in milliseconds, since last updating frame.
2071
2067
  *
@@ -2179,14 +2175,6 @@ class MotionValue {
2179
2175
  * }
2180
2176
  * ```
2181
2177
  *
2182
- * @privateRemarks
2183
- *
2184
- * We could look into a `useOnChange` hook if the above lifecycle management proves confusing.
2185
- *
2186
- * ```jsx
2187
- * useOnChange(x, () => {})
2188
- * ```
2189
- *
2190
2178
  * @param subscriber - A function that receives the latest value.
2191
2179
  * @returns A function that, when called, will cancel this subscription.
2192
2180
  *
@@ -2199,7 +2187,22 @@ class MotionValue {
2199
2187
  if (!this.events[eventName]) {
2200
2188
  this.events[eventName] = new SubscriptionManager();
2201
2189
  }
2202
- return this.events[eventName].add(callback);
2190
+ const unsubscribe = this.events[eventName].add(callback);
2191
+ if (eventName === "change") {
2192
+ return () => {
2193
+ unsubscribe();
2194
+ /**
2195
+ * If we have no more change listeners by the start
2196
+ * of the next frame, stop active animations.
2197
+ */
2198
+ sync.read(() => {
2199
+ if (!this.events.change.getSize()) {
2200
+ this.stop();
2201
+ }
2202
+ });
2203
+ };
2204
+ }
2205
+ return unsubscribe;
2203
2206
  }
2204
2207
  clearListeners() {
2205
2208
  for (const eventManagers in this.events) {
@@ -4570,16 +4573,12 @@ class PanSession {
4570
4573
  onMove && onMove(this.lastMoveEvent, info);
4571
4574
  };
4572
4575
  this.handlePointerMove = (event, info) => {
4573
- if (!isPrimaryPointer(event))
4574
- return;
4575
4576
  this.lastMoveEvent = event;
4576
4577
  this.lastMoveEventInfo = transformPoint(info, this.transformPagePoint);
4577
4578
  // Throttle mouse move event to once per frame
4578
4579
  sync.update(this.updatePoint, true);
4579
4580
  };
4580
4581
  this.handlePointerUp = (event, info) => {
4581
- if (!isPrimaryPointer(event))
4582
- return;
4583
4582
  this.end();
4584
4583
  const { onEnd, onSessionEnd } = this.handlers;
4585
4584
  const panInfo = getPanInfo(transformPoint(info, this.transformPagePoint), this.history);
@@ -5872,7 +5871,7 @@ function updateMotionValuesFromProps(element, next, prev) {
5872
5871
  * and warn against mismatches.
5873
5872
  */
5874
5873
  if (process.env.NODE_ENV === "development") {
5875
- warnOnce(nextValue.version === "8.0.2", `Attempting to mix Framer Motion versions ${nextValue.version} with 8.0.2 may not work as expected.`);
5874
+ warnOnce(nextValue.version === "8.0.4", `Attempting to mix Framer Motion versions ${nextValue.version} with 8.0.4 may not work as expected.`);
5876
5875
  }
5877
5876
  }
5878
5877
  else if (isMotionValue(prevValue)) {
@@ -5916,7 +5915,6 @@ const propEventHandlers = [
5916
5915
  "AnimationStart",
5917
5916
  "AnimationComplete",
5918
5917
  "Update",
5919
- "Unmount",
5920
5918
  "BeforeLayoutMeasure",
5921
5919
  "LayoutMeasure",
5922
5920
  "LayoutAnimationStart",
@@ -6262,11 +6260,12 @@ class VisualElement {
6262
6260
  */
6263
6261
  addValue(key, value) {
6264
6262
  // Remove existing value if it exists
6265
- if (this.hasValue(key))
6263
+ if (value !== this.values.get(key)) {
6266
6264
  this.removeValue(key);
6265
+ this.bindToMotionValue(key, value);
6266
+ }
6267
6267
  this.values.set(key, value);
6268
6268
  this.latestValues[key] = value.get();
6269
- this.bindToMotionValue(key, value);
6270
6269
  }
6271
6270
  /**
6272
6271
  * Remove a motion value and unbind any active subscriptions.
@@ -6285,10 +6284,6 @@ class VisualElement {
6285
6284
  hasValue(key) {
6286
6285
  return this.values.has(key);
6287
6286
  }
6288
- /**
6289
- * Get a motion value for this key. If called with a default
6290
- * value, we'll create one if none exists.
6291
- */
6292
6287
  getValue(key, defaultValue) {
6293
6288
  if (this.props.values && this.props.values[key]) {
6294
6289
  return this.props.values[key];
@@ -8988,24 +8983,6 @@ function transform(...args) {
8988
8983
  return useImmediate ? interpolator(inputValue) : interpolator;
8989
8984
  }
8990
8985
 
8991
- function useOnChange(value, callback) {
8992
- useIsomorphicLayoutEffect(() => {
8993
- if (isMotionValue(value)) {
8994
- callback(value.get());
8995
- return value.on("change", callback);
8996
- }
8997
- }, [value, callback]);
8998
- }
8999
- function useMultiOnChange(values, handler, cleanup) {
9000
- useIsomorphicLayoutEffect(() => {
9001
- const subscriptions = values.map((value) => value.on("change", handler));
9002
- return () => {
9003
- subscriptions.forEach((unsubscribe) => unsubscribe());
9004
- cleanup();
9005
- };
9006
- });
9007
- }
9008
-
9009
8986
  function useCombineMotionValues(values, combineValues) {
9010
8987
  /**
9011
8988
  * Initialise the returned motion value. This remains the same between renders.
@@ -9027,7 +9004,14 @@ function useCombineMotionValues(values, combineValues) {
9027
9004
  * Subscribe to all motion values found within the template. Whenever any of them change,
9028
9005
  * schedule an update.
9029
9006
  */
9030
- useMultiOnChange(values, () => sync.update(updateValue, false, true), () => cancelSync.update(updateValue));
9007
+ useIsomorphicLayoutEffect(() => {
9008
+ const scheduleUpdate = () => sync.update(updateValue, false, true);
9009
+ const subscriptions = values.map((v) => v.on("change", scheduleUpdate));
9010
+ return () => {
9011
+ subscriptions.forEach((unsubscribe) => unsubscribe());
9012
+ cancelSync.update(updateValue);
9013
+ };
9014
+ });
9031
9015
  return value;
9032
9016
  }
9033
9017
 
@@ -9187,7 +9171,11 @@ function useSpring(source, config = {}) {
9187
9171
  return value.get();
9188
9172
  });
9189
9173
  }, [JSON.stringify(config)]);
9190
- useOnChange(source, (v) => value.set(parseFloat(v)));
9174
+ useIsomorphicLayoutEffect(() => {
9175
+ if (isMotionValue(source)) {
9176
+ return source.on("change", (v) => value.set(parseFloat(v)));
9177
+ }
9178
+ }, [value]);
9191
9179
  return value;
9192
9180
  }
9193
9181
 
@@ -9324,7 +9312,13 @@ function useWillChange() {
9324
9312
  }
9325
9313
 
9326
9314
  function useMotionValueEvent(value, event, callback) {
9327
- useIsomorphicLayoutEffect(() => value.on(event, callback), [value, event, callback]);
9315
+ /**
9316
+ * useInsertionEffect will create subscriptions before any other
9317
+ * effects will run. Effects run upwards through the tree so it
9318
+ * can be that binding a useLayoutEffect higher up the tree can
9319
+ * miss changes from lower down the tree.
9320
+ */
9321
+ React.useInsertionEffect(() => value.on(event, callback), [value, event, callback]);
9328
9322
  }
9329
9323
 
9330
9324
  /**
@@ -9831,6 +9825,7 @@ exports.Reorder = Reorder;
9831
9825
  exports.SwitchLayoutGroupContext = SwitchLayoutGroupContext;
9832
9826
  exports.VisualElement = VisualElement;
9833
9827
  exports.addPointerEvent = addPointerEvent;
9828
+ exports.addPointerInfo = addPointerInfo;
9834
9829
  exports.addScaleCorrector = addScaleCorrector;
9835
9830
  exports.animate = animate;
9836
9831
  exports.animateVisualElement = animateVisualElement;
@@ -9898,4 +9893,3 @@ exports.useViewportScroll = useViewportScroll;
9898
9893
  exports.useVisualElementContext = useVisualElementContext;
9899
9894
  exports.useWillChange = useWillChange;
9900
9895
  exports.wrap = wrap;
9901
- exports.wrapHandler = wrapHandler;
@@ -8,11 +8,8 @@ function extractEventInfo(event, pointType = "page") {
8
8
  },
9
9
  };
10
10
  }
11
- const wrapHandler = (handler, shouldFilterPrimaryPointer = false) => {
12
- const listener = (event) => handler(event, extractEventInfo(event));
13
- return shouldFilterPrimaryPointer
14
- ? (event) => isPrimaryPointer(event) && listener(event)
15
- : listener;
11
+ const addPointerInfo = (handler) => {
12
+ return (event) => isPrimaryPointer(event) && handler(event, extractEventInfo(event));
16
13
  };
17
14
 
18
- export { extractEventInfo, wrapHandler };
15
+ export { addPointerInfo, extractEventInfo };
@@ -1,11 +1,11 @@
1
1
  import { addDomEvent, useDomEvent } from './use-dom-event.mjs';
2
- import { wrapHandler } from './event-info.mjs';
2
+ import { addPointerInfo } from './event-info.mjs';
3
3
 
4
4
  function addPointerEvent(target, eventName, handler, options) {
5
- return addDomEvent(target, eventName, wrapHandler(handler, eventName === "pointerdown"), options);
5
+ return addDomEvent(target, eventName, addPointerInfo(handler), options);
6
6
  }
7
7
  function usePointerEvent(ref, eventName, handler, options) {
8
- return useDomEvent(ref, eventName, handler && wrapHandler(handler, eventName === "pointerdown"), options);
8
+ return useDomEvent(ref, eventName, handler && addPointerInfo(handler), options);
9
9
  }
10
10
 
11
11
  export { addPointerEvent, usePointerEvent };
@@ -50,16 +50,12 @@ class PanSession {
50
50
  onMove && onMove(this.lastMoveEvent, info);
51
51
  };
52
52
  this.handlePointerMove = (event, info) => {
53
- if (!isPrimaryPointer(event))
54
- return;
55
53
  this.lastMoveEvent = event;
56
54
  this.lastMoveEventInfo = transformPoint(info, this.transformPagePoint);
57
55
  // Throttle mouse move event to once per frame
58
56
  sync.update(this.updatePoint, true);
59
57
  };
60
58
  this.handlePointerUp = (event, info) => {
61
- if (!isPrimaryPointer(event))
62
- return;
63
59
  this.end();
64
60
  const { onEnd, onSessionEnd } = this.handlers;
65
61
  const panInfo = getPanInfo(transformPoint(info, this.transformPagePoint), this.history);
package/dist/es/index.mjs CHANGED
@@ -71,7 +71,7 @@ export { filterProps } from './render/dom/utils/filter-props.mjs';
71
71
  export { makeUseVisualState } from './motion/utils/use-visual-state.mjs';
72
72
  export { isDragActive } from './gestures/drag/utils/lock.mjs';
73
73
  export { addPointerEvent } from './events/use-pointer-event.mjs';
74
- export { wrapHandler } from './events/event-info.mjs';
74
+ export { addPointerInfo } from './events/event-info.mjs';
75
75
  export { isMotionValue } from './value/utils/is-motion-value.mjs';
76
76
  export { isBrowser } from './utils/is-browser.mjs';
77
77
  export { useUnmountEffect } from './utils/use-unmount-effect.mjs';
@@ -41,7 +41,6 @@ function useVisualElement(Component, visualState, props, createVisualElement) {
41
41
  visualElement.animationState.animateChanges();
42
42
  }
43
43
  });
44
- useIsomorphicLayoutEffect(() => () => visualElement && visualElement.notify("Unmount"), []);
45
44
  return visualElement;
46
45
  }
47
46
 
@@ -24,7 +24,6 @@ const propEventHandlers = [
24
24
  "AnimationStart",
25
25
  "AnimationComplete",
26
26
  "Update",
27
- "Unmount",
28
27
  "BeforeLayoutMeasure",
29
28
  "LayoutMeasure",
30
29
  "LayoutAnimationStart",
@@ -370,11 +369,12 @@ class VisualElement {
370
369
  */
371
370
  addValue(key, value) {
372
371
  // Remove existing value if it exists
373
- if (this.hasValue(key))
372
+ if (value !== this.values.get(key)) {
374
373
  this.removeValue(key);
374
+ this.bindToMotionValue(key, value);
375
+ }
375
376
  this.values.set(key, value);
376
377
  this.latestValues[key] = value.get();
377
- this.bindToMotionValue(key, value);
378
378
  }
379
379
  /**
380
380
  * Remove a motion value and unbind any active subscriptions.
@@ -393,10 +393,6 @@ class VisualElement {
393
393
  hasValue(key) {
394
394
  return this.values.has(key);
395
395
  }
396
- /**
397
- * Get a motion value for this key. If called with a default
398
- * value, we'll create one if none exists.
399
- */
400
396
  getValue(key, defaultValue) {
401
397
  if (this.props.values && this.props.values[key]) {
402
398
  return this.props.values[key];
@@ -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 === "8.0.2", `Attempting to mix Framer Motion versions ${nextValue.version} with 8.0.2 may not work as expected.`);
25
+ warnOnce(nextValue.version === "8.0.4", `Attempting to mix Framer Motion versions ${nextValue.version} with 8.0.4 may not work as expected.`);
26
26
  }
27
27
  }
28
28
  else if (isMotionValue(prevValue)) {
@@ -1,7 +1,13 @@
1
- import { useIsomorphicLayoutEffect } from './use-isomorphic-effect.mjs';
1
+ import { useInsertionEffect } from 'react';
2
2
 
3
3
  function useMotionValueEvent(value, event, callback) {
4
- useIsomorphicLayoutEffect(() => value.on(event, callback), [value, event, callback]);
4
+ /**
5
+ * useInsertionEffect will create subscriptions before any other
6
+ * effects will run. Effects run upwards through the tree so it
7
+ * can be that binding a useLayoutEffect higher up the tree can
8
+ * miss changes from lower down the tree.
9
+ */
10
+ useInsertionEffect(() => value.on(event, callback), [value, event, callback]);
5
11
  }
6
12
 
7
13
  export { useMotionValueEvent };
@@ -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 = "8.0.2";
28
+ this.version = "8.0.4";
29
29
  /**
30
30
  * Duration, in milliseconds, since last updating frame.
31
31
  *
@@ -139,14 +139,6 @@ class MotionValue {
139
139
  * }
140
140
  * ```
141
141
  *
142
- * @privateRemarks
143
- *
144
- * We could look into a `useOnChange` hook if the above lifecycle management proves confusing.
145
- *
146
- * ```jsx
147
- * useOnChange(x, () => {})
148
- * ```
149
- *
150
142
  * @param subscriber - A function that receives the latest value.
151
143
  * @returns A function that, when called, will cancel this subscription.
152
144
  *
@@ -159,7 +151,22 @@ class MotionValue {
159
151
  if (!this.events[eventName]) {
160
152
  this.events[eventName] = new SubscriptionManager();
161
153
  }
162
- return this.events[eventName].add(callback);
154
+ const unsubscribe = this.events[eventName].add(callback);
155
+ if (eventName === "change") {
156
+ return () => {
157
+ unsubscribe();
158
+ /**
159
+ * If we have no more change listeners by the start
160
+ * of the next frame, stop active animations.
161
+ */
162
+ sync.read(() => {
163
+ if (!this.events.change.getSize()) {
164
+ this.stop();
165
+ }
166
+ });
167
+ };
168
+ }
169
+ return unsubscribe;
163
170
  }
164
171
  clearListeners() {
165
172
  for (const eventManagers in this.events) {
@@ -1,6 +1,6 @@
1
1
  import { useMotionValue } from './use-motion-value.mjs';
2
- import { useMultiOnChange } from './use-on-change.mjs';
3
2
  import { cancelSync, sync } from '../frameloop/index.mjs';
3
+ import { useIsomorphicLayoutEffect } from '../utils/use-isomorphic-effect.mjs';
4
4
 
5
5
  function useCombineMotionValues(values, combineValues) {
6
6
  /**
@@ -23,7 +23,14 @@ function useCombineMotionValues(values, combineValues) {
23
23
  * Subscribe to all motion values found within the template. Whenever any of them change,
24
24
  * schedule an update.
25
25
  */
26
- useMultiOnChange(values, () => sync.update(updateValue, false, true), () => cancelSync.update(updateValue));
26
+ useIsomorphicLayoutEffect(() => {
27
+ const scheduleUpdate = () => sync.update(updateValue, false, true);
28
+ const subscriptions = values.map((v) => v.on("change", scheduleUpdate));
29
+ return () => {
30
+ subscriptions.forEach((unsubscribe) => unsubscribe());
31
+ cancelSync.update(updateValue);
32
+ };
33
+ });
27
34
  return value;
28
35
  }
29
36
 
@@ -1,9 +1,9 @@
1
1
  import { useContext, useRef, useMemo } from 'react';
2
2
  import { isMotionValue } from './utils/is-motion-value.mjs';
3
3
  import { useMotionValue } from './use-motion-value.mjs';
4
- import { useOnChange } from './use-on-change.mjs';
5
4
  import { MotionConfigContext } from '../context/MotionConfigContext.mjs';
6
5
  import { animate } from '../animation/legacy-popmotion/index.mjs';
6
+ import { useIsomorphicLayoutEffect } from '../utils/use-isomorphic-effect.mjs';
7
7
 
8
8
  /**
9
9
  * Creates a `MotionValue` that, when `set`, will use a spring animation to animate to its new state.
@@ -49,7 +49,11 @@ function useSpring(source, config = {}) {
49
49
  return value.get();
50
50
  });
51
51
  }, [JSON.stringify(config)]);
52
- useOnChange(source, (v) => value.set(parseFloat(v)));
52
+ useIsomorphicLayoutEffect(() => {
53
+ if (isMotionValue(source)) {
54
+ return source.on("change", (v) => value.set(parseFloat(v)));
55
+ }
56
+ }, [value]);
53
57
  return value;
54
58
  }
55
59
 
@@ -88,7 +88,6 @@
88
88
  visualElement.animationState.animateChanges();
89
89
  }
90
90
  });
91
- useIsomorphicLayoutEffect(() => () => visualElement && visualElement.notify("Unmount"), []);
92
91
  return visualElement;
93
92
  }
94
93
 
@@ -1380,18 +1379,15 @@
1380
1379
  },
1381
1380
  };
1382
1381
  }
1383
- const wrapHandler = (handler, shouldFilterPrimaryPointer = false) => {
1384
- const listener = (event) => handler(event, extractEventInfo(event));
1385
- return shouldFilterPrimaryPointer
1386
- ? (event) => isPrimaryPointer(event) && listener(event)
1387
- : listener;
1382
+ const addPointerInfo = (handler) => {
1383
+ return (event) => isPrimaryPointer(event) && handler(event, extractEventInfo(event));
1388
1384
  };
1389
1385
 
1390
1386
  function addPointerEvent(target, eventName, handler, options) {
1391
- return addDomEvent(target, eventName, wrapHandler(handler, eventName === "pointerdown"), options);
1387
+ return addDomEvent(target, eventName, addPointerInfo(handler), options);
1392
1388
  }
1393
1389
  function usePointerEvent(ref, eventName, handler, options) {
1394
- return useDomEvent(ref, eventName, handler && wrapHandler(handler, eventName === "pointerdown"), options);
1390
+ return useDomEvent(ref, eventName, handler && addPointerInfo(handler), options);
1395
1391
  }
1396
1392
 
1397
1393
  function createLock(name) {
@@ -2063,7 +2059,7 @@
2063
2059
  * This will be replaced by the build step with the latest version number.
2064
2060
  * When MotionValues are provided to motion components, warn if versions are mixed.
2065
2061
  */
2066
- this.version = "8.0.2";
2062
+ this.version = "8.0.4";
2067
2063
  /**
2068
2064
  * Duration, in milliseconds, since last updating frame.
2069
2065
  *
@@ -2177,14 +2173,6 @@
2177
2173
  * }
2178
2174
  * ```
2179
2175
  *
2180
- * @privateRemarks
2181
- *
2182
- * We could look into a `useOnChange` hook if the above lifecycle management proves confusing.
2183
- *
2184
- * ```jsx
2185
- * useOnChange(x, () => {})
2186
- * ```
2187
- *
2188
2176
  * @param subscriber - A function that receives the latest value.
2189
2177
  * @returns A function that, when called, will cancel this subscription.
2190
2178
  *
@@ -2197,7 +2185,22 @@
2197
2185
  if (!this.events[eventName]) {
2198
2186
  this.events[eventName] = new SubscriptionManager();
2199
2187
  }
2200
- return this.events[eventName].add(callback);
2188
+ const unsubscribe = this.events[eventName].add(callback);
2189
+ if (eventName === "change") {
2190
+ return () => {
2191
+ unsubscribe();
2192
+ /**
2193
+ * If we have no more change listeners by the start
2194
+ * of the next frame, stop active animations.
2195
+ */
2196
+ sync.read(() => {
2197
+ if (!this.events.change.getSize()) {
2198
+ this.stop();
2199
+ }
2200
+ });
2201
+ };
2202
+ }
2203
+ return unsubscribe;
2201
2204
  }
2202
2205
  clearListeners() {
2203
2206
  for (const eventManagers in this.events) {
@@ -4583,16 +4586,12 @@
4583
4586
  onMove && onMove(this.lastMoveEvent, info);
4584
4587
  };
4585
4588
  this.handlePointerMove = (event, info) => {
4586
- if (!isPrimaryPointer(event))
4587
- return;
4588
4589
  this.lastMoveEvent = event;
4589
4590
  this.lastMoveEventInfo = transformPoint(info, this.transformPagePoint);
4590
4591
  // Throttle mouse move event to once per frame
4591
4592
  sync.update(this.updatePoint, true);
4592
4593
  };
4593
4594
  this.handlePointerUp = (event, info) => {
4594
- if (!isPrimaryPointer(event))
4595
- return;
4596
4595
  this.end();
4597
4596
  const { onEnd, onSessionEnd } = this.handlers;
4598
4597
  const panInfo = getPanInfo(transformPoint(info, this.transformPagePoint), this.history);
@@ -5885,7 +5884,7 @@
5885
5884
  * and warn against mismatches.
5886
5885
  */
5887
5886
  {
5888
- warnOnce(nextValue.version === "8.0.2", `Attempting to mix Framer Motion versions ${nextValue.version} with 8.0.2 may not work as expected.`);
5887
+ warnOnce(nextValue.version === "8.0.4", `Attempting to mix Framer Motion versions ${nextValue.version} with 8.0.4 may not work as expected.`);
5889
5888
  }
5890
5889
  }
5891
5890
  else if (isMotionValue(prevValue)) {
@@ -5929,7 +5928,6 @@
5929
5928
  "AnimationStart",
5930
5929
  "AnimationComplete",
5931
5930
  "Update",
5932
- "Unmount",
5933
5931
  "BeforeLayoutMeasure",
5934
5932
  "LayoutMeasure",
5935
5933
  "LayoutAnimationStart",
@@ -6275,11 +6273,12 @@
6275
6273
  */
6276
6274
  addValue(key, value) {
6277
6275
  // Remove existing value if it exists
6278
- if (this.hasValue(key))
6276
+ if (value !== this.values.get(key)) {
6279
6277
  this.removeValue(key);
6278
+ this.bindToMotionValue(key, value);
6279
+ }
6280
6280
  this.values.set(key, value);
6281
6281
  this.latestValues[key] = value.get();
6282
- this.bindToMotionValue(key, value);
6283
6282
  }
6284
6283
  /**
6285
6284
  * Remove a motion value and unbind any active subscriptions.
@@ -6298,10 +6297,6 @@
6298
6297
  hasValue(key) {
6299
6298
  return this.values.has(key);
6300
6299
  }
6301
- /**
6302
- * Get a motion value for this key. If called with a default
6303
- * value, we'll create one if none exists.
6304
- */
6305
6300
  getValue(key, defaultValue) {
6306
6301
  if (this.props.values && this.props.values[key]) {
6307
6302
  return this.props.values[key];
@@ -9001,24 +8996,6 @@
9001
8996
  return useImmediate ? interpolator(inputValue) : interpolator;
9002
8997
  }
9003
8998
 
9004
- function useOnChange(value, callback) {
9005
- useIsomorphicLayoutEffect(() => {
9006
- if (isMotionValue(value)) {
9007
- callback(value.get());
9008
- return value.on("change", callback);
9009
- }
9010
- }, [value, callback]);
9011
- }
9012
- function useMultiOnChange(values, handler, cleanup) {
9013
- useIsomorphicLayoutEffect(() => {
9014
- const subscriptions = values.map((value) => value.on("change", handler));
9015
- return () => {
9016
- subscriptions.forEach((unsubscribe) => unsubscribe());
9017
- cleanup();
9018
- };
9019
- });
9020
- }
9021
-
9022
8999
  function useCombineMotionValues(values, combineValues) {
9023
9000
  /**
9024
9001
  * Initialise the returned motion value. This remains the same between renders.
@@ -9040,7 +9017,14 @@
9040
9017
  * Subscribe to all motion values found within the template. Whenever any of them change,
9041
9018
  * schedule an update.
9042
9019
  */
9043
- useMultiOnChange(values, () => sync.update(updateValue, false, true), () => cancelSync.update(updateValue));
9020
+ useIsomorphicLayoutEffect(() => {
9021
+ const scheduleUpdate = () => sync.update(updateValue, false, true);
9022
+ const subscriptions = values.map((v) => v.on("change", scheduleUpdate));
9023
+ return () => {
9024
+ subscriptions.forEach((unsubscribe) => unsubscribe());
9025
+ cancelSync.update(updateValue);
9026
+ };
9027
+ });
9044
9028
  return value;
9045
9029
  }
9046
9030
 
@@ -9200,7 +9184,11 @@
9200
9184
  return value.get();
9201
9185
  });
9202
9186
  }, [JSON.stringify(config)]);
9203
- useOnChange(source, (v) => value.set(parseFloat(v)));
9187
+ useIsomorphicLayoutEffect(() => {
9188
+ if (isMotionValue(source)) {
9189
+ return source.on("change", (v) => value.set(parseFloat(v)));
9190
+ }
9191
+ }, [value]);
9204
9192
  return value;
9205
9193
  }
9206
9194
 
@@ -9945,7 +9933,13 @@
9945
9933
  }
9946
9934
 
9947
9935
  function useMotionValueEvent(value, event, callback) {
9948
- useIsomorphicLayoutEffect(() => value.on(event, callback), [value, event, callback]);
9936
+ /**
9937
+ * useInsertionEffect will create subscriptions before any other
9938
+ * effects will run. Effects run upwards through the tree so it
9939
+ * can be that binding a useLayoutEffect higher up the tree can
9940
+ * miss changes from lower down the tree.
9941
+ */
9942
+ React.useInsertionEffect(() => value.on(event, callback), [value, event, callback]);
9949
9943
  }
9950
9944
 
9951
9945
  /**
@@ -10452,6 +10446,7 @@
10452
10446
  exports.SwitchLayoutGroupContext = SwitchLayoutGroupContext;
10453
10447
  exports.VisualElement = VisualElement;
10454
10448
  exports.addPointerEvent = addPointerEvent;
10449
+ exports.addPointerInfo = addPointerInfo;
10455
10450
  exports.addScaleCorrector = addScaleCorrector;
10456
10451
  exports.animate = animate;
10457
10452
  exports.animateVisualElement = animateVisualElement;
@@ -10519,7 +10514,6 @@
10519
10514
  exports.useVisualElementContext = useVisualElementContext;
10520
10515
  exports.useWillChange = useWillChange;
10521
10516
  exports.wrap = wrap;
10522
- exports.wrapHandler = wrapHandler;
10523
10517
 
10524
10518
  Object.defineProperty(exports, '__esModule', { value: true });
10525
10519