Giter VIP home page Giter VIP logo

motion's People

Contributors

adamseckel avatar alexandredev3 avatar amannn avatar andarist avatar aron avatar benjamindenboer avatar coobaha avatar dependabot[bot] avatar dminkovsky avatar eelco avatar evalon avatar frysztak avatar github0013 avatar huntercaron avatar iam-medvedev avatar james-wallis avatar jethronatividad avatar jonastreub avatar kalimantos avatar kena0ki avatar koenbok avatar koenrh avatar kurtextrem avatar mattgperry avatar mergetron[bot] avatar nvh avatar oielbanna avatar shuangq avatar thebuilder avatar tom-laventure avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

motion's Issues

[BUG] Stop scrolling from interfering with dragging

Is your feature request related to a problem? Please describe.
If you render a list of drag="x" components and try to scroll down on a touch device, a small amount of horizontal drag happens on each element that your finger touches.

Describe the solution you'd like
A generic solution could be to allow the variant styles to override the styles from the drag.

let variants = {
  // this would override whatever x value the drag gesture is providing
  static: { x: 0 },
  swiping: { },
};

let Swipeable = () => {
  let [isSwiping, setIsSwiping] = useState(0);

  let onDrag = (event, info) => setIsSwiping(info.offset.x > 10);

  return (
    <motion.div drag="x" animate={isSwiping ? "swiping" : "static"} onDrag={onDrag} />
  );
}

Describe alternatives you've considered
I also tried overriding by passing transform styles directly to the motion.div element.

A more specific version of this might be adding a dragThreshold prop that would specify the offsets that the gesture must pass before the onDragStart event is called.

Another option might be having some way to cancel the animation (but not the event) from the onDrag handler.

Animating a color to alpha=0 leads to an error

Describe the bug
When moving the mouse FAST over this animation, the animated alpha value becomes negative when the hovering ends.

<motion.div style={{ border: "solid", borderColor:"rgba(0,0,0,0)" }} whileHover={{ borderColor:"rgba(0,0,0,1)" }} > Test </div>

The result is the following error: Uncaught (in promise) Error: Complex values 'rgba(1, 0, 0, -0.00038)' and 'rgba(1, 0, 0, 0)' too different to mix. Ensure all colors are of the same type.

To Reproduce
Past the animation above into an react app.

Expected behavior
The border should become visible while hovering and invisible again after endHover.
The error-message should not tell me about different color types.

Desktop:

  • MacOS
  • Google Chrome 75
  • 1.2.1

[BUG] whileHover doesn't animate back to int value from percent value

Describe the bug
Width gets stuck at 100% when hovering in a basic example

To Reproduce

  1. Visit codesandbox link
  2. hover over the black div for more than a few seconds
  3. When you leave hover it stays at 100%

Screencap
Screen Recording 2019-07-10 at 3 13 16 PM

Expected behavior
It should animate back to the initial width on mouse out.

Codesandbox
https://codesandbox.io/s/variants-k9vfb

Desktop (please complete the following information):

  • OS: macOS mojave
  • Browser chrome
  • Version 75

[FEATURE] onUpdate return a new computed state

Is your feature request related to a problem? Please describe.

Ability to return a new animation state for each frame, inside onUpdate.

Describe the solution you'd like

const Component = props => (
  <motion.div
    {...props}
    onUpdate={state => ({ opacity: computeOpacity(state.rotateX), ...state })}
  />
)

const Test = () => (
  <Component initial={{ rotateX: 0 }} animate={{ rotateX: 90 }} />
)

Describe alternatives you've considered

Passing motionValues to a component via props instead. But using motionValues means you miss out on using variants, whileHover etc.

const Component = ({ rotateX }) => {
  const opacity = useTransform(rotateX, computeOpacity)

  return <motion.div style={{ opacity, rotateX }} />
}

const Test = () => {
  const rotateX = useSpring(0)
  useEffect(() => {
    setTimeout(() => rotateX.set(90), 50)
  }, [])
  
  return <Component rotateX={rotateX} />
}

[FEATURE] Hook up prefersReducedMotion

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

[FEATURE] multiple transitions within a single animation

Let's say you need to get x from 0 to 100 over the course of 7.5 seconds. For the first 2 seconds, you want to use a cubic bezier ease, then for the next 4 seconds you want to use a linear ease, and then for the remaining time, you want to use another cubic bezier ease. You could split this up into 3 separate animations, but you'd need to know what the value of x should be at 2s and 6s. That's not easy to calculate, so turning transition into an array would take care of it. It might look something like this:

x: 100,
transition: [
    {
        duration: 2,
        ease: [.3,0,.3,1]
    },
    {
        duration: 4,
        ease: 'linear'
    },
    {
        duration: 1.5,
        ease: [.6,0,1,.7]
    }
]

[FEATURE]Small introduction to use it with page transitions, like pose had done

It would be great to get some realworld examples. When it"s production ready, we would like to see some real scenarios, like page transitions in use with react router dom.

`
const AnimationSettings = {
transition: { duration: 0.5 },
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -20 },
};

const Routes = () => {
const { location } = React.useContext(__RouterContext);

return (
<AnimatePresence {...AnimationSettings}>

    <Route path="/board/:id" component={({ match }) => <BoardDetail boardId={match.params.id} />} />

    <Route path="/dashboard" exact component={Dashboard} />
    <Route path="/projects" exact component={Projects} />
    <Route path="/createboard" exact component={CreateBoard} />

    <Route path="/statistic/:id" component={({ match }) => <Statistic questionId={match.params.id} />} />
  </Switch>
</AnimatePresence>

);
};

export default Routes;
`

Does not seem to fully support styled-components?

I want to do this, passing the gatsby-image component `Img into a styled component, while animating it, like so:

const AnimatedImage = styled(motion(Img))`
  width: 200px;
  height: auto;
`

but this does not seem to work, giving me this error:

TypeError: Object(...) is not a function
Module.<anonymous>
src/pages/index.js:81
  78 |   }
  79 | `
  80 | 
> 81 | const LaxImg = styled(motion(Img))`
  82 |   width: 200px;
  83 |   height: auto;
  84 | `

