Animations
A good UX lives from good and reasonable animations. With animations users for example spot newly added components easier. Animations can also improve the connection between two elements or a user action (e.g. a menu that slides in after clicking on a button).
But animations are also hard to create, especially enter and exit animations, as you need to keep your elements
available until the exit animation is finished. Existing tooling tries to make this kind of animations easier,
but it's still a lot of boilerplate code or you need to write your own abstractions
(e.g. to make it work with emotion
).
Pablo tries to abstract animations, so you don't need to worry about them too much, all you need to do is wrap
the component that you want to show/hide with an animation in an animation component
(e.g. SlideAnimation
or FadeAnimation
).
Currently Pablo has three build in animations, StackAnimation
, SlideAnimation
and FadeAnimation
. You
can easily write your own animations as well.
Some animations like StackAnimation
and SlideAnimation
need additional props (like the side
where the animation
should happen).
In the example below you can declare the animation duration and show and hide the wrapped component.
In the code you can change AnimationComponent
to be either SlideAnimation
or FadeAnimation
.
() => { const AnimationComponent = SlideAnimation; // or use FadeAnimation const animationComponentProps = { side: 'left', reverse: false, }; const [duration, setDuration] = React.useState(300); const [visible, setVisible] = React.useState(false); return ( <Flex alignItems="stretch" height={400} > <Flex justifyContent="center" alignItems="center" flexGrow={1} flexBasis={0}> <Box mb={4}> <Checkbox mb={1} checked={visible} onChange={() => setVisible((v) => !v)} label="visible" /> <Input label="Duration" mb={1} onChange={(v) => setDuration(parseInt(v, 10) || 0)} value={duration} /> </Box> </Flex> <Box display="flex" justifyContent="center" alignItems="center" flexGrow={1} flexShrink={0} flexBasis={0} bgColor="gray.50" > <Box maxWidth={400} height={200}> <AnimationComponent duration={duration} visible={visible} {...animationComponentProps}> <Card> <Title>I am animated</Title> </Card> </AnimationComponent> </Box> </Box> </Flex> ); }
Common animation props
All animation components share the following props
duration
Duration of the animation in milliseconds.
visible
Boolean value that defines if the wrapped component should be shown or not. If this value changes from false
to true
the enter animation is played, if it changes from true
to false
the exit animation is played.
Animation components
SlideAnimation
The SlideAnimation
is helpful for popups and toasts. It has the following props to affect the animation:
side
You can specify the side
where the animation happens (e.g. top
means ot slides in from the top).
Can be either top
, right
, bottom
or left
.
reverse
You can also revert the direction, which makes it slide in from the opposite site.
This is helpful for things like tooltips, where you want to share the side
prop but want to slide to the other direction
(e.g. slide away from the wrapped component instead of sliding to it).
// reverse prop is false by default
<SlideAnimation duration={300} visible={true} side="top">
<div>hi</div>
</SlideAnimation>
// With reverse being true
<SlideAnimation duration={300} visible={true} side="top" reverse>
<div>ho</div>
</SlideAnimation>
FadeAnimation
The FadeAnimation
is really simple, it fades the component in and out. It does not have any props in addition to the
common animation props.
<FadeAnimation duration={300} visible={true}>
<div>hi</div>
</FadeAnimation>
StackAnimation
The StackAnimation
is similar to the slide animation. Difference is that the animation side is fixed, entering from
the bottom and leaving to the top. It also pushes the surrounding content during the animation. So during the enter
animation it pushes the content below down and pulls it back up when the exit animation is played.
The StackAnimation
is used as the default animation for toasts.
<StackAnimation duration={300} visible={true}>
<div>hi</div>
</StackAnimation>
Usage with bojagi components
Some bojagi components allow to replace the default animation. To do this you simply pass the animation component
as with the animation
prop. If animation customization is possible, the component will also have an animationProps
prop for any custom animation prop.
Among others the following components allow animation replacement:
Menu
Popover
(more internal component that is used byMenu
andTooltip
)
This is an example with the Menu
component:
<Menu
// ... all the other menu props
animation={SlideAnimation}
animationProps={{
duration: 150,
side: 'bottom',
}}
>
// ...the wrapped component
</Menu>
Custom animations
It's really easy to write custom animations, here's the source code for our fade animation:
import { css } from '@emotion/react';
import { createInOutAnimation } from '@bojagi/pablo/animation';
const fadeAnimationBase = css`
transition: ${(props) => css`opacity ${props.duration}ms`};
opacity: 0;
`;
const fadeAnimationEnter = css`
opacity: 1;
transform: translateY(0) translateX(0);
`;
const fadeAnimationExit = css`
opacity: 0;
`;
export const FadeAnimation = createInOutAnimation({
baseStyles: fadeAnimationBase,
enterStyles: fadeAnimationEnter,
exitStyles: fadeAnimationExit,
});
To create a custom animation, you need to use createInOutAnimation
. This creates an animation component.
It takes three styles (just use styled-component's css
tag literal) for different steps.
baseStyles
for shared styles (hold pre init styles and default transitions)enterStyles
for styles when the wrapped component should be visibleexitstyles
for styles when the wrapped component should be hidden
You can use custom props for animations by just accessing it like usual in emotion (like with the duration prop in the example above).