@fto-consult/expo-ui 1.3.12 → 1.4.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.
@@ -34,7 +34,9 @@ module.exports = (opts)=>{
34
34
  r["$expo"] = r["$expo-ui"] = expo;
35
35
  r["$epreloader"] = path.resolve(expo,"components/Preloader");
36
36
  r["$eform"] = path.resolve(expo,"components","Form");
37
- r["$eform-data"] = path.resolve(expo,"components","Form","FormData");
37
+ r["$form"] = r["$form"] || r["$eform"];
38
+ r["$eform-data"] = r["$eformData"]= path.resolve(expo,"components","Form","FormData");
39
+ r["$formData"] = r["$formData"] || r["$eformData"];
38
40
  r["$eform-manager"] = path.resolve(expo,"components","Form/utils/FormManager");
39
41
  r["$echart"] = path.resolve(expo,"components","Chart");
40
42
  r["$efile-system"] = path.resolve(expo,"media","file-system");
@@ -78,6 +80,6 @@ module.exports = (opts)=>{
78
80
  opts.mutator(r);
79
81
  }
80
82
  ///le chemin racine du projet expo-ui
81
- r["$expo-ui-root-path"] = path.resolve(expo,"..");
83
+ r["$expo-ui-root-path"] = r["$expo-ui-root"]= path.resolve(expo,"..");
82
84
  return r;
83
85
  }
package/package.json CHANGED
@@ -1,102 +1,103 @@
1
- {
2
- "name": "@fto-consult/expo-ui",
3
- "version": "1.3.12",
4
- "description": "Bibliothèque de composants UI Expo,react-native",
5
- "main": "index.js",
6
- "scripts": {
7
- "publish1": "npm publish --access=public",
8
- "unpublish": "npm -f unpublish @fto-consult/expo-ui",
9
- "build-web": "",
10
- "dev": "npx expo start -c --no-minify",
11
- "start": "npx expo start --dev --no-minify",
12
- "start-d": "npx expo start -c --no-dev --no-minify",
13
- "start-p": "npm run start-d",
14
- "expo-start-client": "npx expo start --dev --no-minify --dev-client",
15
- "start-m": "npx expo start - c--dev--no -minify",
16
- "android": "npx expo start --android -c",
17
- "ios": "npx expo start --ios",
18
- "web": "npx expo start --web",
19
- "web-c": "npx expo start --web -c",
20
- "eject": "expo eject",
21
- "emulator": "npm run android-emulator",
22
- "web-server": "npx serve web-build",
23
- "build-android": "eas build --clear-cache -p android --profile preview",
24
- "build-android-local": "eas build --platform android --local",
25
- "build-android-dist": "eas build --clear-cache -p android",
26
- "build-ios": "eas build --clear-cache -p ios --profile preview",
27
- "build-ios-dist": "eas build --clear-cache -p ios",
28
- "install-apk": "adb -s emulator-5554 install myapp.apk",
29
- "android-emulator": "emulator -avd EMULATOR",
30
- "flipper": "npx cross-env METRO_SERVER_PORT=19000 E:\\Studies\\react-native\\debugger\\Flipper-win\\Flipper.exe",
31
- "build-electron": "electron-webpack && electron-builder --dir -c.compression=store",
32
- "test:build": "electron-webpack && electron-builder --dir -c.compression=store -c.mac.identity=null",
33
- "compile-electron": "webpack --config ./electron/webpack.config.js",
34
- "compile-electron-p": "webpack --config ./electron/webpack.config.js --mode=production",
35
- "electron": "electron ./electron",
36
- "logcat": "adb -d logcat com.ftc.apps.salite1:E > errors.txt",
37
- "logcat-export": "adb -d logcat com.ftc.apps.salite1 *:S > logcat.txt",
38
- "electron-c": "npm run compile-electron && npm run electron",
39
- "electron-p": "npm run compile-electron-p && npm run electron",
40
- "update-app-version": "node ./update-app-version.js",
41
- "find-licenses": "node ./find-licenses.js",
42
- "fix-dependencies": "expo doctor --fix-dependencies"
43
- },
44
- "repository": {
45
- "type": "git",
46
- "url": "git+https://github.com/borispipo/expo-ui.git"
47
- },
48
- "keywords": [
49
- "Expo",
50
- "React-Native"
51
- ],
52
- "author": "Boris Fouomene",
53
- "license": "ISC",
54
- "bugs": {
55
- "url": "https://github.com/borispipo/expo-ui/issues"
56
- },
57
- "homepage": "https://github.com/borispipo/expo-ui#readme",
58
- "dependencies": {
59
- "@babel/preset-react": "^7.18.6",
60
- "@emotion/native": "^11.10.0",
61
- "@expo/html-elements": "^0.2.0",
62
- "@expo/metro-config": "^0.4.0",
63
- "@expo/webpack-config": "^0.17.2",
64
- "@fto-consult/common": "^1.5.12",
65
- "@gorhom/portal": "^1.0.14",
66
- "@react-native-async-storage/async-storage": "~1.17.3",
67
- "@react-native-community/datetimepicker": "6.2.0",
68
- "@react-native-community/netinfo": "9.3.0",
69
- "@react-navigation/native": "^6.0.13",
70
- "@react-navigation/native-stack": "^6.9.1",
71
- "@shopify/flash-list": "1.1.0",
72
- "babel-plugin-inline-dotenv": "^1.7.0",
73
- "babel-plugin-module-resolver": "^4.1.0",
74
- "babel-plugin-transform-inline-environment-variables": "^0.4.4",
75
- "expo": "^46.0.15",
76
- "expo-camera": "~12.3.0",
77
- "expo-image-picker": "~13.3.1",
78
- "expo-linking": "~3.2.2",
79
- "expo-sqlite": "~10.3.0",
80
- "expo-status-bar": "~1.4.0",
81
- "expo-system-ui": "~1.3.0",
82
- "expo-web-browser": "~11.0.0",
83
- "google-libphonenumber": "^3.2.31",
84
- "htmlparser2-without-node-native": "^3.9.2",
85
- "parent-package-json": "^2.0.1",
86
- "prop-types": "^15.8.1",
87
- "react-apexcharts": "^1.4.0",
88
- "react-content-loader": "^6.2.0",
89
- "react-dom": "18.0.0",
90
- "react-native-big-list": "^1.5.5",
91
- "react-native-gesture-handler": "~2.5.0",
92
- "react-native-paper": "^4.12.5",
93
- "react-native-paper-dates": "^0.9.2",
94
- "react-native-reanimated": "~2.9.1",
95
- "react-native-safe-area-context": "4.3.1",
96
- "react-native-svg": "12.3.0",
97
- "react-native-web": "~0.18.7",
98
- "react-native-webview": "11.23.0",
99
- "sharp-cli": "^2.1.0",
100
- "tippy.js": "^6.3.7"
101
- }
102
- }
1
+ {
2
+ "name": "@fto-consult/expo-ui",
3
+ "version": "1.4.1",
4
+ "description": "Bibliothèque de composants UI Expo,react-native",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "publish1": "npm publish --access=public",
8
+ "unpublish": "npm -f unpublish @fto-consult/expo-ui",
9
+ "build-web": "",
10
+ "dev": "npx expo start -c --no-minify",
11
+ "start": "npx expo start --dev --no-minify",
12
+ "start-d": "npx expo start -c --no-dev --no-minify",
13
+ "start-p": "npm run start-d",
14
+ "expo-start-client": "npx expo start --dev --no-minify --dev-client",
15
+ "start-m": "npx expo start - c--dev--no -minify",
16
+ "android": "npx expo start --android -c",
17
+ "ios": "npx expo start --ios",
18
+ "web": "npx expo start --web",
19
+ "web-c": "npx expo start --web -c",
20
+ "eject": "expo eject",
21
+ "emulator": "npm run android-emulator",
22
+ "web-server": "npx serve web-build",
23
+ "build-android": "eas build --clear-cache -p android --profile preview",
24
+ "build-android-local": "eas build --platform android --local",
25
+ "build-android-dist": "eas build --clear-cache -p android",
26
+ "build-ios": "eas build --clear-cache -p ios --profile preview",
27
+ "build-ios-dist": "eas build --clear-cache -p ios",
28
+ "install-apk": "adb -s emulator-5554 install myapp.apk",
29
+ "android-emulator": "emulator -avd EMULATOR",
30
+ "flipper": "npx cross-env METRO_SERVER_PORT=19000 E:\\Studies\\react-native\\debugger\\Flipper-win\\Flipper.exe",
31
+ "build-electron": "electron-webpack && electron-builder --dir -c.compression=store",
32
+ "test:build": "electron-webpack && electron-builder --dir -c.compression=store -c.mac.identity=null",
33
+ "compile-electron": "webpack --config ./electron/webpack.config.js",
34
+ "compile-electron-p": "webpack --config ./electron/webpack.config.js --mode=production",
35
+ "electron": "electron ./electron",
36
+ "logcat": "adb -d logcat com.ftc.apps.salite1:E > errors.txt",
37
+ "logcat-export": "adb -d logcat com.ftc.apps.salite1 *:S > logcat.txt",
38
+ "electron-c": "npm run compile-electron && npm run electron",
39
+ "electron-p": "npm run compile-electron-p && npm run electron",
40
+ "update-app-version": "node ./update-app-version.js",
41
+ "find-licenses": "node ./find-licenses.js",
42
+ "fix-dependencies": "expo doctor --fix-dependencies"
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/borispipo/expo-ui.git"
47
+ },
48
+ "keywords": [
49
+ "Expo",
50
+ "React-Native"
51
+ ],
52
+ "author": "Boris Fouomene",
53
+ "license": "ISC",
54
+ "bugs": {
55
+ "url": "https://github.com/borispipo/expo-ui/issues"
56
+ },
57
+ "homepage": "https://github.com/borispipo/expo-ui#readme",
58
+ "dependencies": {
59
+ "@babel/preset-react": "^7.18.6",
60
+ "@emotion/native": "^11.10.0",
61
+ "@expo/html-elements": "^0.2.0",
62
+ "@expo/metro-config": "^0.4.0",
63
+ "@expo/webpack-config": "^0.17.2",
64
+ "@fto-consult/common": "^1.6.6",
65
+ "@gorhom/portal": "^1.0.14",
66
+ "@react-native-async-storage/async-storage": "~1.17.3",
67
+ "@react-native-community/datetimepicker": "6.2.0",
68
+ "@react-native-community/netinfo": "9.3.0",
69
+ "@react-navigation/native": "^6.0.13",
70
+ "@react-navigation/native-stack": "^6.9.1",
71
+ "@shopify/flash-list": "1.1.0",
72
+ "babel-plugin-inline-dotenv": "^1.7.0",
73
+ "babel-plugin-module-resolver": "^4.1.0",
74
+ "babel-plugin-transform-inline-environment-variables": "^0.4.4",
75
+ "expo": "^46.0.15",
76
+ "expo-camera": "~12.3.0",
77
+ "expo-clipboard": "~3.1.0",
78
+ "expo-image-picker": "~13.3.1",
79
+ "expo-linking": "~3.2.2",
80
+ "expo-sqlite": "~10.3.0",
81
+ "expo-status-bar": "~1.4.0",
82
+ "expo-system-ui": "~1.3.0",
83
+ "expo-web-browser": "~11.0.0",
84
+ "google-libphonenumber": "^3.2.31",
85
+ "htmlparser2-without-node-native": "^3.9.2",
86
+ "parent-package-json": "^2.0.1",
87
+ "prop-types": "^15.8.1",
88
+ "react-apexcharts": "^1.4.0",
89
+ "react-content-loader": "^6.2.0",
90
+ "react-dom": "18.0.0",
91
+ "react-native-big-list": "^1.5.5",
92
+ "react-native-gesture-handler": "~2.5.0",
93
+ "react-native-paper": "^4.12.5",
94
+ "react-native-paper-dates": "^0.9.2",
95
+ "react-native-reanimated": "~2.9.1",
96
+ "react-native-safe-area-context": "4.3.1",
97
+ "react-native-svg": "12.3.0",
98
+ "react-native-web": "~0.18.7",
99
+ "react-native-webview": "11.23.0",
100
+ "sharp-cli": "^2.1.0",
101
+ "tippy.js": "^6.3.7"
102
+ }
103
+ }
package/src/App.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import '$session';
2
2
  import React from 'react';
