framer-motion 11.3.16 → 11.3.18-alpha.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.
@@ -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.3.16";
282
+ this.version = "11.3.18-alpha.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
@@ -3237,6 +3237,8 @@ class AcceleratedAnimation extends BaseAnimation {
3237
3237
  this.isStopped = true;
3238
3238
  if (this.state === "idle")
3239
3239
  return;
3240
+ this.resolveFinishedPromise();
3241
+ this.updateFinishedPromise();
3240
3242
  const { resolved } = this;
3241
3243
  if (!resolved)
3242
3244
  return;
@@ -3752,7 +3754,7 @@ function updateMotionValuesFromProps(element, next, prev) {
3752
3754
  * and warn against mismatches.
3753
3755
  */
3754
3756
  if (process.env.NODE_ENV === "development") {
3755
- warnOnce(nextValue.version === "11.3.16", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.3.16 may not work as expected.`);
3757
+ warnOnce(nextValue.version === "11.3.18-alpha.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.3.18-alpha.0 may not work as expected.`);
3756
3758
  }
3757
3759
  }
3758
3760
  else if (isMotionValue(prevValue)) {
package/dist/cjs/index.js CHANGED
@@ -4468,6 +4468,8 @@ class AcceleratedAnimation extends BaseAnimation {
4468
4468
  this.isStopped = true;
4469
4469
  if (this.state === "idle")
4470
4470
  return;
4471
+ this.resolveFinishedPromise();
4472
+ this.updateFinishedPromise();
4471
4473
  const { resolved } = this;
4472
4474
  if (!resolved)
4473
4475
  return;
@@ -4813,7 +4815,7 @@ class MotionValue {
4813
4815
  * This will be replaced by the build step with the latest version number.
4814
4816
  * When MotionValues are provided to motion components, warn if versions are mixed.
4815
4817
  */
4816
- this.version = "11.3.16";
4818
+ this.version = "11.3.18-alpha.0";
4817
4819
  /**
4818
4820
  * Tracks whether this value can output a velocity. Currently this is only true
4819
4821
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -7277,7 +7279,7 @@ function updateMotionValuesFromProps(element, next, prev) {
7277
7279
  * and warn against mismatches.
7278
7280
  */
7279
7281
  if (process.env.NODE_ENV === "development") {
7280
- warnOnce(nextValue.version === "11.3.16", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.3.16 may not work as expected.`);
7282
+ warnOnce(nextValue.version === "11.3.18-alpha.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.3.18-alpha.0 may not work as expected.`);
7281
7283
  }
7282
7284
  }
7283
7285
  else if (isMotionValue(prevValue)) {
@@ -10818,31 +10820,6 @@ function createDomMotionComponent(key) {
10818
10820
  */
10819
10821
  const m = createMotionProxy(createDomMotionConfig);
10820
10822
 
10821
- function useIsMounted() {
10822
- const isMounted = React.useRef(false);
10823
- useIsomorphicLayoutEffect(() => {
10824
- isMounted.current = true;
10825
- return () => {
10826
- isMounted.current = false;
10827
- };
10828
- }, []);
10829
- return isMounted;
10830
- }
10831
-
10832
- function useForceUpdate() {
10833
- const isMounted = useIsMounted();
10834
- const [forcedRenderCount, setForcedRenderCount] = React.useState(0);
10835
- const forceRender = React.useCallback(() => {
10836
- isMounted.current && setForcedRenderCount(forcedRenderCount + 1);
10837
- }, [forcedRenderCount]);
10838
- /**
10839
- * Defer this to the end of the next animation frame in case there are multiple
10840
- * synchronous calls.
10841
- */
10842
- const deferredForceRender = React.useCallback(() => frame.postRender(forceRender), [forceRender]);
10843
- return [deferredForceRender, forcedRenderCount];
10844
- }
10845
-
10846
10823
  /**
10847
10824
  * Measurement functionality has to be within a separate component
10848
10825
  * to leverage snapshot lifecycle.
@@ -10966,13 +10943,32 @@ function useUnmountEffect(callback) {
10966
10943
  return React.useEffect(() => () => callback(), []);
10967
10944
  }
10968
10945
 
10969
- const getChildKey = (child) => child.key || "";
10970
- function updateChildLookup(children, allChildren) {
10971
- children.forEach((child) => {
10972
- const key = getChildKey(child);
10973
- allChildren.set(key, child);
10974
- });
10946
+ function useIsMounted() {
10947
+ const isMounted = React.useRef(false);
10948
+ useIsomorphicLayoutEffect(() => {
10949
+ isMounted.current = true;
10950
+ return () => {
10951
+ isMounted.current = false;
10952
+ };
10953
+ }, []);
10954
+ return isMounted;
10955
+ }
10956
+
10957
+ function useForceUpdate() {
10958
+ const isMounted = useIsMounted();
10959
+ const [forcedRenderCount, setForcedRenderCount] = React.useState(0);
10960
+ const forceRender = React.useCallback(() => {
10961
+ isMounted.current && setForcedRenderCount(forcedRenderCount + 1);
10962
+ }, [forcedRenderCount]);
10963
+ /**
10964
+ * Defer this to the end of the next animation frame in case there are multiple
10965
+ * synchronous calls.
10966
+ */
10967
+ const deferredForceRender = React.useCallback(() => frame.postRender(forceRender), [forceRender]);
10968
+ return [deferredForceRender, forcedRenderCount];
10975
10969
  }
10970
+
10971
+ const getChildKey = (child) => child.key || "";
10976
10972
  function onlyElements(children) {
10977
10973
  const filtered = [];
10978
10974
  // We use forEach here instead of map as map mutates the component key by preprending `.$`
@@ -10982,6 +10978,16 @@ function onlyElements(children) {
10982
10978
  });
10983
10979
  return filtered;
10984
10980
  }
10981
+ function arrayEquals(a, b) {
10982
+ if (a.length !== b.length)
10983
+ return false;
10984
+ for (let i = 0; i < a.length; i++) {
10985
+ if (a[i] !== b[i])
10986
+ return false;
10987
+ }
10988
+ return true;
10989
+ }
10990
+
10985
10991
  /**
10986
10992
  * `AnimatePresence` enables the animation of components that have been removed from the tree.
10987
10993
  *
@@ -11015,113 +11021,127 @@ function onlyElements(children) {
11015
11021
  *
11016
11022
  * @public
11017
11023
  */
11018
- const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exitBeforeEnter, presenceAffectsLayout = true, mode = "sync", }) => {
11024
+ const AnimatePresence = ({ children, exitBeforeEnter, custom, initial = true, onExitComplete, presenceAffectsLayout = true, mode = "sync", }) => {
11019
11025
  exports.invariant(!exitBeforeEnter, "Replace exitBeforeEnter with mode='wait'");
11020
- // We want to force a re-render once all exiting animations have finished. We
11021
- // either use a local forceRender function, or one from a parent context if it exists.
11022
- const forceRender = React.useContext(LayoutGroupContext).forceRender || useForceUpdate()[0];
11023
- const isMounted = useIsMounted();
11024
- // Filter out any children that aren't ReactElements. We can only track ReactElements with a props.key
11025
- const filteredChildren = onlyElements(children);
11026
- let childrenToRender = filteredChildren;
11027
- const exitingChildren = React.useRef(new Map()).current;
11028
- // Keep a living record of the children we're actually rendering so we
11029
- // can diff to figure out which are entering and exiting
11030
- const presentChildren = React.useRef(childrenToRender);
11031
- // A lookup table to quickly reference components by key
11032
- const allChildren = React.useRef(new Map()).current;
11033
- // If this is the initial component render, just deal with logic surrounding whether
11034
- // we play onMount animations or not.
11026
+ /**
11027
+ * Filter any children that aren't ReactElements. We can only track components
11028
+ * between renders with a props.key.
11029
+ */
11030
+ const presentChildren = React.useMemo(() => onlyElements(children), [children]);
11031
+ /**
11032
+ * Track the keys of the currently rendered children. This is used to
11033
+ * determine which children are exiting.
11034
+ */
11035
+ const presentKeys = presentChildren.map(getChildKey);
11036
+ /**
11037
+ * If `initial={false}` we only want to pass this to components in the first render.
11038
+ */
11035
11039
  const isInitialRender = React.useRef(true);
11040
+ /**
11041
+ * A ref containing the currently present children. When all exit animations
11042
+ * are complete, we use this to re-render the component with the latest children
11043
+ * *committed* rather than the latest children *rendered*.
11044
+ */
11045
+ const pendingPresentChildren = React.useRef(presentChildren);
11046
+ /**
11047
+ * Track which exiting children have finished animating out.
11048
+ */
11049
+ const exitComplete = useConstant(() => new Map());
11050
+ /**
11051
+ * Save children to render as React state. To ensure this component is concurrent-safe,
11052
+ * we check for exiting children via an effect.
11053
+ */
11054
+ const [diffedChildren, setDiffedChildren] = React.useState(presentChildren);
11055
+ const [renderedChildren, setRenderedChildren] = React.useState(presentChildren);
11036
11056
  useIsomorphicLayoutEffect(() => {
11037
11057
  isInitialRender.current = false;
11038
- updateChildLookup(filteredChildren, allChildren);
11039
- presentChildren.current = childrenToRender;
11040
- });
11041
- useUnmountEffect(() => {
11042
- isInitialRender.current = true;
11043
- allChildren.clear();
11044
- exitingChildren.clear();
11045
- });
11046
- if (isInitialRender.current) {
11047
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: childrenToRender.map((child) => (jsxRuntime.jsx(PresenceChild, { isPresent: true, initial: initial ? undefined : false, presenceAffectsLayout: presenceAffectsLayout, mode: mode, children: child }, getChildKey(child)))) }));
11048
- }
11049
- // If this is a subsequent render, deal with entering and exiting children
11050
- childrenToRender = [...childrenToRender];
11051
- // Diff the keys of the currently-present and target children to update our
11052
- // exiting list.
11053
- const presentKeys = presentChildren.current.map(getChildKey);
11054
- const targetKeys = filteredChildren.map(getChildKey);
11055
- // Diff the present children with our target children and mark those that are exiting
11056
- const numPresent = presentKeys.length;
11057
- for (let i = 0; i < numPresent; i++) {
11058
- const key = presentKeys[i];
11059
- if (targetKeys.indexOf(key) === -1 && !exitingChildren.has(key)) {
11060
- exitingChildren.set(key, undefined);
11061
- }
11062
- }
11063
- // If we currently have exiting children, and we're deferring rendering incoming children
11064
- // until after all current children have exiting, empty the childrenToRender array
11065
- if (mode === "wait" && exitingChildren.size) {
11066
- childrenToRender = [];
11067
- }
11068
- // Loop through all currently exiting components and clone them to overwrite `animate`
11069
- // with any `exit` prop they might have defined.
11070
- exitingChildren.forEach((component, key) => {
11071
- // If this component is actually entering again, early return
11072
- if (targetKeys.indexOf(key) !== -1)
11073
- return;
11074
- const child = allChildren.get(key);
11075
- if (!child)
11076
- return;
11077
- const insertionIndex = presentKeys.indexOf(key);
11078
- let exitingComponent = component;
11079
- if (!exitingComponent) {
11080
- const onExit = () => {
11081
- // clean up the exiting children map
11082
- exitingChildren.delete(key);
11083
- // compute the keys of children that were rendered once but are no longer present
11084
- // this could happen in case of too many fast consequent renderings
11085
- // @link https://github.com/framer/motion/issues/2023
11086
- const leftOverKeys = Array.from(allChildren.keys()).filter((childKey) => !targetKeys.includes(childKey));
11087
- // clean up the all children map
11088
- leftOverKeys.forEach((leftOverKey) => allChildren.delete(leftOverKey));
11089
- // make sure to render only the children that are actually visible
11090
- presentChildren.current = filteredChildren.filter((presentChild) => {
11091
- const presentChildKey = getChildKey(presentChild);
11092
- return (
11093
- // filter out the node exiting
11094
- presentChildKey === key ||
11095
- // filter out the leftover children
11096
- leftOverKeys.includes(presentChildKey));
11097
- });
11098
- // Defer re-rendering until all exiting children have indeed left
11099
- if (!exitingChildren.size) {
11100
- if (isMounted.current === false)
11101
- return;
11102
- forceRender();
11103
- onExitComplete && onExitComplete();
11058
+ pendingPresentChildren.current = presentChildren;
11059
+ /**
11060
+ * Update complete status of exiting children.
11061
+ */
11062
+ for (let i = 0; i < renderedChildren.length; i++) {
11063
+ const key = getChildKey(renderedChildren[i]);
11064
+ if (!presentKeys.includes(key)) {
11065
+ if (exitComplete.get(key) !== true) {
11066
+ exitComplete.set(key, false);
11104
11067
  }
11105
- };
11106
- exitingComponent = (jsxRuntime.jsx(PresenceChild, { isPresent: false, onExitComplete: onExit, custom: custom, presenceAffectsLayout: presenceAffectsLayout, mode: mode, children: child }, getChildKey(child)));
11107
- exitingChildren.set(key, exitingComponent);
11068
+ }
11069
+ else {
11070
+ exitComplete.delete(key);
11071
+ }
11108
11072
  }
11109
- childrenToRender.splice(insertionIndex, 0, exitingComponent);
11110
- });
11111
- // Add `MotionContext` even to children that don't need it to ensure we're rendering
11112
- // the same tree between renders
11113
- childrenToRender = childrenToRender.map((child) => {
11114
- const key = child.key;
11115
- return exitingChildren.has(key) ? (child) : (jsxRuntime.jsx(PresenceChild, { isPresent: true, presenceAffectsLayout: presenceAffectsLayout, mode: mode, children: child }, getChildKey(child)));
11116
- });
11073
+ }, [renderedChildren, presentKeys.length, presentKeys.join("-")]);
11074
+ const exitingChildren = [];
11075
+ if (presentChildren !== diffedChildren) {
11076
+ let nextChildren = [...presentChildren];
11077
+ /**
11078
+ * Loop through all the currently rendered components and decide which
11079
+ * are exiting.
11080
+ */
11081
+ for (let i = 0; i < renderedChildren.length; i++) {
11082
+ const child = renderedChildren[i];
11083
+ const key = getChildKey(child);
11084
+ if (!presentKeys.includes(key)) {
11085
+ nextChildren.splice(i, 0, child);
11086
+ exitingChildren.push(child);
11087
+ }
11088
+ }
11089
+ /**
11090
+ * If we're in "wait" mode, and we have exiting children, we want to
11091
+ * only render these until they've all exited.
11092
+ */
11093
+ if (mode === "wait" && exitingChildren.length) {
11094
+ nextChildren = exitingChildren;
11095
+ }
11096
+ nextChildren = onlyElements(nextChildren);
11097
+ const childrenHaveChanged = !arrayEquals(nextChildren.map(getChildKey), renderedChildren.map(getChildKey));
11098
+ if (childrenHaveChanged) {
11099
+ setRenderedChildren(nextChildren);
11100
+ }
11101
+ setDiffedChildren(presentChildren);
11102
+ /**
11103
+ * Early return to ensure once we've set state with the latest diffed
11104
+ * children, we can immediately re-render.
11105
+ */
11106
+ return;
11107
+ }
11117
11108
  if (process.env.NODE_ENV !== "production" &&
11118
11109
  mode === "wait" &&
11119
- childrenToRender.length > 1) {
11110
+ renderedChildren.length > 1) {
11120
11111
  console.warn(`You're attempting to animate multiple children within AnimatePresence, but its mode is set to "wait". This will lead to odd visual behaviour.`);
11121
11112
  }
