import React from 'react'; import { View, type ViewStyle, StyleSheet, type StyleProp, type TextStyle, type GestureResponderEvent, TouchableOpacity, } from 'react-native'; import { withTheme, useTheme } from '../../core/theming'; import type { Theme } from '../../utils/types'; import { ListAccordionGroupContext } from './TAccordionGroup'; import IconSVG from '../../assets/svgs'; import ATypography from '../TTypography/TTypography'; import { TypographyVariant } from '../TTypography/TTypographyEnum'; import { moderateScale } from 'react-native-size-matters'; import { defaultScale } from '../../utils/Common'; type Props = { /** * Title text for the list accordion. */ title: string; /** * Callback which returns a React element to display on the left side. */ leftIconName?: any; leftIconSize?: number; leftIconStyle?: StyleProp; /** * Whether the accordion is expanded * If this prop is provided, the accordion will behave as a "controlled component". * You'll need to update this prop when you want to toggle the component or on `onPress`. */ expanded?: boolean; /** * Function to execute on press. */ onPress?: () => void; /** * Function to execute on long press. */ onLongPress?: (e: GestureResponderEvent) => void; /** * Content of the section. */ children: any; /** * @optional */ theme: Theme; /** * Style that is passed to the wrapping TouchableRipple element. */ style?: StyleProp; /** * Style that is passed to Title element. */ titleTextStyle?: StyleProp; /** * Truncate Title text such that the total number of lines does not * exceed this number. */ titleNumberOfLines?: number; /** * Id is used for distinguishing specific accordion when using List.AccordionGroup. Property is required when using List.AccordionGroup and has no impact on behavior when using standalone List.Accordion. */ id?: string | number; /** * TestID used for testing purposes */ testID?: string; /** * Accessibility label for the TouchableRipple. This is read by the screen reader when the user taps the touchable. */ accessibilityLabel?: string; }; const ListAccordion = ({ leftIconName, leftIconSize, leftIconStyle, title, children, titleTextStyle, titleNumberOfLines = 1, style, id, testID, onPress, onLongPress, expanded: expandedProp, accessibilityLabel, }: Props): any => { const { colors } = useTheme(); const [expanded, setExpanded] = React.useState( expandedProp || false ); const handlePressAction = () => { onPress?.(); if (expandedProp === undefined) { // Only update state of the `expanded` prop was not passed // If it was passed, the component will act as a controlled component // eslint-disable-next-line @typescript-eslint/no-shadow setExpanded((expanded) => !expanded); } }; const expandedInternal = expandedProp !== undefined ? expandedProp : expanded; const groupContext = React.useContext(ListAccordionGroupContext); if (groupContext !== null && !id) { throw new Error( 'List.Accordion is used inside a List.AccordionGroup without specifying an id prop.' ); } const isExpanded = groupContext ? groupContext.expandedId === id : expandedInternal; const handlePress = groupContext && id !== undefined ? () => groupContext.onAccordionPress(id) : handlePressAction; return ( {leftIconName ? ( ) : null} {title} {isExpanded ? {children} : null} ); }; ListAccordion.displayName = 'List.Accordion'; const styles = StyleSheet.create({ container: { height: moderateScale(44, defaultScale), justifyContent: 'center', alignItems: 'center', }, row: { flexDirection: 'row', alignItems: 'center', }, content: { flex: 1, justifyContent: 'center', }, left: { marginHorizontal: moderateScale(10, defaultScale), }, }); export default withTheme(ListAccordion);