@fto-consult/expo-ui
Version:
Bibliothèque de composants UI Expo,react-native
160 lines (147 loc) • 6.65 kB
JavaScript
import PropTypes from "prop-types";
import {defaultVal,defaultStr,defaultBool,isDecimal,isObj,defaultObj,isNonNullString} from "$cutils";
import View from "$ecomponents/View";
import {Text} from "react-native-paper";
import { StyleSheet } from "react-native";
import theme,{Colors,DISABLED_OPACITY,ALPHA,styles} from "$theme";
import React from "react";
import {canTextBeSelectable} from "$cplatform/utils";
const defaultSelectable = canTextBeSelectable();
export const EllipsizeMode = {'head':'head','middle':'middle', 'tail':'tail' , 'clip':'clip'}
const LabelComponent = React.forwardRef(({ children,userSelect,role,color,upperCase,fontSize,testID,wrap,id,wrapText,error,underlined,splitText,secondary,primary,bold,textBold,disabled,text,style,...rest},ref)=> {
children = defaultVal(children,text);
let isText = false;
if(!React.isValidElement(children) && Array.isArray(children) && children.length){
for(let i in children){
if(typeof children[i] =='string' || typeof children =='number'){
isText = true;
break;
}
}
}
wrap = typeof wrap ==='boolean'? wrap : typeof wrapText ==='boolean' ? wrapText : false;
if(!children || typeof children =='number'){
children = isDecimal(children)? children+"" : isDecimal(text)? text+"" : undefined;
}
if(!children) return null;
rest = defaultObj(rest);
const r1 = {},r2={};
bold = defaultBool(bold,textBold,false);
r2.color = Colors.setAlpha(theme.colors.text,theme.ALPHA);
if(disabled){
r1.opacity = DISABLED_OPACITY;
}
if(underlined){
r1.textDecorationLine = 'underline';
}
if(Colors.isValid(color)){
r1.color = color;
}
style = Object.assign({},StyleSheet.flatten(style));
let hasP = Object.size(style,true);
testID = defaultStr(testID,"RN_LabelComponent");
const restProps = {id};
if(splitText){
restProps.numberOfLines = defaultNumber(restProps.numberOfLines,1);
restProps.ellipsizeMode = defaultStr(restProps.ellipsizeMode,'tail');
if(restProps.numberOfLines > 1 && typeof wrap !=='boolean'){
wrap = true;
}
}
if(wrap){
r1.flexWrap = "wrap";
}
if(disabled){
r1.pointerEvents = "none";
}
userSelect = userSelect === false || defaultSelectable === false ? false : true;
r2.userSelect = !userSelect?"none":"all";
if(isNonNullString(children) || isText || typeof children ==='number'){
if(!isText){
children +="";
if(upperCase){
children = children.toUpperCase();
}
}
if(fontSize){
r1.fontSize = fontSize;
}
if(userSelect){
r2.userSelect = "text";
}
return (<Text allowFontScaling = {true} ref = {ref}
{...rest} {...restProps} testID={testID} disabled={disabled}
role={typeof role =='string' && role && supportedRoles.includes(role.trim()) && role.trim() || undefined}
style={[styles.label,splitText?styles.wrap:null,splitText?styles.w100:null,bold?styles.bold:null,r2,style,r1,styles.webFontFamilly]}>{children}</Text>)
}
if(isObj(rest)){
for(let i in rest){
if(rest[i]!== undefined) {
hasP = true;
break;
}
}
}
if(children == undefined){
return null;
}
const viewStyle = [bold?styles.bold:null,r2,style,r1];
if(React.isValidElement(children)){
if(!hasP) {
if(id || ref){
return <View ref = {ref} testID = {testID} id={id} style={viewStyle}>{children}</View>
}
return children;
}
return <View ref = {ref} {...rest} {...restProps} testID = {testID} style={viewStyle} disabled={disabled}>{children}</View>
}
return null;
})
LabelComponent.displayName = 'LabelComponent';
const LabelComponentExported = theme.withStyles(LabelComponent);
LabelComponentExported.propTypes = {
children : PropTypes.any,
upperCase: PropTypes.bool,///si la transformation sera en majuscule
text : PropTypes.any,
fontSize : PropTypes.number,
wrap : PropTypes.bool, //si le texte sera splité vers la ligne suivantes
wrapText : PropTypes.bool,///alias à wrap
primary : PropTypes.bool,
error : PropTypes.bool,///si le label est liée à une text field sur laquelle il y a erreur
secondary : PropTypes.bool,
color : PropTypes.string,
userSelect : PropTypes.bool, //si le texte est sélectionnable
underlined : PropTypes.bool,//si le style underlined sera appliqué au label
splitText : PropTypes.bool,///si le texte lorsqu'il est long sera splité,
/*useSelect : PropTypes.oneOfType([
'auto', 'text', 'none', 'contain', 'all'
])*/
}
export default LabelComponentExported;
LabelComponentExported.withRef = React.forwardRef((props,ref)=>{
const [state,setState] = React.useState({
children : props.children,
});
const context = {
update : (props)=>{
if(React.isValidElement(props,true)){
return setState({...state,children:props})
} else if(isObj(props)){
return setState({...state,...props})
}
}
}
React.useEffect(()=>{
setState({...state,children:props.children})
},[props.children]);
React.setRef(ref,context);
React.useEffect(()=>{
return ()=>{
React.setRef(ref,null);
}
},[]);
return <LabelComponent {...props} {...state} style={[props.style,state.style]}/>
})
LabelComponentExported.withRef.displayName = "LabelComponent.Dynamic";
LabelComponentExported.WithRef = LabelComponentExported.withRef;
export const supportedRoles = ["alert","alertdialog","application","article","banner","button","cell","checkbox","columnheader","combobox","complementary","contentinfo","definition","dialog","directory","document","feed","figure","form","grid","group","heading","img","link","list","listitem","log","main","marquee","math","menu","menubar","menuitem","meter","navigation","none","note","option","presentation","progressbar","radio","radiogroup","region","row","rowgroup","rowheader","scrollbar","searchbox","separator","slider","spinbutton","status","summary","switch","tab","table","tablist","tabpanel","term","timer","toolbar","tooltip","tree","treegrid","treeitem"];