@fto-consult/expo-ui 6.4.5 → 6.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -69,6 +69,8 @@ module.exports = (opts)=>{
69
69
  if(typeof opts.mutator =='function'){
70
70
  opts.mutator(r);
71
71
  }
72
+ r.$eutils = path.resolve(expo,"utils");
73
+ r.$ehooks = path.resolve(expo,"hooks");
72
74
  ///le chemin racine du projet expo-ui
73
75
  r["$expo-ui-root-path"] = r["$expo-ui-root"]= path.resolve(expo,"..");
74
76
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "6.4.5",
3
+ "version": "6.5.1",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -62,7 +62,7 @@
62
62
  "@emotion/native": "^11.11.0",
63
63
  "@expo/html-elements": "^0.5.1",
64
64
  "@expo/vector-icons": "^13.0.0",
65
- "@fto-consult/common": "^3.20.0",
65
+ "@fto-consult/common": "^3.21.0",
66
66
  "@gorhom/portal": "^1.0.14",
67
67
  "@pchmn/expo-material3-theme": "^1.3.1",
68
68
  "@react-native-async-storage/async-storage": "1.18.2",
package/src/auth/Login.js CHANGED
@@ -199,22 +199,16 @@ export default function LoginComponent(props){
199
199
  });
200
200
  const withScrollView = typeof customWithScrollView =='boolean'? customWithScrollView : true;
201
201
  const Wrapper = withPortal ? ScreenWithoutAuthContainer : withScrollView ? ScrollView: View;