11122
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: exitingChildren.size
11123
- ? childrenToRender
11124
- : childrenToRender.map((child) => React.cloneElement(child)) }));
11113
+ /**
11114
+ * If we've been provided a forceRender function by the LayoutGroupContext,
11115
+ * we can use it to force a re-render amongst all surrounding components once
11116
+ * all components have finished animating out.
11117
+ */
11118
+ const { forceRender } = React.useContext(LayoutGroupContext);
11119
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderedChildren.map((child) => {
11120
+ const key = getChildKey(child);
11121
+ const isPresent = presentChildren === renderedChildren ||
11122
+ presentKeys.includes(key);
11123
+ const onExit = () => {
11124
+ if (exitComplete.has(key)) {
11125
+ exitComplete.set(key, true);
11126
+ }
11127
+ else {
11128
+ return;
11129
+ }
11130
+ let isEveryExitComplete = true;
11131
+ exitComplete.forEach((isExitComplete) => {
11132
+ if (!isExitComplete)
11133
+ isEveryExitComplete = false;
11134
+ });
11135
+ if (isEveryExitComplete) {
11136
+ forceRender === null || forceRender === void 0 ? void 0 : forceRender();
11137
+ setRenderedChildren(pendingPresentChildren.current);
11138
+ onExitComplete && onExitComplete();
11139
+ }
11140
+ };
11141
+ return (jsxRuntime.jsx(PresenceChild, { isPresent: isPresent, initial: !isInitialRender.current || initial
11142
+ ? undefined
11143
+ : false, custom: isPresent ? undefined : custom, presenceAffectsLayout: presenceAffectsLayout, mode: mode, onExitComplete: isPresent ? undefined : onExit, children: child }, key));
11144
+ }) }));
11125
11145
  };
11126
11146
 
11127
11147
  /**
@@ -11445,6 +11465,14 @@ const Reorder = {
11445
11465
  Item,
11446
11466
  };
11447
11467
 
11468
+ /**
11469
+ * @public
11470
+ */
11471
+ const domMin = {
11472
+ renderer: createDomVisualElement,
11473
+ ...animations,
11474
+ };
11475
+
11448
11476
  /**
11449
11477
  * @public
11450
11478
  */
@@ -12442,6 +12470,7 @@ exports.distance = distance;
12442
12470
  exports.distance2D = distance2D;
12443
12471
  exports.domAnimation = domAnimation;
12444
12472
  exports.domMax = domMax;
12473
+ exports.domMin = domMin;
12445
12474
  exports.easeIn = easeIn;
12446
12475
  exports.easeInOut = easeInOut;
12447
12476
  exports.easeOut = easeOut;