@fto-consult/expo-ui
Version:
Bibliothèque de composants UI Expo,react-native
107 lines (103 loc) • 4.49 kB
JavaScript
import React from '$react';
import { Dimensions} from 'react-native';
import PropTypes from "prop-types";
import View from "$ecomponents/View";
import theme from "$theme";
import {defaultStr,defaultObj,defaultNumber} from "$cutils";
import ActivityIndicator from "$ecomponents/ActivityIndicator";
/***
* ce composant a pour but de définir la taille d'un contenu en se basant sur sa positin top, de manière à ce que, le contentu du composant fit
* le reste de la taille de la page, avec comme valeur de la props minHeight
*/
const AutoSizerVerticalComponent = React.forwardRef(({onLayout,isScrollView,screenIndent,getRenderingStyle,withActivityIndicator,testID,withPadding,paddingBottom,maxHeight,minHeight,style,children:cChildren,...rest},ref) => {
testID = defaultStr(testID,'RN_AutoSizerVerticalComponent');
const hasUpdateLayoutRef = React.useRef(false);
const layoutRef = React.useRef(null);
const [layout,setLayout] = React.useState(Dimensions.get("window"));
const {height,width} = layout;
const hasInitializedRef = React.useRef(false);
const children = React.useStableMemo(()=>cChildren,[cChildren]);
withActivityIndicator = typeof withActivityIndicator =='boolean'? withActivityIndicator : !isScrollView;
const updateLayout = ()=>{
return new Promise((resolve)=>{
hasUpdateLayoutRef.current = true;
if(layoutRef.current && layoutRef.current.measureInWindow){
layoutRef.current.measureInWindow((x, y, width, height) => {
const r = {...Dimensions.get("window"),layout:{ x, y, width, height }};
setLayout(r);
hasInitializedRef.current = true;
resolve(r);
});
} else {
setLayout(Dimensions.get("window"))
}
})
}
React.setRef(ref,{
updateLayout,
layoutRef,
ref : layoutRef
});
React.useEffect(()=>{
const onResizePage = ()=>{
setTimeout(()=>{
updateLayout();
},500);
}
const dim = Dimensions.addEventListener("change",onResizePage);
return ()=>{
React.setRef(ref,null);
dim?.remove();
}
},[]);
const hasUpdateLayout = hasUpdateLayoutRef.current;
const cStyle ={width:'100%',maxHeight:Math.max(height-100,250)};
const contentLayout = defaultObj(layout.layout);
screenIndent = typeof screenIndent =='number' && screenIndent > 50 ? screenIndent : 100;
const y = Math.abs(defaultNumber(contentLayout.y));
const heightY = y < height - screenIndent ? y : height - screenIndent;
cStyle.minHeight = Math.min(Math.max(layout.height-heightY,minHeight && minHeight ||250));
const cMaxHeight = layout.height-heightY;
if(cMaxHeight>=200){
cStyle.maxHeight = cMaxHeight;
}
if(typeof paddingBottom =='number'){
cStyle.paddingBottom = paddingBottom; //: 50;
}
if(cStyle.minHeight && cStyle.maxHeight && cStyle.minHeight > cStyle.maxHeight){
cStyle.minHeight = cStyle.maxHeight;
}
const restStyle = {};
const canUpdate = hasUpdateLayout || hasUpdateLayout || withActivityIndicator === false;
const fStyle = !canUpdate && {flex:1,flexDirection:'column',maxHeight:cStyle.maxHeight,maxWidth : Math.max(layout.width-defaultNumber(contentLayout.x)),justifyContent:'center',alignItems:'center'} || {};
if(maxHeight){
restStyle.maxHeight = maxHeight;
}
if(minHeight){
restStyle.minHeight = minHeight;
}
if(canUpdate && typeof getRenderingStyle ==='function'){
getRenderingStyle({...cStyle,...restStyle});
}
return children;
return <View ref={layoutRef}
onLayout={(a,b,c)=>{
if(onLayout && onLayout(a,b,c) === false) return;
if(!hasInitializedRef.current){
updateLayout();
}
}}
{...rest}
style={[theme.styles.w100,cStyle,style,fStyle,restStyle]} testID={testID+"_ScrollViewContainer"}>
{ canUpdate?children : <ActivityIndicator size={'large'}/>}
</View>
});
AutoSizerVerticalComponent.displayName = "AutoSizerVerticalComponent";
export default AutoSizerVerticalComponent;
AutoSizerVerticalComponent.propTypes = {
...defaultObj(View.propTypes),
withActivityIndicator : PropTypes.bool,//si l'on utilisera l'activity indicator pour le chargement du contentu
maxHeight : PropTypes.number,
minHeight : PropTypes.number,
paddingBottom : PropTypes.number,
}