@fto-consult/expo-ui 2.20.0 → 2.21.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.20.0",
3
+ "version": "2.21.0",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -61,7 +61,7 @@
61
61
  "@emotion/native": "^11.10.0",
62
62
  "@expo/html-elements": "^0.2.0",
63
63
  "@expo/vector-icons": "^13.0.0",
64
- "@fto-consult/common": "^1.23.2",
64
+ "@fto-consult/common": "^1.23.9",
65
65
  "@gorhom/portal": "^1.0.14",
66
66
  "@react-native-async-storage/async-storage": "~1.17.3",
67
67
  "@react-native-community/datetimepicker": "6.5.2",
@@ -38,6 +38,40 @@ import View from "$ecomponents/View";
38
38
  import {Menu} from "$ecomponents/BottomSheet";
39
39
  import {styles as tableStyles} from "$ecomponents/Table";
40
40
  import {DialogProvider} from "$ecomponents/Form/FormData";
41
+ import Chart from "$ecomponents/Chart";
42
+
43
+ export const displayTypes = {
44
+ table : {
45
+ code : "table",
46
+ label : 'Tableau',
47
+ icon : "table",
48
+ type : 'table',
49
+ },
50
+ /*lineChart : {
51
+ code : 'lineChart',
52
+ label : 'Graphique|Linéaire',
53
+ icon : "chart-areaspline",
54
+ type : 'line',
55
+ },
56
+ areaChart : {
57
+ code : 'areaChart',
58
+ label : 'Graphique|Surface',
59
+ icon : "chart-areaspline-variant",
60
+ type: 'area',
61
+ },
62
+ barChart : {
63
+ code : 'barChart',
64
+ label : 'Graphique|Barres',
65
+ icon : "chart-bar",
66
+ type: 'bar'
67
+ },
68
+ donutChar : {
69
+ code : 'donutChart',
70
+ label : 'Graphique|Circulaire',
71
+ icon : "chart-donut",
72
+ type: 'donut'
73
+ },*/
74
+ }
41
75
 
42
76
  export const arrayValueSeparator = ", ";
43
77
 
@@ -85,6 +119,17 @@ export default class CommonDatagridComponent extends AppComponent {
85
119
  showFooters : defaultBool(props.showFooters,(sData.showFooters? true : false)),
86
120
  fixedTable : sData.fixedTable
87
121
  });
