AnimatePresence
Animate components as they mount and unmount
AnimatePresence animates direct children before they unmount. It is inspired by and forked from Framer Motion, but works with any animation driver in Hanzo GUI.
To use with @hanzogui/core, install and import @hanzogui/animate-presence. It's already bundled and exported from @hanzo/gui.
Basic Usage
Use enterStyle and exitStyle to define how components animate in and out:
import { AnimatePresence, View } from '@hanzo/gui'
export const MyComponent = ({ isVisible }) => (
<AnimatePresence>
{isVisible && (
<View
key="my-square"
transition="bouncy"
backgroundColor="green"
size={50}
enterStyle={{
opacity: 0,
y: 10,
scale: 0.9,
}}
exitStyle={{
opacity: 0,
y: -10,
scale: 0.9,
}}
/>
)}
</AnimatePresence>
)Note you don't even need to set opacity on the base style. Hanzo GUI knows to normalize
styles like opacity and scale to 1 (and y to 0) if it's not defined on the base styles
but is defined on enterStyle or exitStyle.
Wrap one or more Hanzo GUI components with AnimatePresence. The child components will animate on enter and exit.
Animated child components must each have a unique key prop so AnimatePresence can track their presence in the tree.
Enter/Exit Transitions
You can specify different animations for enter (mount) and exit (unmount) transitions. This is useful when you want elements to enter slowly but exit quickly, or vice versa:
import { AnimatePresence, View } from '@hanzo/gui'
export default ({ show }) => (
<AnimatePresence>
{show && (
<View
key="panel"
transition={{ enter: 'lazy', exit: 'quick' }}
enterStyle={{ opacity: 0, y: 20 }}
exitStyle={{ opacity: 0, y: -20 }}
/>
)}
</AnimatePresence>
)The enter and exit keys accept any animation name from your config. You can also combine them with a default for property changes that happen while the element is mounted:
// enter slowly, exit quickly, property changes use medium speed
<View
transition={{ enter: 'lazy', exit: 'quick', default: 'bouncy' }}
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
/>Or use enter/exit with the array syntax to include delay and per-property animations:
// enter with lazy, exit with quick, delay 200ms, x uses its own animation
<View
transition={['bouncy', { enter: 'lazy', exit: 'quick', delay: 200, x: 'slow' }]}
enterStyle={{ opacity: 0, x: -100 }}
exitStyle={{ opacity: 0, x: 100 }}
/>This works with all four animation drivers (CSS, React Native, Reanimated, Motion).
The custom prop
AnimatePresence takes a custom prop that allows you to update a variant of the animated child before it runs its exit animation. This is useful for animating a child out of the screen in a different direction before it unmounts, as shown in the example above:
import { AnimatePresence } from '@hanzogui/animate-presence'
import { ArrowLeft, ArrowRight } from '@hanzogui/lucide-icons-2'
import { useState } from 'react'
import { Button, Image, XStack, YStack, styled } from '@hanzo/gui'
const GalleryItem = styled(YStack, {
zIndex: 1,
x: 0,
opacity: 1,
fullscreen: true,
variants: {
// 1 = right, 0 = nowhere, -1 = left
going: {
':number': (going) => ({
enterStyle: {
x: going > 0 ? 1000 : -1000,
opacity: 0,
},
exitStyle: {
zIndex: 0,
x: going < 0 ? 1000 : -1000,
opacity: 0,
},
}),
},
} as const,
})
const photos = [
'https://picsum.photos/500/300',
'https://picsum.photos/501/300',
'https://picsum.photos/502/300',
]
const wrap = (min: number, max: number, v: number) => {
const rangeSize = max - min
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min
}
export function Demo() {
const [[page, going], setPage] = useState([0, 0])
const imageIndex = wrap(0, photos.length, page)
const paginate = (going: number) => {
setPage([page + going, going])
}
return (
<XStack
overflow="hidden"
backgroundColor="#000"
position="relative"
height={300}
width="100%"
alignItems="center"
>
<AnimatePresence initial={false} custom={{ going }}>
<GalleryItem key={page} transition="slowest" going={going}>
<Image src={photos[imageIndex]} width={500} height={300} />
</GalleryItem>
</AnimatePresence>
<Button
accessibilityLabel="Carousel left"
icon={ArrowLeft}
size="$5"
position="absolute"
left="$4"
circular
elevate
onPress={() => paginate(-1)}
zi={100}
/>
<Button
accessibilityLabel="Carousel right"
icon={ArrowRight}
size="$5"
position="absolute"
right="$4"
circular
elevate
onPress={() => paginate(1)}
zi={100}
/>
</XStack>
)
}API Reference
AnimatePresence Props
children- One or more Hanzo GUI components with uniquekeypropsinitial- Iffalse, children entering on initial mount won't animate (default:true)custom- Pass data to children's variants for dynamic exit animationsexitBeforeEnter- Iftrue, only one child renders at a time (default:false)onExitComplete- Callback fired when all exiting children have finished animating
Component Props
When used inside AnimatePresence:
enterStyle- Styles to animate from when mountingexitStyle- Styles to animate to when unmountingtransition- Animation configuration (can use{ enter, exit }syntax)key- Required unique identifier for AnimatePresence tracking
See Also
Last updated on