it seems to work with regular html tags, just not react components, which is no bueno for me :-(

Am i doing something wrong? Is something like this not supported? It really needs to be supported, so hopefully I am doing something wrong or it's on the way.

[BUG] AnimatePresence uses undesired values

I am using AnimatePresence to slide an element up from the bottom of the screen on mount, and then slide it out to the left on unmount. Here are my variants:

            defaultInitial: {
                position: 'fixed',
                top: '100vh',
                marginLeft: '0%',
            },
            defaultEnter: {
                position: 'relative',
                marginLeft: '0%',
                top: '0vh',
                transition: {
                    duration: .5
                },
            },
            defaultExit: {
                marginLeft: '-100%',
                top: '0vh',
                transition: {
                    duration: .5
                }
            },

Here is my component:

                <motion.div
                    key={currPost.id}
                    variants={variants}
                    initial="defaultInitial"
                    animate="defaultEnter"
                    exit="defaultExit"
                >

The problem I am having is that on mount, the component gets a left-margin value of NEGATIVE % and then animates to 0%.

Here is a snapshot of the div as it is animating in: <div style="position: relative; margin-left: -10.2873%; top: 10.2645vh;">

I have no idea where this negative value is coming from. I have tried changing units, position values, everything. I even change leftMargin to left or even x. It still gives it some negative initial value.

This only occurs on the initial load. Subsequent transitions use their proper values.

[FEATURE] useSpring (optional length parameter)

Im struggling to figure out how i might rewrite the following example if there was an indefinite number of cards in the UI.

https://codesandbox.io/s/happy-bhabha-i3q10

As you can see Ive manually declared springs at the top for each of my cards, each using the last as a base:

  const frontX = useMotionValue(0)
  const middleX = useSpring(frontX, spring)
  const backX = useSpring(middleX, spring)

My initial thought was to map through an array of cards and create a spring for each one to later iterate through in my return, but quickly remembered that you cant use hooks inside closures.

Does something like useSprings exist in the API where you might be able to pass a base motionValue & springConfig and returns an array of springs, each based on the last? Another use case for something like this might be chatheads.

Thanks!

[BUG] AnimatePresence + positionTransition broken in 1.4

Describe the bug
Somewhere between 1.3 and 1.4 the combination of <AnimatePresence> and positionTransition on its children has stopped working - the children no longer animate their position after the exit animation of the removed component.

To Reproduce
See https://codesandbox.io/s/framer-motion-reorder-animation-z0esb - clicking a button animates the button away, but there is no animation when reordering the other components.

If you change the framer-motion dependency back to 1.3 the position animations work again.

Additional context
I thought I was going crazy because the example sandboxes showed this working (they're pinned to a much older version of framer), and at some point during my debugging I observed that point where the position measurement was happening was getting different results in 1.3 and 1.4. It seemed like the measuring in 1.4 was happening before the exit animation had finished, so the components position didn't seem to have changed.

Nested dragging not working as expected

Describe the bug

Hello, I tried copied example /dev/examples/dragPropagation.tsx which renders a red box nested within a blue box, both draggable.

What I experience is that after dragging the blue box once, I can not drag the inner red box without effecting the blue box.
When dragging the red box before touching the blue box everything works as I expected.
Somehow stopPropagation stops working after the first drag on the outer box.

To Reproduce

Expected behavior
I expected the blue box to be uneffected by the drag of the inner, red box. Regardless of the order in which I touch them.

Desktop

  • MacOS
  • Google Chrome 75 and Safari 12.1.1.
  • "framer-motion": "^1.2.6"
  • "react": "^16.8.6" on

[BUG] dragConstraints ref is ignored when onDragStart updates a state

Describe the bug

When the onDragStart callback updates a state (and schedules a render) the dragConstraints are initially ignored.

https://codesandbox.io/s/determined-meitner-zufuz

To Reproduce
Steps to reproduce the behavior:

  1. open the sandbox example
  2. move the small box outside the big box

Expected behavior
The dragConstraints should be always respected

Desktop (please complete the following information):

  • OS: MacOS
  • Browser Chrome
  • Version latest

<motion.div> breaks styled jsx

Describe the bug
With styled-jsx a <style jsx>{...}</style> tag is added right before the closing element tag in a component. Adding Motion to that component breaks the styled-jsx and does not style the component.

To Reproduce
Check out this sandbox showing the issue:
https://codesandbox.io/s/hello-world-ec8og

Expected behavior
Its expected that the styles would be applied to a motion element just like it would if it wasn't a motion element.

Desktop (please complete the following information):

  • OS: MacOS
  • Browser Chrome
  • Version 75

[BUG] Animate height โ€œ0โ€ to โ€œautoโ€ when switching to โ€œdisplay: blockโ€ from โ€œnoneโ€

Animating height from 0 to auto not is working properly when switching to display: block from display: none:

accordion-bug

According to the Migrate from Pose documentation, non-animatable properties are automatically applied at the start of an animation. Anything that you want to be applied at the end can be set to transitionEnd.

The bug occurs with the following combination of properties:

{
  open: { display: "block", opacity: 1, height: "auto" },
  collapsed: { opacity: 0, height: 0, transitionEnd: { display: "none" } }
}

To Reproduce
Steps to reproduce the behavior:

  1. Go to https://codesandbox.io/s/framer-motion-accordion-o0to4
  2. Click on the accordion headers
  3. Animation doesnโ€™t work as expected on open (works fine on close)

Expected behavior
Smooth animation on opening and closing the accordion:

accordion-expected

This works fine in Pose using the following combination of properties:

{
  open: {  opacity: 1, height: "auto" , applyAtStart: { display: "block" } },
  collapsed: { opacity: 0, height: 0, applyAtEnd: { display: "none" }
}

[BUG] SVG animation fails when no initial value set

Describe the bug
When I don't define default/initial values as attributes, the component fails with the error:

Uncaught TypeError: Cannot read property 'red' of null

To Reproduce
As an example, this component/animation fails. This should be a looping spinner.

const animation = {
  strokeDasharray: ['1px, 200px', '100px, 200px', '100px, 200px'],
  strokeDashoffset: [0, -15, -125],
  transition: { duration: 1.4, ease: 'linear' },
};

const Spinner: FC = (): ReactElement => {
  const controls = useAnimation();

  const handleAnimationComplete = useCallback(() => {
    controls.start(animation);
  }, [controls]);

  useEffect(() => {
    controls.start(animation);
  }, [controls]);

  return (
    <svg viewBox='22 22 44 44'>
      <Circle
        animate={controls}
        onAnimationComplete={handleAnimationComplete}
        cx='44'
        cy='44'
        r='20.2'
        fill='none'
        strokeWidth='3.6'
      />
    </svg>
  );
};

Expected behavior
Modifing the circle to the below works, but this is the only way to resolve the issue. Setting the styles in CSS (with styled-components as an example) does not help.

      <Circle
        animate={controls}
        onAnimationComplete={handleAnimationComplete}
        strokeDasharray='80px, 200px'
        strokeDashoffset='0'
        cx='44'
        cy='44'
        r='20.2'
        fill='none'
        strokeWidth='3.6'
      />

Desktop (please complete the following information):

  • OS: MacOS 10.14.5 (18F132)
  • Browser Version: Chrome 75.0.3770.100 (Official Build) (64-bit)

Additional context
I had the same issue when trying to add a rotate animation to an SVG element. I could not find any workaround for this one, so any help would be greatly appreciated.

const Spinner: FC= (): ReactElement => {
  return (
    <motion.svg viewBox='22 22 44 44' animate={{ rotate: 100 }}>
      <Circle />
    </motion.svg>
  );
};

Other than this, I'm loving Framer Motion - amazing work!

Add error warning for multiple children of `AnimatePresence` with the same key.

Currently AnimatePresence doesn't warn if a component doesn't have a valid key. This is to allow toggling the visibility of single components without needing one.

We can either:

  1. Require even for single-child examples and throw
  2. Detect multiple of the same key if we have more than one child and throw

2 would miss the Slideshow- esque use-case where we have a single child with a changing key, but would enable the toggling of visibility of a single child without a key. I am leaning towards 1.

useRelative

The useRelative hook allows for complex transforms against multiple values or motion values.

ScreenFlow

const averageX = useRelative(
    (a, b, c) => (a + b + c) / 3, 
    xA,
    xB,
    xC
)

The hook works by taking a computing function and one or more related values. These related values may be numbers, strings, or motion values. When any of the related values change, the hook will compute a new value for its motion value by running the current value of each of its related values through the computing function.

The computed values may be quite complex โ€“ and they may also include other computed values. However, the resulting code is nonetheless declarative, highly efficient, and fully juices the creative plane.

You can preview the useRelative hook on the useRelative-useBetween branch. (An earlier version of this branch also included a second hook, useBetween).

Limitations

At the moment, each related value passed to the hook must be either of the same type (e.g. all numbers) or a mix of values and motion values of the same type (e.g. numbers and MotionValue<number>s). This is not a hard constraint: the hook should be able to take any values and pass them into the callback accordingly; however, this may be beyond the limits of my TypeScript-Fu.

Background

The useTransform hook is great for computing a motion value from the result of some other motion value.

const shadowX= useTransform(xA, v => v - 4)

However, the library does not support computed values that are the result of several other values. For example, if I wanted a motion value that was between two other motion values, and which would update when either of those values changed, the solution would be pretty tedious:

const betweenX = useMotionValue(0)

const calc = React.useCallback((a, b) => {
   betweenX.set(a + (b - a) / 2)
}, [])

React.useEffect(() => {
  const cancelA = xA.onChange(v => calc(v, xB.get()))
  const cancelB = xB.onChange(v => calc(xA.get(), v))
  return () => {
    cancelA()
    cancelB()
  }
}, [])

This hook greatly simplifies this (common) part of complex interfaces/animations.

Other options

This hook could possibly be merged into the useTransform hook.

// Simple
useTransform(xA, v => v - 4)

// Range interpolation
useTransform(xA, [0, 100], [32, 68])

// Relative
useTransform([xA, xB], (a, b) => (a + b)  / 2)

[FEATURE] Reducing bundle size

Currently Framer Motion is around 24kb gzipped and minified as a whole. With tree-shaking the motion component alone is about 22kb.

This isn't unprecedented, with Pose being around 25kb and GSAP being in the low 30s. But a low bundle size is quite (either the American or British "quite") important to me, and I've had this thought in my head for a while that it's daft that the animation part of an animation library has to load synchronously.

I've done some experiments and I think it'd be possible to crank the core library down to 10kb. The rest could either be loaded synchronously with the main bundle, but as optional bits (for instance someone who only wants to use animations). Or using import() the rest could be loaded in asynchronously.

For ease of use I'd like the main entry point to remain the same, with something like motion/lazy as a safe second entry point for people who want to crank down the bundle size.

Potential savings

Functionality: ~5kb

Functionality is loaded in via renderless components so we don't run, for instance, draggable code on components that aren't draggable.

These are already abstracted and loaded into a single function. It could be that we allow this to be configured and loaded in via the currently private MotionPluginContext API. So only the functionality used in the site is loaded at all.

A further step could be that users could dynamically import this configuration, re-rendering MotionPluginContext and its subscribers when functionality has downloaded. This could be used to defer the loading of dynamic functionality until after the initial render has finished.

Popmotion animations: ~4.5kb

At this point all animations have been abstracted behind a single function that returns a promise. As all composition also works via Promises it might work quite neatly that calls to startAnimation occuring before Popmotion has loaded in simply wait for it to load before running.

Element names: ~0.7kb

Currently motion components are created by iterating over two lists of tag names. Pose used to use a Proxy to do this without maintaining lists but I had to replace it because Googlebot would crash on Pose-powered pages. Proxy is now supported by Googlebot, which means we can support it too.

This would also theoretically reduce memory usage and start times, and allow us to support arbitrary web components out of the box.

Value conversion: ~2kb

Motion performs a step of preprocessing on animation definitions to make the unanimatable animatable.

Specifically, it reads CSS variable definitions from the DOM and makes them numbers/colors, and it detects incompatible from/tos like "100vh" -> "100px" and converts those to pixel values by measuring the DOM. This function is only called when we start an animation. This wouldn't be as neat to abstract as startAnimation as it doesn't currently live behind a Promise. But ValueAnimationControls.animate does - and maybe we can do something there to defer until this functionality is present.

[BUG] "Component is not a function" when used with react-ssr-prepass

Describe the bug

When creating a simple button like this: <motion.button animate={{opacity: 1}}>Test</motion.button> I get the following error:

/Users/bjoern/projects/CoolPlaces/frontend/node_modules/react-ssr-prepass/dist/react-ssr-prepass.development.js:546
      throw error;
      ^

TypeError: Component is not a function
    at renderWithHooks (/Users/bjoern/projects/CoolPlaces/frontend/node_modules/react-ssr-prepass/dist/react-ssr-prepass.development.js:271:18)
    at render$1 (/Users/bjoern/projects/CoolPlaces/frontend/node_modules/react-ssr-prepass/dist/react-ssr-prepass.development.js:543:12)
    at mount$1 (/Users/bjoern/projects/CoolPlaces/frontend/node_modules/react-ssr-prepass/dist/react-ssr-prepass.development.js:566:10)
    at render$3 (/Users/bjoern/projects/CoolPlaces/frontend/node_modules/react-ssr-prepass/dist/react-ssr-prepass.development.js:804:82)
    at visitElement (/Users/bjoern/projects/CoolPlaces/frontend/node_modules/react-ssr-prepass/dist/react-ssr-prepass.development.js:860:23)
    at visitLoop (/Users/bjoern/projects/CoolPlaces/frontend/node_modules/react-ssr-prepass/dist/react-ssr-prepass.development.js:912:22)
    at resumeVisitChildren (/Users/bjoern/projects/CoolPlaces/frontend/node_modules/react-ssr-prepass/dist/react-ssr-prepass.development.js:954:20)
    at Immediate.<anonymous> (/Users/bjoern/projects/CoolPlaces/frontend/node_modules/react-ssr-prepass/dist/react-ssr-prepass.development.js:978:9)

To Reproduce

I am using Next.js together with urql, so I also use react-ssr-prepass, which is probably causing the problem

To reproduce just take this example repo: https://github.com/FormidableLabs/urql/tree/master/examples/3-ssr-with-nextjs

install framer motion and create a basic button

Desktop (please complete the following information):

  • OS: Mac
  • Browser firefox
  • Version: 1.4

[BUG] State update after AnimatePresence is unmouted

Describe the bug

When an exit animation is running while the <AnimatePresence/> component itself gets unmounted, you get an Can't perform a React state update on an unmounted component error.

To Reproduce
Steps to reproduce the behavior:

  1. Go to https://codesandbox.io/s/nice-vaughan-wcr1z
  2. Click on "Toggle Content"
  3. While the box is disappearing, click on "Toggle Container"

Expected behavior
No state update should happen when the parent AnimatePresence is unmounted

Desktop (please complete the following information):

  • OS: MacOS
  • Browser: Chrome
  • Version: latest

Need help getting `useViewportScroll` to work properly

Hi there,

Apologies in advance if this isn't to correct place to ask for help.

I'm working on adding framer-motion into a react project I'm working on and can't seem to get the useViewportScroll feature to work properly in my project.

I've created an isolated component within my app to test out this feature called DivTest
you can find the project here: https://codesandbox.io/s/github/h-jennings/portfolio-2019 and the test component is in the src/js/components/ folder in the project. Here's a public github repo link if that's easier: https://github.com/h-jennings/portfolio-2019.

Anyway, by following the docs I'm expecting the <motion.div className="divTest" style={{ scale }} /> components scale value to increase on scroll. This is the codeSandbox that I referenced: https://codesandbox.io/s/c4ww4?module=%2Fsrc%2FExample.tsx

I've been poking away at this component for an hour or 2, plus reading the docs and I'm just not sure at this point if I'm using the syntax correctly, or importing the library incorrect etc.

Any help or advice would be appreciated!

[FEATURE] Introduce useTransition for custom animations

I would like to create a custom animation with my own transition setup that is not a spring transition (e.g. tween or keyframes based).

Currently useSpring exposes a way of creating a MotionValue that can transition to a new value when set; however, there is no way to create a MotionValue that uses a different transition configuration. The use cases are the same for the useSpring hook (just using a different transition).

I could be wrong but I don't think useMotionValue does this right now, it's more of a tracking variable for animations that are occurring.

I'd imagine this would work like useSpring except it would allow for any transition to be specified -- useSpring could then just be derived from useTransition. An alternative could be to expose useTween and useKeyframes, but that feels like it would get annoying. Something like:

// Simple transition
const x = useTransition(0, { duration: 1, delay: 0.5 });
x.set(500); // x transitions to 500 and takes 1s after a 0.5s delay

// Spring transition
const x = useTransition(0, { type: 'spring', ...}); 

[BUG] useLayoutEffect warning for positionTransition

When rendering components with positionTransition server-side, React complains about useLayoutEffect.

We're not doing anything that would affect the first render but we do need useLayoutEffect for this specific use-case.

As this functionality is loaded in via a renderless component, we can add the presence of window to the check as to whether or not this component should be rendered.

[BUG] motion.circle and other components aren't recognizable by browser

Describe the bug
The <motion.div> works only, but if I'm trying to render <motion.circle> (as well as <motion.path>) I get the error:

Warning: The tag <circle> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.
    in circle (created by RenderComponent)
    in RenderComponent (created by ForwardRef(MotionComponent))
    in ForwardRef(MotionComponent) (at App.js:7)
    in div (at App.js:6)
    in App (at src/index.js:7)

My code was taken from examples:

import React from 'react';
import { motion } from 'framer-motion';

function App() {
  return (
    <div className="App">
      <motion.circle
        style={{ scale: 2, originX: "100px", originY: "100px" }}
      />
    </div>
  );
}

export default App;

To Reproduce
Steps to reproduce the behavior:

  1. Run the code sample provided above
  2. See error

Expected behavior
<motion.{anything}> shouldn't cause the error.

Screenshots
image

Desktop (please complete the following information):

  • OS: Ubuntu 18.04
  • Browser: Chrome
  • Version 74.0.3729.131 (Official Build) (64-bit)

[BUG] positionTransition animation delayed when children exit

Describe the bug
When AnimatePresence children unmount, the exit animation happens to completion before positionTransition animations take place. When new children mount, no such delay exists.

To Reproduce
Steps to reproduce the behavior:

  1. Create basic example with AnimatePresence parent and <motion.*> children.
<AnimatePresence>
  <motion.div />
  <motion.div />
</AnimatePresence>
  1. Add animation props to <motion.div> children
<motion.div
  animate={{ opacity: 1 }}
  initial={{ opacity: 0 }}
  exit={{ opacity: 0 }}
  key={uniqueKey}
  positionTransition
/>
  1. Create a way to add/remove <motion.div> children.
<button onClick={handleAdd}>Add Child</button>

<AnimatePresence>
  <motion.div onClick={handleRemove} {...} />
</AnimatePresence>
  1. Observe that when adding a child, all animations (opacity and position) happen simultaneous, but when removing a child, opacity/exit transitions happen first, and then position animations.

See example: https://codesandbox.io/s/framer-motion-reorder-animation-rlojg

Expected behavior
All animations happen simultaneously unless otherwise specified via delay prop, etc.

Desktop (please complete the following information):

  • OS: Mac
  • Browser: Chrome
  • Version 75.0.3770.142

[FEATURE] use closest scroll container in useViewportScroll

Is your feature request related to a problem? Please describe.
useViewportScroll only works with the body element.

Describe the solution you'd like
I'd like if useViewportScroll could optionally accept a ref to an element and use the closest scroll container.

Describe alternatives you've considered
I noticed that the docs suggest rolling this yourself, but I think it could be helpful to provide out of the box.


I'd be happy to submit a PR with this functionality, please let me know ๐Ÿ˜Š.

How to animate children on parent hover

Hi everyone!

I want to animate children (rotate the icon to 90 degrees) when hovering at a parent element which is a button.

<motion.button type="button" whileHover={{scale: 1.1}}>
    Visit our Industry 
    {/*Animate this Icon to rotate 90 degrees*/}
    <Icon type="arrow-up" /> 
</motion.button>

I also posted this question on stackoverflow and surprisingly there wasn't a framer-motion tag yet.
Couldn't create it too, my rep < 1500. ๐Ÿ™„

[FEATURE] XY for drag

Is your feature request related to a problem? Please describe.
I wanted to make a sortable grid (like this) but figured out that there is support for either x or y direction only
It would be amazing to have xy

Describe the solution you'd like
Add support for xy drag

[BUG] DOM unit type conversion doesn't account for scale transforms

Add scale: 0.5 to collapsed and scale: 1 to open in https://codesandbox.io/s/framer-motion-viewport-scroll-and-svg-path-animation-9r68o - you can see the open/collapse animations jump at the end.

This is because we're using getBoundingClientRect to measure the element before and after we apply height: auto. We need to do this because we're also measuring unit type conversion for x and y too - otherwise we could probably just use offsetHeight etc.

It might be that we can first set scale and rotate to their defaults before measuring the before/after bounding boxes. And then restore them to their previous values.

[FEATURE] Improve AnimatePresence API with custom components

Currently, because of a usually-hidden implementation detail with AnimatePresence, using custom components works a little like this:

const Custom = ({ animate, onAnimationComplete }) => (
  <motion.div
    animate={animate}
    onAnimationComplete={onAnimationComplete})
  />
)

const MyComponent = ({ isVisible }) => (
  <AnimatePresence>
    {isVisible && (
      <Custom exit={{ opacity: 0 }} />
    )}
  </AnimatePresence>
)

Which is a bit of a mess and doesn't work well with types.

It might be possible with context to achieve an intuitive API like this:

const Custom = () => (
  <motion.div exit={{ opacity: 0 }} />
)

const MyComponent = ({ isVisible }) => (
  <AnimatePresence>
    {isVisible &&  <Custom  />}
  </AnimatePresence>
)

[BUG] Simple render testing give element.getTotalLength is not a function

Describe the bug

I created this component and put it on my app page:

function Punch({ punchIt, initialIsExit }: { initialIsExit: boolean, punchIt(): Promise<void> }) {

  const [exit, setExit] = useState(initialIsExit);
  const [canDrag, setCanDrag] = useState<'x' | false>('x');
  const controls = useAnimation();
  const [ok, setOk] = useState(false);
  const x = useMotionValue(0);
  const background = useTransform(x, v => backgroundColorInterpolation(Math.abs(v)));
  const scale = useTransform(x, v => backgroundScaleInterpolation(Math.abs(v)));
  const color = useTransform(x, v => indicatorColorInterpolation(Math.abs(v)));
  const tickPath = useTransform(x, v => indicatorProgressInterpolation(Math.abs(v)));
  const [svgDisplay, setSvgDisplay] = useState('none');
  const okpath = useMotionValue(0);

  async function onDragEnd(event: MouseEvent, info: PanInfo) {

    if (Math.abs(info.point.x) > moveSize) {

      setCanDrag(false);

      await controls.start({
        x: exit ? -moveSize : moveSize,
        transition: {
          ease: 'easeOut'
        }
      });

      setExit(!exit);

      await punchIt();

      setOk(true);

      await controls.start({
        x: 0,
        left: exit ? 8 : moveSize + 8,
        transition: {
          delay: 0.5,
          duration: 0.6,

        }
      });

      setOk(false);
      setCanDrag('x');

      return;
    }

    await controls.start({
      x: 0,
      transition: {
        duration: 0.5
      }
    });

    setSvgDisplay('none');
  }

  function okAnimationComplete() {

    if (okpath.get() === 0) {

      setSvgDisplay('none');
    }
  }

  return (
    <div className="punch-container">
      <motion.span>
        {exit ? 'Sair' : 'Entrar'}
      </motion.span>
      <motion.div
        drag={canDrag}
        animate={controls}
        dragMomentum={false}
        dragElastic={1}
        className="punch-button"
        onDragStart={() => setSvgDisplay('block')}
        onDragEnd={onDragEnd}
        style={{ x, left: initialIsExit ? moveSize + 8 : 8 }}>

        <motion.div className="back" style={{ scale, background }} />

        <motion.div animate={{ rotate: exit ? 180 : 0 }} className="icon-container">
          <Icon>keyboard_arrow_right</Icon>
        </motion.div>
      </motion.div>
      <motion.svg viewBox="0 0 50 50" style={{ display: svgDisplay }}>
        <motion.path
          fill="none"
          strokeWidth="2"
          stroke={color}
          d="m 20 0 a 1 1 0 0 0 0 40 a -20 -20 20 0 0 0 -40"
          style={{ translateX: 5, translateY: 5, pathLength: tickPath }}
        />
        <motion.path
          fill="none"
          strokeWidth="2"
          stroke="black"
          d="M14,26 L 22,33 L 35,16"
          strokeDasharray="1 0"
          animate={{
            pathLength: ok ? 1 : 0,
            transition: {
              duration: 0.4
            }
          }}
          onAnimationComplete={okAnimationComplete}
          style={{ pathLength: okpath }}
        />
      </motion.svg>
    </div>
  );
}

But now when I try to run the test to render the entire app, throws this error:

image

To Reproduce

  1. Create some component that animate pathLength of an SVG, os something like my Punch component.
  2. Run the test renderer like:
it('should renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
  ReactDOM.unmountComponentAtNode(div);
});
  1. See error:
TypeError: element.getTotalLength is not a function

      11 |   const div = document.createElement('div');
      12 |   ReactDOM.render(<App />, div);
    > 13 |   ReactDOM.unmountComponentAtNode(div);
         |            ^
      14 | });
      15 | 

      at svg (node_modules/framer-motion/node_modules/stylefire/lib/index.js:466:48)
      at createDOMStyler (node_modules/framer-motion/node_modules/stylefire/lib/index.js:491:18)
      at getStyler (node_modules/framer-motion/node_modules/stylefire/lib/index.js:501:48)
      at index (node_modules/framer-motion/node_modules/stylefire/lib/index.js:507:12)
      at node_modules/framer-motion/dist/framer-motion.cjs.js:564:25
      at commitHookEffectList (node_modules/react-dom/cjs/react-dom.development.js:17283:26)
      at commitPassiveHookEffects (node_modules/react-dom/cjs/react-dom.development.js:17307:3)
      at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:149:14)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
      at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
      at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
      at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:199:16)
      at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:256:31)
      at commitPassiveEffects (node_modules/react-dom/cjs/react-dom.development.js:18774:9)
      at wrapped (node_modules/scheduler/cjs/scheduler-tracing.development.js:207:34)
      at flushPassiveEffects (node_modules/react-dom/cjs/react-dom.development.js:18822:5)
      at scheduleRootUpdate (node_modules/react-dom/cjs/react-dom.development.js:20570:3)
      at updateContainerAtExpirationTime (node_modules/react-dom/cjs/react-dom.development.js:20600:10)
      at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:20657:10)
      at ReactRoot.Object.<anonymous>.ReactRoot.render (node_modules/react-dom/cjs/react-dom.development.js:20953:3)
      at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:21105:12)
      at node_modules/react-dom/cjs/react-dom.development.js:21178:9
      at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:20459:10)
      at Object.unmountComponentAtNode (node_modules/react-dom/cjs/react-dom.development.js:21177:7)
      at Object.unmountComponentAtNode (src/App.spec.tsx:13:12)

  console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
    Error: Uncaught [TypeError: element.getTotalLength is not a function]
        at reportException (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
        at invokeEventListeners (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:209:9)
        at HTMLUnknownElementImpl._dispatch (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
        at HTMLUnknownElementImpl.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
        at HTMLUnknownElementImpl.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
        at HTMLUnknownElement.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
        at Object.invokeGuardedCallbackDev (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:199:16)
        at invokeGuardedCallback (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:256:31)
        at commitPassiveEffects (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:18774:9)
        at wrapped (/home/rhogeranacleto/repos/dale-ponto/node_modules/scheduler/cjs/scheduler-tracing.development.js:207:34) TypeError: element.getTotalLength is not a function
        at svg (/home/rhogeranacleto/repos/dale-ponto/node_modules/framer-motion/node_modules/stylefire/lib/index.js:466:48)
        at createDOMStyler (/home/rhogeranacleto/repos/dale-ponto/node_modules/framer-motion/node_modules/stylefire/lib/index.js:491:18)
        at getStyler (/home/rhogeranacleto/repos/dale-ponto/node_modules/framer-motion/node_modules/stylefire/lib/index.js:501:48)
        at index (/home/rhogeranacleto/repos/dale-ponto/node_modules/framer-motion/node_modules/stylefire/lib/index.js:507:12)
        at /home/rhogeranacleto/repos/dale-ponto/node_modules/framer-motion/dist/framer-motion.cjs.js:564:25
        at commitHookEffectList (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:17283:26)
        at commitPassiveHookEffects (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:17307:3)
        at HTMLUnknownElement.callCallback (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:149:14)
        at invokeEventListeners (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
        at HTMLUnknownElementImpl._dispatch (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
        at HTMLUnknownElementImpl.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
        at HTMLUnknownElementImpl.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
        at HTMLUnknownElement.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
        at Object.invokeGuardedCallbackDev (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:199:16)
        at invokeGuardedCallback (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:256:31)
        at commitPassiveEffects (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:18774:9)
        at wrapped (/home/rhogeranacleto/repos/dale-ponto/node_modules/scheduler/cjs/scheduler-tracing.development.js:207:34)
        at flushPassiveEffects (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:18822:5)
        at scheduleRootUpdate (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:20570:3)
        at updateContainerAtExpirationTime (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:20600:10)
        at updateContainer (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:20657:10)
        at ReactRoot.Object.<anonymous>.ReactRoot.render (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:20953:3)
        at legacyRenderSubtreeIntoContainer (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:21105:12)
        at /home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:21178:9
        at unbatchedUpdates (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:20459:10)
        at Object.unmountComponentAtNode (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:21177:7)
        at Object.unmountComponentAtNode (/home/rhogeranacleto/repos/dale-ponto/src/App.spec.tsx:13:12)
        at Object.asyncJestTest (/home/rhogeranacleto/repos/dale-ponto/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)
        at resolve (/home/rhogeranacleto/repos/dale-ponto/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
        at new Promise (<anonymous>)
        at mapper (/home/rhogeranacleto/repos/dale-ponto/node_modules/jest-jasmine2/build/queueRunner.js:26:19)
        at promise.then (/home/rhogeranacleto/repos/dale-ponto/node_modules/jest-jasmine2/build/queueRunner.js:73:41)
        at processTicksAndRejections (internal/process/task_queues.js:86:5)

  console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
    Error: Uncaught [TypeError: element.getTotalLength is not a function]
        at reportException (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
        at invokeEventListeners (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:209:9)
        at HTMLUnknownElementImpl._dispatch (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
        at HTMLUnknownElementImpl.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
        at HTMLUnknownElementImpl.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
        at HTMLUnknownElement.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
        at Object.invokeGuardedCallbackDev (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:199:16)
        at invokeGuardedCallback (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:256:31)
        at commitPassiveEffects (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:18774:9)
        at wrapped (/home/rhogeranacleto/repos/dale-ponto/node_modules/scheduler/cjs/scheduler-tracing.development.js:207:34) TypeError: element.getTotalLength is not a function
        at svg (/home/rhogeranacleto/repos/dale-ponto/node_modules/framer-motion/node_modules/stylefire/lib/index.js:466:48)
        at createDOMStyler (/home/rhogeranacleto/repos/dale-ponto/node_modules/framer-motion/node_modules/stylefire/lib/index.js:491:18)
        at getStyler (/home/rhogeranacleto/repos/dale-ponto/node_modules/framer-motion/node_modules/stylefire/lib/index.js:501:48)
        at index (/home/rhogeranacleto/repos/dale-ponto/node_modules/framer-motion/node_modules/stylefire/lib/index.js:507:12)
        at /home/rhogeranacleto/repos/dale-ponto/node_modules/framer-motion/dist/framer-motion.cjs.js:564:25
        at commitHookEffectList (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:17283:26)
        at commitPassiveHookEffects (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:17307:3)
        at HTMLUnknownElement.callCallback (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:149:14)
        at invokeEventListeners (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
        at HTMLUnknownElementImpl._dispatch (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
        at HTMLUnknownElementImpl.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
        at HTMLUnknownElementImpl.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
        at HTMLUnknownElement.dispatchEvent (/home/rhogeranacleto/repos/dale-ponto/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
        at Object.invokeGuardedCallbackDev (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:199:16)
        at invokeGuardedCallback (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:256:31)
        at commitPassiveEffects (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:18774:9)
        at wrapped (/home/rhogeranacleto/repos/dale-ponto/node_modules/scheduler/cjs/scheduler-tracing.development.js:207:34)
        at flushPassiveEffects (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:18822:5)
        at scheduleRootUpdate (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:20570:3)
        at updateContainerAtExpirationTime (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:20600:10)
        at updateContainer (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:20657:10)
        at ReactRoot.Object.<anonymous>.ReactRoot.render (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:20953:3)
        at legacyRenderSubtreeIntoContainer (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:21105:12)
        at /home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:21178:9
        at unbatchedUpdates (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:20459:10)
        at Object.unmountComponentAtNode (/home/rhogeranacleto/repos/dale-ponto/node_modules/react-dom/cjs/react-dom.development.js:21177:7)
        at Object.unmountComponentAtNode (/home/rhogeranacleto/repos/dale-ponto/src/App.spec.tsx:13:12)
        at Object.asyncJestTest (/home/rhogeranacleto/repos/dale-ponto/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)
        at resolve (/home/rhogeranacleto/repos/dale-ponto/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
        at new Promise (<anonymous>)
        at mapper (/home/rhogeranacleto/repos/dale-ponto/node_modules/jest-jasmine2/build/queueRunner.js:26:19)
        at promise.then (/home/rhogeranacleto/repos/dale-ponto/node_modules/jest-jasmine2/build/queueRunner.js:73:41)
        at processTicksAndRejections (internal/process/task_queues.js:86:5)

  console.error node_modules/react-dom/cjs/react-dom.development.js:17117
    The above error occurred in the <ForwardRef(MountMotionValuesComponent)> component:
        in ForwardRef(MountMotionValuesComponent)
        in ForwardRef(MountMotionValuesComponent) (created by ForwardRef(MotionComponent))
        in ForwardRef(MotionComponent) (at Punch.component.tsx:105)
        in svg (created by RenderComponent)
        in RenderComponent (created by ForwardRef(MotionComponent))
        in ForwardRef(MotionComponent) (at Punch.component.tsx:104)
        in div (at Punch.component.tsx:84)
        in Punch (at Home.page.tsx:24)
        in div (created by Styled(MuiBox))
        in Styled(MuiBox) (at Home.page.tsx:23)
        in div (created by Styled(MuiBox))
        in Styled(MuiBox) (at Home.page.tsx:19)
        in HomePage (created by Context.Consumer)
        in Route (at App.tsx:26)
        in Switch (at App.tsx:25)
        in div (created by Styled(MuiBox))
        in Styled(MuiBox) (at App.tsx:24)
        in div (created by Styled(MuiBox))
        in Styled(MuiBox) (at App.tsx:17)
        in Router (created by BrowserRouter)
        in BrowserRouter (at App.tsx:15)
        in App (at App.spec.tsx:12)
    
    Consider adding an error boundary to your tree to customize error handling behavior.
    Visit https://fb.me/react-error-boundaries to learn more about error boundaries.

  console.error node_modules/react-dom/cjs/react-dom.development.js:17117
    The above error occurred in the <ForwardRef(MountMotionValuesComponent)> component:
        in ForwardRef(MountMotionValuesComponent)
        in ForwardRef(MountMotionValuesComponent) (created by ForwardRef(MotionComponent))
        in ForwardRef(MotionComponent) (at Punch.component.tsx:112)
        in svg (created by RenderComponent)
        in RenderComponent (created by ForwardRef(MotionComponent))
        in ForwardRef(MotionComponent) (at Punch.component.tsx:104)
        in div (at Punch.component.tsx:84)
        in Punch (at Home.page.tsx:24)
        in div (created by Styled(MuiBox))
        in Styled(MuiBox) (at Home.page.tsx:23)
        in div (created by Styled(MuiBox))
        in Styled(MuiBox) (at Home.page.tsx:19)
        in HomePage (created by Context.Consumer)
        in Route (at App.tsx:26)
        in Switch (at App.tsx:25)
        in div (created by Styled(MuiBox))
        in Styled(MuiBox) (at App.tsx:24)
        in div (created by Styled(MuiBox))
        in Styled(MuiBox) (at App.tsx:17)
        in Router (created by BrowserRouter)
        in BrowserRouter (at App.tsx:15)
        in App (at App.spec.tsx:12)
    
    Consider adding an error boundary to your tree to customize error handling behavior.
    Visit https://fb.me/react-error-boundaries to learn more about error boundaries.

Expected behavior

To not throw an error and pass in render test

Screenshots

Already attached

Desktop (please complete the following information):

  • OS: Linux
  • Browser chrome (any)
  • Version framer-motion: 1.2.2, react: 16.8.6

Additional context

When I mock the component with something like, pass correctly (although I do not want to do this)

jest.mock('./pages/Home/Punch.component', () => ({
  Punch:  jest.fn().mockReturnValue(<div></div>)
}));

A Parallax example would be very nice :-)

Is your feature request related to a problem? Please describe.
I can't figure out how to implement a basic parallax on viewport scroll, so a simple and clear example in the docs would be awesome.

Describe the solution you'd like
A simple example of a few different divs moving around in relationship to viewport scroll position.

Describe alternatives you've considered
I'm reading through the MotionValue API docs but it's not really clicking for me yet.

Additional context
I mean, any other use cases for MotionValue I can think of I will add, I guess.

XD

[FEATURE] React Native Support

Is your feature request related to a problem? Please describe.
Can't currently use with react native components

Describe the solution you'd like
support for react-native (motion.View?)

Describe alternatives you've considered
I haven't dug much into if this is even possible atm.

[SOLVED] onClick touch event not registered when button inside drag element

Describe the bug
onClick event is not registered on touch screens if the button is inside a draggable element

To Reproduce
https://codesandbox.io/s/interesting-elbakyan-on2k1

Expected behavior
Button click event should be triggered even if inside a draggable element

Smartphone (please complete the following information):

  • Device: iPad 9.7" 6th generation
  • OS: 12.3.1
  • Browser: Safari

Additional context
Probably has something to do with event propogation. Setting dragPropogation={ true } does not help

image

[BUG] AnimatePresence doesn't unmount "exited" children

Describe the bug
AnimatePresence doesn't unmount "exited" children

Expected
After the exit animation is finished, the exited child unmounts

Actual
All the previously exited children stay in DOM

Version
1.2.0

Code to reproduce

import * as React from "react"
import { Frame } from "framer"
import { motion, AnimatePresence } from "framer-motion"

export function Billboard({
    width,
    height,
    url,
    background,
    backgroundSize,
    transitionType,
    damping,
    stiffness,
    duration,
    easing,
}) {
    const animation = {
        initial: { opacity: 0 },
        active: { opacity: 1 },
        exit: { opacity: 0 },
    }

    const transition =
        transitionType === "spring"
            ? { type: "spring", damping, stiffness }
            : { type: "tween", duration, ease: easing }

    return (
        <Frame size="100%" overflow="hidden" background={background}>
            <AnimatePresence initial={false}>
                <motion.div
                    key={url}
                    initial={animation.initial}
                    animate={animation.active}
                    exit={animation.exit}
                    transition={transition}
                    style={{
                        position: "absolute",
                        width,
                        height,
                        backgroundImage: `url(${url})`,
                        backgroundSize,
                        backgroundRepeat: "no-repeat",
                    }}
                />
            </AnimatePresence>
        </Frame>
    )
}

RFC: sizeTransition

Overview

A motion prop for HTML elements, sizeTransition, that enables content to animate between layout sizes.

Mirroring positionTransition, sizeTransition would animate components when they change width/height as the result of a re-render.

<motion.div sizeTransition>
  <Content />
</motion.div>

Use-case(s)

  • Tabbed content
  • Accordions
  • Modals

Proposal

sizeTransition can be defined either a boolean:

<motion.div sizeTransition />

or a Transition:

<motion.div sizeTransition={{ duration: 1 }} />

Release 1: width/height

In the first iteration, it'll animate width and height from their previous to their new measured dimension.

Release 2: scaleX/scaleY

By default, animating width and height will trigger layout. This can be slow and is better avoided for consistent 60fps animations. A more performant way would be animate scale.

This will necessitate either an inversion prop or component that can "undo" the scaling effect (so only the container visually scales).

Prop:

<motion.div sizeTransition>
  <motion.div invertScale>{contents}</motion.div>
</motion.div>

Component:

<motion.div sizeTransition>
  <InvertScale>{contents}</InvertScale>
</motion.div>

At parent scales of < ~0.05 - ~0.1 we can fade this element out to prevent scaling to Infinity.

Is the presence of an inversion prop/component a pre-requisite to enable the scale performance animation? And/or the signal to use scale over width/height?

Release 3: Interactions with positionTransition (prospective)

width and height will naturally reflow-components every frame, but it isn't performant. But scale doesn't effect layout, so its surrounding components would "jump" into their new layout.

It'd be good if at least sibling components could respond to each other's scale resizing with a co-ordinated animation. So for instance this code:

<motion.div style={{ height: isOpen ? 'auto' : 0 }} sizeTransition positionTransition>
  <InvertScale>{contents}</InvertScale>
</motion.div>
<motion.div style={{ height: isOpen ? 'auto' : 0 }} sizeTransition positionTransition>
  <InvertScale>{contents}</InvertScale>
</motion.div>

As one component animate in size via scale, its surrounding components would animate in position using x/y.

Framer X considerations

As sizing isn't abstracted the way positional layout is to x/y, this should drop-in to Frame. Animating the position of surrounding components would require them to be in a DOM layout, ie Stack.

[BUG] AnimatePresence: Incorrect transition when using spring type positionTransition

Describe the bug
I came across this bug trying to replicate the same functionality of PoseGroup in react-pose using AnimatePresence and positionTransition in framer-motion instead. In both cases, the goal is the perform layout transition when adding and removing items inside a flexbox.

react-pose (PoseGroup): https://codesandbox.io/s/elegant-sara-6htck
framer-motion: https://codesandbox.io/s/nostalgic-carson-kezqg

In the framer-motion example, positionTransition is used in AnimatePresence to animate layout change when adding and removing items inside flexbox. The codesandbox link will show the default case (which looks like a tween) and a spring type transition.

If the Red box is toggled AFTER the unmount animation starts and BEFORE the animation finishes and completely unmounts, the spring transition target veers off course for a moment before correcting itself.

I've created some BUG buttons that toggles with specific timings to replicate this bug in the codesandbox link.

To Reproduce

  1. Go to https://codesandbox.io/s/nostalgic-carson-kezqg
  2. Click on BUGS buttons

Expected behavior
In the documentation,
https://www.framer.com/api/motion/migrate-from-pose/#posegroup

Paired with AnimatePresence, you have all the previous functionality of PoseGroup.

The flipMove animation from PoseGroup should be replicable with AnimatePresence and positionTransition. (If not, then consider this a feature request).

It looks like PoseGroup is able to bring the exiting component outside the layout the instance it starts its exiting transition. The remaining components is therefore able to immediately transition to its new layout

However, AnimatePresence will wait for the exiting component to finish its transition before leaving the layout causing a delay in the positionTransition of the remaining components in the layout.

Implementing this feature may solve the bug described above

Desktop (please complete the following information):
OS - windows 10
Browser - chrome

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.