UNPKG

@fto-consult/expo-ui

Version:

Bibliothèque de composants UI Expo,react-native

239 lines (231 loc) 8.26 kB
import {Colors} from "$theme"; import React from 'react'; import View from "$ecomponents/View"; import {StyleSheet,ScrollView,TouchableWithoutFeedback} from 'react-native'; //import ScrollView from "$ecomponents/ScrollView"; import Label from "$ecomponents/Label"; import Icon from "$ecomponents/Icon" import {defaultObj,isNonNullString,defaultStr} from "$cutils"; import PropTypes from "prop-types"; import Item from "./Item"; import Surface from "$ecomponents/Surface"; import theme from "$theme"; const ExpandableComponent = React.forwardRef(({ left, right, title, description, children, titleStyle, descriptionStyle, titleNumberOfLines = 1, descriptionNumberOfLines = 2, testID, onPress, onLongPress, expanded: expandedProp, expandedIcon, defaultExpanded, expandIconProps, unexpandedIcon, leftProps, titleProps, noPadding, rightProps, descriptionProps, contentProps, centerProps, contentContainerProps, showExpandIcon, icon, containerProps, autoMountChildren = false, expandIconPosition, withScrollView = false, scrollViewProps, ...props },ref) => { props = defaultObj(props); leftProps = defaultObj(leftProps) rightProps = defaultObj(rightProps); titleProps = defaultObj(titleProps); contentProps = defaultObj(contentProps); centerProps = defaultObj(centerProps), contentContainerProps = defaultObj(contentContainerProps); descriptionProps = defaultObj(descriptionProps); containerProps = defaultObj(containerProps); expandIconPosition = defaultStr(expandIconPosition,"right").toLowerCase().trim(); const isIconPositionLeft = expandIconPosition =='left'? true : false; const isControlled = typeof expandedProp =='boolean'? true : false; const [expanded, setExpanded] = React.useState(isControlled ? expandedProp : !!defaultExpanded); const handlePressAction = (e) => { onPress?.({...React.getOnPressArgs(e),expanded:!expanded,checked:!expanded}); if (!isControlled) { setExpanded((expanded) => !expanded); } }; if(isControlled){ React.useEffect(()=>{ if(typeof expandedProp =='boolean' && expandedProp !== expanded){ setExpanded(expandedProp) } },[expandedProp]) } const titleColor = Colors.toAlpha(theme.colors.text,0.87); const descriptionColor = Colors.toAlpha(theme.colors.text,theme.ALPHA); const isExpanded = expanded ? true : false; titleProps.style = [styles.title,{color: isExpanded ? theme.colors.primary : titleColor},titleStyle,titleProps.style] const eProps = {color: isExpanded ? theme.colors.primary : descriptionColor} left = typeof left =='function'? left(eProps) : React.isValidElement(left)? left : null; right = typeof right =="function" ? right(eProps) : React.isValidElement(right)? right : null; if((isNonNullString(icon) || isObj(icon)) && !left){ icon = isNonNullString(icon)? {icon} : icon; left = <Icon {...eProps} {...icon} /> } if(!React.isValidElement(left)){ left = null; } if(!React.isValidElement(right)){ right = null; } testID = defaultStr(testID,"RN_ExpandableComponent"); if(withScrollView){ scrollViewProps = Object.assign({},scrollViewProps); children = <ScrollView vertical style={[{flex:1}]} {...scrollViewProps} testID={testID+"_ScrollView"}> {children} </ScrollView> } const expandIcon = showExpandIcon !== false ? <Icon color={titleColor} size={24} {...defaultObj(expandIconProps)} icon = {isExpanded ? defaultVal(expandedIcon,"chevron-up") : defaultVal(unexpandedIcon,"chevron-down")} onPress = {handlePressAction} />:null; return ( <View testID={testID+"_ExpandableContainer"} {...containerProps}> <Surface {...props} ref={ref} testID={testID}> <TouchableWithoutFeedback delayPressIn={0} borderless = {false} accessibilityTraits="button" accessibilityComponentType="button" //role="button" style={[styles.container,props.style]} onPress={handlePressAction} onLongPress={onLongPress} accessibilityState={{ expanded: isExpanded }} testID={testID+"_Container"} > <View testID={testID+'_ContentContainer'} {...contentContainerProps} style={[styles.row,theme.styles.cursorPointer,contentContainerProps.style]} pointerEvents1="none"> {left || (expandIcon && isIconPositionLeft) ? <View testID={testID+'_Left'} {...leftProps} style={[styles.left]}> {isIconPositionLeft ? expandIcon : null} {left} </View> : null} <View testID={testID+'_Center'} {...centerProps} style={[styles.item, styles.content,styles.center,centerProps.style]}> {isNonNullString(title)? <Label userSelect={false} numberOfLines={titleNumberOfLines} {...titleProps} > {title} </Label> : React.isValidElement(title)? title : null} {isNonNullString(description) ? ( <Label testID={testID+'_Description'} userSelect={false} numberOfLines={descriptionNumberOfLines} {...descriptionProps} style={[ styles.description, { color: descriptionColor, }, descriptionStyle, descriptionProps.style, ]} > {description} </Label> ) : null} </View> <View testID={testID+'_Right'} {...rightProps} style={[styles.item, description ? styles.multiline : undefined,styles.row,rightProps.style]}> {right} {!isIconPositionLeft ? expandIcon:null} </View> </View> </TouchableWithoutFeedback> {(autoMountChildren !== false || isExpanded) ? <View testID={testID+'_Content'} {...contentProps} style={[{maxWidth:'100%'},styles.children,contentProps.style,!isExpanded && {opacity:0,height:0}]} > {children} </View> : null} </Surface> </View> ); }); ExpandableComponent.displayName = 'ExpandableComponent'; const styles = StyleSheet.create({ center : { justifyContent : 'flex-start', }, container: { padding: 8, }, left : { flexDirection : 'row', alignItems : 'center', justifyContent : 'flex-start', }, row: { flexDirection: 'row', alignItems: 'center', justifyContent:'center' }, multiline: { height: 40, alignItems: 'center', justifyContent: 'center', }, title: { fontSize: 16, paddingHorizontal:10, }, description: { fontSize: 14, }, item: { margin:0, }, child: { paddingLeft: 64, }, content: { flex: 1, justifyContent: 'center', }, children : { marginLeft : 8, } }); ExpandableComponent.propTypes = { left : PropTypes.oneOfType([ PropTypes.func, PropTypes.node, ]), right : PropTypes.oneOfType([ PropTypes.func, PropTypes.node, ]), expandIconPosition : PropTypes.oneOf([ 'left','right' ]), withScrollView : PropTypes.bool,///si le contenu sera rendu avec le scrollView autoMountChildren : PropTypes.bool,///si les enfants du composant seront montés mais masqués et lorsqu'on cliquera sur toggle ceux-ci seront affichés leftProps : PropTypes.object, ///les props à paser à la vue qui rend le contenu gouche rightProps : PropTypes.object, ///les props à passer à la vue qui rend le contenu droit descriptionProps : PropTypes.object,///les props à passer à la valeur de la description de l'expandable } ExpandableComponent.Item = Item; export default ExpandableComponent;