122
+ const disTypes = {};
123
+ let hasFoundDisplayTypes = false;
124
+ Object.map(this.props.displayTypes,(dType,v)=>{
125
+ if(isNonNullString(dType)){
126
+ dType = dType.toLowerCase().trim();
127
+ if(displayTypes[dType]){
128
+ disTypes[dType] = Object.clone(displayTypes[dType]);
129
+ }
130
+ hasFoundDisplayTypes = true;
131
+ }
132
+ });
88
133
  Object.defineProperties(this,{
89
134
  layoutRef : {
90
135
  value : React.createRef(null),
@@ -118,6 +163,9 @@ export default class CommonDatagridComponent extends AppComponent {
118
163
  sectionListHeaderFooters : {value : {}},
119
164
  sectionListDataSize : {value : {current : 0}},
120
165
  enablePointerEventsRef : {value : {current:false}},
166
+ configureSectionListSelectedValues : {value : {}},
167
+ ///les types d'affichage
168
+ displayTypes : {value : hasFoundDisplayTypes ? disTypes : Object.clone(displayTypes)},
121
169
  sectionListColumnsSize : {value : {current:0}}, //la taille du nombre d'éléments de section dans les colonnes
122
170
  })
123
171
  this.isLoading = this.isLoading.bind(this);
@@ -149,10 +197,11 @@ export default class CommonDatagridComponent extends AppComponent {
149
197
  this.state.filteredColumns = defaultObj(this.getSessionData("filteredColumns"+this.getSessionNameKey()),this.props.filters);
150
198
  this.filtersSelectors = {selector:this.getFilters()};
151
199
  const {sectionListColumns} = this.prepareColumns();
152
- this.state.sectionListColumns = sectionListColumns;
153
200
  if(this.canHandleColumnResize()){
154
201
  this.state.columnsWidths = this.preparedColumns.widths;
155
202
  }
203
+ const dType = defaultStr(this.props.displayType,this.getSessionData("diplayType"),"table");
204
+ this.state.displayType = this.displayTypes[dType] ? this.displayTypes[dType].code : "table" in this.displayTypes ? "table" : Object.keys(this.displayTypes)[0];
156
205
  extendObj(this.state,this.prepareData({data}));
157
206
  const {width:windowWidth,height:windowHeight} = Dimensions.get("window");
158
207
  this.state.layout = {
@@ -197,7 +246,10 @@ export default class CommonDatagridComponent extends AppComponent {
197
246
  } else {
198
247
  this.currentDataSources = Object.toArray(this.currentDataSources);
199
248
  }
249
+ this.state.sectionListColumns = sectionListColumns;
250
+ this.state.displayOnlySectionListHeaders = defaultBool(this.getSessionData("displayOnlySectionListHeaders"),this.props.displayOnlySectionListHeaders,false)
200
251
  }
252
+
201
253
  /*** si une ligne peut être selectionable */
202
254
  canSelectRow(row){
203
255
  return isObj(row) && row.isSectionListHeader !== true ? true : false;
@@ -205,7 +257,7 @@ export default class CommonDatagridComponent extends AppComponent {
205
257
  prepareSectionListColumns(props){
206
258
  props = defaultObj(props,this.props);
207
259
  const l = {};
208
- (Array.isArray(props.sectionListColumns) ? props.sectionListColumns : []).map((col)=>{
260
+ (Array.isArray(props.sectionListColumns) ? props.sectionListColumns : defaultArray(this.getSessionData("sectionListColumns"))).map((col)=>{
209
261
  if(isNonNullString(col)){
210
262
  l[col.trim()] = {};
211
263
  }
@@ -1004,12 +1056,13 @@ export default class CommonDatagridComponent extends AppComponent {
1004
1056
  if(type.contains("date") || type =='time'){
1005
1057
  return new Promise((resolve,reject)=>{
1006
1058
  DialogProvider.open({
1059
+ title : 'Format de date',
1007
1060
  fields : {
1008
1061
  dateFormat : {
1009
1062
  type : 'select_dateformat',
1010
1063
  required : true,
1011
1064
  text : 'Sélectionnez un format de date',
1012
- defaultValue : "dd/mm/yyyy",
1065
+ defaultValue : defaultStr(this.configureSectionListSelectedValues[column.field],"dd/mm/yyyy"),
1013
1066
  }
1014
1067
  },
1015
1068
  onCancelButtonPress : ()=>{
@@ -1021,6 +1074,7 @@ export default class CommonDatagridComponent extends AppComponent {
1021
1074
  icon : "check",
1022
1075
  onPress : ({data})=>{
1023
1076
  column.format = data.dateFormat;
1077
+ this.configureSectionListSelectedValues[column.field] = data.dateFormat;
1024
1078
  DialogProvider.close();
1025
1079
  setTimeout(()=>{
1026
1080
  resolve(column);
@@ -1049,6 +1103,7 @@ export default class CommonDatagridComponent extends AppComponent {
1049
1103
  this.prepareData({data:this.INITIAL_STATE.data,sectionListColumns:pSListColumns},(state)=>{
1050
1104
  this.setState({...state,sectionListColumns:pSListColumns},()=>{
1051
1105
  this.setIsLoading(false,false);
1106
+ this.setSessionData("sectionListColumns",Object.keys(pSListColumns));
1052
1107
  });
1053
1108
  });
1054
1109
  },true);
@@ -1058,7 +1113,7 @@ export default class CommonDatagridComponent extends AppComponent {
1058
1113
  return cb();
1059
1114
  }
1060
1115
  return this.configureSectionListColumn(sectionListColumns[columnName]).then(cb).catch(notify.error)
1061
- }, 200);
1116
+ }, 100);
1062
1117
  }
1063
1118
  removeAllColumnsInSectionList(){
1064
1119
  const {sectionListColumns} = this.prepareColumns({sectionListColumns:{}});
@@ -1066,16 +1121,106 @@ export default class CommonDatagridComponent extends AppComponent {
1066
1121
  this.prepareData({data:this.INITIAL_STATE.data,sectionListColumns},(state)=>{
1067
1122
  this.setState({...state,sectionListColumns},()=>{
1068
1123
  this.setIsLoading(false,false);
1124
+ this.setSessionData("sectionListColumns",null);
1069
1125
  });
1070
1126
  });
1071
1127
  },true);
1072
1128
  }
1129
+ canDisplayOnlySectionListHeaders(){
1130
+ return this.hasFooterFields() && this.isSectionList() && this.hasSectionListData();
1131
+ }
1132
+ /*** si l'on peut rendre le contenu de type graphique */
1133
+ isChartRendable(){
1134
+ return !this.isPivotDatagrid() && this.hasFooterFields() && this.isSectionList();
1135
+ }
1136
+ canRenderChart(){
1137
+ return this.isChartRendable() && this.state.displayType.toLowerCase().contains("chart");
1138
+ }
1139
+ /***modifie le type de données d'affichage du tableau */
1140
+ setDisplay(type){
1141
+ if(!isObj(type) || !isNonNullString(type.code) || !displayTypes[type.code]) return;
1142
+ const tt = displayTypes[type.code];
1143
+ if(tt.code == 'table'){
1144
+ if(this.state.displayType == 'table') return;
1145
+ return this.setIsLoading(true,()=>{
1146
+ this.setState({displayTypes:'table'},()=>{
1147
+ this.setIsLoading(false,false);
1148
+ });
1149
+ },true)
1150
+ } else {
1151
+ DialogProvider.open({
1152
+ title : 'Configuration de la courbe'
1153
+ })
1154
+ }
1155
+ }
1156
+ renderDisplayTypes(){
1157
+ const m = [];
1158
+ let activeType = null;
1159
+ Object.map(this.displayTypes,(type,k)=>{
1160
+ let c = k.toLowerCase();
1161
+ if(c.contains('chart') && !this.isChartRendable()) return null;
1162
+ const active = this.state.displayType === k;
1163
+ if(active){
1164
+ activeType = type;
1165
+ }
1166
+ m.push({
1167
+ ...type,
1168
+ labelStyle : active && {fontWeight:'bold',color:theme.colors.primaryOnSurface} || null,
1169
+ onPress:()=>{
1170
+ this.setDisplay(type);
1171
+ }
1172
+ })
1173
+ });
1174
+ if(m.length <= 1 || !activeType) return null;
1175
+ if(!isMobileOrTabletMedia()){
1176
+ m.unshift({text:"Type d'affichage des données",divider:true});
1177
+ }
1178
+ return <Menu
1179
+ title = "Type d'affichage"
1180
+ items = {m}
1181
+ anchor = {(p)=>{
1182
+ return <Icon
1183
+ {...p}
1184
+ name = {activeType.icon}
1185
+ title = {"Les données s'affichent actuellement en {0}. Cliquez pour modifier le type d'affichage".sprintf(activeType.label)}
1186
+ />
1187
+ }}
1188
+ />
1189
+ }
1190
+ renderChart(){
1191
+ if(!this.canRenderChart()) return null;
1192
+ }
1193
+ toggleDisplayOnlySectionListHeaders(){
1194
+ if(!this.canDisplayOnlySectionListHeaders()) return
1195
+ setTimeout(()=>{
1196
+ const displayOnlySectionListHeaders = !!!this.state.displayOnlySectionListHeaders;
1197
+ this.setSessionData("displayOnlySectionListHeaders",displayOnlySectionListHeaders);
1198
+ if(!displayOnlySectionListHeaders){
1199
+ return this.prepareData({data:this.INITIAL_STATE.data,displayOnlySectionListHeaders},(state)=>{
1200
+ this.setState(state)
1201
+ })
1202
+ } else {
1203
+ this.setIsLoading(true,()=>{
1204
+ const data = [];
1205
+ this.state.data.map((d)=>{
1206
+ if(isObj(d) && d.isSectionListHeader === true){
1207
+ data.push(d);
1208
+ }
1209
+ });
1210
+ this.setState({data,displayOnlySectionListHeaders},()=>{
1211
+ this.setIsLoading(false),false;
1212
+ });
1213
+ },true)
1214
+ }
1215
+ },100);
1216
+ }
1073
1217
  /*** permet d'effectuer le rendu des colonnes groupable dans le menu item */
1074
1218
  renderSectionListMenu(){
1075
1219
  const m = Array.isArray(this.preparedColumns?.sectionListColumnsMenuItems)? this.preparedColumns?.sectionListColumnsMenuItems : [];
1076
1220
  if(!m.length){
1077
1221
  return null;
1078
1222
  }
1223
+ const hasList = this.sectionListColumnsSize.current;
1079
1224
  const isMobile = isMobileOrTabletMedia();
1080
1225
  return <Menu
1081
1226
  title = {"Grouper les données du tableau"}
@@ -1090,14 +1235,19 @@ export default class CommonDatagridComponent extends AppComponent {
1090
1235
  closeOnPress : false,
1091
1236
  divider : true,
1092
1237
  },
1093
- this.sectionListColumnsSize.current && {
1238
+ this.canDisplayOnlySectionListHeaders() && {
1239
+ text : "Afficher uniquement totaux",
1240
+ icon : this.state.displayOnlySectionListHeaders?"check":null,
1241
+ onPress : this.toggleDisplayOnlySectionListHeaders.bind(this)
1242
+ },
1243
+ hasList && {
1094
1244
  text : "Supprimer les groupes",
1095
1245
  icon: "ungroup",
1096
1246
  divider : true,
1097
1247
  onPress : ()=>{
1098
1248
  setTimeout(()=>{
1099
1249
  this.removeAllColumnsInSectionList();
1100
- },300)
1250
+ },100)
1101
1251
  }
1102
1252
  },
1103
1253
  ...m,
@@ -1176,7 +1326,7 @@ export default class CommonDatagridComponent extends AppComponent {
1176
1326
  onPress : ()=>{
1177
1327
  setTimeout(() => {
1178
1328
  this.toggleColumnVisibility(header.field);
1179
- },300);
1329
+ },100);
1180
1330
  return false;
1181
1331
  },
1182
1332
  title : title,
@@ -1311,9 +1461,9 @@ export default class CommonDatagridComponent extends AppComponent {
1311
1461
  getFooterValues(){
1312
1462
  return defaultObj(this.___evaluatedFootersValues);
1313
1463
  }
1314
-
1464
+
1315
1465
  /**** s'il s'agit d'une section list */
1316
- isSectionList(sectionListColumns){
1466
+ isSectionList (sectionListColumns){
1317
1467
  sectionListColumns = isObj(sectionListColumns) ? sectionListColumns : this.state.sectionListColumns;
1318
1468
  return !this.isPivotDatagrid() && isObj(sectionListColumns) && Object.size(sectionListColumns,true) ? true : false;
1319
1469
  }
@@ -1338,13 +1488,14 @@ export default class CommonDatagridComponent extends AppComponent {
1338
1488
  return defaultNumber(this.sectionListDataSize.current)
1339
1489
  }
1340
1490
  prepareData(args,cb){
1341
- let {pagination,data,force,sectionListColumns,updateFooters} = defaultObj(args);
1491
+ let {pagination,displayOnlySectionListHeaders:cdisplayOnlySectionListHeaders,data,force,sectionListColumns,updateFooters} = defaultObj(args);
1342
1492
  cb = typeof cb ==='function'? cb : typeof args.cb == 'function'? args.cb : undefined;
1343
1493
  sectionListColumns = isObj(sectionListColumns) ? sectionListColumns : this.state.sectionListColumns;
1494
+ const displayOnlySectionListHeaders = typeof cdisplayOnlySectionListHeaders == 'boolean'?cdisplayOnlySectionListHeaders : this.state.displayOnlySectionListHeaders;
1344
1495
  let isArr = Array.isArray(data);
1345
1496
  //let push = (d,index) => isArr ? newData.push(d) : newData[index] = d;
1346
1497
  const hasLocalFilter = this.props.filters !== false && this.hasLocalFilters;
1347
- let footersColumns = this.getFooterFields(),hasFooterFields = Object.size(footersColumns,true);
1498
+ let footersColumns = this.getFooterFields(),hasFooterFields = this.hasFooterFields();
1348
1499
  const canUpdateFooters = !!(updateFooters !== false && hasFooterFields);
1349
1500
  this.hasFoundSectionData.current = false;
1350
1501
  this.sectionListDataSize.current = 0;
@@ -1427,9 +1578,11 @@ export default class CommonDatagridComponent extends AppComponent {
1427
1578
  //this.sectionListData[i] = sortConfig ? sortBy(this.sectionListData[i],sortConfig):this.sectionListData[i];
1428
1579
  //const v = i;// === this.emptySectionListHeaderValue ? "" : i;
1429
1580
  data.push({isSectionListHeader:true,sectionListHeaderKey:i});
1430
- this.sectionListData[i].map((d)=>{
1431
- data.push(d);
1432
- })
1581
+ if(!displayOnlySectionListHeaders){
1582
+ this.sectionListData[i].map((d)=>{
1583
+ data.push(d);
1584
+ })
1585
+ }
1433
1586
  }
1434
1587
  }
1435
1588
  if(!this.hasSectionListData() && this.canPaginateData()){
@@ -1441,7 +1594,7 @@ export default class CommonDatagridComponent extends AppComponent {
1441
1594
  } else if(force){
1442
1595
  this.setSelectedRows();
1443
1596
  }
1444
- const state = {data};
1597
+ const state = {data,displayOnlySectionListHeaders};
1445
1598
  if((cb)){
1446
1599
  cb(state);
1447
1600
  }
@@ -1896,7 +2049,7 @@ export default class CommonDatagridComponent extends AppComponent {
1896
2049
  }
1897
2050
  cb && setTimeout(() => {
1898
2051
  cb();
1899
- }, 500);
2052
+ }, 200);
1900
2053
  }
1901
2054
  isAllRowsSelected(update){
1902
2055
  return this.selectedRowsCount && this.selectedRowsCount === this.getMaxSelectableRows()? true : false;
@@ -2271,7 +2424,7 @@ export const ProgressBar = CommonDatagridComponent.LinesProgressBar;
2271
2424
  CommonDatagridComponent.getDefaultPreloader = (props)=>{
2272
2425
  return <Preloader {...defaultObj(props)}/>
2273
2426
  }
2274
-
2427
+ const allDTypes = Object.keys(displayTypes);
2275
2428
  CommonDatagridComponent.propTypes = {
2276
2429
  canMakePhoneCall : PropTypes.bool,//si l'on peut faire un appel sur la données sélectionnées
2277
2430
  makePhoneCallProps : PropTypes.oneOfType([
@@ -2448,6 +2601,13 @@ CommonDatagridComponent.propTypes = {
2448
2601
  /**** la fonction permettant de faire le rendu dun contenu paginé, personalisé */
2449
2602
  renderCustomPagination : PropTypes.func,
2450
2603
  getActionsArgs : PropTypes.func,//fonction permettant de récupérer les props supplémentaires à passer aux actions du datagrid
2604
+ displayOnlySectionListHeaders : PropTypes.bool,// si uniquement les entêtes des sections seront affichés, valides uniquement en affichage des sectionHeader
2605
+
2606
+ /*** types d'affichage displayTypes */
2607
+ /** les types d'affichage supportés */
2608
+ displayType : PropTypes.oneOf(allDTypes),
2609
+ /*** les types d'afichates supportés par l'application */
2610
+ displayTypes : PropTypes.arrayOf(PropTypes.oneOf(allDTypes))
2451
2611
  }
2452
2612
 
2453
2613
  const styles = StyleSheet.create({
@@ -0,0 +1,12 @@
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
+ Les propriétés d'états :
6
+ displayType, displayOnlySectionListHeaders, sectionListHeaderColumns sont persistées
7
+ ça sous entend que lorsqu'on charge la table data, ces valeurs sont restaurées
8
+
9
+ - Pour faire un affichage en graphique, il faut :
10
+ 1. grouper les éléments du tableau avec au moins une colonne
11
+ 2. disposer dans le tableau, des colonnes de totalisation (de type montant et somme)
12
+ 3.
@@ -284,6 +284,7 @@ const DatagridFactory = (Factory)=>{
284
284
 
285
285
  />
286
286
  {this.renderSectionListMenu()}
287
+ {this.renderDisplayTypes()}
287
288
  <View testID={testID+"_HeaderPagination"} style = {styles.paginationItem}>
288
289
  <BottomSheetMenu
289
290
  testID={testID+"_HeaderMenus"}
@@ -82,14 +82,15 @@ export const selectDateFormatFieldProps = ({onAdd:customOnAdd,onAddCustomFormat,
82
82
  ...defaultObj(props),
83
83
  onAdd,
84
84
  onAdd : undefined,
85
+ showAdd : false,
85
86
  }
86
87
  }
87
- export const getDateFormatSelectorItems = x=> Object.map(DateLib.formats,(format)=>{
88
+ export const getDateFormatSelectorItems = x=> Object.map(DateLib.sortedFormats,(format)=>{
88
89
  return {code : format,label:new Date().toFormat(format)}
89
90
  });
90
91
 
91
92
  export const dateFormatSelectorRenderItem = ({item})=>{
92
- return "{0}, EX : {1}".sprintf(item.code,item.label);
93
+ return "{0} [{1}]".sprintf(item.label,item.code);
93
94
  }
94
95
 
95
96
  DateFormatSelector.propTypes = {
@@ -2,6 +2,7 @@ import Field from "./Field";
2
2
  import Dropdown from "$ecomponents/Dropdown";
3
3
  import PropTypes from "prop-types";
4
4
  import {isObj} from "$utils";
5
+ import appConfig from "$capp/config";
5
6
 
6
7
  export default class FormSelectField extends Field{
7
8
  constructor(props) {
@@ -115,8 +116,9 @@ export default class FormSelectField extends Field{
115
116
  delete props.format;
116
117
  delete props.import;
117
118
  delete props.exports;
118
- if( defaultStr(props.name,this.name) === 'country' && props.multiple !== true){
119
- props.defaultValue = defaultStr(props.defaultValue);
119
+ const isCountry = this.type.contains('country');
120
+ if( isCountry && props.multiple !== true){
121
+ props.defaultValue = defaultStr(props.defaultValue,appConfig.countryCode,appConfig.get("countryCode","country"));
120
122
  }
121
123
  return <Dropdown
122
124
  {...props}
@@ -1,5 +1,6 @@
1
1
  import PhoneInput from "$ecomponents/PhoneInput";
2
2
  import Field from "./Field";
3
+ import appConfig from "$capp/config";
3
4
 
4
5
  export default class FormPhoneInputField extends Field {
5
6
  canFocus(){
@@ -9,6 +10,7 @@ export default class FormPhoneInputField extends Field {
9
10
  props.onChange = (args)=>{
10
11
  this.validate(args);
11
12
  }
13
+ props.country = defaultStr(props.country,appConfig.countryCode,appConfig.get("countryCode","country"))
12
14
  return <PhoneInput
13
15
  {...props}
14
16
  setRef = {setRef}
@@ -27,12 +27,13 @@ const MenuItemComponent = React.forwardRef(({
27
27
  style,
28
28
  contentStyle,
29
29
  testID,
30
- titleStyle,
30
+ labelStyle,
31
31
  primary,
32
32
  secondary,
33
33
  iconProps,
34
34
  isBottomSheetItem,
35
35
  accessibilityLabel,
36
+ right,
36
37
  ...rest
37
38
  },ref) => {
38
39
  title = defaultVal(label,text,title);
@@ -49,20 +50,20 @@ const MenuItemComponent = React.forwardRef(({
49
50
  ? disabledColor
50
51
  : color(theme.colors.text).alpha(theme.ALPHA).rgb().string();
51
52
  iconProps = defaultObj(iconProps);
52
- titleStyle = Object.assign({},StyleSheet.flatten(titleStyle));
53
+ labelStyle = Object.assign({},StyleSheet.flatten(labelStyle));
53
54
  style = Object.assign({},StyleSheet.flatten(style));
54
55
 
55
- if(Colors.isValid(titleStyle.color)){
56
- iconColor = titleStyle.color;
56
+ if(Colors.isValid(labelStyle.color)){
57
+ iconColor = labelStyle.color;
57
58
  } else if(Colors.isValid(style.color)){
58
59
  titleColor = iconColor = style.color;
59
60
  }
60
-
61
61
  const pointerEvents = disabled ? 'none' : 'auto';
62
62
  const disabledStyle = disabled ? {opacity:DISABLED_OPACITY} : null;
63
63
  const winW = Dimensions.get("window").width-30;
64
64
  const maxWidthStyle = isBottomSheetItem ? {width:winW,maxWidth:null} : undefined;
65
65
  const maxWidthTextStyle = isBottomSheetItem ? {width:winW-50} : null;
66
+ right = typeof right =='function'? right ({color:titleColor}) : right;
66
67
  return (
67
68
  <Tooltip
68
69
  {...defaultObj(rest)}
@@ -77,13 +78,14 @@ const MenuItemComponent = React.forwardRef(({
77
78
  accessibilityState={{ disabled }}
78
79
  pointerEvents = {pointerEvents}
79
80
  >
80
- <View style={[styles.row]} ref={ref}>
81
+ <View style={[styles.row]} ref={ref} testID={testID+"_ContentContainer"}>
81
82
  {icon ? (
82
- <View style={[styles.item, styles.icon]} pointerEvents="box-none">
83
+ <View testID={testID+"_IconContainer"} style={[styles.item, styles.icon]} pointerEvents="box-none">
83
84
  <Icon source={icon} size={24} {...iconProps} style={[iconProps.style,styles.iconT]} color={iconColor} />
84
85
  </View>
85
86
  ) : null}
86
87
  <View
88
+ testID={testID+"_LabelContainer"}
87
89
  style={[
88
90
  styles.item,
89
91
  styles.content,
@@ -95,14 +97,16 @@ const MenuItemComponent = React.forwardRef(({
95
97
  pointerEvents="none"
96
98
  >
97
99
  <Label
100
+ testID={testID+"_Label"}
98
101
  selectable={false}
99
102
  numberOfLines={1}
100
103
  ellipsizeMode = {"tail"}
101
- style={[styles.title, { color: titleColor }, titleStyle,styles.noMargin,maxWidthTextStyle]}
104
+ style={[styles.title, { color: titleColor }, labelStyle,styles.noMargin,maxWidthTextStyle]}
102
105
  >
103
106
  {title}
104
107
  </Label>
105
108
  </View>
109
+ {React.isValidElement(right) && right || null}
106
110
  </View>
107
111
  </Tooltip>
108
112
  );
@@ -185,7 +189,7 @@ MenuItemComponent.propTypes = {
185
189
  */
186
190
  style: StylePropTypes,
187
191
  contentStyle: StylePropTypes,
188
- titleStyle : StylePropTypes,
192
+ labelStyle : StylePropTypes,
189
193
  /**
190
194
  * @optional
191
195
  */