@fto-consult/expo-ui 2.4.8 → 2.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.
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.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
  "@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",
@@ -8,7 +8,7 @@ import PropTypes from "prop-types";
8
8
  import {getContentHeight} from "./utils";
9
9
 
10
10
  const BottomSheetMenuComponent = React.forwardRef((props,ref)=>{
11
- let {anchor,screenIndent,height:customHeight,bindResizeEvent,onDismiss,testID,visible:customVisible,controlled,mobile,animateOnClose,renderMenuContent,sheet,children,...rest} = props;
11
+ let {anchor,anchorProps,screenIndent,height:customHeight,bindResizeEvent,onDismiss,testID,visible:customVisible,controlled,mobile,animateOnClose,renderMenuContent,sheet,children,...rest} = props;
12
12
  rest = defaultObj(rest);
13
13
  const isControlled = controlled ? true : false;
14
14
  const visibleRef = React.useRef(null);
@@ -44,12 +44,13 @@ const BottomSheetMenuComponent = React.forwardRef((props,ref)=>{
44
44
  setState({...state,visible:false})
45
45
  }
46
46
  const Component = isMob ? BottomSheet : Menu;
47
+ anchorProps = defaultObj(anchorProps);
47
48
  if(isMob){
48
49
  if(typeof anchor ==='function'){
49
50
  anchor = anchor(!isControlled?{onPress:open}:{});
50
51
  }
51
52
  if(React.isValidElement(anchor)){
52
- anchor = <View testID={testID+"_Anchor"} ref={anchorRef} collapsable={false}>{anchor}</View>
53
+ anchor = <View testID={testID+"_Anchor"} ref={anchorRef} {...anchorProps} collapsable={false}>{anchor}</View>
53
54
  }
54
55
  if(renderMenuContent !== false){
55
56
  children = renderItems({testID:testID+".Items",...props,closeMenu:close,openMenu:open,isBottomSheetItem:true});
@@ -101,6 +102,7 @@ const BottomSheetMenuComponent = React.forwardRef((props,ref)=>{
101
102
  height = {controlled?customHeight:height}
102
103
  ref = {React.useMergeRefs(innerRef,ref)}
103
104
  anchor = {anchor}
105
+ anchorProps = {anchorProps}
104
106
  children = {visible && (React.isValidElement(children) || Array.isArray(children))?children:undefined}
105
107
  />
106
108
  </>
@@ -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) : {};
@@ -381,7 +385,7 @@ const DatagridFactory = (Factory)=>{
381
385
  if(toggleFilters === false){
382
386
  filters = false;
383
387
  }
384
- let {showFilters,showFooter} = this.state;
388
+ let {showFilters,showFooters} = this.state;
385
389
  let max = this.getMaxSelectableRows();
386
390
  let restItems = [];
387
391
 
@@ -495,9 +499,9 @@ const DatagridFactory = (Factory)=>{
495
499
  closeOnPress : false,
496
500
  } : null,
497
501
  hasFooterFields ? {
498
- onPress : ()=>{showFooter?this.hideFooter():this.showFooter()}
499
- ,icon : showFooter?'view-column':'view-module'
500
- ,text : (showFooter?'Masquer/Ligne des totaux':'Afficher/Ligne des totaux')
502
+ onPress : ()=>{showFooters?this.hideFooter():this.showFooters()}
503
+ ,icon : showFooters?'view-column':'view-module'
504
+ ,text : (showFooters?'Masquer/Ligne des totaux':'Afficher/Ligne des totaux')
501
505
  }:null,
502
506
  ...restItems,
503
507
  this.canScrollTo() && {
@@ -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)}>
@@ -554,7 +557,7 @@ const DatagridFactory = (Factory)=>{
554
557
  />
555
558
  {datagridHeader}
556
559
  {_progressBar}
557
- {showFooter ? (
560
+ {showFooters ? (
558
561
  <View testID={testID+"_FooterContainer"} pointerEvents={pointerEvents} style={[{justifyContent:'center'}]}>
559
562
  <View testID={testID+"_FooterContentContainer"} style={[styles.footersContainer]}>
560
563
  <ScrollView testID={testID+"_FooterScrollView"} horizontal contentContainerStyle={[styles.contentContainerStyle]}>
@@ -564,6 +567,7 @@ const DatagridFactory = (Factory)=>{
564
567
  key = {field}
565
568
  testID={testID+"_FooterItem_"+field}
566
569
  {...footer}
570
+ anchorProps = {{style:[theme.styles.ph1,theme.styles.mh05]}}
567
571
  />
568
572
  })}
569
573
  </View>
@@ -591,7 +595,7 @@ const DatagridFactory = (Factory)=>{
591
595
  }:false}
592
596
  keyExtractor = {this.getRowKey.bind(this)}
593
597
  /> : <View style={styles.hasNotData}>
594
- {renderEmpty()}
598
+ {this.renderEmpty()}
595
599
  </View>}
596
600
  </View>}
597
601
  {backToTopRef ? <BackToTop testID={testID+"_BackToTop"} {...backToTopProps} ref={this.backToTopRef} style={[styles.backToTop,backToTopProps.style]} onPress={this.scrollToTop.bind(this)}/>:null}
@@ -71,13 +71,13 @@ export default class CommonDatagridComponent extends AppComponent {
71
71
  });
72
72
  selectedRows = sRows;
73
73
  let sData = this.getSessionData()
74
- sData.showFooter = defaultVal(sData.showFooter,true);
74
+ sData.showFooters = defaultVal(sData.showFooters,true);
75
75
  sData.fixedTable = defaultBool(sData.fixedTable,false);
76
76
  extendObj(this.state, {
77
77
  data,
78
78
  sort :defaultObj(props.sort),
79
79
  showFilters : defaultBool(props.showFilters,(sData.showFilter? true : this.isPivotDatagrid())),
80
- showFooter : defaultBool(props.showFooter,(sData.showFooter? true : false)),
80
+ showFooters : defaultBool(props.showFooters,(sData.showFooters? true : false)),
81
81
  fixedTable : sData.fixedTable
82
82
  });
83
83
  Object.defineProperties(this,{
@@ -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')
@@ -783,16 +784,16 @@ export default class CommonDatagridComponent extends AppComponent {
783
784
  }
784
785
 
785
786
 
786
- showFooter(){
787
+ showFooters(){
787
788
  if(!this._isMounted()) {
788
789
  this.isUpdating = false;
789
790
  return;
790
791
  }
791
792
  if(this.isUpdating) return false;
792
793
  this.isUpdating = true;
793
- this.setState( {showFooter:true},()=>{
794
+ this.setState( {showFooters:true},()=>{
794
795
  this.isUpdating = false;
795
- this.setSessionData({showFooter:true})
796
+ this.setSessionData({showFooters:true})
796
797
  })
797
798
  }
798
799
  hideFooter (){
@@ -801,9 +802,9 @@ export default class CommonDatagridComponent extends AppComponent {
801
802
  return;
802
803
  }
803
804
  if(this.isUpdating) return false;
804
- this.setState({showFooter:false},()=>{
805
+ this.setState({showFooters:false},()=>{
805
806
  this.isUpdating = false;
806
- this.setSessionData({showFooter:false});
807
+ this.setSessionData({showFooters:false});
807
808
  })
808
809
  }
809
810
 
@@ -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);
@@ -891,14 +899,18 @@ export default class CommonDatagridComponent extends AppComponent {
891
899
  let colFilter = defaultVal(restCol.filter,true);
892
900
  field = header.field = defaultStr(header.field,field,headerIndex);
893
901
  delete restCol.filter;
902
+
903
+ const type = defaultStr(header.type).toLowerCase();
904
+ sortType = defaultStr(sortType,type).toLowerCase();
894
905
  width = defaultDecimal(width);
895
906
  if(width <COLUMN_WIDTH/2){
896
907
  width = COLUMN_WIDTH;
897
908
  }
898
- const type = defaultStr(header.type).toLowerCase();
899
- sortType = defaultStr(sortType,type).toLowerCase();
900
909
  if(type.contains("date")|| type.contains("time")){
901
- width = Math.max(width,DATE_COLUMN_WIDTH);
910
+ const mWidth = type.toLowerCase().contains('datetime')? (DATE_COLUMN_WIDTH+30) : DATE_COLUMN_WIDTH;
911
+ width = Math.max(width,mWidth);
912
+ } else if((type.contains("number") || type.contains("decimal") && this.props.format)){
913
+ width = Math.max(width,DATE_COLUMN_WIDTH-30);
902
914
  }
903
915
  totalWidths +=width;
904
916
  widths[header.field] = width;
@@ -945,6 +957,17 @@ export default class CommonDatagridComponent extends AppComponent {
945
957
  delete restCol.sortable;
946
958
  filterProps = {
947
959
  ...restCol,
960
+ columnIndex,
961
+ visibleColumnIndex,
962
+ sortable:isColumnSortable,
963
+ sorted:isColumnSorted,
964
+ sortedColumn :sortedProps,///les props de la columns triée
965
+ sortedProps,
966
+ width,
967
+ columnField : field,
968
+ columnDef : header,
969
+ index : headerIndex,
970
+ visible,
948
971
  key : header.field,
949
972
  label : defaultStr(header.label,header.text),
950
973
  orOperator : filterOrOperator,
@@ -958,6 +981,7 @@ export default class CommonDatagridComponent extends AppComponent {
958
981
  operator : fCol.operator,
959
982
  action : defaultStr(fCol.originAction,fCol.action),
960
983
  };
984
+ this.currentFilteringColumns[header.field] = filterProps;
961
985
  this.prepareFilter(filterProps,headerFilters);
962
986
  }
963
987
  this.prepareColumn({
@@ -1169,19 +1193,15 @@ export default class CommonDatagridComponent extends AppComponent {
1169
1193
  onFilterChange(arg){
1170
1194
  this.filteredValues = defaultObj(this.filteredValues);
1171
1195
  let {field,operator,originAction,action,value} = defaultObj(arg);
1172
- const filters = this.preparedColumns.filters;
1173
- if(isNonNullString(field) && isNonNullString(operator) && isNonNullString(action)){
1196
+ const filter = isNonNullString(field)? this.currentFilteringColumns[field] : null;
1197
+ if(!isObj(filter)) return;
1198
+ if(isNonNullString(operator) && isNonNullString(action)){
1174
1199
  this.filteredValues[field] = {
1175
1200
  operator,action,value,field
1176
1201
  }
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
-
1202
+ filter.originValue = filter.defaultValue = arg.defaultValue;
1203
+ filter.operator = operator;
1204
+ filter.action = defaultStr(originAction,action);
1185
1205
  }
1186
1206
  return this.doFilter(arg);
1187
1207
  }
@@ -1705,7 +1725,7 @@ CommonDatagridComponent.propTypes = {
1705
1725
  /*** affiche ou masque les filtres */
1706
1726
  showFilters : PropTypes.bool,
1707
1727
  /*** si le pied de page sera affiché */
1708
- showFooter : PropTypes.bool,
1728
+ showFooters : PropTypes.bool,
1709
1729
  /*** les donnnées peuvent être soient retournées par une fonction, soit par un tableau soit une promesse */
1710
1730
  data : PropTypes.oneOfType([PropTypes.array, PropTypes.func,PropTypes.object]),//.isRequired,
1711
1731
  columns:PropTypes.oneOfType([PropTypes.array,PropTypes.object]),//.isRequired,
@@ -3,7 +3,7 @@ import Menu from "$ecomponents/BottomSheet/Menu";
3
3
  import View from "$ecomponents/View";
4
4
  import {Pressable,StyleSheet} from "react-native";
5
5
  import Label from "$ecomponents/Label";
6
- import {defaultVal} from "$utils";
6
+ import {defaultVal,defaultObj} from "$utils";
7
7
  import React from "$react";
8
8
  import theme from "$theme"
9
9
 
@@ -18,7 +18,9 @@ const formatValue = ({value,format,method})=>{
18
18
  return (format === 'money' && method != 'count')? value.formatMoney():value.formatNumber();
19
19
  }
20
20
  export default function DGGridFooterValue (props){
21
- let {label,text,displayLabel,style,format} = props;
21
+ let {label,text,displayLabel,style,format,testID,anchorProps} = props;
22
+ anchorProps = defaultObj(anchorProps);
23
+ testID = defaultStr(testID,"RN_DatagridFooterComponent");
22
24
  label = defaultVal(label,text);
23
25
  const defLabel = label;
24
26
  if(displayLabel !== false){
@@ -50,19 +52,19 @@ export default function DGGridFooterValue (props){
50
52
  }
51
53
  }
52
54
  return <Menu
55
+ testID = {testID+"_Menu"}
53
56
  items = {menuItems}
54
- style = {{minWidth:220}}
55
57
  title = {'Totaux de la colonne '+(defLabel?("[ "+defLabel+"]"):'')}
56
58
  animateOnClose
57
59
  anchor = {(p)=>{
58
- return <Pressable {...p} style={[styles.anchor,style,label?styles.row:null]} title={title}>
60
+ return <Pressable {...anchorProps} {...p} testID={testID} style={[styles.anchor,anchorProps.style,label?styles.row:null]} title={title}>
59
61
  {label ?
60
62
  <>
61
- <View><Label style={[styles.label]}>{label}</Label></View>
62
- <View><Label style = {styles.label}> : </Label></View>
63
+ <View testID={testID+"_Label"}><Label style={[styles.label]}>{label}</Label></View>
64
+ <View testID={testID+"_LabelPoint"}><Label style = {styles.label}> : </Label></View>
63
65
  </>
64
66
  : null}
65
- <Label primary style={[styles.value]}>
67
+ <Label testID={testID+"_LabelContent"} primary style={[styles.value]}>
66
68
  {formatValue({value:defaultDecimal(props[active]),method:active,format})}
67
69
  </Label>
68
70
  </Pressable>
@@ -75,11 +77,7 @@ const styles = StyleSheet.create({
75
77
  flexDirection : 'row',
76
78
  alignItems : 'center',
77
79
  },
78
- anchor : {
79
- paddingVertical : 10,
80
- marginHorizontal : 10,
81
- paddingHorizontal : 5,
82
- },
80
+ anchor : {},
83
81
  value : {
84
82
  fontWeight : 'bold'
85
83
  }
@@ -13,6 +13,7 @@ import React from "$react";
13
13
  import {Menu as BottomSheetMenu} from "$ecomponents/BottomSheet"
14
14
  import RenderType from "../RenderType";
15
15
  import Footer from "../Footer/Footer";
16
+ import theme from "$theme";
16
17
  import Table from "$ecomponents/Table";
17
18
 
18
19
 
@@ -62,41 +63,23 @@ const DatagridFactory = (Factory)=>{
62
63
  }
63
64
  return null;
64
65
  }
65
- renderHeaderCell(props){
66
- let ret = super.renderHeaderCell(props);
67
- const {columnField,columnDef,style} = props;
68
- if(this.state.showFilters){
69
- const filterC = this.customFilteredColumns[columnField];
70
- if(isObj(filterC)){
71
- return <View testID={"RN_DatagridTableComponent_HeaderField_"+columnField} style={[style,{minHeight:100}]}>
72
- {ret}
73
- <Filter
74
- {...filterC}
75
- withLabel = {false}
76
- style = {[styles.filter,style]}
77
- anchorProps ={{size:20}}
78
- inputProps = {{
79
- style : [styles.filter,style]
80
- }}
81
- />
82
- </View>
83
- }
84
- }
85
- return ret;
86
- }
87
- beforePrepareColumns(){
88
- this.customFilteredColumns = {};
89
- }
90
- prepareColumn({filterProps,columnField,columnDef,key,field,visible,filter},filters){
91
- this.customFilteredColumns = defaultObj(this.customFilteredColumns);
92
- if(visible){
93
- if(filter){
94
- this.customFilteredColumns[columnField] = filterProps;
95
- } else {
96
- this.customFilteredColumns[columnField] = null;
97
- }
66
+ renderFilterCell(props){
67
+ const {columnField,style} = props;
68
+ const filterC = this.currentFilteringColumns[columnField];
69
+ if(isObj(filterC)){
70
+ return <Filter
71
+ {...filterC}
72
+ withLabel = {false}
73
+ style = {[styles.filter,theme.styles.pv0,theme.styles.mv0]}
74
+ anchorProps ={{size:20}}
75
+ mode = "flat"
76
+ inputProps = {{
77
+ style : [styles.filter],
78
+ mode : "flat",
79
+ }}
80
+ />
98
81
  }
99
- return filters;
82
+ return null;
100
83
  }
101
84
  updateLayout(e){
102
85
  if(this.state.fixedTable === false) return;
@@ -176,7 +159,7 @@ const DatagridFactory = (Factory)=>{
176
159
  })*/
177
160
  const {visibleColumns} = this.preparedColumns;
178
161
  const hasFooterFields = this.hasFooterFields();
179
- const {columnsWidths:widths,showFilters,showFooter} = this.state;
162
+ const {columnsWidths:widths,showFilters,showFooters} = this.state;
180
163
  let isAllRowsSelected = this.isAllRowsSelected();
181
164
  const isLoading = this.isLoading();
182
165
  let _progressBar = this.getProgressBar();
@@ -227,10 +210,10 @@ const DatagridFactory = (Factory)=>{
227
210
  {hasFooterFields ? <Button
228
211
  normal
229
212
  style={styles.paginationItem}
230
- onPress = {()=>{showFooter?this.hideFooter():this.showFooter()} }
231
- icon = {showFooter?'view-column':'view-module'}
213
+ onPress = {()=>{showFooters?this.hideFooter():this.showFooters()} }
214
+ icon = {showFooters?'view-column':'view-module'}
232
215
  >
233
- {showFooter?'Masquer/Ligne des totaux':'Afficher/Ligne des totaux'}
216
+ {showFooters?'Masquer/Ligne des totaux':'Afficher/Ligne des totaux'}
234
217
  </Button>:null}
235
218
  {selectableMultiple && (<>
236
219
  {restItems.map((item,index)=>{
@@ -287,9 +270,9 @@ const DatagridFactory = (Factory)=>{
287
270
  ,text : (showFilters?'Masquer/Filtres':'Afficher/Filtres')
288
271
  } : null,
289
272
  isMobile && hasFooterFields?{
290
- onPress : ()=>{showFooter?this.hideFooter():this.showFooter()}
291
- ,icon : showFooter?'view-column':'view-module'
292
- ,text : (showFooter?'Masquer/Ligne des totaux':'Afficher/Ligne des totaux')
273
+ onPress : ()=>{showFooters?this.hideFooter():this.showFooters()}
274
+ ,icon : showFooters?'view-column':'view-module'
275
+ ,text : (showFooters?'Masquer/Ligne des totaux':'Afficher/Ligne des totaux')
293
276
  } : null,
294
277
  ...(selectableMultiple ? restItems : [])
295
278
  ] : visibleColumns}
@@ -340,7 +323,7 @@ const DatagridFactory = (Factory)=>{
340
323
  ref = {this.listRef}
341
324
  hasFooters = {hasFooterFields}
342
325
  showFilters = {showFilters}
343
- showFooters = {showFooter}
326
+ showFooters = {showFooters}
344
327
  headerContainerProps = {{}}
345
328
  headerCellContainerProps = {{
346
329
  style : showFilters?{justifyContent:'flex-start'}:null
@@ -358,7 +341,9 @@ const DatagridFactory = (Factory)=>{
358
341
  }}
359
342
  data = {this.state.data}
360
343
  renderHeaderCell={this.renderHeaderCell.bind(this)}
344
+ renderFilterCell={this.renderFilterCell.bind(this)}
361
345
  renderFooterCell={this.renderFooterCell.bind(this)}
346
+ renderEmpty = {this.renderEmpty.bind(this)}
362
347
  />
363
348
  </View>
364
349
  }
@@ -440,8 +425,10 @@ const styles = StyleSheet.create({
440
425
  maxHeight : 40,
441
426
  height : 40,
442
427
  width : "100%",
428
+ alignSelf : 'flex-start',
443
429
  flexGrow : 1,
444
430
  minHeight : 40,
431
+ backgroundColor : 'transparent'
445
432
  },
446
433
  layoutContent : {
447
434
  maxWidth : '100%',
@@ -166,7 +166,7 @@ const DatePickerInput = React.forwardRef(({
166
166
  onChange({dateObject:state.inputDate,date:state.inputDate,sqlDate:date,value:date})
167
167
  }
168
168
  },[state])
169
- const labelText = render_filter ? label : withLabel!==false ? getLabel({ label, inputFormat:inputFormatLabel, withDateFormatInLabel }):"";
169
+ const labelText = withLabel === false ? null: (render_filter ? label : getLabel({ label, inputFormat:inputFormatLabel, withDateFormatInLabel }));
170
170
  return (
171
171
  <>
172
172
  <TextField
@@ -13,7 +13,7 @@ import { toDateObj } from "./utils";
13
13
  import TextField from "$components/TextField";
14
14
  import PeriodActionComponent from "./PeriodAction";
15
15
 
16
- export default function DateTimePickerComponent({left,isPeriodAction,withSeconds,right,format,dateFormat,timeFormat,defaultValue,onChange,testID,dateProps,disabled,readOnly,timeProps,...rest}){
16
+ export default function DateTimePickerComponent({left,isPeriodAction,contentProps,withSeconds,right,format,dateFormat,timeFormat,defaultValue,onChange,testID,dateProps,disabled,readOnly,timeProps,...rest}){
17
17
  if(!isPeriodAction){
18
18
  isPeriodAction = isNonNullString(defaultValue) && defaultValue.contains("=>");
19
19
  }
@@ -28,6 +28,7 @@ export default function DateTimePickerComponent({left,isPeriodAction,withSeconds
28
28
  }
29
29
  dateProps = defaultObj(dateProps);
30
30
  timeProps = defaultObj(timeProps);
31
+ contentProps = defaultObj(contentProps);
31
32
  testID = defaultStr(testID,"RN_DateTimeComponent")
32
33
  const anchorTimeProps = defaultObj(timeProps.anchorProps);
33
34
  const timePropsContainerProps = defaultObj(timeProps.containerProps);
@@ -52,8 +53,8 @@ export default function DateTimePickerComponent({left,isPeriodAction,withSeconds
52
53
  const timeDefaultValue = getTimeValue(dateObj);
53
54
  const changedTimeArgsRef = {current:{...defaultObj(parseTime(timeDefaultValue,withSeconds))}};
54
55
  withSeconds = defaultBool(timeProps.withSeconds,withSeconds,true);
55
-
56
- const maxWidth = 120;//withSeconds ? 120 : 120;
56
+ const cStyle = [theme.styles.noPadding,theme.styles.noMargin];
57
+ const maxWidth = 110;
57
58
  const callOnChange = ()=>{
58
59
  if(onChange){
59
60
  const dObj = changeDateArgsRef.current;
@@ -71,6 +72,8 @@ export default function DateTimePickerComponent({left,isPeriodAction,withSeconds
71
72
  onChange(args);
72
73
  }
73
74
  }
75
+ const tInputProps = defaultObj(timeProps.inputProps);
76
+ const dStyle = flattenStyle([rest.style,dateProps.style]);
74
77
  return <DateComponent
75
78
  defaultValue = {dateObj}
76
79
  disabled = {disabled}
@@ -79,7 +82,7 @@ export default function DateTimePickerComponent({left,isPeriodAction,withSeconds
79
82
  {...rest}
80
83
  format = {dateFormat}
81
84
  {...dateProps}
82
- style = {[rest.style,dateProps.style]}
85
+ style = {dStyle}
83
86
  calendarIconBefore = {true}
84
87
  onChange = {(args)=>{
85
88
  changeDateArgsRef.current = args;
@@ -102,15 +105,17 @@ export default function DateTimePickerComponent({left,isPeriodAction,withSeconds
102
105
  }}
103
106
  withLabel = {false}
104
107
  mode = {"flat"}
105
- containerProps = {{...timePropsContainerProps,style:[{maxWidth},timePropsContainerProps.style]}}
108
+ contentProps = {{style:cStyle}}
109
+ containerProps = {{...timePropsContainerProps,style:[{maxWidth},theme.styles.noPadding,theme.styles.noMargin,timePropsContainerProps.style]}}
106
110
  divider = {false}
111
+ style = {[theme.styles.noPadding,{maxHeight:40},theme.styles.noMargin,timeProps.style,dStyle.backgroundColor && {backgroundColor:dStyle.backgroundColor}]}
107
112
  anchorProps = {{
108
113
  ...anchorTimeProps,
109
114
  testID:testID+"_TimeAnchor",
110
115
  style : [theme.styles.noPadding,{borderRadius:0},theme.styles.noMargin,anchorTimeProps.style]
111
116
  }}
112
117
  inputProps = {{
113
- ...defaultObj(timeProps.inputProps),
118
+ ...tInputProps,
114
119
  mode : "flat",
115
120
  }}
116
121
  />
@@ -44,8 +44,9 @@ export const timeToString = (value,withSeconds)=>{
44
44
  return value.substring(0,5);
45
45
  }
46
46
  export default function TimePickerComponent (props){
47
- let {right:customRight,upper,anchorProps,dialogProps,withLabel,containerProps,mode,onChange,withSeconds,cancelLabel,confirmLabel,label,text,upperCase,defaultValue,disabled,editable,withModal,readOnly,...rest} = props;
47
+ let {right:customRight,upper,anchorProps,dialogProps,withLabel,inputProps,containerProps,mode,onChange,withSeconds,cancelLabel,confirmLabel,label,text,upperCase,defaultValue,disabled,editable,withModal,readOnly,...rest} = props;
48
48
  rest = defaultObj(rest);
49
+ inputProps = defaultObj(inputProps);
49
50
  const isEditable = disabled !== true && readOnly !== true && editable !== false?true : false;
50
51
  withModal = defaultBool(withModal,true);
51
52
  if(!isEditable){
@@ -110,6 +111,7 @@ export default function TimePickerComponent (props){
110
111
  if(!disabled){
111
112
  containerProps.style = [containerProps.style,{opacity:1}]
112
113
  }
114
+ const iContainerProps = defaultObj(inputProps.containerProps);
113
115
  return <>
114
116
  <TouchableRipple {...containerProps}
115
117
  disabled = {!isEditable}
@@ -120,6 +122,8 @@ export default function TimePickerComponent (props){
120
122
  <TextField
121
123
  mode = {mode||theme.textFieldMode}
122
124
  {...rest}
125
+ {...inputProps}
126
+ containerProps = {{...iContainerProps,style:[containerProps.style,iContainerProps.style]}}
123
127
  label = {label}
124
128
  right = {right}
125
129
  disabled = {disabled}
@@ -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)=>{
@@ -745,9 +745,10 @@ class DropdownComponent extends AppComponent {
745
745
  const inputRest = {disabled,editable,label,error}
746
746
  clearTimeout(this.doSearchFilter);
747
747
  this.doSearchFilter = null;
748
-
748
+ mode = defaultStr(mode,inputProps.mode);
749
749
  const textInputProps = {
750
750
  ...inputRest,
751
+ mode,
751
752
  editable,disabled,
752
753
  style : StyleSheet.flatten([styles.input,inputProps.style])
753
754
  }
@@ -840,8 +841,7 @@ class DropdownComponent extends AppComponent {
840
841
  }
841
842
  helperText = <HelperText disabled = {disabled} error={error}>{helperText}</HelperText>
842
843
  let labelTextField = defaultVal(label,text);
843
-
844
- const isFlatMode = textInputProps.mode === flatMode;
844
+ const isFlatMode = textInputProps.mode === flatMode;
845
845
  let backgroundColor = Colors.isValid(textInputProps.style.backgroundColor)?textInputProps.style.backgroundColor : Colors.isValid(flattenStyle.backgroundColor)? flattenStyle.backgroundColor : theme.colors.surface;
846
846
  const tagLabelStyle = {backgroundColor,color:Colors.setAlpha(theme.colors.text,theme.ALPHA)}
847
847
  if(!isFlatMode && backgroundColor ==='transparent'){
@@ -904,9 +904,9 @@ class DropdownComponent extends AppComponent {
904
904
  defaultValue={selectedText}
905
905
  autoHeight = {renderTag}
906
906
  useReadOnlyOpacity = {false}
907
- mode = {mode}
908
907
  {...inputProps}
909
908
  {...textInputProps}
909
+ mode = {mode}
910
910
  enableCopy = {enableCopy}
911
911
  label = {labelTextField}
912
912
  pointerEvents = "none"
@@ -1270,7 +1270,6 @@ DropdownComponent.propTypes = {
1270
1270
  onUnmount : PropTypes.func,
1271
1271
  label : PropTypes.string,
1272
1272
  placeholder : PropTypes.string,
1273
- mode : PropTypes.oneOf(["outlined", "flat"]),
1274
1273
  inputProps : PropTypes.object,
1275
1274
  selectedColor:PropTypes.string,
1276
1275
  accessibilityLabel : PropTypes.string,
@@ -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){
@@ -24,6 +24,7 @@ export * from "./utils";
24
24
 
25
25
  const _actions = {
26
26
  '$eq' : 'Egal à',
27
+ "$ne" : 'Défférent de',
27
28
  '$gt' : 'Supérieur à',
28
29
  '$gte' : 'Supérieur ou égal',
29
30
  '$lt' : 'Inférieur à',
@@ -135,6 +136,10 @@ export default class Filter extends AppComponent {
135
136
  this.props.onValidate({...this.getStateValues(),field:this.props.name,...arg})
136
137
  }
137
138
  }
139
+ isDecimal(){
140
+ const t = defaultStr(this.type,this.props.type).toLowerCase();
141
+ return t =="number" || t =='decimal' ? true : false;
142
+ }
138
143
  onFilterValidate(arg){
139
144
  arg = defaultObj(arg);
140
145
  if(JSON.stringify(this.state.defaultValue) === JSON.stringify(arg.value)){
@@ -190,11 +195,15 @@ export default class Filter extends AppComponent {
190
195
  value = undefined;
191
196
  }
192
197
  let originValue = value;
193
- const type = defaultStr(this.props.type).toLowerCase().trim();
194
- value = parseDecimal(value,type);
195
198
  if(action =="$today" || action =='$yesterday'){
196
199
  force = true;
197
200
  }
201
+ if(this.isDecimal()){
202
+ value = parseDecimal(value)
203
+ if(value == 0){
204
+ value = undefined;
205
+ }
206
+ }
198
207
  const prev = JSON.stringify(defaultObj(this.previousRef.current)), current = {value,operator,action,ignoreCase};
199
208
  let tV = isArray(value) && value.length <= 0 ? undefined : value;
200
209
  this.isInitializedRef.current = this.props.dynamicRendered || this.isInitializedRef.current;
@@ -290,8 +299,7 @@ export default class Filter extends AppComponent {
290
299
  if(data.start && data.end && data.start> data.end){
291
300
  return notify.error("La date de fin doit être supérieure à la date de début");
292
301
  }
293
- console.log(data," is dataa")
294
- if(isFunction(success)){
302
+ if(isFunction(success)){
295
303
  success(data.start+"=>"+data.end);
296
304
  }
297
305
  DialogProvider.close();
@@ -324,7 +332,7 @@ export default class Filter extends AppComponent {
324
332
  diff = DateLib.currentMonthDaysLimits(currentDate);
325
333
  break;
326
334
  case "$week":
327
- diff = DateLib.currentWeekDaysLimits(currentDate)
335
+ diff = DateLib.currentWeekDaysLimits(currentDate);
328
336
  break;
329
337
  case "$prevWeek":
330
338
  diff = DateLib.previousWeekDaysLimits(currentDate)
@@ -382,8 +390,8 @@ export default class Filter extends AppComponent {
382
390
  field,
383
391
  style,
384
392
  anchorProps,
385
- mode,
386
- inputProps,
393
+ //mode,
394
+ //inputProps,
387
395
  moreOptions,
388
396
  isLoading,
389
397
  searchIconTooltip,
@@ -471,6 +479,7 @@ export default class Filter extends AppComponent {
471
479
  }
472
480
  anchorProps = defaultObj(anchorProps);
473
481
  rest.anchorProps = anchorProps;
482
+ rest.withLabel = withLabel;
474
483
  rest.pointerEvents = "auto";
475
484
  rest.right = isLoading ? <ActivityIndicator color={theme.colors.secondaryOnSurface} animating/> :<>
476
485
  <Menu
@@ -556,7 +565,7 @@ export default class Filter extends AppComponent {
556
565
  if(ignoreDefaultValue) {
557
566
  rest.isPeriodAction = true;
558
567
  }
559
- return <View testID={testID+"_FilterContainer"} {...containerProps} style={[theme.styles.w100,containerProps.style]}>
568
+ return <View testID={testID+"_FilterContainer"} {...containerProps} style={StyleSheet.flatten([theme.styles.w100,containerProps.style])}>
560
569
  <Component
561
570
  {...rest}
562
571
  readOnly = {ignoreDefaultValue}
@@ -0,0 +1,91 @@
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,isNumber} from "$utils";
8
+ import Portal from "$ecomponents/Portal";
9
+ import {isMobileNative,isTouchDevice} from "$platform";
10
+
11
+ const isNative = isMobileNative() || isTouchDevice();
12
+ const AbsoluteScrollView = React.forwardRef(({testID,contentProps,listRef,containerProps,...props},ref)=>{
13
+ if(isNative) return null;
14
+ containerProps = defaultObj(containerProps);
15
+ contentProps = defaultObj(contentProps);
16
+ const win = useWindowDimensions();
17
+ const scrollViewRef = React.useRef(null);
18
+ testID = defaultStr(testID,"RN_TableAbsoluteScrollViewComponent");
19
+ const [state,setState] = React.useState({
20
+ styles : {},
21
+ visible : true,
22
+ })
23
+ const {styles,visible} = state,setStyles = (s)=>{
24
+ if(isObj(s)){
25
+ setState({...state,styles:{...styles,...s}});
26
+ }
27
+ },toggleVisible = ()=>{
28
+ if(isObj(styles.content) && isObj(styles.container)){
29
+ const visible = isNumber(styles.content.height) && isNumber(styles.container.height) && (styles.content.height-20)> styles.container.height? true : false;
30
+ if(visible != state.visible){
31
+ setState({...state,visible});
32
+ }
33
+ }
34
+ }
35
+ React.setRef(ref,{
36
+ setStyles,
37
+ checkVisibility : (args)=>{
38
+ args = defaultObj(args);
39
+ if(isObj(args.contentOffset) && isObj(args.contentSize)){
40
+ const {x} = args.contentOffset;
41
+ const visible = x >=win.width ? false : true;
42
+ if(state.visible != visible){
43
+ return setState({...state,visible});
44
+ }
45
+ }
46
+ return toggleVisible();
47
+ },
48
+ scrollViewRef
49
+ });
50
+ React.useEffect(()=>{
51
+ return ()=>{
52
+ React.setRef(ref,null);
53
+ }
54
+ },[]);
55
+ React.useEffect(()=>{
56
+ toggleVisible();
57
+ },[styles])
58
+ return <Portal>
59
+ {<View testID={testID+"_Containter"} {...containerProps} style={[mainStyles.container,containerProps.style,styles.container,{left:win.width-10},!visible &&{display:'none',width:0,opacity:0}]}>
60
+ <ScrollView
61
+ {...props}
62
+ ref = {scrollViewRef}
63
+ testID={testID}
64
+ contentContainerStyle = {[props.contentContainerStyle,mainStyles.contentContainer,styles.containerContainer]}
65
+ vertical
66
+ >
67
+ <View
68
+ testID={testID+"Content"}
69
+ {...contentProps}
70
+ style={[mainStyles.content,contentProps.style,styles.content]}
71
+ />
72
+ </ScrollView>
73
+ </View>}
74
+ </Portal>
75
+ });
76
+
77
+ export default AbsoluteScrollView;
78
+
79
+ const mainStyles = StyleSheet.create({
80
+ container : {
81
+ ...StyleSheet.absoluteFill,
82
+ width : 10,
83
+ },
84
+ content : {
85
+ width:10,
86
+ },
87
+ contentContainer : {
88
+
89
+ }
90
+ })
91
+ 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,19 +20,29 @@ 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
  }
32
44
 
33
- const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScrollViewProps,footerScrollViewProps,scrollViewProps,showFooters,renderFooterCell,footerCellContainerProps,headerContainerProps,headerCellContainerProps,headerProps,rowProps:customRowProps,renderCell,cellContainerProps,hasFooters,renderHeaderCell,columnProps,getRowKey,columnsWidths,colsWidths,footerContainerProps,showFilters,columns,data,testID,...props},tableRef)=>{
45
+ const TableComponent = React.forwardRef(({containerProps,renderEmpty,isRowSelected,headerScrollViewProps,footerScrollViewProps,scrollViewProps,showFooters,renderFooterCell,footerCellContainerProps,filterCellContainerProps,headerContainerProps,headerCellContainerProps,headerProps,rowProps:customRowProps,renderCell,cellContainerProps,hasFooters,renderHeaderCell,renderFilterCell,columnProps,getRowKey,columnsWidths,colsWidths,footerContainerProps,showFilters,columns,data,testID,...props},tableRef)=>{
34
46
  containerProps = defaultObj(containerProps);
35
47
  testID = defaultStr(testID,"RN_TableComponent");
36
48
  cellContainerProps = defaultObj(cellContainerProps);
@@ -41,13 +53,14 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
41
53
  const getRowProps = typeof rowProps ==='function'? rowProps : undefined;
42
54
  let rowProps = isObj(customRowProps)? customRowProps:{};
43
55
  const prepareState = React.useCallback(()=>{
44
- const cols = {},headers = {},footers = {},visibleColumns = [];
56
+ const cols = {},headers = {},footers = {},filters = {},visibleColumns = [];
45
57
  let hasFooters = false;
46
58
  columnProps = defaultObj(columnProps);
47
59
  let columnIndex = 0;
48
60
  const widths = defaultObj(columnsWidths,colsWidths);
49
61
  headerCellContainerProps = defaultObj(headerCellContainerProps);
50
62
  footerCellContainerProps = defaultObj(footerCellContainerProps);
63
+ filterCellContainerProps = defaultObj(filterCellContainerProps);
51
64
  Object.map(columns,(columnDef,field)=>{
52
65
  if(!isObj(columnDef) /*|| columnDef.visible === false*/) return;
53
66
  const columnField = defaultStr(columnDef.field,field);
@@ -73,6 +86,12 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
73
86
  headers[columnField] = <View testID={testID+"_HeaderCell_"+columnField} {...headerCellContainerProps} {...hContainerProps} key={columnField} style={[styles.headerItem,styles.headerItemOrCell,headerCellContainerProps.style,hContainerProps.style,style]}>
74
87
  <Label textBold primary>{content}</Label>
75
88
  </View>;
89
+ if(typeof renderFilterCell =='function'){
90
+ const filterCell = renderFilterCell(colArgs);
91
+ filters[columnField] = <View testID={testID+"_Filter_Cell_"+columnField} {...filterCellContainerProps} key={columnField} style={[styles.headerItem,styles.headerItemOrCell,styles.filterCell,filterCellContainerProps.style,style]}>
92
+ {React.isValidElement(filterCell)? filterCell : null}
93
+ </View>
94
+ }
76
95
  if(typeof renderFooterCell ==='function') {
77
96
  const footerProps = {...colArgs,containerProps:{}};
78
97
  let cellFooter = renderFooterCell(footerProps);
@@ -87,7 +106,7 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
87
106
  if(!hasFooters && cellFooter){
88
107
  hasFooters = true;
89
108
  }
90
- footers[columnField] = <View testID={testID+"_Footer_Cell_"+columnField} {...fContainerProps} key={columnField} style={[styles.headerItem,styles.headerItemOrCell,footerCellContainerProps.style,fContainerProps.style,style]}>
109
+ footers[columnField] = <View testID={testID+"_Footer_Cell_"+columnField} key={columnField} style={[styles.headerItem,styles.headerItemOrCell,footerCellContainerProps.style,style]}>
91
110
  <Label primary children={cellFooter}/>
92
111
  </View>
93
112
  }
@@ -104,7 +123,7 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
104
123
  }
105
124
  columnIndex++;
106
125
  });
107
- return {columns:cols,visibleColumns,headers,hasFooters,footers};
126
+ return {columns:cols,visibleColumns,headers,hasFooters,footers,filters};
108
127
  },[columns,data]);
109
128
  const [state,setState] = React.useState({
110
129
  headers : {},
@@ -117,11 +136,13 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
117
136
  React.useEffect(()=>{
118
137
  setState({...state,...prepareState()});
119
138
  },[data,columns]);
120
- const {visibleColumns,columns:cols,headers,footers} = state;
139
+ const emptyData = typeof renderEmpty =='function' && !Object.size(data,true)? renderEmpty() : null;
140
+ const hasEmptyData = emptyData && React.isValidElement(emptyData);
141
+ const {visibleColumns,columns:cols,headers,footers,filters} = state;
121
142
  headerContainerProps = defaultObj(headerContainerProps);
122
143
  footerContainerProps = defaultObj(footerContainerProps);
123
144
  let hProps = typeof headerProps =='function'? hProps({columns:col,visibleColumns}) : {};
124
- const h = [],f = [];
145
+ const h = [],f = [],fFilters = [];
125
146
  let totalWidths = 0;
126
147
  visibleColumns.map((i)=>{
127
148
  if(!isObj(cols[i])) return;
@@ -130,6 +151,9 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
130
151
  if(showFooters && state.hasFooters){
131
152
  f.push(footers[i]);
132
153
  }
154
+ if(showFilters && filters[i]){
155
+ fFilters.push(filters[i]);
156
+ }
133
157
  });
134
158
  const scrollContentContainerStyle = {flex:1,width:listWidth,minWidth:totalWidths,height:'100%'};
135
159
  const scrollEventThrottle = isMobileNative()?200:50;
@@ -138,7 +162,7 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
138
162
  scrollEventThrottle,
139
163
  horizontal : true,
140
164
  ...scrollViewProps,
141
- style : [{maxHeight:120},scrollViewProps.style],
165
+ style : [scrollViewProps.style],
142
166
  contentContainerStyle : [styles.scrollView,scrollViewProps.contentContainerStyle,scrollViewFlexGrow,scrollContentContainerStyle]
143
167
  }
144
168
  const listWidth = '100%';
@@ -175,13 +199,19 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
175
199
  const hContent = h.length ? <View testID={testID+"_Header"}{...hProps} {...headerContainerProps} style={[styles.header,headerContainerProps.style,hProps.style,f.length]}>
176
200
  {h}
177
201
  </View> : null,
178
- fContent = f.length ? <View testID={testID+"_Footer"} {...footerContainerProps} style={[styles.header,styles.footers,footerContainerProps.style]}>
202
+ fContent = f.length ? <View testID={testID+"_Footer"} {...footerContainerProps} style={[styles.header,styles.footers,footerContainerProps.style,theme.styles.pt0,theme.styles.pb0,theme.styles.ml0,theme.styles.mr0]}>
179
203
  {f}
180
- </View> : null;
204
+ </View> : null,
205
+ filtersContent = fFilters.length ? <View testID={testID+"_Filters"} style={[styles.header,styles.footers,theme.styles.pt0,theme.styles.pb0,theme.styles.ml0,theme.styles.mr0]}>
206
+ {fFilters}
207
+ </View> : null
208
+
209
+ const absoluteScrollViewRefCanScroll = React.useRef(true);
181
210
  React.setRef(tableRef,context);
182
211
  const cStyle = {width:listWidth}
183
- return <View testID= {testID+"_Container"} {...containerProps} style={[styles.container,{alignItems:'stretch'},containerProps.style]}>
184
- <View autoHeight style={[cStyle]} testID={testID+"_Headers_ScrollViewContainer"}>
212
+ const absoluteScrollViewRef = React.useRef(null);
213
+ return <View testID= {testID+"_Container"} {...containerProps} style={[styles.container,{alignItems:'stretch'},containerProps.style,theme.styles.pl0,theme.styles.pr0]}>
214
+ <RNView style={[cStyle]} testID={testID+"_Headers_ScrollViewContainer"}>
185
215
  <ScrollView
186
216
  testID={testID+"_HeaderScrollView"}
187
217
  {...headerScrollViewProps}
@@ -191,15 +221,49 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
191
221
  onScroll = {getOnScrollCb([scrollViewRef,footerScrollViewRef])}
192
222
  showsHorizontalScrollIndicator
193
223
  >
194
- {hContent}
224
+ <View testID={testID+"Header2FootersWrapper"} style={[theme.styles.w100]}>
225
+ {hContent}
226
+ {filtersContent}
227
+ {fContent}
228
+ </View>
195
229
  </ScrollView>
196
- </View>
197
- <ScrollView {...scrollViewProps} scrollEventThrottle = {scrollEventThrottle} horizontal contentContainerStyle={[scrollContentContainerStyle,scrollViewProps.contentContainerStyle]} showsVerticalScrollIndicator={false} onScroll = {getOnScrollCb([headerScrollViewRef,footerScrollViewRef])} ref={scrollViewRef} testID={testID+"_ScrollView"}>
230
+ </RNView>
231
+ {hasEmptyData ? <View testID={testID+"_Empty"} style={styles.hasNotData}>
232
+ {emptyData}
233
+ </View> : <ScrollView {...scrollViewProps} scrollEventThrottle = {scrollEventThrottle} horizontal contentContainerStyle={[scrollContentContainerStyle,scrollViewProps.contentContainerStyle]} showsVerticalScrollIndicator={false}
234
+ onScroll = {getOnScrollCb([headerScrollViewRef,footerScrollViewRef],null,(args)=>{
235
+ const nativeEvent = args.nativeEvent;
236
+ if(absoluteScrollViewRef.current && absoluteScrollViewRef.current.checkVisibility){
237
+ absoluteScrollViewRef.current.checkVisibility(nativeEvent);
238
+ }
239
+ })} ref={scrollViewRef} testID={testID+"_ScrollView"}>
198
240
  <FlashList
199
241
  containerProps = {{style:[cStyle]}}
200
242
  //prepareItems = {Array.isArray(items)? false : undefined}
201
243
  estimatedItemSize = {200}
202
244
  {...props}
245
+ onContentSizeChange = {(width,height)=>{
246
+ if(props.onContentSizeChange){
247
+ props.onContentSizeChange(width,height);
248
+ }
249
+ if(!absoluteScrollViewRef.current) return;
250
+ absoluteScrollViewRef.current.setStyles({
251
+ content : {height,width}
252
+ });
253
+ }}
254
+ onLayout = {(args)=>{
255
+ if(props.onLayout){
256
+ props.onLayout(args);
257
+ }
258
+ if(!absoluteScrollViewRef.current) return;
259
+ const {nativeEvent:{layout}}=args;
260
+ const top = defaultNumber(layout.top,layout.y);
261
+ const height = layout.height;
262
+ absoluteScrollViewRef.current.setStyles({
263
+ container : {top,height},
264
+ contentContainer : {height},
265
+ });
266
+ }}
203
267
  ref = {listRef}
204
268
  numberOfLines = {1}
205
269
  responsive = {false}
@@ -209,6 +273,18 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
209
273
  style = {[styles.datagrid,{width:listWidth,minWidth:totalWidths}]}
210
274
  keyExtractor = {typeof getRowKey =='function'? getRowKey : React.getKey}
211
275
  //stickyHeaderIndices={[0]}
276
+ onScroll = {getOnScrollCb([absoluteScrollViewRef],(args)=>{
277
+ if(!absoluteScrollViewRef.current) return;
278
+ const offset = args?.nativeEvent?.contentOffset.y;
279
+ const scrollViewRef = absoluteScrollViewRef.current?.scrollViewRef;
280
+ if(typeof offset =='number' && scrollViewRef.current && scrollViewRef.current.scrollTo){
281
+ absoluteScrollViewRefCanScroll.current = false;
282
+ scrollViewRef.current.scrollTo({animated:false,y:offset});
283
+ setTimeout(()=>{
284
+ absoluteScrollViewRefCanScroll.current = true;
285
+ },500);
286
+ }
287
+ })}
212
288
  renderItem = {(arg)=>{
213
289
  const item = arg.item, data = arg.item,allData=Array.isArray(item.items)? item.items : data;
214
290
  const cells = visibleColumns.map((i,index)=>{
@@ -237,11 +313,23 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
237
313
  </View>;
238
314
  }}
239
315
  />
240
- </ScrollView>
316
+ <AbsoluteScrollView
317
+ ref={absoluteScrollViewRef}
318
+ listRef = {listRef}
319
+ scrollEventThrottle = {scrollEventThrottle}
320
+ onScroll = {(args)=>{
321
+ if(!absoluteScrollViewRefCanScroll.current) return;
322
+ const offset = args?.nativeEvent?.contentOffset.y;
323
+ if(typeof offset =='number' && listRef.current && listRef.current.scrollToOffset){
324
+ listRef.current.scrollToOffset({animated:true,offset});
325
+ }
326
+ }}
327
+ />
328
+ </ScrollView>}
329
+
241
330
  </View>
242
331
  });
243
332
 
244
-
245
333
  const ColumnType = PropTypes.shape({
246
334
  field : PropTypes.string,
247
335
  label : PropTypes.text,
@@ -299,6 +387,15 @@ const styles = StyleSheet.create({
299
387
  paddingHorizontal:5,
300
388
  paddingVertical : 0,
301
389
  },
390
+ filterCell : {
391
+ alignSelf : "flex-start",
392
+ textAlign : "left",
393
+ paddingHorizontal : 2,
394
+ paddingVertical : 0,
395
+ marginVertical : 0,
396
+ marginHorizontal : 0,
397
+ justifyContent : 'flex-start',
398
+ },
302
399
  headerItem: {
303
400
  minHeight: 30,
304
401
  },
@@ -318,14 +415,22 @@ const styles = StyleSheet.create({
318
415
  marginHorizontal : 0,
319
416
  marginVertical : 0,
320
417
  },
418
+ hasNotData : {
419
+ flexDirection : 'column',
420
+ width : '100%',
421
+ justifyContent : 'center',
422
+ alignItems : 'center'
423
+ }
321
424
  })
322
425
  TableComponent.popTypes = {
323
426
  containerProps : PropTypes.object,
324
427
  renderHeaderCell : PropTypes.func,
428
+ renderFilterCell : PropTypes.func,
325
429
  renderRow : PropTypes.func,
326
430
  renderCell : PropTypes.func,
327
431
  renderFooterCell : PropTypes.func,///la fonction appelée pour le rendu des entêtes du footer
328
432
  footerCellContainerProps : PropTypes.object,
433
+ filterCellContainerProps : PropTypes.object,
329
434
  footerContainerProps : PropTypes.object,
330
435
  showFilters : PropTypes.bool,
331
436
  showFooters : PropTypes.bool,
@@ -364,19 +469,6 @@ TableComponent.popTypes = {
364
469
  footerScrollViewProps : PropTypes.object,
365
470
  }
366
471
 
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
472
 
381
473
  TableComponent.displayName = "TableComponent";
382
474
 
@@ -244,12 +244,12 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
244
244
  if(isFocused || error){
245
245
  placeholderColor = labelColor;
246
246
  }
247
+ let labelText = React.isValidElement(label,true)?React.getTextContent(label):"";
247
248
  const defaultBackgroundColor = theme.surfaceBackgroundColor;
248
249
  let backgroundColor = Colors.isValid(flattenStyle.backgroundColor)? flattenStyle.backgroundColor : defaultBackgroundColor;
249
- if(backgroundColor ==='transparent' && dynamicBackgroundColor !== false){
250
+ if(labelText && (backgroundColor ==='transparent' && dynamicBackgroundColor !== false)){
250
251
  backgroundColor = defaultBackgroundColor;
251
252
  }
252
- let labelText = React.isValidElement(label,true)?React.getTextContent(label):"";
253
253
  placeholder = defaultStr(placeholder,labelText);
254
254
  const parsedValue = canValueBeDecimal ? parseValueToDecimal(text):text;
255
255
  const formattedValue = formatValue(text);