@fto-consult/expo-ui 2.4.8 → 2.5.0

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": "2.4.8",
3
+ "version": "2.5.0",
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
  "@expo/html-elements": "^0.2.0",
63
63
  "@expo/metro-config": "^0.4.0",
64
64
  "@expo/webpack-config": "^0.17.2",
65
- "@fto-consult/common": "^1.11.15",
65
+ "@fto-consult/common": "^1.12.2",
66
66
  "@gorhom/portal": "^1.0.14",
67
67
  "@react-native-async-storage/async-storage": "~1.17.3",
68
68
  "@react-native-community/datetimepicker": "6.5.2",
@@ -73,7 +73,7 @@
73
73
  "babel-plugin-inline-dotenv": "^1.7.0",
74
74
  "babel-plugin-module-resolver": "^4.1.0",
75
75
  "babel-plugin-transform-inline-environment-variables": "^0.4.4",
76
- "expo": "^47.0.0",
76
+ "expo": "^47.0.8",
77
77
  "expo-camera": "~13.0.0",
78
78
  "expo-clipboard": "~4.0.1",
79
79
  "expo-image-picker": "~14.0.1",
@@ -245,9 +245,6 @@ const DatagridFactory = (Factory)=>{
245
245
  getMaxSelectedRows(){
246
246
  return isMobileMedia()? 30 : 50;
247
247
  }
248
- prepareFilter(props,headerFilters){
249
- return headerFilters.push(props);
250
- }
251
248
  showFilters(){
252
249
  if(!this._isMounted()) {
253
250
  this.isUpdating = false;
@@ -299,6 +296,12 @@ const DatagridFactory = (Factory)=>{
299
296
  </View>
300
297
  })
301
298
  }
299
+ renderEmpty(){
300
+ if(isObj(this.currentAccordionProps) && typeof this.currentAccordionProps.renderEmpty =='function'){
301
+ return this.currentAccordionProps.renderEmpty();
302
+ }
303
+ return super.renderEmpty();
304
+ }
302
305
  render (){
303
306
  let {
304
307
  filters,
@@ -332,6 +335,7 @@ const DatagridFactory = (Factory)=>{
332
335
  if(isObj(accordion)){
333
336
  accordionProps = {...accordion,...accordionProps};
334
337
  }
338
+ this.currentAccordionProps = accordionProps;
335
339
  backToTopRef = defaultVal(backToTopRef,accordionProps.backToTopRef,true);
336
340
 
337
341
  let descOrContentProps = isObj(accordionProps.descriptionProps)? Object.assign({},accordionProps.descriptionProps) : isObj(accordionProps.contentProps)? Object.assign({},accordionProps.contentProps) : {};
@@ -539,7 +543,6 @@ const DatagridFactory = (Factory)=>{
539
543
  </View>
540
544
  </ScrollView>
541
545
  </View>
542
- renderEmpty = defaultFunc(accordionProps.renderEmpty,renderEmpty,x=>null)
543
546
  return <View testID={testID+"_Container"} pointerEvents={pointerEvents} style={[styles.container]} collapsable={false}>
544
547
  { <View testID={testID+"_ContentContainer"} style={[this.bindResizeEvents()?{height:this.renderedListHeight}:undefined]}>
545
548
  <View testID={testID+"_AccordionHeader"} style={[styles.accordionHeader]} ref={this.layoutRef} onLayout={this.updateLayout.bind(this)}>
@@ -591,7 +594,7 @@ const DatagridFactory = (Factory)=>{
591
594
  }:false}
592
595
  keyExtractor = {this.getRowKey.bind(this)}
593
596
  /> : <View style={styles.hasNotData}>
594
- {renderEmpty()}
597
+ {this.renderEmpty()}
595
598
  </View>}
596
599
  </View>}
597
600
  {backToTopRef ? <BackToTop testID={testID+"_BackToTop"} {...backToTopProps} ref={this.backToTopRef} style={[styles.backToTop,backToTopProps.style]} onPress={this.scrollToTop.bind(this)}/>:null}
@@ -96,6 +96,7 @@ export default class CommonDatagridComponent extends AppComponent {
96
96
  [footerFieldName] : {
97
97
  value : uniqid(footerFieldName),override:false, writable: false
98
98
  },
99
+ currentFilteringColumns : {value:{}}
99
100
  })
100
101
 
101
102
  this.state.sort.dir = defaultStr(this.state.sort.dir,this.state.sort.column == "date"?"desc":'asc')
@@ -847,13 +848,20 @@ export default class CommonDatagridComponent extends AppComponent {
847
848
  });
848
849
  }