3
+ import {defaultObj} from "$utils";
3
4
  import {updateTheme,defaultTheme} from "$theme";
4
5
  import {Provider as PaperProvider } from 'react-native-paper';
5
6
  import Index from './index';
@@ -23,18 +24,31 @@ import {Provider as AlertProvider} from '$ecomponents/Dialog/confirm/Alert';
23
24
  import APP from "$app";
24
25
 
25
26
  export default function getIndex(options){
26
- const {App} = defaultObj(options);
27
+ const {App,onMount,onUnmount,preferences:appPreferences} = defaultObj(options);
27
28
  return function MainIndexComponent() {
28
29
  React.useEffect(()=>{
29
- return ()=>{}
30
+ ///la fonction de rappel lorsque le composant est monté
31
+ let cb = typeof onMount =='function'? onMount() : null;
32
+ return ()=>{
33
+ if(typeof onUnmount =='function'){
34
+ onUnmount();
35
+ }
36
+ if(typeof cb =='function'){
37
+ cb();
38
+ }
39
+ }
30
40
  },[])
31
41
  const [theme,setTheme] = React.useState(updateTheme(defaultTheme));
42
+ const updatePreferenceTheme = (customTheme,persist)=>{
43
+ setTheme(updateTheme(customTheme));
44
+ };
45
+ const forceRender = React.useForceRender();
46
+ const pref = typeof appPreferences =='function'? appPreferences({setTheme,forceRender,updateTheme:updatePreferenceTheme}) : appPreferences;
32
47
  const preferences = React.useMemo(()=>({
33
- updateTheme : (customTheme,persist)=>{
34
- setTheme(updateTheme(customTheme));
35
- },
48
+ updateTheme:updatePreferenceTheme,
36
49
  theme,
37
- }),[theme]);
50
+ ...defaultObj(pref),
51
+ }),[theme,pref]);
38
52
  const child = <Index theme={theme}/>;
39
53
  const children = typeof App =='function'? App({children:child,APP}) : child;
