@fto-consult/expo-ui 6.15.0 → 6.15.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "6.15.0",
3
+ "version": "6.15.2",
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.22.0",
65
+ "@fto-consult/common": "^3.23.1",
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",
@@ -10,7 +10,7 @@ import {isPhoneMedia} from "$cplatform/dimensions";
10
10
  import View from "$ecomponents/View";
11
11
  import {StyleSheet} from "react-native";
12
12
  import {List} from "react-native-paper";
13
- import FlashList from "$ecomponents/List";
13
+ import FlashList from "$ecomponents/Table/List";
14
14
  import Surface from "$ecomponents/Surface";
15
15
  import {navigate} from "$cnavigation";
16
16
  import { handleBeforeSaveCallback } from "$ecomponents/Form/FormData/utils";
@@ -476,7 +476,7 @@ export default class FormListComponent extends AppComponent {
476
476
  addIconLabel = defaultVal(addIconLabel,"Ajouter un élément");
477
477
  addIcon = defaultVal(addIcon,"plus")
478
478
  addIconObj = {...onCHandle,icon:addIcon,text:addIconLabel};
479
- if(isNonNullString(addIcon)) _addIcon = <Icon name={addIcon} size={40} title={'ajouter un élément'}></Icon>;
479
+ if(isNonNullString(addIcon)) _addIcon = <Icon name={addIcon} size={30} title={'ajouter un élément'}></Icon>;
480
480
  if(!React.isValidElement(addIcon)){
481
481
  addIcon = _addIcon;
482
482
  }
@@ -1,16 +1,18 @@
1
1
 
2
2
  import React from "$react";
3
3
  import { prepareItems as customPrepareItems,getBToTopRef } from "./utils";
4
- import theme,{grid,StylePropTypes} from "$theme";
4
+ import {grid,StylePropTypes} from "$theme";
5
5
  import PropTypes from "prop-types";
6
- import {defaultObj,isObj,defaultDecimal,defaultArray,defaultFunc} from "$cutils";
6
+ import {defaultObj,extendObj,isObj,defaultDecimal,defaultArray,defaultFunc} from "$cutils";
7
7
  import {isMobileMedia} from "$cplatform/dimensions";
8
8
  import BackToTop from "$ecomponents/BackToTop";
9
9
  import {FlatList,StyleSheet,View} from "react-native";
10
10
  import Label from "$ecomponents/Label";
11
11
  import { useWindowDimensions,Dimensions } from "react-native";
12
+ import { useList } from "./hooks";
12
13
 
13
14
  const CommonListComponent = React.forwardRef((props,ref)=>{
15
+ const context = useList(props);
14
16
  let {responsive,defaultItemHeight,itemHeight,windowWidth,onRender,componentProps,columnWrapperStyle,onViewableItemsChanged,withFlatListItem,Component,withBackToTop,backToTopRef:customBackToTopRef,withBackToTopButton,onScroll,onScrollEnd,onMount,onUnmount,renderScrollViewWrapper,prepareItems,getItemKey,getKey,keyExtractor,items,filter,renderItem,numColumns,containerProps,bindResizeEvents,...rest} = props;
15
17
  withBackToTopButton = withBackToTop === true || withBackToTopButton == true || isMobileMedia()? true : false;
16
18
  rest = defaultObj(rest);
@@ -28,10 +30,7 @@ const CommonListComponent = React.forwardRef((props,ref)=>{
28
30
  const hasCustomBackToTop = typeof customBackToTopRef == 'function'? true : false;
29
31
  const backToTopRef = React.useRef(null);
30
32
  const isFlatList = Component === FlatList;
31
-
32
- const context = {
33
- itemsRefs : [],
34
- prepareItems : defaultFunc((prepareItems === false ? (items)=> items:null),prepareItems,customPrepareItems),
33
+ extendObj(context,{
35
34
  getKey : typeof keyExtractor =='function'? keyExtractor : typeof getItemKey =='function'? getItemKey : typeof getKey =='function'? getKey : undefined,
36
35
  addItemsRefs : function(ref, itemRef){
37
36
  context.itemsRefs[itemRef.index] = {
@@ -130,21 +129,10 @@ const CommonListComponent = React.forwardRef((props,ref)=>{
130
129
  onBackActionPress : !hasCustomBackToTop ? function(){
131
130
  return context?.scrollToTop()
132
131
  }: undefined,
133
- };
134
- const contextRef = React.useRef({}).current;
135
- contextRef.prevItems = React.usePrevious(items);
136
- const getItems = React.useCallback(()=>{
137
- if(items === contextRef.prevItems && contextRef.items) {
138
- return contextRef.items;
139
- }
140
- return context.prepareItems(items,filter);
141
- },[items]);
132
+ })
133
+
142
134
  context.listRef = listRef.current;
143
- context.items = contextRef.items = prepareItems === false ? items : getItems();
144
- if(!Array.isArray(context.items)){
145
- console.error(context.items," is not valid list data array",props);
146
- context.items = [];
147
- }
135
+
148
136
  React.useOnRender(onRender,Math.max(items.length/10 || 0,500));
149
137
  React.setRef(ref,context);
150
138
  React.useEffect(()=>{
@@ -2,11 +2,14 @@
2
2
  // Use of this source code is governed by a BSD-style
3
3
  // license that can be found in the LICENSE file.
4
4
 
5
- import {Virtuoso} from "react-virtuoso/dist/index.mjs";
5
+ import {Virtuoso,VirtuosoGrid} from "react-virtuoso/dist/index.mjs";
6
6
  import React from "$react";
7
7
  import PropTypes from "prop-types";
8
- import {defaultObj,defaultNumber,isDOMElement,isNumber,uniqid,isNonNullString,defaultStr} from "$cutils";
8
+ import {defaultObj,classNames,defaultNumber,isObj,isDOMElement,isNumber,uniqid,isNonNullString,defaultStr} from "$cutils";
9
9
  import { View } from "react-native";
10
+ import {useList} from "../hooks";
11
+ import theme,{grid} from "$theme";
12
+ import Dimensions from "$cdimensions";
10
13
 
11
14
  const propTypes = {
12
15
  ...defaultObj(Virtuoso.propTypes),
@@ -26,13 +29,17 @@ const propTypes = {
26
29
  isScrolling : PropTypes.func,
27
30
  };
28
31
  /***@see : https://virtuoso.dev/virtuoso-api-reference/ */
29
- const VirtuosoListComponent = React.forwardRef(({items,onRender,testID,renderItem,onEndReached,onLayout,onContentSizeChange,onScroll,isScrolling,estimatedItemSize,onEndReachedThreshold,containerProps,style,autoSizedStyle,...props},ref)=>{
32
+ const VirtuosoListComponent = React.forwardRef(({onRender,listClassName,components,itemProps,windowWidth,numColumns,responsive,testID,renderItem,onEndReached,onLayout,onContentSizeChange,onScroll,isScrolling,estimatedItemSize,onEndReachedThreshold,containerProps,style,autoSizedStyle,...props},ref)=>{
33
+ const Component = React.useMemo(()=>responsive?VirtuosoGrid:Virtuoso,[responsive])
34
+ const context = useList(props);
35
+ itemProps = defaultObj(itemProps);
36
+ const items = context.items;
30
37
  const r2 = {};
31
- for(let i in propTypes){
38
+ Object.map(Component.propTypes,(_,i)=>{
32
39
  if(i in props){
33
40
  r2[i] = props[i];
34
41
  }
35
- }
42
+ });
36
43
  containerProps = defaultObj(containerProps);
37
44
  testID = defaultStr(testID,containerProps.testID,"RN_VirtuosoListComponent");
38
45
  const listIdRef = React.useRef(uniqid("virtuoso-list-id"));
@@ -95,10 +102,20 @@ const VirtuosoListComponent = React.forwardRef(({items,onRender,testID,renderIte
95
102
  },[]);
96
103
  React.useOnRender((a,b,c)=>{
97
104
  if(onRender && onRender(a,b,c));
98
- },Math.max(Array.isArray(items) && items.length/10 || 0,500))
105
+ },Math.max(Array.isArray(items) && items.length/10 || 0,500));
106
+ const listP = responsive ? {
107
+ listClassName : classNames(listClassName,"rn-virtuoso-list",responsive && gridClassName)
108
+ } : {
109
+ atBottomThreshold : typeof onEndReachedThreshold =='number'? onEndReachedThreshold : undefined,
110
+ totalListHeightChanged : (height)=>{
111
+ checkSize();
112
+ },
113
+ defaultItemHeight : typeof estimatedItemSize=='number' && estimatedItemSize || undefined,
114
+ };
99
115
  return <View {...containerProps} {...props} style={[{flex:1},containerProps.style,style,autoSizedStyle,{minWidth:'100%',height:'100%',maxWidth:'100%'}]} onLayout={onLayout} testID={testID}>
100
- <Virtuoso
116
+ <Component
101
117
  {...r2}
118
+ {...listP}
102
119
  style = {listStyle}
103
120
  ref = {listRef}
104
121
  data = {items}
@@ -108,7 +125,6 @@ const VirtuosoListComponent = React.forwardRef(({items,onRender,testID,renderIte
108
125
  itemContent = {(index)=>{
109
126
  return renderItem({index,item:items[index],items})
110
127
  }}
111
- atBottomThreshold = {typeof onEndReachedThreshold =='number'? onEndReachedThreshold : undefined}
112
128
  atBottomStateChange = {()=>{
113
129
  if(typeof onEndReached =='function'){
114
130
  onEndReached();
@@ -120,16 +136,23 @@ const VirtuosoListComponent = React.forwardRef(({items,onRender,testID,renderIte
120
136
  return isScrolling(isC);
121
137
  }
122
138
  }}
123
- totalListHeightChanged = {(height)=>{
124
- checkSize();
139
+ components = {{
140
+ Item : responsive ? function(props){return <ItemContainer {...props} style={[itemProps.style,props.style]} numColumns={numColumns}/>} : undefined,
141
+ //List : responsive ? ResponsiveVirtuosoListItemContainer: undefined,
142
+ ...defaultObj(components),
125
143
  }}
126
- defaultItemHeight = {typeof estimatedItemSize=='number' && estimatedItemSize || undefined}
127
144
  />
128
145
  </View>
129
146
  });
130
147
 
131
148
  VirtuosoListComponent.propTypes = {
132
- ...propTypes
149
+ ...propTypes,
150
+ numColumns : PropTypes.number,
151
+ items : PropTypes.oneOfType([
152
+ PropTypes.object,
153
+ PropTypes.array,
154
+ PropTypes.func,
155
+ ])
133
156
  };
134
157
 
135
158
  VirtuosoListComponent.displayName = "VirtuosoListComponent";
@@ -166,4 +189,47 @@ const normalizeEvent = (e)=>{
166
189
  },
167
190
  timeStamp: Date.now()
168
191
  };
169
- }
192
+ }
193
+
194
+ function ItemContainer({numColumns,responsive,windowWidth,...props}){
195
+ const width = React.useMemo(()=>{
196
+ if(!numColumns || numColumns <= 1) return undefined;
197
+ if(typeof windowWidth =='number' && windowWidth <=600) return "100%";
198
+ if(Dimensions.isMobileMedia()){
199
+ return "100%";
200
+ }
201
+ return (100/numColumns)+"%";
202
+ },[windowWidth,numColumns]);
203
+ const style = width && {width} || grid.col(windowWidth);
204
+ const dataIntex = "index" in props ? props.index : "data-index" in props ? props["data-index"] : ""
205
+ const dataItemIndex = props["data-item-index"];
206
+ if(isObj(style)){
207
+ style.paddingRight = style.paddingLeft = style.paddingHorizontal = undefined;
208
+ }
209
+ return <View
210
+ testID={`RN_VirtosoGridItem_${dataIntex}-${dataItemIndex}`}
211
+ {...props}
212
+ style = {[style,props.style]}
213
+ />
214
+ }
215
+ const ResponsiveVirtuosoListItemContainer = React.forwardRef((props,ref)=>{
216
+ return <View ref={ref} testID={"RN_ResponsiveVirtuosoListItemContainer"} {...props} style={[responsiveListStyle,props.style,]}/>
217
+ });
218
+
219
+ export const gridClassName = "rn-virtuoso-responsive-list";
220
+
221
+ const responsiveListStyle = [theme.styles.row,theme.styles.row,theme.styles.flexWrap,theme.styles.justifyContentStart,theme.styles.alignItemsStart]
222
+ ResponsiveVirtuosoListItemContainer.displayName = "ResponsiveVirtuosoListItemContainer";
223
+
224
+ if(typeof document !=='undefined' && document && document?.createElement){
225
+ const gridDomId = "dynamic-virtuoso-grid-styles";
226
+ let style = document.getElementById(gridDomId);
227
+ if(!style){
228
+ style = document.createElement("style");
229
+ }
230
+ style.id = gridDomId;
231
+ style.textContent = `
232
+ .${gridClassName}{display:flex;flex-direction:row;align-items:flex-start;flex-wrap:wrap;justify-content:flex-start;};
233
+ `;
234
+ document.body.appendChild(style);
235
+ }
@@ -0,0 +1,26 @@
1
+ import React from "$react";
2
+ import { prepareItems as customPrepareItems} from "./utils";
3
+ import {defaultFunc} from "$cutils";
4
+
5
+ /**** retourne le contexte associé au composant List
6
+
7
+ */
8
+ export const useList = ({items,filter,prepareItems,...props})=>{
9
+ const contextRef = React.useRef({itemsRefs:[]});
10
+ const context = contextRef.current;
11
+ context.itemsRefs = Array.isArray(context.itemsRefs) && context.itemsRefs || [];
12
+ context.prepareItems = defaultFunc((prepareItems === false ? (items)=> items:null),prepareItems,customPrepareItems);
13
+ contextRef.prevItems = React.usePrevious(items);
14
+ const getItems = React.useCallback(()=>{
15
+ if(items === context.prevItems && context.items) {
16
+ return context.items;
17
+ }
18
+ return context.prepareItems(items,filter);
19
+ },[items]);
20
+ context.items = contextRef.items = prepareItems === false ? items : getItems();
21
+ if(!Array.isArray(context.items)){
22
+ console.error(context.items," is not valid list data array",items,props);
23
+ context.items = [];
24
+ }
25
+ return context;
26
+ }
@@ -2,7 +2,7 @@ import FlashList from "./FlashList";
2
2
 
3
3
  export * from "./utils";
4
4
 
5
- export default FlashList;
5
+ export {default} from "./Virtuoso";
6
6
 
7
7
  export {default as FlatList} from "./FlatList";
8
8
 
@@ -10,3 +10,5 @@ export {default as FlashList} from "./FlashList";
10
10
 
11
11
  export {default as BigList} from "./BigList";
12
12
 
13
+ export {default as Virtuoso} from "./Virtuoso";
14
+
@@ -1,6 +1,6 @@
1
1
  import React from "$react";
2
2
  import {Vertical as AutoSizeVertical} from "$ecomponents/AutoSizer";
3
- import List from "./List";
3
+ import List from "$ecomponents/List/Virtuoso";
4
4
  import {defaultStr,isObj,defaultObj} from "$cutils";
5
5
  const normalize = (size)=>{
6
6
  if(isObj(size)){
@@ -7,7 +7,6 @@ import { screenName } from "$escreens/Auth/utils";
7
7
  import Image from "$ecomponents/Image";
8
8
  import { StyleSheet,View,Pressable} from "react-native";
9
9
  import avatarProps from "$eauth/avatarProps";
10
- import Button from "$ecomponents/Button";
11
10
  import Label from "$ecomponents/Label";
12
11
  import Icon from "$ecomponents/Icon";
13
12
  import {navigate} from "$cnavigation";
@@ -17,6 +16,7 @@ import appConfig from "$capp/config";
17
16
  import Preloader from "$preloader";
18
17
  import {defaultNumber} from "$cutils";
19
18
  import Tooltip from "$ecomponents/Tooltip";
19
+ import {isMultiUsersAllowed} from "$cauth/utils/session";
20
20
  const UserProfileAvatarComponent = React.forwardRef(({drawerRef,chevronIconProps:customChevronIconProps,size,withLabel,...props},ref)=>{
21
21
  let u = defaultObj(Auth.getLoggedUser());
22
22
  const deviceNameRef = React.useRef(null);
@@ -77,7 +77,7 @@ const UserProfileAvatarComponent = React.forwardRef(({drawerRef,chevronIconProps
77
77
  });
78
78
  }
79
79
  },
80
- {
80
+ isMultiUsersAllowed() && {
81
81
  label : i18n.lang("logout",'Déconnexion'),
82
82
  icon : "logout",
83
83
  onPress : (a)=>{
@@ -11,7 +11,6 @@ import {goBack} from "$cnavigation";
11
11
 
12
12
  export default class FormDataLayout extends FormDataActions {
13
13
  getComponentProps(props){
14
- this.__mainProps = null;
15
14
  return super.getComponentProps(props);
16
15
  }
17
16
  getDataProp(){
@@ -28,17 +28,19 @@ export default class FormDataListScreen extends FormData{
28
28
  ,saveAction : typeof saveAction !=='undefined'? saveAction:true,
29
29
  });
30
30
  }
31
- createNew (){
31
+ createNew (...p){
32
32
  const {show} = this.props;
33
33
  if(typeof show =='function'){
34
- show({...this.props,index:undefined,data:{}});
34
+ return show({...this.props,index:undefined,data:{}});
35
35
  }
36
+ return super.createNew(...p)
36
37
  }
37
- doSave2New(args){
38
+ doSave2New(args,...rest){
38
39
  const {show} = this.props;
39
40
  if(typeof show =='function'){
40
- show({...args,index:undefined,data:{}});
41
+ return show({...args,index:undefined,data:{}});
41
42
  }
43
+ return super.doSave2Close(args,...rest);
42
44
  }
43
45
  doSave2Close(args){
44
46
  return this.close();