about summary refs log tree commit diff
path: root/src/lib/custom-animations/AccordionAnimation.tsx
diff options
context:
space:
mode:
authorCaidan <caidan@internet.dev>2025-08-21 11:56:17 -0700
committerGitHub <noreply@github.com>2025-08-21 21:56:17 +0300
commiteabcd9150d3513988f5b3c47b95a601d5f1bf738 (patch)
tree1a07a27f9d6c4fb9d675f75e9559071a408077f5 /src/lib/custom-animations/AccordionAnimation.tsx
parentd900d0b7a79f2edfbd3865c2484694a0de61a35c (diff)
downloadvoidsky-eabcd9150d3513988f5b3c47b95a601d5f1bf738.tar.zst
[APP-1357] profile header follow recommendations (#8784)
Diffstat (limited to 'src/lib/custom-animations/AccordionAnimation.tsx')
-rw-r--r--src/lib/custom-animations/AccordionAnimation.tsx77
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} />
+}