I see the following example JSX code:
const AppBar = styled(MuiAppBar, {
shouldForwardProp: (prop) => prop !== 'open',
})<AppBarProps>(({ theme, open }) => ({
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
...(open && {
marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
}),
}));
and I don't understand what is doing.
So I used babel to translate and get:
const AppBar = styled(MuiAppBar, {
shouldForwardProp: prop => prop !== 'open'
}) < AppBarProps > (({
theme,
open
}) => ({
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
}),
...(open && {
marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen
})
})
}));
What does this ... < AppBarProps > ... mean? (The rest I I understand just fine)
Sorry if this seems like the dummest question ever, but can't imagine what is going on here.
It's a way to declare generic type parameter in typescript. styled returns a HOC that creates a component with the styles attached. I'll breakdown the code to make it more easier to digest:
const hoc = styled(MuiComponent)
// StyledMuiComponent now can accept the props with type MuiComponentProps
const StyledMuiComponent = hoc<MuiComponentProps>(styles)
Related
I'm trying to spin an image infinitely, a rotating disk.
I checked using animated or the react-native-animatable. They've got duration and timing, how do I rotate without putting a time or angle of spin to it.
const handleAnimation = () => {
Animated.timing(rotateAnimation, {
toValue: 1,
duration: 72000,
useNativeDriver: false,
}).start(() => {
rotateAnimation.setValue(0);
});
};
<TouchableOpacity onPress={async () => handleAnimation()}>
<Animated.Image
style={{
width: 300,
height: 300,
transform: [{ rotate: interpolateRotating }]
}}
source={abcd} >
</Animated.Image>
</TouchableOpacity>
Try adding the Animated.timing in a Animated.loop
Animated.loop(
Animated.timing(rotateAnimation, {
toValue: 1,
duration: 72000,
useNativeDriver: false,
})
).start();
I'm trying to make a squeezing bubble animation on repeat, using framer motion & react, but I cant make the squeeze animation happen every time the movement animation is beginning.
instead only the first time the animations run it works but after that only the movement animation repeats itself, if I try to repeat the squeeze animation it just gets out of order
import React from "react";
import styled from "styled-components";
import { motion } from "framer-motion";
const Bubble = () => {
const shapeVariants = {
hidden: {
height: 450,
width: 50,
},
visible: {
height: 250,
width: 250,
transition: {
type: "spring",
bounce: 1,
stiffness: 700,
ease: "easeIn",
},
},
};
const MoveVariants = {
hidden: {
y: 1300,
},
visible: {
y: -280,
transition: {
duration: 2,
ease: "easeIn",
repeat: Infinity,
},
},
};
return (
<motion.div variants={MoveVariants} initial={"hidden"} animate={"visible"}>
<RoundDiv
onAnimationComplete={(definition) => console.log(definition)}
variants={shapeVariants}
/>
</motion.div>
);
};
const RoundDiv = styled(motion.div)`
height: 250px;
width: 250px;
background-color: #05386b;
border-radius: 50%;
`;
export default Bubble;
You just needed to add to your shapeVariants transition to get them to sync up.
import React from "react";
import styled from "styled-components";
import { motion } from "framer-motion";
const Bubble = () => {
const shapeVariants = {
hidden: {
height: 450,
width: 50,
},
visible: {
height: 250,
width: 250,
transition: {
type: "spring",
bounce: 1,
stiffness: 700,
ease: "easeIn",
duration: 2, /* new */
repeat: Infinity, /* new */
},
},
};
const MoveVariants = {
hidden: {
y: 1300,
},
visible: {
y: -280,
transition: {
duration: 2,
ease: "easeIn",
repeat: Infinity,
},
},
};
return (
<motion.div
variants={MoveVariants}
initial={"hidden"}
animate={"visible"}
>
<RoundDiv
onAnimationComplete={(definition) => console.log(definition)}
variants={shapeVariants}
/>
</motion.div>
);
};
const RoundDiv = styled(motion.div)`
height: 250px;
width: 250px;
background-color: #05386b;
border-radius: 50%;
`;
export default Bubble;
I would also recommend using originX and originY to manipulate the spring transition on the bubble otherwise it will animate the bounce based on the top left corner. I would use percentage values such as originX: "50%" but it depends on the effect you are looking for.
The cascading animation in framer-motion is powered by the variant being propagated through the children.
You are running into this setback because you are only animating to the `visible variant once. Thus the variant propagation only happens once.
Potential Solutions
Dumb solution: include a duration into the shapeVariant and make it also repeat then manually time your animation to where you need it. This isn't optimal because you probably want your bubble animation to be type spring?
const shapeVariants = {
hidden: {
height: 450,
width: 50,
},
visible: {
height: 250,
width: 250,
transition: {
type: "spring",
bounce: 1,
stiffness: 700,
ease: "easeIn",
duration: 2,
repeat: Infinity
},
},
};
Alternatively you could control your animation with an effect that would use setTimeout or something to change the variant of the parent over and over to get the cascading effect
I'm working with Framer-motion and i'm trying to find a way to delay the the animation of rotateY while the x animates to a specific position then start the rotateY.
Is this possible in Framer motion ?
Example:
const variants = {
flip: {
rotateY: 0,
x: -20,
scale: 1,
transition: {
ease: "easeInOut",
duration: 1.2
}
},
hidden: {
rotateY: 180,
x: 150,
scale: 0.5,
transition: {
ease: "easeInOut",
duration: 1
}
}
};
You can configure a transition per property. This allows you to add the necessary delay to rotateY:
const duration = 1.2;
const variants = {
flip: {
rotateY: 0,
x: -20,
scale: 1,
transition: {
ease: "easeInOut",
duration,
rotateY: {
delay: duration,
duration
}
}
},
hidden: {
rotateY: 180,
x: 150,
scale: 0.5,
transition: {
ease: "easeInOut",
duration,
rotateY: {
delay: duration,
duration
}
}
}
};
See this CodeSandbox.
#amann's post above didn't wor for me in Sep 2020 v2.65
I had to update all relevant properties in the transition to ensure they ran in succession:
transition: {
x: {
ease: "easeInOut",
duration: duration
},
rotateY: {
duration: duration,
delay: duration
}
}
Full example:
import * as React from "react";
import { motion } from "framer-motion";
import styled from "styled-components";
const duration = 1.2;
const variants = {
flip: {
rotateY: 180,
x: 150,
transition: {
x: {
ease: "easeInOut",
duration: duration
},
rotateY: {
duration: duration,
delay: duration
}
}
},
hidden: {
rotateY: 0,
x: -20,
transition: {
x: {
ease: "easeInOut",
duration: duration
},
rotateY: {
duration: duration,
delay: duration
}
}
}
};
const Box = styled(motion.div)`
background: white;
border-radius: 30px;
width: 150px;
height: 150px;
`;
export const Example = (props) => {
return (
<motion.div
initial={false}
animate={props.toggle ? "flip": "hidden"}
>
<Box variants={variants} />
</motion.div>
)
}
Codesandbox Demo
You can give specific values for each transition. Therefore, you can control them individually like so:
transition={{
rotate: { duration: 1 },
scale: { duration: 0.2 }
}}
I have an application created with create-react-app. By default it seems to check that object keys are sorted alphabetically. This is not too bad when I'm typing the code myself, but it's crazy when I copy'n'paste from other sources. Here's an example:
const styles = theme => ({
appBar: {
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
})
},
appBarShift: {
marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen
})
},
content: {
flexGrow: 1,
backgroundColor: theme.palette.background.default,
padding: theme.spacing.unit * 3
},
drawerPaper: {
position: 'relative',
whiteSpace: 'nowrap',
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen
})
},
drawerPaperClose: {
overflowX: 'hidden',
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
}),
width: theme.spacing.unit * 7,
[theme.breakpoints.up('sm')]: {
width: theme.spacing.unit * 9
}
},
hide: {
display: 'none'
},
menuButton: {
marginLeft: 12,
marginRight: 36
},
root: {
flexGrow: 1,
height: 430,
zIndex: 1,
overflow: 'hidden',
position: 'relative',
display: 'flex'
},
toolbar: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
...theme.mixins.toolbar
}
});
I sorted the first level keys but it seems to check the nested ones too! Now I'm getting
C:/Source/portal/src/components/MenuAppBar.js
(19,5): The key 'transition' is not sorted alphabetically
I can't seem to find a way to enable the JS linting. There were hints about disabling tslint but I'm not using Typescript in this case.
I am using VS Code and have tried Sort JS object keys as well as Sort JSON objects. Unfortunately neither of them sort nested keys.
/* eslint sort-keys: 0 */
Add this on the top of the styles file
I'm a beginner in anime.js. I animate something and after the animations is complete i want to remove the element that i'm animating.
The animation is working perfect. I just can't remove the element that im working and i dont want to hide it
logoTimeline
.add({
targets: text1,
duration: 700,
delay: function(el, index) { return index*50; },
opacity: 1,
easing: 'easeOutCirc',
translateX: function(el, index) {
return [(-50+index*10),0]
},
offset:0
})
.add({
remove:text1
})
Per the API Documentation you need to add a complete callback function which will fire once the animation has completed:
logoTimeline
.add({
targets: text1,
duration: 700,
delay: function(el, index) { return index*50; },
opacity: 1,
easing: 'easeOutCirc',
translateX: function(el, index) {
return [(-50+index*10),0]
},
offset:0,
complete: function(anim) {
logoTimeline.remove();
}
});