202
- const mQueryUpdateProps = (a)=>{
203
- const style = StyleSheet.flatten([updateMediaQueryStyle(),contentProps.style]);
204
- if(typeof contentProps.updateMediaQueryStyle =='function'){
205
- return contentProps.updateMediaQueryStyle({style})
206
- }
207
- return {style};
202
+ const mediaQueryUpdateStyle = (a)=>{
203
+ return StyleSheet.flatten([updateMediaQueryStyle(),contentProps.style]);
208
204
  };
209
205
  const wrapperProps = withPortal ? {appBarProps,authRequired:false,title:loginTitle,withScrollView} : { style:styles.wrapper};
210
- const sH = React.isComponent(HeaderTopContent)? <HeaderTopContent
211
- mediaQueryUpdateNativeProps = {mQueryUpdateProps}
212
- /> : React.isValidElement(HeaderTopContent)? HeaderTopContent : null;
206
+ const sH = React.isComponent(HeaderTopContent)? <HeaderTopContent mediaQueryUpdateStyle = {mediaQueryUpdateStyle} /> : React.isValidElement(HeaderTopContent)? HeaderTopContent : null;
213
207
  return <Wrapper testID = {testID+"_Wrapper" }{...wrapperProps}>
214
208
  <DialogProvider ref={dialogProviderRef}/>
215
209
  {sH}
216
210
  <Surface {...containerProps} {...defaultObj(loginProps?.containerProps)} style={[styles.container,{backgroundColor},containerProps.style,loginProps?.containerProps?.style]} testID={testID}>
217
- <Surface elevation = {0} {...contentProps} mediaQueryUpdateNativeProps = {mQueryUpdateProps} {...contentProps} testID={testID+"_Content"} style={[styles.content,updateMediaQueryStyle(),{backgroundColor},contentProps.style]}>
211
+ <Surface elevation = {0} {...contentProps} mediaQueryUpdateStyle = {mediaQueryUpdateStyle} {...contentProps} testID={testID+"_Content"} style={[styles.content,{backgroundColor},contentProps.style]}>
218
212
  <FormData
219
213
  formName = {formName}
220
214
  testID = {testID+"_FormData"}
@@ -64,6 +64,7 @@ const AvatarComponent = React.forwardRef((props,ref)=>{
64
64
  const c = <Component
65
65
  {...rest}
66
66
  {...cProps}
67
+ containerProps = {containerProps}
67
68
  ref={ref}
68
69
  onPress = {!handleOnPress && onPress ? onPress : undefined}
69
70
  title = {onPress?null : defaultVal(toolip,title)}
@@ -71,7 +72,7 @@ const AvatarComponent = React.forwardRef((props,ref)=>{
71
72
  style = {style}
72
73
  size= {size}
73
74
  />;
74
- return onPress && handleOnPress ? <Tooltip title={title} toolip={toolip} Component = {Pressable} testID={testID+"_Container"} {...containerProps} onPress={onPress}>{c}</Tooltip> : c;
75
+ return onPress && handleOnPress ? <Tooltip title={title} toolip={toolip} Component = {Pressable} testID={testID+"_Container"} onPress={onPress}>{c}</Tooltip> : c;
75
76
  });
76
77
 
77
78
  AvatarComponent.displayName = "AvatarComponent";
@@ -41,7 +41,7 @@ const DialogComponent = React.forwardRef((props,ref)=>{
41
41
  onCancelButtonPress,no,yes,
42
42
  onDismiss:customOnDismiss,backAction,onShow,backActionProps,
43
43
  fullScreen:customFullScreen,appBarProps,contentProps,actionsProps,
44
- title,subtitle,onMount,onUnmount,mediaQueryUpdateNativeProps,
44
+ title,subtitle,onMount,onUnmount,
45
45
  titleProps,
46
46
  visible,
47
47
  scrollViewProps,withScrollView,
@@ -146,11 +146,6 @@ const DialogComponent = React.forwardRef((props,ref)=>{
146
146
  const {height} = Dimensions.get("window");
147
147
  return Math.max((height>600?(50):70)*height/100,MIN_HEIGHT);
148
148
  }
149
- const modalStyle = React.useMediaQueryUpdateStyle({
150
- mediaQueryUpdateStyle : (args)=>{
151
- return null;
152
- }
153
- });
154
149
  const onModalShown = (a)=>{
155
150
  if(onShow){
156
151
  onShow(a);
@@ -197,7 +192,7 @@ const DialogComponent = React.forwardRef((props,ref)=>{
197
192
  dismissable = {isDimissable}
198
193
  onShow = {onModalShown}
199
194
  visible={visible}
200
- style = {[styles.modal,modalProps.style,modalStyle]}
195
+ style = {[styles.modal,modalProps.style]}
201
196
  ref={modalRef}
202
197
  testID = {testID}
203
198
  contentContainerProps = {contentContainerProps}
@@ -672,9 +672,11 @@ export default class DropdownAlert extends Component {
672
672
  accessibilityLabel={accessibilityLabel}
673
673
  accessible={accessible}>
674
674
  <View style={style} testID={testID+"_ContentContainer"}>
675
- <View testID={testID+"_ContentWrapper"} style={[contentContainerStyle,getContainerStyle().style]}
676
- mediaQueryUpdateNativeProps={(args)=>{
677
- return getContainerStyle(args);
675
+ <View testID={testID+"_ContentWrapper"} style={[contentContainerStyle]}
676
+ mediaQueryUpdateStyle={({isMobile,isTablet,width,...rest})=>{
677
+ return {
678
+ maxWidth : isMobile ? (90*width)/100 : isTablet? Math.max((70*width/100),350) : 500
679
+ }
678
680
  }}
679
681
  >
680
682
  {this._renderImage(imageSrc, imageStyle)}
@@ -690,16 +692,4 @@ export default class DropdownAlert extends Component {
690
692
  </Portal>
691
693
  );
692
694
  }
693
- }
694
-
695
- const getContainerStyle = (args)=>{
696
- if(!isObj(args)){
697
- args = {isMobile : isMobileMedia(),isTablet : isTabletMedia()};
698
- }
699
- const {width} = Dimensions.get("window");
700
- return {
701
- style : {
702
- maxWidth : args.isMobile ? (90*width)/100 : args.isTablet? Math.max((70*width/100),350) : 500
703
- }
704
- }
705
695
  }
@@ -1,5 +1,7 @@
1
1
  import PropTypes from "prop-types";
2
2
  import KeyboardEventHandler from "../KeyboardEventHandler";
3
+ import { addMediaQueryUpdateStyeSubscription } from "$ehooks";
4
+ import Dimensions from "$cdimensions";
3
5
  const {getActions,getFormFields,Forms} = require("../utils")
4
6
  import TextField,{parseDecimal} from "$ecomponents/TextField";
5
7
  import Icon from "$ecomponents/Icon";
@@ -219,10 +221,10 @@ export default class Field extends AppComponent {
219
221
  this.state.validatingValue = this.validatingValue = defaultVal(this.props.defaultValue);
220
222
  this.keybaordEvents = [...Object.keys(defaultKeyboardEvents),...this.keybaordEvents]
221
223
  this.state.isMobile = isMobileMedia();
222
- this.state.textFieldMode = theme.textFieldMode;
223
224
  this.state.isReadOnlyOrDisabled = false;
224
225
  this.state.isFieldEditable = true;
225
226
  this.state.isFieldVisible = typeof this.props.visible =='boolean'? this.props.visible : true;
227
+ this.state.wrapperStyle = this.getMediaQueryUpdateStyle();
226
228
  }
227
229
  validatorBeforeValidate({value,validRule,validParams,event,...rest}){
228
230
  let _result = undefined;
@@ -610,18 +612,11 @@ export default class Field extends AppComponent {
610
612
  }
611
613
  return ob;
612
614
  }
613
- componentDidUpdate(){
614
- super.componentDidUpdate();
615
- if(typeof this.props.updateNativePropsOnUpdate ==='function'){
616
- this.props.updateNativePropsOnUpdate({
617
- target : this.wrapperRef,
618
- props : this.props,
619
- });
620
- }
621
- }
615
+
616
+
622
617
  componentDidMount (validate){
623
618
  super.componentDidMount();
624
- this.mediaQueryPropsSubscription = React.getMediaQueryPropsSubscription(this.mediaQueryUpdateNativeProps.bind(this),this.wrapperRef);
619
+ this.mediaQueryUpdateStyleSubscription = addMediaQueryUpdateStyeSubscription(this.doUpdateMediaQueryStyle.bind(this));
625
620
  if(this.canValidate !== false){
626
621
  Forms.trigger("registerField",this.getName(),this.getFormName(),this);
627
622
  }
@@ -632,8 +627,8 @@ export default class Field extends AppComponent {
632
627
  this._fieldRef = undefined;
633
628
  this.offAll();
634
629
  this.clearEvents();
635
- if(this.mediaQueryPropsSubscription){
636
- this.mediaQueryPropsSubscription.remove();
630
+ if(this.mediaQueryUpdateStyleSubscription && this.mediaQueryUpdateStyleSubscription?.remove){
631
+ this.mediaQueryUpdateStyleSubscription.remove();
637
632
  }
638
633
  if(this.canValidate !== false){
639
634
  Forms.trigger("unregisterField",this.getName(),this.getFormName());
@@ -642,20 +637,17 @@ export default class Field extends AppComponent {
642
637
  isHtml(){
643
638
  return false;
644
639
  }
645
- mediaQueryUpdateNativeProps(args){
646
- const {isMobile} = args;
647
- if(typeof this.props.mediaQueryUpdateNativeProps =='function'){
648
- args.props = this.props;
649
- args.context = this;
650
- return this.props.mediaQueryUpdateNativeProps(args);
651
- }
652
- const hasTextFieldModeChanged = true;// = this.state.textFieldMode !== theme.textFieldMode && this.state.isMobile !== isMobile;
653
- if(this.props.responsive === false && !hasTextFieldModeChanged) return;
654
- if((hasTextFieldModeChanged)){
655
- this.setState({isMobile,textFieldMode:theme.textFieldMode});
656
- return null;
640
+ doUpdateMediaQueryStyle(args){
641
+ const wrapperStyle = this.getMediaQueryUpdateStyle(args);
642
+ this.setState({isMobile:args.isMobile,wrapperStyle});
643
+ }
644
+ getMediaQueryUpdateStyle(args){
645
+ if(this.props.responsive === false) return null;
646
+ if(!isObj(args)){
647
+ args = Dimensions.getDimensionsProps();
657
648
  }
658
- return {style:grid.col(this.props.windowWidth)};
649
+ const style2 = typeof this.props.mediaQueryUpdateStyle =='function'? this.props.mediaQueryUpdateStyle(args) : null;
650
+ return StyleSheet.flatten([grid.col(this.props.windowWidth),style2]);
659
651
  }
660
652
  onKeyEvent(key,event){
661
653
  let form = this.getForm();
@@ -1032,11 +1024,13 @@ export default class Field extends AppComponent {
1032
1024
  rest.height = height;
1033
1025
  }
1034
1026
  }
1035
- return <KeyboardEventHandler formFieldName={this.getName()} testID={'RN_FormFieldContainer_'+this.getName()} innerRef={this.wrapperRef} {...wrapperProps}
1027
+ return <KeyboardEventHandler formFieldName={this.getName()} testID={'RN_FormFieldContainer_'+this.getName()} innerRef={this.wrapperRef}
1028
+ {...wrapperProps}
1036
1029
  handleKeys={this.keybaordEvents}
1037
1030
  onKeyEvent = {this.onKeyEvent.bind(this)}
1038
1031
  isDisabled = {rest.disabled}
1039
- style = {[wrapperProps.style,visibleStyle]}
1032
+ mediaQueryUpdateStyle={null}
1033
+ style = {[this.state.wrapperStyle,wrapperProps.style,visibleStyle]}
1040
1034
  >
1041
1035
  {(kProps)=>{
1042
1036
  return this._render({...rest,...kProps},this.setRef.bind(this))
@@ -42,10 +42,10 @@ const FormDataDialogProvider = React.forwardRef((props,innerRef)=>{
42
42
  if(state.visible){
43
43
  formProps.fieldProps = defaultObj(formProps.fieldProps);
44
44
  formProps.fieldProps.windowWidth = !isMobile ? MAX_WIDTH : undefined;
45
- formProps.fieldProps.updateNativePropsOnUpdate = ({target})=>{
46
- if(!target || !target.current || target.setNativeProps || !formRef.current || !formRef.current.dialogRef || !formRef.current.dialogRef.current || !formRef.current.dialogRef.current.isFullScreen) return;
45
+ formProps.fieldProps.mediaQueryUpdateStyle = ({target})=>{
46
+ if(!formRef.current || !formRef.current.dialogRef || !formRef.current.dialogRef.current || !formRef.current.dialogRef.current.isFullScreen) return;
47
47
  const f = formRef.current.dialogRef.current.isFullScreen();
48
- target.current.setNativeProps({ style : f? grid.col() : {width:'100%'}});
48
+ return f ? grid.col() : {width:'100%'};
49
49
  }
50
50
  }
51
51
  return <Dialog
@@ -4,7 +4,7 @@ import React from '$react';
4
4
  import {Pressable, StyleSheet} from 'react-native';
5
5
  import Dimensions from "$cplatform/dimensions";
6
6
  import View from "$ecomponents/View";
7
- import {defaultStr} from "$cutils";
7
+ import {defaultStr,isObj} from "$cutils";
8
8
  import PropTypes from "prop-types";
9
9
  import {medias} from "$theme/grid";
10
10
  import theme from "$theme";
@@ -66,14 +66,11 @@ export const getSizeStyle = (props)=>{
66
66
  }
67
67
  paddingMultiplicator = typeof paddingMultiplicator =='number'? paddingMultiplicator : 1.8;
68
68
  marginMultiplicator = typeof marginMultiplicator =="number"? marginMultiplicator : 0;
69
- const marginRight = marginMultiplicator*gutter;
70
- return {
71
- style : {paddingRight:gutter*paddingMultiplicator,marginVertical:gutter,width : (((size)/totalSize)*100)+"%"}
72
- }
69
+ return {paddingRight:gutter*paddingMultiplicator,marginVertical:gutter,width : (((size)/totalSize)*100)+"%"}
73
70
  }
74
71
 
75
72
  const GridCellComponent = React.forwardRef((p,ref)=>{
76
- const {style,size,children,phoneSize,withSurface,elevation:cElev,mediaQueryUpdateNativeProps,contentProps:cProps,tabletSize,desktopSize,smallPhoneSize,onPress,activeOpacity,onLongPress,flex:customFlex,onPressIn,onPressOut,...props} = p;
73
+ const {style,size,children,phoneSize,withSurface,elevation:cElev,mediaQueryUpdateStyle,contentProps:cProps,tabletSize,desktopSize,smallPhoneSize,onPress,activeOpacity,onLongPress,flex:customFlex,onPressIn,onPressOut,...props} = p;
77
74
  const testID = defaultStr(props.testID,"RN_Grid.CellComponent");
78
75
  const contentProps = defaultObj(cProps);
79
76
  const C = onPress || onLongPress || onPressIn || onPressOut ? Pressable : View;
@@ -82,13 +79,16 @@ const GridCellComponent = React.forwardRef((p,ref)=>{
82
79
  return <View
83
80
  {...props}
84
81
  testID={testID}
85
- mediaQueryUpdateNativeProps = {(args)=>{
86
- console.log("calling ",args);
87
- if(typeof mediaQueryUpdateNativeProps =='function' && mediaQueryUpdateNativeProps(args) === false) return;
88
- return getSizeStyle(p);
82
+ mediaQueryUpdateStyle = {(args)=>{
83
+ const style2 = getSizeStyle(p);
84
+ const style = typeof mediaQueryUpdateStyle =='function' && mediaQueryUpdateStyle(args) || undefined;
85
+ if(isObj(style) || Array.isArray(style)){
86
+ return StyleSheet.flatten([style2,styles]);
87
+ }
88
+ return style2;
89
89
  }}
90
90
  ref={ref}
91
- style = {[styles.container,customFlex !== undefined && {flex:customFlex},getSizeStyle(p).style,style]}
91
+ style = {[styles.container,customFlex !== undefined && {flex:customFlex},style]}
92
92
  >
93
93
  <C testID={testID+"_Content"} activeOpacity={activeOpacity} {...contentProps}
94
94
 
@@ -3,10 +3,11 @@ import PropTypes from "prop-types";
3
3
  import React from "$react";
4
4
  import {isMobileNative} from "$cplatform";
5
5
  import {debounce,isNumber} from "$cutils";
6
+ import {useMediaQueryUpdateStyle} from "$ehooks";
6
7
 
7
8
 
8
- const ViewComponent = React.forwardRef(({mediaQueryUpdateNativeProps,onRender,onLayoutTimeout,onLayout,autoHeight,autoWidth,elevation,...props},ref)=>{
9
- const style = React.useMediaQueryUpdateStyle(props);
9
+ const ViewComponent = React.forwardRef(({onRender,onLayoutTimeout,onLayout,autoHeight,autoWidth,elevation,...props},ref)=>{
10
+ const style = useMediaQueryUpdateStyle(props);
10
11
  const autoSize = autoHeight||autoWidth ? true : false;
11
12
  const [state,setState] = autoSize ? React.useState({}) : [{}];
12
13
  const {width,height} = state;
@@ -32,7 +33,7 @@ const ViewComponent = React.forwardRef(({mediaQueryUpdateNativeProps,onRender,on
32
33
  ]
33
34
  ]}
34
35
  onLayout = {isMobileNative()? onL : debounce(onL,typeof onLayoutTimeout =='number'? onLayoutTimeout : 100)}
35
- ref={typeof mediaQueryUpdateNativeProps =='function' ? React.useMediaQueryUpdateNativeProps(mediaQueryUpdateNativeProps,ref) : ref}
36
+ ref={ref}
36
37
  />
37
38
  });
38
39
 
@@ -41,7 +42,6 @@ export default ViewComponent;
41
42
  ViewComponent.displayName = "ViewComponent";
42
43
 
43
44
  ViewComponent.propTypes = {
44
- mediaQueryUpdateNativeProps : PropTypes.func,
45
45
  mediaQueryUpdateStyle : PropTypes.func,
46
46
  autoWidth : PropTypes.bool,//si la taille de la vue est calculée automatiquement
47
47
  autoHeight : PropTypes.bool,//si la taille de
@@ -0,0 +1,41 @@
1
+
2
+ import Dimensions from "$cplatform/dimensions";
3
+ import useStableMemo from "$react/useStableMemo";
4
+ import { useWindowDimensions } from "$cdimensions";
5
+ import {isObj} from "$cutils";
6
+ import { StyleSheet } from "react-native";
7
+
8
+
9
+ /*** permet d'attacher un lister sur la modification des props de manière responsive :
10
+ permet de récupérer la fonction à attacher par défaut au listener DimensionChange, pour la mise à jour automatique de la propriété style
11
+ * @param mediaQueryUpdateStyleCb{function}, la fonction permettant de mettre à jour les props lorsque la taille de l'écran change
12
+ * @param timeout {number}, le délai d'attente à passer à la fonction debounce, pour pouvoir appeler la fonction de mise à jour des props lorsque la taile de l'écran change
13
+ * @return {object{remove:function}||null} l'objet null ou ayan la fonction remove permettant de suprimer le listerner lorsque le composant est démonté
14
+ */
15
+ export const addMediaQueryUpdateStyeSubscription = (mediaQueryUpdateStyleCb,timeout)=>{
16
+ if(typeof mediaQueryUpdateStyleCb !='function') return null;
17
+ const options = isObj(timeout)? timeout : {};
18
+ timeout = typeof timeout =='number'? timeout : typeof options.timeout =='number'? options.timeout : 200;
19
+ return Dimensions.addEventListener("change",debounce((dimensions)=>{
20
+ return mediaQueryUpdateStyleCb(Dimensions.getDimensionsProps(dimensions));
21
+ },timeout));
22
+ }
23
+
24
+ /*** met à jour dynamiquemnet les propriétés style d'un objet en fonction du changement de la taille de l'objet
25
+ * @param {useCurrentMedia} {boolean} si true, alors les propriétés sont mis à jour uniquement si le current media change
26
+ @param {mediaQueryUpdateStyle}, la fonction permettant d'obtenir les propriétés css du composant à retourner
27
+ @return {object}, le flatten style des propriétés css associés aux props du composant react l'object
28
+ */
29
+ export function useMediaQueryUpdateStyle({useCurrentMedia,target,mediaQueryUpdateStyle,...props}){
30
+ if(typeof mediaQueryUpdateStyle !=='function') return props.style;
31
+ const dimensions = useWindowDimensions();
32
+ const handleProps = dimensions && useCurrentMedia === true ? Dimensions.getCurrentMedia() : dimensions;
33
+ return useStableMemo(()=>{
34
+ const args = Dimensions.getDimensionsProps();
35
+ args.props = props,
36
+ args.target = target;
37
+ const nStyle = mediaQueryUpdateStyle(args);
38
+ if(isObj(nStyle) || Array.isArray(nStyle)) return StyleSheet.flatten([props.style,nStyle]);
39
+ return StyleSheet.flatten(props.style)||{};
40
+ },[handleProps,useCurrentMedia,dimensions,props.style]);
41
+ }
@@ -1,5 +0,0 @@
1
- // Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
2
- // Use of this source code is governed by a BSD-style
3
- // license that can be found in the LICENSE file.
4
-
5
- export default [];