import React, { forwardRef, ReactElement, useCallback, useEffect, useState } from 'react'; import Animated, { AnimatedStyle, Easing, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'; import { Container, ContainerRef } from '@cleartrip/ct-design-container'; import useIsomorphicEffect from '@cleartrip/ct-design-use-isomorphic-effect'; import type { IAccordionProps } from './type'; import staticStyles from './style'; import { ViewStyle } from 'react-native'; const ANIMATION_DURATION = 300; const AccordionV2 = forwardRef( ( { expanded = false, label, onClick, children, expandIcon, disabled = false, styleConfig, isWrappedInAccordionGroup = false, onAccordionGroupClick, }: IAccordionProps, ref: React.ForwardedRef, ): ReactElement => { const { childrenContainer = [], icon = [], label: labelStyle = [], root = [] } = styleConfig || {}; const [isExpanded, setIsExpanded] = useState(expanded); const [rootContainerHeight, setRootContainerHeight] = useState(); const [childContainerHeight, setChildContainerHeight] = useState(); useIsomorphicEffect(() => { setIsExpanded(expanded); }, [expanded]); const rotation = useSharedValue(expanded ? 180 : 0); const height = useSharedValue(expanded ? rootContainerHeight : 0); useEffect(() => { rotation.value = withTiming(isExpanded ? 180 : 0, { duration: ANIMATION_DURATION, }); if (rootContainerHeight !== undefined && childContainerHeight !== undefined) { height.value = withTiming(isExpanded ? rootContainerHeight : rootContainerHeight - childContainerHeight, { duration: ANIMATION_DURATION, easing: Easing.inOut(Easing.ease), }); } }, [isExpanded, rootContainerHeight, childContainerHeight, rotation, height]); const iconAnimation = useAnimatedStyle(() => ({ transform: [{ rotate: `${rotation.value}deg` }], })); const contentAnimation = useAnimatedStyle(() => ({ height: height.value })); const handleAccordionClick = useCallback(() => { if (disabled) return; if (isWrappedInAccordionGroup) { onAccordionGroupClick?.(); } else { setIsExpanded((previouslyExpanded) => !previouslyExpanded); } onClick?.(); }, [disabled, isWrappedInAccordionGroup, onAccordionGroupClick, onClick]); return ( { setRootContainerHeight(event.layout.height); }} ref={ref} styleConfig={{ root }} > {label} {expandIcon && ( [])]} > {expandIcon} )} { setChildContainerHeight(event.layout?.height); }} > {children} ); }, ); AccordionV2.displayName = 'AccordionV2'; export default AccordionV2;