diff options
Diffstat (limited to 'src/lib/custom-animations/AccordionAnimation.tsx')
-rw-r--r-- | src/lib/custom-animations/AccordionAnimation.tsx | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/src/lib/custom-animations/AccordionAnimation.tsx b/src/lib/custom-animations/AccordionAnimation.tsx new file mode 100644 index 000000000..146735aa6 --- /dev/null +++ b/src/lib/custom-animations/AccordionAnimation.tsx @@ -0,0 +1,77 @@ +import { + type LayoutChangeEvent, + type StyleProp, + View, + type ViewStyle, +} from 'react-native' +import Animated, { + Easing, + FadeInUp, + FadeOutUp, + useAnimatedStyle, + useSharedValue, + withTiming, +} from 'react-native-reanimated' + +import {isIOS, isWeb} from '#/platform/detection' + +type AccordionAnimationProps = React.PropsWithChildren<{ + isExpanded: boolean + duration?: number + style?: StyleProp<ViewStyle> +}> + +function WebAccordion({ + isExpanded, + duration = 300, + style, + children, +}: AccordionAnimationProps) { + const heightValue = useSharedValue(0) + + const animatedStyle = useAnimatedStyle(() => { + const targetHeight = isExpanded ? heightValue.get() : 0 + return { + height: withTiming(targetHeight, { + duration, + easing: Easing.out(Easing.cubic), + }), + overflow: 'hidden', + } + }) + + const onLayout = (e: LayoutChangeEvent) => { + if (heightValue.get() === 0) { + heightValue.set(e.nativeEvent.layout.height) + } + } + + return ( + <Animated.View style={[animatedStyle, style]}> + <View onLayout={onLayout}>{children}</View> + </Animated.View> + ) +} + +function MobileAccordion({ + isExpanded, + duration = 200, + style, + children, +}: AccordionAnimationProps) { + if (!isExpanded) return null + + return ( + <Animated.View + style={style} + entering={FadeInUp.duration(duration)} + exiting={FadeOutUp.duration(duration / 2)} + pointerEvents={isIOS ? 'auto' : 'box-none'}> + {children} + </Animated.View> + ) +} + +export function AccordionAnimation(props: AccordionAnimationProps) { + return isWeb ? <WebAccordion {...props} /> : <MobileAccordion {...props} /> +} |