forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {
2 type LayoutChangeEvent,
3 type StyleProp,
4 View,
5 type ViewStyle,
6} from 'react-native'
7import Animated, {
8 Easing,
9 FadeInUp,
10 FadeOutUp,
11 useAnimatedStyle,
12 useSharedValue,
13 withTiming,
14} from 'react-native-reanimated'
15
16import {IS_IOS, IS_WEB} from '#/env'
17
18type AccordionAnimationProps = React.PropsWithChildren<{
19 isExpanded: boolean
20 duration?: number
21 style?: StyleProp<ViewStyle>
22}>
23
24function WebAccordion({
25 isExpanded,
26 duration = 300,
27 style,
28 children,
29}: AccordionAnimationProps) {
30 const heightValue = useSharedValue(0)
31
32 const animatedStyle = useAnimatedStyle(() => {
33 const targetHeight = isExpanded ? heightValue.get() : 0
34 return {
35 height: withTiming(targetHeight, {
36 duration,
37 easing: Easing.out(Easing.cubic),
38 }),
39 overflow: 'hidden',
40 }
41 })
42
43 const onLayout = (e: LayoutChangeEvent) => {
44 if (heightValue.get() === 0) {
45 heightValue.set(e.nativeEvent.layout.height)
46 }
47 }
48
49 return (
50 <Animated.View style={[animatedStyle, style]}>
51 <View onLayout={onLayout}>{children}</View>
52 </Animated.View>
53 )
54}
55
56function MobileAccordion({
57 isExpanded,
58 duration = 200,
59 style,
60 children,
61}: AccordionAnimationProps) {
62 if (!isExpanded) return null
63
64 return (
65 <Animated.View
66 style={style}
67 entering={FadeInUp.duration(duration)}
68 exiting={FadeOutUp.duration(duration / 2)}
69 pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
70 {children}
71 </Animated.View>
72 )
73}
74
75export function AccordionAnimation(props: AccordionAnimationProps) {
76 return IS_WEB ? <WebAccordion {...props} /> : <MobileAccordion {...props} />
77}