40
54
  return (
@@ -28,7 +28,6 @@ import {getRowStyle,styles as rStyles} from "../utils";
28
28
  import Avatar from "$ecomponents/Avatar";
29
29
  import {defaultObj,isOb,isNonNullString} from "$utils";
30
30
  import PropTypes from "prop-types";
31
- import ActivityIndicator from "$ecomponents/ActivityIndicator";
32
31
 
33
32
  const DatagridFactory = (Factory)=>{
34
33
  Factory = Factory || CommonDatagrid;
@@ -127,6 +126,9 @@ const DatagridFactory = (Factory)=>{
127
126
  }
128
127
  rowProps = defaultObj(renderedContent.rowProps);
129
128
  avatarProps.color = color;
129
+ if(typeof avatarContent =='function'){
130
+ avatarContent = avatarContent({...avatarProps,suffix:index,testID:testID+"_Avatar"})
131
+ }
130
132
  if(isNonNullString(avatarContent)){
131
133
  let src = undefined;
132
134
  let avatarSuffix = index;
@@ -212,19 +214,19 @@ const DatagridFactory = (Factory)=>{
212
214
  return INFINITE_SCROLL_PAGE_SIZE;
213
215
  }
214
216
  scrollToEnd(){
215
- if(!this._isMounted()) return;
217
+ if(!this._isMounted() || !this.canScrollTo()) return;
216
218
  if(this.listRef.current && this.listRef.current.scrollToEnd){
217
219
  this.listRef.current.scrollToEnd();
218
220
  }
219
221
  }
220
222
  scrollToTop(opts){
221
- if(!this._isMounted()) return;
223
+ if(!this._isMounted() || !this.canScrollTo()) return;
222
224
  if(this.listRef.current && this.listRef.current.scrollToTop){
223
225
  this.listRef.current.scrollToTop(defaultObj(opts));
224
226
  }
225
227
  }
226
228
  scrollToIndex(index){
227
- if(!this._isMounted()) return;
229
+ if(!this._isMounted() || !this.canScrollTo()) return;
228
230
  index = typeof index =='number'? index : 0;
229
231
  if(this.listRef.current && this.listRef.current.scrollToIndex){
230
232
  this.listRef.current.scrollToIndex({index});
@@ -318,6 +320,7 @@ const DatagridFactory = (Factory)=>{
318
320
  testID,
319
321
  renderEmpty,
320
322
  } = this.props
323
+ const hasData = this.state.data.length ? true : false;
321
324
  testID = defaultStr(testID,"RN_DatagridAccordion");
322
325
  backToTopProps = defaultObj(backToTopProps);
323
326
  accordionProps = defaultObj(accordionProps);
@@ -494,12 +497,12 @@ const DatagridFactory = (Factory)=>{
494
497
  ,text : (showFooter?'Masquer/Ligne des totaux':'Afficher/Ligne des totaux')
495
498
  }:null,
496
499
  ...restItems,
497
- {
500
+ this.canScrollTo() && {
498
501
  text : 'Retour en haut',
499
502
  icon : "arrow-up-bold",
500
503
  onPress : this.scrollToTop.bind(this)
501
504
  },
502
- {
505
+ this.canScrollTo() && {
503
506
  text : 'Aller à la dernière ligne',
504
507
  icon : "arrow-down-bold",
505
508
  onPress : this.scrollToEnd.bind(this)
@@ -533,7 +536,6 @@ const DatagridFactory = (Factory)=>{
533
536
  </View>
534
537
  </ScrollView>
535
538
  </View>
536
- const hasData = this.state.data.length ? true : false;
537
539
  renderEmpty = defaultFunc(accordionProps.renderEmpty,renderEmpty,x=>null)
538
540
  return <View testID={testID+"_Container"} pointerEvents={pointerEvents} style={[styles.container]} collapsable={false}>
539
541
  { <View testID={testID+"_ContentContainer"} style={[this.bindResizeEvents()?{height:this.renderedListHeight}:undefined]}>
@@ -1,25 +1,22 @@
1
1
  import theme from "$theme";
2
2
  import APP from "$capp";
3
- import {isMobileOrTabletMedia,isSmallPhoneMedia} from "$cplatform/dimensions";
3
+ import {isMobileOrTabletMedia} from "$cplatform/dimensions";
4
4
  import PropTypes from "prop-types";
5
5
  import {Component as AppComponent} from "$react"
6
6
  import $session from "$session";
7
7
  import Auth from "$cauth";
8
- import Button from "$ecomponents/Button";
9
8
  import Tooltip from "$ecomponents/Tooltip";
10
9
  import setQueryLimit from "./setQueryLimit";
11
10
  import {notify,showConfirm} from "$ecomponents/Dialog";
12
11
  import Label from "$ecomponents/Label";
13
12
  import Image from "$ecomponents/Image";
14
13
  import Icon,{COPY_ICON} from "$ecomponents/Icon";
15
- //import TableLink from "$containers/TableLink";
16
- //import filterUtils from "$ccomponents/Filter/utils";
14
+ import filterUtils from "$ecomponents/Filter/utils";
17
15
  import Hashtag from "$ecomponents/Hashtag";
18
- import {sortBy,extendObj,isObjOrArray,defaultNumber,defaultStr,isFunction,defaultBool,defaultArray,defaultObj,isNonNullString,defaultDecimal} from "$utils";
16
+ import {sortBy,isDecimal,extendObj,isObjOrArray,defaultNumber,defaultStr,isFunction,defaultBool,defaultArray,defaultObj,isNonNullString,defaultDecimal} from "$utils";
19
17
  import {Datagrid as DatagridContentLoader} from "$ecomponents/ContentLoader";
20
18
  import React from "$react";
21
19
  import DateLib from "$lib/date";
22
- //import dataFileManager from "$database/dataFileManager";
23
20
  import Filter,{canHandleFilter} from "$ecomponents/Filter";
24
21
  import {CHECKED_ICON_NAME} from "$ecomponents/Checkbox";
25
22
  import { COLUMN_WIDTH,DATE_COLUMN_WIDTH } from "../utils";
@@ -29,13 +26,13 @@ import Checkbox from "../Checkbox";
29
26
  import { TouchableRipple } from "react-native-paper";
30
27
  import { evalSingleValue } from "../Footer";
31
28
  import i18n from "$i18n";
32
- import { makePhoneCall,canMakePhoneCall as canMakeCall} from "$capp/MakePhoneCall";
29
+ import { makePhoneCall,canMakePhoneCall as canMakeCall} from "$makePhoneCall";
33
30
  import copyToClipboard from "$capp/clipboard";
34
31
  import { Pressable } from "react-native";
35
32
 
36
33
  export const arrayValueSeparator = ", ";
37
34
 
38
- const databaseArgs = {};
35
+ const dataSourceArgs = {};
39
36
  export const footerFieldName = "dgrid-fters-fields";
40
37
 
41
38
 
@@ -500,7 +497,7 @@ export default class CommonDatagridComponent extends AppComponent {
500
497
  getActionsArgs(selected){
501
498
  const r = isObj(selected)? selected : {};
502
499
  const ret = {
503
- ...databaseArgs,
500
+ ...dataSourceArgs,
504
501
  selected : defaultBool(selected,false),
505
502
  ...r,
506
503
  isMobile : isMobileOrTabletMedia(),
@@ -544,7 +541,9 @@ export default class CommonDatagridComponent extends AppComponent {
544
541
  return r
545
542
  };
546
543
  let selectedR = this.props.selectedRowsActions;
547
- let sArgs = this.getActionsArgs(true);
544
+ const sArgs = this.getActionsArgs(true);
545
+ sArgs.size = sArgs.selectedRowsCount = Object.size(sArgs.selectedRows);
546
+ sArgs.selectedRowsKeys = Object.keys(sArgs.selectedRows);
548
547
  if(isFunction(selectedR)) {
549
548
  selectedR = selectedR.call(this,sArgs)
550
549
  }
@@ -904,10 +903,11 @@ export default class CommonDatagridComponent extends AppComponent {
904
903
  if(!visible){
905
904
  colProps.style.display = 'none';
906
905
  }
906
+ const title = header.text = header.text || header.label || header.title||header.field
907
907
  visibleColumnsNames[header.field] = visible ? true : false;
908
908
  visibleColumns.push({
909
909
  onPress : ()=>{this.toggleColumnVisibility(header.field);return false},
910
- title : header.text||header.title||header.field,
910
+ title : title,
911
911
  icon : visible?CHECKED_ICON_NAME : null,
912
912
  });
913
913
  restCol.field = header.field;
@@ -1247,23 +1247,28 @@ export default class CommonDatagridComponent extends AppComponent {
1247
1247
  this.refresh(true);
1248
1248
  }
1249
1249
  setQueryLimit(){
1250
- this.currentDatagridQueryLimit = this.getSessionData("databaseQueryLimit");
1250
+ if(!this.canHandleQueryLimit()) return;
1251
+ this.currentDatagridQueryLimit = this.getSessionData("dataSourceQueryLimit");
1251
1252
  setQueryLimit(this.currentDatagridQueryLimit,(limit)=>{
1252
- this.setSessionData("databaseQueryLimit",limit)
1253
+ this.setSessionData("dataSourceQueryLimit",limit)
1253
1254
  notify.success("Le nombre maximal d'élément a été définit à la valeur "+(limit==0?" infinit ":limit.formatNumber())+". Cette valeur sera prise en compte à la prochaine réactualisation du tableau")
1254
1255
  });
1255
1256
  }
1256
1257
 
1257
1258
  canSetQueryLimit(){
1258
- return isDecimal(this.props.queryLimit) && (this.props.queryLimit >=0) ? false : true;
1259
+ return this.canHandleQueryLimit() && isDecimal(this.props.queryLimit) && (this.props.queryLimit >=0) ? false : true;
1259
1260
  }
1260
1261
  getQueryLimit(){
1261
1262
  if(isDecimal(this.props.queryLimit) && (this.props.queryLimit >=0)) return this.props.queryLimit
1262
- let sLimit = this.getSessionData("databaseQueryLimit");
1263
+ let sLimit = this.getSessionData("dataSourceQueryLimit");
1263
1264
  if(isDecimal(sLimit) && sLimit >= 0) return sLimit;
1264
1265
  return 0;
1265
1266
  }
1267
+ canHandleQueryLimit(){
1268
+ return true;
1269
+ }
1266
1270
  renderQueryLimit(content){
1271
+ if(!this.canHandleQueryLimit()) return null;
1267
1272
  let cLImit = this.getQueryLimit();
1268
1273
  if(cLImit == 0) cLImit = " infinit"
1269
1274
  let s = "";
@@ -1444,6 +1449,9 @@ export default class CommonDatagridComponent extends AppComponent {
1444
1449
  </>
1445
1450
  </TouchableRipple>
1446
1451
  }
1452
+ canScrollTo(){
1453
+ return this.state.data.length? true :false;
1454
+ }
1447
1455
  renderSelectableCheckboxCell(props){
1448
1456
  const {containerProps} = props;
1449
1457
  if(isObj(containerProps)){
@@ -1502,24 +1510,15 @@ export default class CommonDatagridComponent extends AppComponent {
1502
1510
 
1503
1511
  renderArgs.extra = extra;
1504
1512
  renderArgs.item = rowData;
1513
+ const defaultValue = renderArgs.defaultValue = renderArgs.value = rowData[columnField];
1505
1514
  let key = this.getRowKey(rowData,rowIndex)+"-"+columnField,isTagRender = defaultStr(columnDef.table).toLowerCase().contains("tags");
1506
1515
  if(isObj(columnDef.datagrid) && isFunction(columnDef.datagrid.render)){
1507
1516
  _render = columnDef.datagrid.render.call(this,renderArgs);
1508
1517
  } else if(isFunction(columnDef.multiplicater)){
1509
1518
  _render = defaultDecimal(columnDef.multiplicater({...renderArgs,value:rowData[columnField]}),rowData[columnField]);
1510
1519
  } else {
1511
- _render = rowData[columnField];
1520
+ _render = defaultValue;
1512
1521
  let _type = defaultStr(columnDef.type).trim().toLowerCase();
1513
- if(false && _type == 'datafile' && !isFunction(columnDef.render)){
1514
- columnDef.render = ({rowData,columnField})=>{
1515
- let v = rowData[columnField];
1516
- let dF = dataFileManager.get(v);
1517
- if(dF){
1518
- return dF.code.toUpperCase();
1519
- }
1520
- return isNonNullString(v)? v.toUpperCase() : isArray(v)? v.join(arrayValueSeparator): v;
1521
- }
1522
- }
1523
1522
  if(defaultStr(columnDef.format).toLowerCase() === 'hashtag'){
1524
1523
  _render = <Hashtag>{_render}</Hashtag>
1525
1524
  } else if(typeof columnDef.render === "function"){
@@ -1539,32 +1538,6 @@ export default class CommonDatagridComponent extends AppComponent {
1539
1538
  if(val === checkedValue){
1540
1539
  _render = checkedLabel;
1541
1540
  } else _render = uncheckedLabel;
1542
- } else if(false && arrayValueExists(['piece','selecttabledata','id'],_type)){
1543
- let _id = rowData[columnField];
1544
- if(isNonNullString(_id)){
1545
- let tableName = defaultStr(columnDef.tableName,columnDef.table).toUpperCase();
1546
- let dbName = defaultStr(columnDef.dbName);
1547
- if(!dataFileManager.isCommon(dbName) && (columnField == 'code' || _type =='piece')){
1548
- dbName = defaultStr(rowData.dbId,dbName);
1549
- tableName = defaultStr(rowData.table,tableName)
1550
- }
1551
- dbName = dataFileManager.sanitizeName(dbName,tableName);
1552
- let pref = "";
1553
- if(_type !=='piece'){
1554
- pref = (tableName+"/").rtrim("/")+"/";
1555
- _id = pref+_id.ltrim(pref);
1556
- }
1557
- if(rowData[columnField+"FoundInDB"] === false){
1558
- let fTitle = "Cet élément n'existe pas en base car n'a pas été trouvé dans un fichier";
1559
- _render = <Button icon={"database-remove"} title={fTitle}>
1560
- {rowData[columnField]}
1561
- </Button>
1562
- } else {
1563
- /*_render = <TableLink dbName={dbName} tableName = {tableName} _id = {
1564
- _id
1565
- }>{rowData[columnField]}</TableLink>*/
1566
- }
1567
- }
1568
1541
  } else if((_type.contains('select'))){
1569
1542
  let v1 = rowData[columnField];
1570
1543
  _render = v1;
@@ -1679,19 +1652,6 @@ export default class CommonDatagridComponent extends AppComponent {
1679
1652
 
1680
1653
  export const ProgressBar = CommonDatagridComponent.LinesProgressBar;
1681
1654
 
1682
- ///cette fonction permet de retourner le nom de la base de données à utiliser pour la récupération des données
1683
- export const getDBName = CommonDatagridComponent.getDBName = (arg)=>{
1684
- if(isNonNullString(arg)){
1685
- arg = {dbName:arg};
1686
- }
1687
- arg = defaultObj(arg);
1688
- let {dbName} = arg;
1689
- if(typeof (dbName) =='function'){
1690
- dbName = dbName(arg)
1691
- }
1692
- return defaultStr(dbName);
1693
- }
1694
-
1695
1655
  CommonDatagridComponent.getDefaultPreloader = (props)=>{
1696
1656
  return <Preloader {...defaultObj(props)}/>
1697
1657
  }
@@ -1864,3 +1824,16 @@ const styles = StyleSheet.create({
1864
1824
  //width : 27,
1865
1825
  },
1866
1826
  })
1827
+
1828
+ /**** cette fonction permet de retourner le nom de la source de données à utiliser pour l'exécution de la requête */
1829
+ export const getDataSource = CommonDatagridComponent.getDataSource = (arg)=>{
1830
+ if(isNonNullString(arg)){
1831
+ arg = {dataSource:arg};
1832
+ }
1833
+ arg = defaultObj(arg);
1834
+ let {dataSource} = arg;
1835
+ if(typeof (dataSource) =='function'){
1836
+ dataSource = dataSource(arg)
1837
+ }
1838
+ return defaultStr(dataSource);
1839
+ }
@@ -1,34 +1,24 @@
1
1
  import CommonDatagrid from "./Common";
2
- import {defaultObj,defaultStr,isNonNullString,isFunction,isPromise} from "$utils";
3
- //import {mountDatabaseTable,unmountDatabaseTable,unlockTable,isTableLocked} from "$database/utils";
2
+ import {defaultObj,extendObj,defaultStr,isNonNullString,isFunction,isPromise} from "$utils";
4
3
  import actions from "$actions";
5
4
  import PropTypes from "prop-types";
6
- import APP from "$capp";
7
- //import {getDataFunc} from "$database/getData";
8
5
 
9
6
  export default class CommonTableDatagrid extends CommonDatagrid{
10
7
  constructor(props){
11
8
  super(props);
12
9
  let {
13
- data,
14
10
  tableName,
15
11
  table,
16
- dbName,
17
- server,
12
+ dataSource,
18
13
  } = props;
19
- dbName = CommonDatagrid.getDBName({...props,server,dbName,context:this});
14
+ dataSource = CommonDatagrid.getDataSource({...props,dataSource,context:this});
20
15
  tableName = defaultStr(tableName,table).toUpperCase();
21
16
  if(tableName){
22
17
  Object.defineProperties(this,{
23
18
  tableName : {value:tableName,override:false,writable:false}
24
19
  })
25
20
  }
26
- if(isNonNullString(tableName)){
27
- data = defaultVal(data,dbName+'['+tableName+']');
28
- unlockTable(tableName);
29
- mountDatabaseTable(tableName,dbName);
30
- }
31
- this.INITIAL_STATE.fetchData = defaultVal(this.props.fetchData,data);
21
+ this.INITIAL_STATE.fetchData = defaultVal(this.props.fetchData);
32
22
  let isPv = this.isPivotDatagrid();
33
23
  if(isPv){
34
24
  isPv = this.props.dbSelector !== false;
@@ -38,9 +28,9 @@ export default class CommonTableDatagrid extends CommonDatagrid{
38
28
  ['table','tableName'].map((tb,idx)=>{
39
29
  dbSelectorProps[tb] = defaultStr(this.props[tb],dbSelectorProps[tb]);
40
30
  });
41
- this.setSessionData({selectedDatabases:this.currentDatabases});
31
+ this.setSessionData({selectedDataSources:this.currentDataSources});
42
32
  } else {
43
- this.currentDatabases = Object.toArray(this.currentDatabases);
33
+ this.currentDataSources = Object.toArray(this.currentDataSources);
44
34
  }
45
35
  this.state.isLoading = true;
46
36
  }
@@ -48,9 +38,6 @@ export default class CommonTableDatagrid extends CommonDatagrid{
48
38
  /*** lorsque la données est modifiée */
49
39
  onUpsertData =(arg) =>{
50
40
  if(!this._isMounted()) return;
51
- if(isTableLocked(this.tableName)) {
52
- return;
53
- }
54
41
  this.isDataJustComeToUpsert = true; ///on empêche d'afficher le progress bar
55
42
  this.fetchData(true).finally(()=>{
56
43
  this.isDataJustComeToUpsert = undefined;
@@ -59,38 +46,29 @@ export default class CommonTableDatagrid extends CommonDatagrid{
59
46
 
60
47
  componentDidMount(){
61
48
  super.componentDidMount();
62
- APP.extend(this._events,{
49
+ extendObj(this._events,{
63
50
  onUpsertData : this.onUpsertData.bind(this),
64
51
  });
65
- if(isNonNullString(this.tableName)){
66
- APP.on(actions.upsert(this.tableName),this._events.onUpsertData)
67
- APP.on(actions.onRemove(this.tableName),this._events.onUpsertData)
68
- }
69
52
  this.fetchData(true);
70
53
  }
71
54
 
72
55
  componentWillUnmount(){
73
56
  super.componentWillUnmount();
74
- if(isNonNullString(this.tableName)){
75
- unmountDatabaseTable(this.tableName);
76
- APP.off(actions.upsert(this.tableName),this._events.onUpsertData);
77
- APP.off(actions.onRemove(this.tableName),this._events.onUpsertData);
78
- }
79
57
  this.clearEvents();
80
58
  this.setSelectedRows();
81
59
  }
82
60
 
83
- onChangeDatabases(args){
84
- let {databases,server} = args;
85
- this.currentDatabases = databases;
86
- if(JSON.stringify({databases:this.previousDatabases}) != JSON.stringify({databases})){
61
+ onChangeDataSources(args){
62
+ let {dataSources,server} = args;
63
+ this.currentDataSources = dataSources;
64
+ if(JSON.stringify({dataSources:this.previousDataSources}) != JSON.stringify({dataSources})){
87
65
  if(isObj(this.props.dbSelectorProps) && isFunction(this.props.dbSelectorProps.onChange)){
88
66
  args.datagridContext = this;
89
67
  this.props.dbSelectorProps.onChange(args);
90
68
  }
91
69
  this.refresh(true);
92
70
  }
93
- this.previousDatabases = databases;
71
+ this.previousDataSources = dataSources;
94
72
  this.previousServer = server;
95
73
  }
96
74
  refresh (force,cb){
@@ -112,7 +90,7 @@ export default class CommonTableDatagrid extends CommonDatagrid{
112
90
  }
113
91
  /**** retourne la liste des items, utile lorsqu'une s'agit d'une fonction
114
92
  Lorsque data est une chaine de caractère, alors elle doit être sous la forme recommandée par la function
115
- getDataFunc de l'object database
93
+ getDataFunc de l'object dataSource
116
94
  la props data, peut être une chaine de caractère contenant le nom de la base et de la bd de travail de l'application
117
95
  example common[articles], dans ce cas, la fonction fetchData, aura pour rôle de chercher toutes les données qui match
118
96
  la table dans la base common.
@@ -160,9 +138,9 @@ export default class CommonTableDatagrid extends CommonDatagrid{
160
138
  fetchOptions = defaultObj(fetchOptions);
161
139
  fetchOptions.selector = defaultObj(fetchOptions.selector);
162
140
  fetchOptions.selector.$and = defaultArray(fetchOptions.selector.$and);
163
- fetchOptions.databases = this.currentDatabases;
164
- fetchOptions = APP.extend(true,true,{},{selector : this.getFilters()},fetchOptions,this.filtersSelectors);
165
- fetchOptions.databases = this.currentDatabases;
141
+ fetchOptions.dataSources = this.currentDataSources;
142
+ fetchOptions = extendObj(true,true,{},{selector : this.getFilters()},fetchOptions,this.filtersSelectors);
143
+ fetchOptions.dataSources = this.currentDataSources;
166
144
  let limit = this.getQueryLimit();
167
145
  if(limit > 0 && !this.isPivotDatagrid()){
168
146
  fetchOptions.limit = limit;
@@ -172,13 +150,9 @@ export default class CommonTableDatagrid extends CommonDatagrid{
172
150
  }
173
151
  }
174
152
  if(isFunction(this.props.fetchData)){
175
- //fetchOptions.limit = defaultNumber(fetchOptions.limit,100);
176
153
  /**** l'on peut définir la props fetchData, qui est la fonction appelée pour la recherche des données */
177
154
  fetchData = this.props.fetchData.call(this,fetchOptions);
178
155
  }
179
- if(isNonNullString(fetchData)) {
180
- //fetchData = getDataFunc(fetchData,fetchOptions);
181
- }
182
156
  fetchData = isFunction(fetchData)? fetchData.call(this,fetchOptions) : fetchData;
183
157
  this.updateProgress({isLoading:true},()=>{
184
158
  if(isPromise(fetchData)){
@@ -103,21 +103,25 @@ const DatagridFactory = (Factory)=>{
103
103
  return super.updateLayout(e);
104
104
  }
105
105
  scrollToEnd(){
106
+ if(!this.canScrollTo()) return;
106
107
  if(this.listRef.current && this.listRef.current.scrollToEnd){
107
108
  return this.listRef.current.scrollToEnd();
108
109
  }
109
110
  }
110
111
  scrollToLeft(){
112
+ if(!this.canScrollTo()) return;
111
113
  if(this.listRef.current && this.listRef.current.scrollToLeft){
112
114
  return this.listRef.current.scrollToLeft();
113
115
  }
114
116
  }
115
117
  scrollToTop(opts){
118
+ if(!this.canScrollTo()) return;
116
119
  if(this.listRef.current && this.listRef.current.scrollToTop){
117
120
  return this.listRef.current.scrollToTop(opts);
118
121
  }
119
122
  }
120
123
  scrollToIndex(index){
124
+ if(!this.canScrollTo()) return;
121
125
  index = typeof index =='number'? index : 0;
122
126
  if(this.listRef.current && this.listRef.current.scrollToIndex){
123
127
  this.listRef.current.scrollToIndex({index});
@@ -296,17 +300,17 @@ const DatagridFactory = (Factory)=>{
296
300
  testID={testID+"_HeaderMenus"}
297
301
  anchor={(props)=>(<Icon {...props} icon={'axis-z-arrow'}/>)}
298
302
  items = {[
299
- {
303
+ this.canScrollTo() && {
300
304
  text : 'Retour en haut',
301
305
  icon : "arrow-up-bold",
302
306
  onPress : this.scrollToTop.bind(this)
303
307
  },
304
- {
308
+ this.canScrollTo() &&{
305
309
  text : 'Retour A gauche',
306
310
  icon : "arrow-up-bold",
307
311
  onPress : this.scrollToLeft.bind(this)
308
312
  },
309
- {
313
+ this.canScrollTo() &&{
310
314
  text : 'Aller à la dernière ligne',
311
315
  icon : "arrow-down-bold",
312
316
  onPress : this.scrollToEnd.bind(this)
@@ -11,7 +11,7 @@ export * from "./Common";
11
11
  const DatagridMainComponent = React.forwardRef((props,ref)=>{
12
12
  const isDesk = isDesktopMedia();
13
13
  const isMob = isMobileMedia();
14
- const [isTableData] = React.useStateIfMounted(defaultStr(props.tableName,props.table) || typeof props.fetchData ==='function' || props.isTableData?true : false);
14
+ const [isTableData] = React.useState(defaultStr(props.tableName,props.table) || typeof props.fetchData ==='function' || props.isTableData?true : false);
15
15
  const TableComponent = isTableData ? DatagridTableData : Table;
16
16
  const AccordionComponent = isTableData ? TableDataAccordion : Accordion;
17
17
  let Component = TableComponent;
@@ -1,4 +1,4 @@
1
- import * as React from 'react'
1
+ import React from '$react'
2
2
 
3
3
  import {useInputFormat,compareTwoDates,locale as defaultLocale,toDateObj} from "../utils";
4
4
  import TextInputWithMask from './TextInputMask'
@@ -34,6 +34,7 @@ const DatePickerInput = React.forwardRef(({
34
34
  withModal = true,
35
35
  withDateFormatInLabel = true,
36
36
  right:customRight,
37
+ left : customLeft,
37
38
  helperText,
38
39
  format,
39
40
  disabled,readOnly,editable
@@ -42,6 +43,7 @@ const DatePickerInput = React.forwardRef(({
42
43
  style,
43
44
  anchorProps,
44
45
  render_filter,
46
+ calendarIconBefore = false, //si l'icone calendar sera en position left où non
45
47
  ...rest
46
48
  },ref)=>{
47
49
  inputMode = defaultStr(inputMode,"start");
@@ -104,10 +106,14 @@ const DatePickerInput = React.forwardRef(({
104
106
  anchorProps = defaultObj(anchorProps);
105
107
  label = defaultStr(label,text);
106
108
  customRight = React.isValidElement(customRight) || typeof customRight =='function'? customRight : null;
107
- let right = null;
109
+ let right = customRight,left = customLeft, isIconLeft = calendarIconBefore;
108
110
  if(withModal){
109
- right = (props)=>{
111
+ const customLOrR = isIconLeft ? customLeft : customRight;
112
+ const leftOrRight = (props)=>{
113
+ let c = typeof customLOrR =='function'? customLOrR(props): customLOrR;
114
+ c = React.isValidElement(c)? c : null;
110
115
  return <>
116
+ {isIconLeft ? c : null}
111
117
  <Icon
112
118
  {...anchorProps}
113
119
  {...props}
@@ -119,10 +125,15 @@ const DatePickerInput = React.forwardRef(({
119
125
  hasTVPreferredFocus={undefined}
120
126
  tvParallaxProperties={undefined}
121
127
  />
122
- {typeof customRight =='function'? customRight(props): customRight}
128
+ {!isIconLeft ? c : null}
123
129
  </>
124
130
  }
125
- } else right = customRight;
131
+ if(isIconLeft){
132
+ left = leftOrRight;
133
+ } else {
134
+ right = leftOrRight;
135
+ }
136
+ }
126
137
  const onConfirm = (date,updateVisibility) => {
127
138
  const vDate = validateDate(date);
128
139
  const inputDate = !vDate.error ? date : state.inputDate;
@@ -149,6 +160,7 @@ const DatePickerInput = React.forwardRef(({
149
160
  style = {[styles.input,style]}
150
161
  editable = {editable}
151
162
  disabled = {disabled}
163
+ left = {left}
152
164
  right = {right}
153
165
  pointerEvents = {isEditable?"auto":"none"}
154
166
  ref={ref}
@@ -250,4 +262,5 @@ const styles = StyleSheet.create({
250
262
  DatePickerInput.propTypes = {
251
263
  onChange : PropTypes.func,
252
264
  anchorProps : PropTypes.object,///les props à appliquer à l'icone date permettant de sélectionner la date
265
+ calendarIconBefore : PropTypes.bool,///la position de l'icone calendrier pour la sélection de la date
253
266
  }
@@ -2,11 +2,12 @@ import "../utils";
2
2
  import DateTimePicker from '@react-native-community/datetimepicker';
3
3
  import DateLib from "$lib/date";
4
4
  export default function DateTimePickerComponent(props){
5
- const {visible,date,onDateChange,startDate,endDate,onCancel} = props;
5
+ const {visible,date,onDateChange,startDate,endDate,onCancel,...rest} = props;
6
6
  const value = DateLib.isDateObj(date)?date:new Date();
7
7
  return visible? <DateTimePicker
8
- value = {value}
9
8
  mode = {"date"}
9
+ {...rest}
10
+ value = {value}
10
11
  minimumDate = {startDate}
11
12
  maximumDate = {endDate}
12
13
  onChange = {(e,selectedDate)=>{
@@ -2,5 +2,34 @@
2
2
  // Use of this source code is governed by a BSD-style
3
3
  // license that can be found in the LICENSE file.
4
4
 
5
- import Date from "./Date";
6
- import Time from "./Time";
5
+ import Date from "./DatePickerInput";
6
+ import Time from "./Time";
7
+ import React from "$react";
8
+ import PropTypes from "prop-types";
9
+ import {defaultObj} from "$utils";
10
+
11
+ export default function DateTimePickerComponent({left,right,dateProps,timeProps,defaultValue,...porps}){
12
+ dateProps = defaultObj(dateProps);
13
+ timeProps = defaultObj(timeProps);
14
+ return <Date
15
+ defaultValue = {defaultValue}
16
+ {...dateProps}
17
+ calendarIconBefore = {true}
18
+ left = {left}
19
+ right = {(p)=>{
20
+ const r = typeof right =='function'? right(p): React.isValidElement(right)? right : null;
21
+ return <>
22
+ <Time
23
+ defaultValue = {defaultValue}
24
+ {...timeProps}
25
+ />
26
+ {r}
27
+ </>
28
+ }}
29
+ />
30
+ }
31
+
32
+ DateTimePickerComponent.propTypes = {
33
+ dateProps : PropTypes.object,
34
+ timeProps : PropTypes.object,
35
+ }
@@ -2,12 +2,13 @@ import "../utils";
2
2
  import DateLib from "$lib/date";
3
3
  import DateTimePicker from '@react-native-community/datetimepicker';
4
4
  export default function TimePickerComponent(props){
5
- const {visible,date,onTimeChange,onCancel} = props;
5
+ const {visible,date,onTimeChange,onCancel,...rest} = props;
6
6
  const value = DateLib.isDateObj(date)?date:new Date();
7
7
  return visible? <DateTimePicker
8
- value = {value}
9
8
  mode = {"time"}
10
9
  is24Hour={true}
10
+ {...rest}
11
+ value = {value}
11
12
  onChange = {(e,selectedDate)=>{
12
13
  if(!selectedDate){
13
14
  if(typeof onCancel ==='function'){
@@ -1,4 +1,4 @@
1
- import PickerInput from "./PickerInput";
1
+ import PickerInput from "./DatePickerInput";
2
2
 
3
3
  export * from "./utils";
4
4
 
@@ -9,3 +9,5 @@ export default DateComponent;
9
9
 
10
10
 
11
11
  export {default as Time} from "./Time";
12
+
13
+ export {default as DateTime} from "./DateTime";
@@ -52,6 +52,7 @@ const DialogComponent = React.forwardRef((props,ref)=>{
52
52
  onAlertRequestClose,
53
53
  isFormData,
54
54
  isPreloader,
55
+ borderRadius,
55
56
  ...modalProps
56
57
  } = props;
57
58
  withScrollView = typeof withScrollView =='boolean'? withScrollView : false;
@@ -161,9 +162,13 @@ const DialogComponent = React.forwardRef((props,ref)=>{
161
162
  const testID = defaultStr(modalProps.testID,"RN_DialogComponent");
162
163
  const maxHeight = getMaxHeight(),maxWidth = getMaxWidth();
163
164
  const backgroundColor = theme.surfaceBackgroundColor;
165
+ borderRadius = fullScreen || !isMobileNative() || isPreloader ? 0 : typeof borderRadius =='number'? borderRadius : 7*theme.roundness;
164
166
  const fullScreenStyle = fullScreen ? {width:dimensions.width,height:dimensions.height,marginHorizontal:0,paddingHorizontal:0}: {
165
167
  maxWidth,
166
168
  maxHeight,
169
+ borderRadius,
170
+ paddingTop : borderRadius,
171
+ paddingBottom : borderRadius,
167
172
  };
168
173
  const alertContentStyle = isAlert ? {paddingHorizontal:15} : null;
169
174
  content = <Surface ref={contentRef} testID = {testID+"_Content11"} {...contentProps} style={[fullScreen? {flex:1}:{maxWidth,maxHeight:maxHeight-Math.min(SCREEN_INDENT*2+50,100)},isPreloader && {paddingHorizontal:10},{backgroundColor},alertContentStyle,contentProps.style]}>
@@ -1,14 +1,15 @@
1
1
  import {Pressable} from "react-native";
2
2
  import View from "$ecomponents/View";
3
3
  import Icon from "$ecomponents/Icon";
4
- import {defaultObj,isBool,defaultBool} from "$utils";
4
+ import {defaultObj,isBool,defaultBool,defaultStr} from "$utils";
5
5
  import PropTypes from "prop-types"
6
6
  import React from "$react";
7
7
  import DrawerItem from "./DrawerItem";
8
8
  import theme from "$theme";
9
9
 
10
10
  export default function ExpandableItem(props){
11
- let {children,expanded,expandedIcon,minimized,onPress,expandIconProps,unexpandedIcon,onToggleExpand,wrapperProps,...rest} = props;
11
+ let {children,expanded,expandedIcon,testID,minimized,onPress,expandIconProps,unexpandedIcon,onToggleExpand,wrapperProps,...rest} = props;
12
+ testID = defaultStr(testID,"RN_ExpandableDrawerItemComponent")
12
13
  wrapperProps = defaultObj(wrapperProps);
13
14
  const [expandedControled,setExpended] = React.useStateIfMounted(defaultBool(expanded,false))
14
15
  let _expanded = expanded;
@@ -24,10 +25,10 @@ export default function ExpandableItem(props){
24
25
  }
25
26
  expandIconProps = defaultObj(expandIconProps);
26
27
  const icon = _expanded ? defaultVal(expandedIcon,"chevron-up") : defaultVal(unexpandedIcon,"chevron-down")
27
- rest.right = (props)=> <Icon {...props} style={{margin:0}} size={minimized?15:24} icon={icon} onPress={_onToggleExpand}/>
28
- return <View {...wrapperProps}>
29
- <DrawerItem color={_expanded?theme.colors.primary:undefined} {...rest} minimized={minimized} isExpandable onPress={_onToggleExpand}/>
30
- {_expanded && <Pressable style={{marginLeft:10}}>
28
+ rest.right = (props)=> <Icon testID={testID+"_Right"} {...props} style={{margin:0}} size={minimized?15:24} icon={icon} onPress={_onToggleExpand}/>
29
+ return <View {...wrapperProps} testID={testID+"_Wrapper"}>
30
+ <DrawerItem testID={testID} color={_expanded?theme.colors.primary:undefined} {...rest} minimized={minimized} isExpandable onPress={_onToggleExpand}/>
31
+ {_expanded && <Pressable testID={testID+"_ExpandedContent"} style={{marginLeft:10}}>
31
32
  <React.Fragment>{children}</React.Fragment>
32
33
  </Pressable>}
33
34
  </View>
@@ -1,7 +1,7 @@
1
1
  import {Colors} from "$theme";
2
2
  import React from 'react';
3
3
  import View from "$ecomponents/View";
4
- import {StyleSheet,TouchableWithoutFeedback} from 'react-native';
4
+ import {StyleSheet,TouchableWithoutFeedback,ScrollView} from 'react-native';
5
5
  import {withTheme,TouchableRipple} from "react-native-paper"
6
6
  import Label from "$ecomponents/Label";
7
7
  import Icon from "$ecomponents/Icon"
@@ -42,6 +42,8 @@ const ExpandableComponent = React.forwardRef(({
42
42
  containerProps,
43
43
  autoMountChildren = false,
44
44
  expandIconPosition,
45
+ withScrollView = false,
46
+ scrollViewProps,
45
47
  ...props
46
48
  },ref) => {
47
49
  props = defaultObj(props);
@@ -88,6 +90,12 @@ const ExpandableComponent = React.forwardRef(({
88
90
  right = null;
89
91
  }
90
92
  testID = defaultStr(testID,"RN_ExpandableComponent");
93
+ if(withScrollView){
94
+ scrollViewProps = Object.assign({},scrollViewProps);
95
+ children = <ScrollView vertical style={[{flex:1}]} {...scrollViewProps} testID={testID+"_ScrollView"}>
96
+ {children}
97
+ </ScrollView>
98
+ }
91
99
  const expandIcon = showExpandIcon !== false ? <Icon
92
100
  color={titleColor}
93
101
  size={24}
@@ -151,7 +159,8 @@ const ExpandableComponent = React.forwardRef(({
151
159
  </View>
152
160
  </TouchableWithoutFeedback>
153
161
  {(autoMountChildren !== false || isExpanded) ? <View testID={testID+'_Content'} {...contentProps}
154
- style={[styles.children,contentProps.style,!isExpanded && {opacity:0,height:0}]}>
162
+ style={[{maxWidth:'100%'},styles.children,contentProps.style,!isExpanded && {opacity:0,height:0}]}
163
+ >
155
164
  {children}
156
165
  </View> : null}
157
166
  </Surface>
@@ -217,6 +226,7 @@ ExpandableComponent.propTypes = {
217
226
  expandIconPosition : PropTypes.oneOf([
218
227
  'left','right'
219
228
  ]),
229
+ withScrollView : PropTypes.bool,///si le contenu sera rendu avec le scrollView
220
230
  autoMountChildren : PropTypes.bool,///si les enfants du composant seront montés mais masqués et lorsqu'on cliquera sur toggle ceux-ci seront affichés
221
231
  leftProps : PropTypes.object, ///les props à paser à la vue qui rend le contenu gouche
222
232
  rightProps : PropTypes.object, ///les props à passer à la vue qui rend le contenu droit
@@ -567,8 +567,11 @@ export default class Field extends AppComponent {
567
567
  let form = this.getForm();
568
568
  if(!this.canValidate) return;
569
569
  let {keyboardEvents,onKeyEvent} = this.props;
570
- let formInstance = this.getForm();
571
- let arg = {key,event,context:this,isFormField:true,formInstance};
570
+ const formInstance = this.getForm();
571
+ const arg = {key,event,formInstance,field:this.name,formName:this.getFormName(),value:this.getValidRule(),validValue:this.getValidValue(),context:this,isFormField:true,data:{},formInstance};
572
+ if(formInstance ){
573
+ arg.data = formInstance.getData();
574
+ }
572
575
  let handler = undefined;
573
576
  if(isObj(keyboardEvents)){
574
577
  handler = keyboardEvents[key];
@@ -584,16 +587,19 @@ export default class Field extends AppComponent {
584
587
  }
585
588
  handler = undefined;
586
589
  if(formInstance && isObj(formInstance.props)){
587
- let pIP = formInstance.props;
588
- if(isObj(pIP.keyboardEvents)){
589
- handler = pIP.keyboardEvents[key];
590
+ const formInstanceProps = formInstance.props;
591
+ if(key =='enter' && isFunction(formInstanceProps.onEnterKeyPress) && formInstance.isValid()){
592
+ if(formInstanceProps.onEnterKeyPress.call(this,arg) === false) return;
593
+ }
594
+ if(isObj(formInstanceProps.keyboardEvents)){
595
+ handler = formInstanceProps.keyboardEvents[key];
590
596
  if(isFunction(handler)) handler.call(this,arg);
591
597
  }
592
598
  if(!isFunction(handler)){
593
- if(isFunction(pIP.keyboardEvents)){
594
- handler = pIP.keyboardEvents;
595
- } if(isFunction(pIP.onKeyEvent)){
596
- handler = pIP.onKeyEvent;
599
+ if(isFunction(formInstanceProps.keyboardEvents)){
600
+ handler = formInstanceProps.keyboardEvents;
601
+ } if(isFunction(formInstanceProps.onKeyEvent)){
602
+ handler = formInstanceProps.onKeyEvent;
597
603
  }
598
604
  if(isFunction(handler)) handler.call(this,arg);
599
605
  }
@@ -101,6 +101,7 @@ export default class FormComponent extends React.AppComponent {
101
101
  onNoValidateField,
102
102
  onKeyEvent,
103
103
  keyboardEvents,
104
+ onEnterKeyPress,
104
105
  testID,
105
106
  ...rest
106
107
  } = this.props;
@@ -210,6 +211,7 @@ FormComponent.propTypes = {
210
211
  PropTypes.object,
211
212
  PropTypes.func,
212
213
  ]),
214
+ onEnterKeyPress : PropTypes.func, ///Lorsque l'on table la touche entrée du clavier
213
215
  onKeyEvent : PropTypes.func/*** l'évènement global appelé lorsqu'on clique sur une champ de la form */,
214
216
  }
215
217
 
@@ -55,7 +55,7 @@ export default class FormDataActionComponent extends FormData {
55
55
  }
56
56
  appBarProps.isEditing = isEditing;
57
57
  if(appBarProps.subtitle !== false && this.props.subtitle !== false && mainProps.subtitle !== false){
58
- appBarProps.subtitle = subtitle = defaultVal(appBarProps.subtitle,subtitle);
58
+ appBarProps.subtitle = subtitle = defaultVal(appBarProps.subtitle,this.props.subtitle,subtitle);
59
59
  }
60
60
  return appBarProps;
61
61
  }
@@ -159,7 +159,7 @@ const CommonListComponent = React.forwardRef((props,ref)=>{
159
159
  const restP = numColumns > 1 && isFlatList ? {
160
160
  columnWrapperStyle : [styles.columnWrapperStyle,props.columnWrapperStyle]
161
161
  } : {};
162
- return <View {...containerProps} style={[{backgroundColor:theme.colors.surface},styles.container,containerProps.style]}>
162
+ return <View {...containerProps} style={[styles.container,containerProps.style]}>
163
163
  <Component
164
164
  onEndReachedThreshold={0}
165
165
  scrollEventThrottle={16}
@@ -20,6 +20,7 @@ import {defaultDecimal,extendObj} from "$utils";
20
20
  import theme,{StylePropTypes} from "$theme";
21
21
  import APP from "$app/instance";
22
22
  import MenuItem from "./Item";
23
+ import {isWeb} from "$platform";
23
24
 
24
25
  const RESIZE_PAGE = APP.EVENTS.RESIZE_PAGE;
25
26
 
@@ -277,7 +278,6 @@ class _Menu extends AppComponent {
277
278
  } = this.props;
278
279
  const testID = defaultStr(this.props.testID,"RN_MainMenuComponent");
279
280
  const {
280
- rendered1,
281
281
  menuLayout,
282
282
  anchorLayout,
283
283
  opacityAnimation,
@@ -389,12 +389,10 @@ class _Menu extends AppComponent {
389
389
 
390
390
  // Scrollable menu max height
391
391
  if(handleScroll){
392
- scrollableMenuHeight =
393
- scrollableMenuHeight > windowLayout.height - 2 * SCREEN_INDENT
392
+ scrollableMenuHeight = scrollableMenuHeight > windowLayout.height - 2 * SCREEN_INDENT
394
393
  ? windowLayout.height - 2 * SCREEN_INDENT
395
394
  : scrollableMenuHeight;
396
395
  }
397
-
398
396
  // _Menu is typically positioned below the element that generates it
399
397
  // So first check if it fits below the anchor (expands downwards)
400
398
  if (
@@ -475,7 +473,8 @@ class _Menu extends AppComponent {
475
473
  if(positionStyle.top < SCREEN_INDENT){
476
474
  positionStyle.top = SCREEN_INDENT;
477
475
  }
478
-
476
+ const maxMenuHeight = windowLayout.height - top - SCREEN_INDENT;
477
+ const contentContainerStyle = maxMenuHeight > SCREEN_INDENT ? {maxHeight:maxMenuHeight} : undefined;
479
478
  return (
480
479
  <View
481
480
  testID = {testID}
@@ -521,8 +520,7 @@ class _Menu extends AppComponent {
521
520
  ]
522
521
  }
523
522
  >
524
- {(scrollableMenuHeight && (
525
- <ScrollView testID={testID+"_ScrollView"}>{children}</ScrollView>
523
+ {((scrollableMenuHeight|| contentContainerStyle) && (<ScrollView contentContainerStyle={contentContainerStyle} testID={testID+"_ScrollView"}>{children}</ScrollView>
526
524
  )) || children}
527
525
  </Surface>
528
526
  </Animated.View>
@@ -0,0 +1,67 @@
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
+ /****Le composant TableLink est utilisé pour les liens cliquable vers les tables de données */
5
+ import {TouchableOpacity,StyleSheet} from "react-native";
6
+ import React from "$react";
7
+ import View from "$components/View";
8
+ import PropTypes from "prop-types";
9
+ import Label from "$components/Label";
10
+ import {defaultStr,isPromise,defaultObj} from "$utils";
11
+ import {open as openPreloader,close as closePreloader} from "$preloader";
12
+ import {styles as _styles} from "$theme";
13
+ import Tooltip from "$components/Tooltip";
14
+
15
+ const TableLinKComponent = React.forwardRef((props,ref)=>{
16
+ let {disabled,labelProps,server,containerProps,testID,Component,routeName,routeParams,component,_id,primary,triggerProps,onPress,children, ...rest} = props;
17
+ testID = defaultStr(testID,"RN_TableDataLinkContainer")
18
+ rest = defaultObj(rest);
19
+ containerProps = defaultObj(containerProps)
20
+ labelProps = defaultObj(labelProps);
21
+ _id = defaultStr(_id);
22
+ if(!_id){
23
+ disabled = true;
24
+ }
25
+ const pointerEvents = disabled || !_id? 'none' : 'auto';
26
+ const onPressLink = (event)=>{
27
+ React.stopEventPropagation(event);
28
+ const r = typeof onPress =='function'? onPress(event) : undefined;
29
+ if(isPromise(r)){
30
+ openPreloader("traitement de la requête...");
31
+ r.finally(closePreloader);
32
+ }
33
+ }
34
+ rest.style = [rest.style,_styles.cursorPointer];
35
+ const CP = disabled ? View : TouchableOpacity;
36
+ return <CP testID={testID} onLongPres={(e)=>React.stopEventPropagation(e)} {...containerProps} onPress={disabled? undefined : onPressLink} style={[styles.container,containerProps.style]}>
37
+ <Tooltip testID={testID+"_Tooltip"} {...rest} Component={Component} onPress={disabled?undefined:onPressLink} ref={ref} pointerEvents={pointerEvents} disabled = {disabled}>
38
+ <Label testID={testID+"_Label"} underlined primary {...labelProps} style={[_styles.lh15,labelProps.style]} disabled={disabled}>{children}</Label>
39
+ </Tooltip>
40
+ </CP>
41
+ });
42
+
43
+ export default TableLinKComponent;
44
+
45
+
46
+ TableLinKComponent.propTypes = {
47
+ server : PropTypes.string,//le serveur sur lequel rechercher les données
48
+ primary : PropTypes.bool,//si le composant sera stylé en theme primary de react
49
+ ///les props à utiliser pour afficher la table de données en cas de click sur le lien
50
+ triggerProps : PropTypes.object,
51
+ /*** l'id de la données à récupérer en cas de clic sur le lien */
52
+ _id : PropTypes.string.isRequired,
53
+ routeName : PropTypes.string,///la route via laquelle on devra naviguer
54
+ routeParam : PropTypes.object,///les props à passer à la route en question
55
+ children : PropTypes.node
56
+ }
57
+
58
+ const styles = StyleSheet.create({
59
+ container : {
60
+ alignSelf : 'flex-start',
61
+ flexGrow : 0,
62
+ paddingRight : 5,
63
+ paddingVertical : 5,
64
+ }
65
+ })
66
+
67
+ TableLinKComponent.displayName = "TableLinKComponent";
@@ -7,10 +7,10 @@ import PropTypes from "prop-types";
7
7
  import HelperText from "$ecomponents/HelperText";
8
8
  import Icon,{COPY_ICON} from "$ecomponents/Icon";
9
9
  import Label from "$ecomponents/Label";
10
- import {isAndroid as _isAndroid,isMobileNative,isIos as _isIos,isWeb as _isWeb} from "$cplatform";
10
+ import {isAndroid as _isAndroid,isIos as _isIos,isWeb as _isWeb} from "$cplatform";
11
11
  import {isMobileMedia,isDesktopMedia} from "$cplatform/dimensions";
12
12
  import {keyboardTypes,FONT_SIZE,parseDecimal,HEIGHT,outlinedMode,modes,flatMode,normalMode,shadowMode} from "./utils";
13
- import {copyTextToClipboard} from "$capp/clipboard/utils";
13
+ import {copyTextToClipboard} from "$clipboard/utils";
14
14
  import Surface from "$ecomponents/Surface";
15
15
  import View from "$ecomponents/View";
16
16
  const PADDING_HORIZONTAL_FLAT_MODE = 2;