849
850
  prepareFilter(props,filteredColumns){
850
-
851
+ filteredColumns.push(props);
851
852
  }
852
853
  renderFilter(props){
853
854
  return <Filter {...props}/>
854
855
  }
855
856
  prepareColumn(){}
856
857
  beforePrepareColumns(){}
858
+ renderEmpty(){
859
+ if(typeof this.props.renderEmpty =='function'){
860
+ const r = this.props.renderEmpty();
861
+ return React.isValidElement(r)? r : null;
862
+ }
863
+ return null;
864
+ }
857
865
  prepareColumns (args){
858
866
  this.beforePrepareColumns();
859
867
  args = defaultObj(args);
@@ -958,6 +966,7 @@ export default class CommonDatagridComponent extends AppComponent {
958
966
  operator : fCol.operator,
959
967
  action : defaultStr(fCol.originAction,fCol.action),
960
968
  };
969
+ this.currentFilteringColumns[header.field] = filterProps;
961
970
  this.prepareFilter(filterProps,headerFilters);
962
971
  }
963
972
  this.prepareColumn({
@@ -1169,19 +1178,15 @@ export default class CommonDatagridComponent extends AppComponent {
1169
1178
  onFilterChange(arg){
1170
1179
  this.filteredValues = defaultObj(this.filteredValues);
1171
1180
  let {field,operator,originAction,action,value} = defaultObj(arg);
1172
- const filters = this.preparedColumns.filters;
1173
- if(isNonNullString(field) && isNonNullString(operator) && isNonNullString(action)){
1181
+ const filter = isNonNullString(field)? this.currentFilteringColumns[field] : null;
1182
+ if(!isObj(filter)) return;
1183
+ if(isNonNullString(operator) && isNonNullString(action)){
1174
1184
  this.filteredValues[field] = {
1175
1185
  operator,action,value,field
1176
1186
  }
1177
- Object.map(filters,(filter)=>{
1178
- if(isObj(filter) && filter.field == field){
1179
- filter.originValue = filter.defaultValue = arg.defaultValue;
1180
- filter.operator = operator;
1181
- filter.action = defaultStr(originAction,action);
1182
- }
1183
- });
1184
-
1187
+ filter.originValue = filter.defaultValue = arg.defaultValue;
1188
+ filter.operator = operator;
1189
+ filter.action = defaultStr(originAction,action);
1185
1190
  }
1186
1191
  return this.doFilter(arg);
1187
1192
  }
@@ -30,6 +30,7 @@ export default function showConfirm (p,cb){
30
30
  buttons,
31
31
  messageProps,
32
32
  inputProps,
33
+ format,
33
34
  placeholder,
34
35
  children,
35
36
  withInputField,
@@ -116,8 +117,11 @@ export default function showConfirm (p,cb){
116
117
  {messageContent}
117
118
  {withInputField !== false ? <Component
118
119
  type = {type}
120
+ enableCopy = {false}
119
121
  defaultValue = {defaultValue}
120
122
  placeholder = {placeholder}
123
+ affix = {false}
124
+ format = {format}
121
125
  {...inputProps}
122
126
  ref = {inputRef}
123
127
  onChange = {(args)=>{
@@ -7,7 +7,7 @@ import {MENU_ICON} from "$ecomponents/Icon";
7
7
  import theme,{Colors} from "$theme";
8
8
  import Group from "./GroupComponent";
9
9
  import Portal from "$ecomponents/Portal";
10
- import Auth from "$cauth";
10
+ import {isAllowedFromStr} from "$cauth/perms";
11
11
 
12
12
  const FabGroupComponent = React.forwardRef((props,innerRef)=>{
13
13
  let {openedIcon,screenName,display:customDisplay,primary,actionMutator,secondary,onOpen,prepareActions,fabStyle,open:customOpen,onClose,onStateChange:customOnStateChange,closedIcon,color,actions:customActions,children,...customRest} = props;
@@ -63,7 +63,7 @@ const FabGroupComponent = React.forwardRef((props,innerRef)=>{
63
63
  if(!isObj(a) || !isNonNullString(a.label)) return null;
64
64
  const {perm,isAllowed,primary,secondary,...restItem} = a;
65
65
  if(typeof isAllowed =='function' && isAllowed() === false) return null;
66
- if(isNonNullString(perm) && !Auth.isAllowedFromStr(perm)) return false;
66
+ if(isNonNullString(perm) && !isAllowedFromStr(perm)) return false;
67
67
  if(primary){
68
68
  restItem.style = StyleSheet.flatten([restItem.style,{color:theme.colors.primaryText,backgroundColor:theme.colors.primary}])
69
69
  } else if(secondary){
@@ -324,7 +324,8 @@ export default class Filter extends AppComponent {
324
324
  diff = DateLib.currentMonthDaysLimits(currentDate);
325
325
  break;
326
326
  case "$week":
327
- diff = DateLib.currentWeekDaysLimits(currentDate)
327
+ diff = DateLib.currentWeekDaysLimits(currentDate);
328
+ console.log(diff," is diffffff");
328
329
  break;
329
330
  case "$prevWeek":
330
331
  diff = DateLib.previousWeekDaysLimits(currentDate)
@@ -0,0 +1,63 @@
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
+ import { ScrollView,StyleSheet,View,useWindowDimensions} from "react-native";
6
+ import React from "$react";
7
+ import {defaultStr,defaultObj,isObj} from "$utils";
8
+ import Portal from "$ecomponents/Portal";
9
+
10
+ const AbsoluteScrollView = React.forwardRef(({testID,contentProps,containerProps,...props},ref)=>{
11
+ containerProps = defaultObj(containerProps);
12
+ contentProps = defaultObj(contentProps);
13
+ const win = useWindowDimensions();
14
+ const scrollViewRef = React.useRef(null);
15
+ testID = defaultStr(testID,"RN_TableAbsoluteScrollViewComponent");
16
+ const [styles,setStyles] = React.useState({});
17
+ React.setRef(ref,{
18
+ setStyles : (s)=>{
19
+ if(isObj(s)){
20
+ setStyles({...styles,...s});
21
+ }
22
+ },
23
+ scrollViewRef
24
+ })
25
+ React.useEffect(()=>{
26
+ return ()=>{
27
+ React.setRef(ref,null);
28
+ }
29
+ },[])
30
+ return <Portal>
31
+ <View testID={testID+"_Containter"} {...containerProps} style={[mainStyles.container,containerProps.style,styles.container,{left:win.width-10}]}>
32
+ <ScrollView
33
+ {...props}
34
+ ref = {scrollViewRef}
35
+ testID={testID}
36
+ contentContainerStyle = {[props.contentContainerStyle,mainStyles.contentContainer,styles.containerContainer]}
37
+ vertical
38
+ >
39
+ <View
40
+ testID={testID+"Content"}
41
+ {...contentProps}
42
+ style={[mainStyles.content,contentProps.style,styles.content]}
43
+ />
44
+ </ScrollView>
45
+ </View>
46
+ </Portal>
47
+ });
48
+
49
+ export default AbsoluteScrollView;
50
+
51
+ const mainStyles = StyleSheet.create({
52
+ container : {
53
+ ...StyleSheet.absoluteFill,
54
+ width : 10,
55
+ },
56
+ content : {
57
+ width:10,
58
+ },
59
+ contentContainer : {
60
+
61
+ }
62
+ })
63
+ AbsoluteScrollView.displayName = "TableVerticalScrollView";
@@ -1,14 +1,16 @@
1
- import {FlashList,BigList} from "$ecomponents/List";
1
+ import {FlashList} from "$ecomponents/List";
2
2
  import View from "$ecomponents/View";
3
- import {defaultObj,defaultStr,debounce,isNumber,defaultVal} from "$utils";
3
+ import {defaultObj,defaultStr,debounce,defaultNumber,defaultVal} from "$utils";
4
4
  import PropTypes from "prop-types";
5
5
  export const DEFAULT_COLUMN_WIDTH = 60;
6
6
  import React from "$react";
7
7
  import Label from "$ecomponents/Label";
8
- import { StyleSheet,ScrollView,Dimensions} from "react-native";
8
+ import { StyleSheet,View as RNView,ScrollView,Dimensions} from "react-native";
9
9
  import { getRowStyle } from "$ecomponents/Datagrid/utils";
10
10
  import {isMobileNative} from "$cplatform";
11
11
  import theme from "$theme";
12
+ import AbsoluteScrollView from "./AbsoluteScrollView";
13
+
12
14
  const isSCrollingRef = React.createRef();
13
15
  const scrollLists = (opts,refs)=>{
14
16
  refs.map((ref)=>{
@@ -18,14 +20,24 @@ const scrollLists = (opts,refs)=>{
18
20
  });
19
21
  isSCrollingRef.current = false;
20
22
  }
21
- const getOnScrollCb = (refs)=>{
23
+ const getOnScrollCb = (refs,pos,cb2)=>{
22
24
  const cb = (args)=>{
23
25
  if(isSCrollingRef.current) return;
24
26
  if(!isObj(args) || !args.nativeEvent) {
25
27
  isSCrollingRef.current = false;
26
28
  }
27
29
  isSCrollingRef.current = true;
28
- scrollLists({x:args.nativeEvent.contentOffset?.x},refs);
30
+ if(typeof pos =='function'){
31
+ pos(args);
32
+ isSCrollingRef.current = false;
33
+ return;
34
+ }
35
+ pos = pos && (pos =='x' || pos=='y')? pos : "x";
36
+ const a = {[pos]:args.nativeEvent.contentOffset?.[pos]};
37
+ scrollLists(a,refs);
38
+ if(typeof cb2 == 'function'){
39
+ cb2(args);
40
+ }
29
41
  };
30
42
  return isMobileNative()? cb : debounce(cb,200);
31
43
  }
@@ -178,8 +190,10 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
178
190
  fContent = f.length ? <View testID={testID+"_Footer"} {...footerContainerProps} style={[styles.header,styles.footers,footerContainerProps.style]}>
179
191
  {f}
180
192
  </View> : null;
193
+ const absoluteScrollViewRefCanScroll = React.useRef(true);
181
194
  React.setRef(tableRef,context);
182
195
  const cStyle = {width:listWidth}
196
+ const absoluteScrollViewRef = React.useRef(null);
183
197
  return <View testID= {testID+"_Container"} {...containerProps} style={[styles.container,{alignItems:'stretch'},containerProps.style]}>
184
198
  <View autoHeight style={[cStyle]} testID={testID+"_Headers_ScrollViewContainer"}>
185
199
  <ScrollView
@@ -194,12 +208,36 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
194
208
  {hContent}
195
209
  </ScrollView>
196
210
  </View>
197
- <ScrollView {...scrollViewProps} scrollEventThrottle = {scrollEventThrottle} horizontal contentContainerStyle={[scrollContentContainerStyle,scrollViewProps.contentContainerStyle]} showsVerticalScrollIndicator={false} onScroll = {getOnScrollCb([headerScrollViewRef,footerScrollViewRef])} ref={scrollViewRef} testID={testID+"_ScrollView"}>
211
+ <ScrollView {...scrollViewProps} scrollEventThrottle = {scrollEventThrottle} horizontal contentContainerStyle={[scrollContentContainerStyle,scrollViewProps.contentContainerStyle]} showsVerticalScrollIndicator={false}
212
+ onScroll = {getOnScrollCb([headerScrollViewRef,footerScrollViewRef],null,(args)=>{
213
+ })} ref={scrollViewRef} testID={testID+"_ScrollView"}>
198
214
  <FlashList
199
215
  containerProps = {{style:[cStyle]}}
200
216
  //prepareItems = {Array.isArray(items)? false : undefined}
201
217
  estimatedItemSize = {200}
202
218
  {...props}
219
+ onContentSizeChange = {(width,height)=>{
220
+ if(props.onContentSizeChange){
221
+ props.onContentSizeChange(width,height);
222
+ }
223
+ if(!absoluteScrollViewRef.current) return;
224
+ absoluteScrollViewRef.current.setStyles({
225
+ content : {height}
226
+ });
227
+ }}
228
+ onLayout = {(args)=>{
229
+ if(props.onLayout){
230
+ props.onLayout(args);
231
+ }
232
+ if(!absoluteScrollViewRef.current) return;
233
+ const {nativeEvent:{layout}}=args;
234
+ const top = defaultNumber(layout.top,layout.y);
235
+ const height = layout.height;
236
+ absoluteScrollViewRef.current.setStyles({
237
+ container : {top,height},
238
+ contentContainer : {height},
239
+ });
240
+ }}
203
241
  ref = {listRef}
204
242
  numberOfLines = {1}
205
243
  responsive = {false}
@@ -209,6 +247,17 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
209
247
  style = {[styles.datagrid,{width:listWidth,minWidth:totalWidths}]}
210
248
  keyExtractor = {typeof getRowKey =='function'? getRowKey : React.getKey}
211
249
  //stickyHeaderIndices={[0]}
250
+ onScroll = {getOnScrollCb([absoluteScrollViewRef],(args)=>{
251
+ const offset = args?.nativeEvent?.contentOffset.y;
252
+ const scrollViewRef = absoluteScrollViewRef.current?.scrollViewRef;
253
+ if(typeof offset =='number' && scrollViewRef.current && scrollViewRef.current.scrollTo){
254
+ absoluteScrollViewRefCanScroll.current = false;
255
+ scrollViewRef.current.scrollTo({animated:false,y:offset});
256
+ setTimeout(()=>{
257
+ absoluteScrollViewRefCanScroll.current = true;
258
+ },500);
259
+ }
260
+ })}
212
261
  renderItem = {(arg)=>{
213
262
  const item = arg.item, data = arg.item,allData=Array.isArray(item.items)? item.items : data;
214
263
  const cells = visibleColumns.map((i,index)=>{
@@ -237,11 +286,21 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
237
286
  </View>;
238
287
  }}
239
288
  />
289
+ <AbsoluteScrollView
290
+ ref={absoluteScrollViewRef}
291
+ scrollEventThrottle = {scrollEventThrottle}
292
+ onScroll = {(args)=>{
293
+ if(!absoluteScrollViewRefCanScroll.current) return;
294
+ const offset = args?.nativeEvent?.contentOffset.y;
295
+ if(typeof offset =='number' && listRef.current && listRef.current.scrollToOffset){
296
+ listRef.current.scrollToOffset({animated:true,offset});
297
+ }
298
+ }}
299
+ />
240
300
  </ScrollView>
241
301
  </View>
242
302
  });
243
303
 
244
-
245
304
  const ColumnType = PropTypes.shape({
246
305
  field : PropTypes.string,
247
306
  label : PropTypes.text,
@@ -364,19 +423,6 @@ TableComponent.popTypes = {
364
423
  footerScrollViewProps : PropTypes.object,
365
424
  }
366
425
 
367
- const ScrollViewCustom = React.forwardRef((props,ref)=>{
368
- const {testID,onScroll,style,handle} = props;
369
- const context = {};
370
- React.setRef(ref,context);
371
- return <View
372
- {...props}
373
- ref = {ref}
374
- style = {[styles.scrollViewCustom,style,{backgroundColor:theme.colors.primary}]}
375
- onScroll={onScroll}
376
- testID={(testID||'RN_TableComponentScrollViewCustom')}
377
- />
378
- });
379
- ScrollViewCustom.displayName = "TableComponentScrollViewCustom";
380
426
 
381
427
  TableComponent.displayName = "TableComponent";
382
428