@fto-consult/expo-ui 8.14.5 → 8.15.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/babel.config.alias.js +1 -21
- package/bin/create-app/dependencies.js +0 -1
- package/bin/create-app/metro.config.js +38 -1
- package/metro.config.js +0 -20
- package/package.json +4 -4
- package/src/components/Checkbox/Checkbox.js +183 -0
- package/src/components/Checkbox/Item.js +168 -0
- package/src/components/Checkbox/Item.native.js +13 -0
- package/src/components/Checkbox/index.js +5 -2
- package/src/components/Datagrid/SWRDatagrid.js +7 -1
- package/src/components/Form/Fields/Field.js +1 -1
- package/src/components/Image/index.js +9 -4
- package/src/components/View/index.js +1 -1
- package/src/screens/Auth/PermLine.js +45 -37
- package/src/screens/Auth/PermText.js +4 -0
- package/src/screens/Help/openLibraries.js +13 -8
- package/src/components/Date/DatePickerModal/index.native1.js +0 -23
package/babel.config.alias.js
CHANGED
@@ -2,7 +2,6 @@ const path = require("path");
|
|
2
2
|
const fs = require("fs");
|
3
3
|
|
4
4
|
module.exports = (opts)=>{
|
5
|
-
const isLocalDev = require("./is-local-dev")();
|
6
5
|
const dir = path.resolve(__dirname);
|
7
6
|
const projectRoot = typeof opts.projectRoot =='string' && fs.existsSync(opts.projectRoot.trim()) && opts.projectRoot.trim() || process.cwd();
|
8
7
|
const assets = path.resolve(dir,"assets");
|
@@ -19,9 +18,7 @@ module.exports = (opts)=>{
|
|
19
18
|
const expo = path.resolve(expoUI,"src");
|
20
19
|
r["$ecomponents"] = r["$expo-components"] = path.resolve(expo,"components");
|
21
20
|
r["$econfirm"] = path.resolve(r["$expo-components"],"Dialog","confirm");
|
22
|
-
r["$confirm"] = r["$confirm"] || r["$econfirm"];
|
23
21
|
r["$eauth"] = path.resolve(expo,"auth");
|
24
|
-
r["$components"] = r["$components"] || r["$ecomponents"];
|
25
22
|
r["$elayouts"] = path.resolve(expo,"layouts");
|
26
23
|
r["$emedia"] = path.resolve(expo,"media");
|
27
24
|
r["$enavigation"] = path.resolve(expo,"navigation");
|
@@ -36,8 +33,6 @@ module.exports = (opts)=>{
|
|
36
33
|
r.$tableLink = r.$TableLink = r["$etableLink"] = r["$eTableLink"] = path.resolve(r["$ecomponents"],"TableLink");
|
37
34
|
|
38
35
|
r["$Screen"] = r["$Screen"] || r["$eScreen"];
|
39
|
-
r["$screens"] = r["$screens"] || r["$escreens"];
|
40
|
-
|
41
36
|
r["$expo"] = r["$expo-ui"] = expo;
|
42
37
|
r["$epreloader"] = path.resolve(expo,"components/Preloader");
|
43
38
|
r["$eform"] = path.resolve(expo,"components","Form");
|
@@ -55,12 +50,7 @@ module.exports = (opts)=>{
|
|
55
50
|
if(!r["$preloader"] || r["$preloader"] === r["$cpreloader"]){
|
56
51
|
r["$preloader"] = r["$epreloader"];
|
57
52
|
}
|
58
|
-
|
59
|
-
r["$enotify"] = r["$cnotify"];
|
60
|
-
}
|
61
|
-
if(!r["$chart"]){
|
62
|
-
r["$chart"] = r["$echart"];
|
63
|
-
}
|
53
|
+
r["$enotify"] = r["$cnotify"];
|
64
54
|
if(!r["$file-system"]){
|
65
55
|
r["$file-system"] = r["$efile-system"];
|
66
56
|
}
|
@@ -84,15 +74,5 @@ module.exports = (opts)=>{
|
|
84
74
|
r.$electronProjectRoot = path.resolve(r.$projectRoot,"electron");
|
85
75
|
r.$econtext = path.resolve(expo,"context");
|
86
76
|
r.$epdf = path.resolve(expo,"pdf");
|
87
|
-
if(!r.$context){
|
88
|
-
r.$context = r.$econtext;
|
89
|
-
}
|
90
|
-
r["$erealm"] = path.resolve(expo,'realm');
|
91
|
-
if(!r.$realm){
|
92
|
-
r.$realm = r.$erealm;
|
93
|
-
}
|
94
|
-
const {withRealm} = opts; //si la prise en compte de la base de données realm est nécessaire
|
95
|
-
const $realmProvider = path.resolve(r.$realm,"Provider");
|
96
|
-
r.$erealmProvider = r.$realmProvider = false && !withRealm ? path.resolve($realmProvider,"realm.not-enabled.js") : $realmProvider;
|
97
77
|
return r;
|
98
78
|
}
|
@@ -4,7 +4,6 @@ module.exports = {
|
|
4
4
|
"@expo/html-elements": "^0.5.1",
|
5
5
|
"@expo/vector-icons": "^14.0.0",
|
6
6
|
"@pchmn/expo-material3-theme": "^1.3.2",
|
7
|
-
"@react-native-community/datetimepicker": "^7.6.1",
|
8
7
|
"@react-native-community/netinfo": "^11.1.0",
|
9
8
|
"@react-native/assets-registry": "^0.72.0",
|
10
9
|
"@react-navigation/native": "^6.1.9",
|
@@ -1 +1,38 @@
|
|
1
|
-
|
1
|
+
const path = require("path");
|
2
|
+
const { getDefaultConfig } = require('@expo/metro-config');
|
3
|
+
module.exports = function(opts){
|
4
|
+
opts = opts && typeof opts =='object'? opts : {};
|
5
|
+
let {assetExts,sourceExts} = opts;
|
6
|
+
assetExts = Array.isArray(assetExts)? assetExts: [];
|
7
|
+
sourceExts= Array.isArray(sourceExts)?sourceExts : [];
|
8
|
+
const projectRoot = path.resolve(process.cwd());
|
9
|
+
//@see : https://docs.expo.dev/versions/latest/config/metro/
|
10
|
+
const config = getDefaultConfig(projectRoot,{});
|
11
|
+
// 2. Let Metro know where to resolve packages and in what order
|
12
|
+
const nodeModulesPaths = (Array.isArray(config.resolver.nodeModulesPaths)?config.resolver.nodeModulesPaths : []);
|
13
|
+
const nodeModulePath = path.resolve(projectRoot, 'node_modules');
|
14
|
+
if(!nodeModulesPaths.includes(nodeModulePath)){
|
15
|
+
nodeModulesPaths.unshift(nodeModulePath);
|
16
|
+
}
|
17
|
+
config.resolver.nodeModulesPaths = nodeModulesPaths;
|
18
|
+
config.projectRoot = projectRoot;
|
19
|
+
config.resolver.assetExts = [
|
20
|
+
...config.resolver.assetExts,
|
21
|
+
...assetExts,
|
22
|
+
"db",
|
23
|
+
"txt"
|
24
|
+
];
|
25
|
+
config.resolver.sourceExts = [
|
26
|
+
...config.resolver.sourceExts,
|
27
|
+
...sourceExts,"txt",
|
28
|
+
'jsx', 'js','tsx',
|
29
|
+
]
|
30
|
+
|
31
|
+
// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths`
|
32
|
+
config.resolver.disableHierarchicalLookup = true;
|
33
|
+
|
34
|
+
// Remove all console logs in production...
|
35
|
+
config.transformer.minifierConfig.compress.drop_console = false;
|
36
|
+
|
37
|
+
return config;
|
38
|
+
}
|
package/metro.config.js
CHANGED
@@ -2,7 +2,6 @@ const path = require("path");
|
|
2
2
|
const fs = require("fs");
|
3
3
|
const { getDefaultConfig } = require('@expo/metro-config');
|
4
4
|
module.exports = function(opts){
|
5
|
-
const isDev = 'development' === process.env.NODE_ENV;
|
6
5
|
opts = opts && typeof opts =='object'? opts : {};
|
7
6
|
let {assetExts,sourceExts} = opts;
|
8
7
|
assetExts = Array.isArray(assetExts)? assetExts: [];
|
@@ -20,17 +19,6 @@ module.exports = function(opts){
|
|
20
19
|
if(hasTranspilePath){
|
21
20
|
config.transformer.babelTransformerPath = transpilePath;
|
22
21
|
}
|
23
|
-
config.watchFolders = Array.isArray(config.watchFolders) && config.watchFolders || [];
|
24
|
-
const isLocalTest = require("./is-local-dev")();
|
25
|
-
if(!isLocalTest && isDev){
|
26
|
-
config.watchFolders.push(localDir);
|
27
|
-
}
|
28
|
-
if(isDev){
|
29
|
-
const commonP = path.resolve(projectRoot,"node_modules","@fto-consult","common");
|
30
|
-
if(fs.existsSync(commonP)){
|
31
|
-
config.watchFolders.push(commonP);
|
32
|
-
}
|
33
|
-
}
|
34
22
|
// 2. Let Metro know where to resolve packages and in what order
|
35
23
|
const nodeModulesPaths = (Array.isArray(config.resolver.nodeModulesPaths)?config.resolver.nodeModulesPaths : []);
|
36
24
|
const nodeModulePath = path.resolve(projectRoot, 'node_modules');
|
@@ -60,13 +48,5 @@ module.exports = function(opts){
|
|
60
48
|
// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths`, @see : https://docs.expo.dev/guides/monorepos/
|
61
49
|
config.resolver.disableHierarchicalLookup = true;
|
62
50
|
|
63
|
-
/*config.platforms = Array.isArray(config.platforms) && config.platforms || [];
|
64
|
-
['ios', 'android', 'windows', 'web',"electron"].map(p=>{
|
65
|
-
if(!config.platforms.includes(p)){
|
66
|
-
config.platforms.push(p);
|
67
|
-
}
|
68
|
-
});*/
|
69
|
-
///on génère les librairies open sources utilisées par l'application
|
70
|
-
//require("./find-licenses");
|
71
51
|
return config;
|
72
52
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@fto-consult/expo-ui",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.15.1",
|
4
4
|
"description": "Bibliothèque de composants UI Expo,react-native",
|
5
5
|
"scripts": {
|
6
6
|
"clear-npx-cache": "npx clear-npx-cache",
|
@@ -48,7 +48,7 @@
|
|
48
48
|
"dev": "npx expo start --no-dev --minify -c",
|
49
49
|
"modifier-url-remote-git": "git remote set-url origin 'https://borispipo@github.com/borispipo/smart-eneo.git'",
|
50
50
|
"update-app": "expo @emotion/native@latest react-native-big-list@latest @pchmn/expo-material3-theme@latest @emotion/native@latest @react-navigation/stack react-native-blob-util @react-navigation/native@latest @react-navigation/native-stack@latest && npx expo install --fix",
|
51
|
-
"update": "npm i @fto-consult/node-utils@latest apexcharts@latest file-saver@latest google-libphonenumber@latest @fto-consult/common@latest react-native-iphone-x-helper@latest react-native-mime-types@latest react-native-paper@5 react-native-paper-dates@latest react-virtuoso@latest tippy.js@latest websql@latest xlsx@latest react-native-
|
51
|
+
"update": "npm i @fto-consult/node-utils@latest apexcharts@latest file-saver@latest google-libphonenumber@latest @fto-consult/common@latest react-native-iphone-x-helper@latest react-native-mime-types@latest react-native-paper@5 react-native-paper-dates@latest react-virtuoso@latest tippy.js@latest websql@latest xlsx@latest react-native-get-random-values@latest && npm run update-apexchart && npm run find-licenses"
|
52
52
|
},
|
53
53
|
"bin": {
|
54
54
|
"expo-ui": "./bin/index.js"
|
@@ -70,7 +70,7 @@
|
|
70
70
|
"dependencies": {
|
71
71
|
"@emotion/react": "^11.11.1",
|
72
72
|
"@faker-js/faker": "^8.0.2",
|
73
|
-
"@fto-consult/common": "^4.
|
73
|
+
"@fto-consult/common": "^4.15.56",
|
74
74
|
"@fto-consult/node-utils": "^1.4.7",
|
75
75
|
"apexcharts": "^3.45.2",
|
76
76
|
"commander": "^11.1.0",
|
@@ -89,7 +89,7 @@
|
|
89
89
|
"react-native-get-random-values": "^1.10.0",
|
90
90
|
"react-native-iphone-x-helper": "^1.3.1",
|
91
91
|
"react-native-mime-types": "^2.4.0",
|
92
|
-
"react-native-paper": "^5.12.
|
92
|
+
"react-native-paper": "^5.12.3",
|
93
93
|
"react-native-paper-dates": "^0.21.7",
|
94
94
|
"react-native-web": "^0.19.10",
|
95
95
|
"react-virtuoso": "^4.6.2",
|
@@ -0,0 +1,183 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import {
|
3
|
+
Animated,
|
4
|
+
StyleSheet,
|
5
|
+
View,
|
6
|
+
} from 'react-native';
|
7
|
+
|
8
|
+
import { TouchableRipple } from 'react-native-paper';
|
9
|
+
import PropTypes from "prop-types";
|
10
|
+
import FontIcon from "$ecomponents/Icon/Font";
|
11
|
+
import theme, {StyleProp} from "$theme";
|
12
|
+
|
13
|
+
const ANIMATION_DURATION = 100;
|
14
|
+
|
15
|
+
const CheckboxWeb = ({
|
16
|
+
status,
|
17
|
+
theme: themeOverrides,
|
18
|
+
disabled,
|
19
|
+
onPress,
|
20
|
+
testID,
|
21
|
+
rippleColor,
|
22
|
+
color,
|
23
|
+
...rest
|
24
|
+
}) => {
|
25
|
+
const { current: scaleAnim } = React.useRef(
|
26
|
+
new Animated.Value(1)
|
27
|
+
);
|
28
|
+
const isFirstRendering = React.useRef(true);
|
29
|
+
|
30
|
+
const {
|
31
|
+
animation: { scale },
|
32
|
+
} = theme;
|
33
|
+
|
34
|
+
React.useEffect(() => {
|
35
|
+
// Do not run animation on very first rendering
|
36
|
+
if (isFirstRendering.current) {
|
37
|
+
isFirstRendering.current = false;
|
38
|
+
return;
|
39
|
+
}
|
40
|
+
|
41
|
+
const checked = status === 'checked';
|
42
|
+
|
43
|
+
Animated.sequence([
|
44
|
+
Animated.timing(scaleAnim, {
|
45
|
+
toValue: 0.85,
|
46
|
+
duration: checked ? ANIMATION_DURATION * scale : 0,
|
47
|
+
useNativeDriver: false,
|
48
|
+
}),
|
49
|
+
Animated.timing(scaleAnim, {
|
50
|
+
toValue: 1,
|
51
|
+
duration: checked
|
52
|
+
? ANIMATION_DURATION * scale
|
53
|
+
: ANIMATION_DURATION * scale * 1.75,
|
54
|
+
useNativeDriver: false,
|
55
|
+
}),
|
56
|
+
]).start();
|
57
|
+
}, [status, scaleAnim, scale]);
|
58
|
+
|
59
|
+
const checked = status === 'checked';
|
60
|
+
const indeterminate = status === 'indeterminate';
|
61
|
+
|
62
|
+
const borderWidth = scaleAnim.interpolate({
|
63
|
+
inputRange: [0.8, 1],
|
64
|
+
outputRange: [7, 0],
|
65
|
+
});
|
66
|
+
|
67
|
+
const icon = indeterminate
|
68
|
+
? 'minus-box'
|
69
|
+
: checked
|
70
|
+
? 'checkbox-marked'
|
71
|
+
: 'checkbox-blank-outline';
|
72
|
+
const selectionControlColor = theme.Colors.isValid(color)? color : theme.colors.primary;
|
73
|
+
return (
|
74
|
+
<TouchableRipple
|
75
|
+
{...rest}
|
76
|
+
borderless
|
77
|
+
rippleColor={rippleColor}
|
78
|
+
onPress={onPress}
|
79
|
+
disabled={disabled}
|
80
|
+
accessibilityRole="checkbox"
|
81
|
+
accessibilityState={{ disabled, checked }}
|
82
|
+
accessibilityLiveRegion="polite"
|
83
|
+
style={styles.container}
|
84
|
+
testID={testID}
|
85
|
+
theme={theme}
|
86
|
+
>
|
87
|
+
<Animated.View style={{ transform: [{ scale: scaleAnim }] }}>
|
88
|
+
<FontIcon
|
89
|
+
allowFontScaling={false}
|
90
|
+
name={icon}
|
91
|
+
size={24}
|
92
|
+
color={selectionControlColor}
|
93
|
+
direction="ltr"
|
94
|
+
/>
|
95
|
+
<View style={[StyleSheet.absoluteFill, styles.fillContainer]}>
|
96
|
+
<Animated.View
|
97
|
+
style={[
|
98
|
+
styles.fill,
|
99
|
+
{ borderColor: selectionControlColor },
|
100
|
+
{ borderWidth },
|
101
|
+
]}
|
102
|
+
/>
|
103
|
+
</View>
|
104
|
+
</Animated.View>
|
105
|
+
</TouchableRipple>
|
106
|
+
);
|
107
|
+
};
|
108
|
+
|
109
|
+
CheckboxWeb.displayName = 'Checkbox.Android';
|
110
|
+
|
111
|
+
const styles = StyleSheet.create({
|
112
|
+
container: {
|
113
|
+
borderRadius: 18,
|
114
|
+
width: 36,
|
115
|
+
height: 36,
|
116
|
+
padding: 6,
|
117
|
+
},
|
118
|
+
fillContainer: {
|
119
|
+
alignItems: 'center',
|
120
|
+
justifyContent: 'center',
|
121
|
+
},
|
122
|
+
fill: {
|
123
|
+
height: 14,
|
124
|
+
width: 14,
|
125
|
+
},
|
126
|
+
});
|
127
|
+
|
128
|
+
export default CheckboxWeb;
|
129
|
+
|
130
|
+
CheckboxWeb.propTypes = {
|
131
|
+
status: PropTypes.oneOf(['checked','unchecked','indeterminate']),
|
132
|
+
/**
|
133
|
+
* Whether checkbox is disabled.
|
134
|
+
*/
|
135
|
+
disabled : PropTypes.bool,
|
136
|
+
/**
|
137
|
+
* Label to be displayed on the item.
|
138
|
+
*/
|
139
|
+
label: PropTypes.string,
|
140
|
+
/**
|
141
|
+
* Function to execute on press.
|
142
|
+
*/
|
143
|
+
onPress : PropTypes.func,//(e) => void;
|
144
|
+
/**
|
145
|
+
* Function to execute on long press.
|
146
|
+
*/
|
147
|
+
onLongPress : PropTypes.func,//(e) => void;
|
148
|
+
/**
|
149
|
+
* Type of background drawabale to display the feedback (Android).
|
150
|
+
* https://reactnative.dev/docs/pressable#rippleconfig
|
151
|
+
*/
|
152
|
+
background: PropTypes.any,
|
153
|
+
accessibilityLabel : PropTypes.string,
|
154
|
+
/**
|
155
|
+
* Custom color for unchecked checkbox.
|
156
|
+
*/
|
157
|
+
uncheckedColor : PropTypes.string,
|
158
|
+
/**
|
159
|
+
* Custom color for checkbox.
|
160
|
+
*/
|
161
|
+
color : PropTypes.string,
|
162
|
+
/**
|
163
|
+
* Color of the ripple effect.
|
164
|
+
*/
|
165
|
+
rippleColor : PropTypes.string,
|
166
|
+
/**
|
167
|
+
* Additional styles for container View.
|
168
|
+
*/
|
169
|
+
style : StyleProp,
|
170
|
+
/**
|
171
|
+
* Specifies the largest possible scale a label font can reach.
|
172
|
+
*/
|
173
|
+
labelMaxFontSizeMultiplier : PropTypes.number,
|
174
|
+
/**
|
175
|
+
* Style that is passed to Label element.
|
176
|
+
*/
|
177
|
+
labelStyle : StyleProp,
|
178
|
+
testID : PropTypes.string,
|
179
|
+
/**
|
180
|
+
* Checkbox control position.
|
181
|
+
*/
|
182
|
+
position : PropTypes.string,
|
183
|
+
}
|
@@ -0,0 +1,168 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import PropTypes from "prop-types";
|
3
|
+
import {
|
4
|
+
StyleSheet,
|
5
|
+
View,
|
6
|
+
} from 'react-native';
|
7
|
+
import { StyleProp } from '$theme';
|
8
|
+
import theme from "$theme";
|
9
|
+
import Checkbox from './Checkbox';
|
10
|
+
import { TouchableRipple,Text } from 'react-native-paper';
|
11
|
+
|
12
|
+
const CheckboxItem = ({
|
13
|
+
style,
|
14
|
+
status,
|
15
|
+
label,
|
16
|
+
onPress,
|
17
|
+
onLongPress,
|
18
|
+
labelStyle,
|
19
|
+
theme: themeOverrides,
|
20
|
+
testID,
|
21
|
+
mode,
|
22
|
+
position = 'trailing',
|
23
|
+
accessibilityLabel = label,
|
24
|
+
disabled,
|
25
|
+
labelVariant = 'bodyLarge',
|
26
|
+
labelMaxFontSizeMultiplier = 1.5,
|
27
|
+
rippleColor,
|
28
|
+
background,
|
29
|
+
...props
|
30
|
+
}) => {
|
31
|
+
const checkboxProps = { ...props, status, theme, disabled };
|
32
|
+
const isLeading = position === 'leading';
|
33
|
+
const checkbox = <Checkbox {...checkboxProps} />
|
34
|
+
|
35
|
+
const textColor = theme.isV3 ? theme.colors.onSurface : theme.colors.text;
|
36
|
+
const disabledTextColor = theme.isV3
|
37
|
+
? theme.colors.onSurfaceDisabled
|
38
|
+
: theme.colors.disabled;
|
39
|
+
const textAlign = isLeading ? 'right' : 'left';
|
40
|
+
|
41
|
+
const computedStyle = {
|
42
|
+
color: disabled ? disabledTextColor : textColor,
|
43
|
+
textAlign,
|
44
|
+
}
|
45
|
+
|
46
|
+
return (
|
47
|
+
<TouchableRipple
|
48
|
+
accessibilityLabel={accessibilityLabel}
|
49
|
+
accessibilityRole="checkbox"
|
50
|
+
accessibilityState={{
|
51
|
+
checked: status === 'checked',
|
52
|
+
disabled,
|
53
|
+
}}
|
54
|
+
onPress={onPress}
|
55
|
+
onLongPress={onLongPress}
|
56
|
+
testID={testID}
|
57
|
+
disabled={disabled}
|
58
|
+
rippleColor={rippleColor}
|
59
|
+
theme={theme}
|
60
|
+
background={background}
|
61
|
+
>
|
62
|
+
<View
|
63
|
+
style={[styles.container, style]}
|
64
|
+
pointerEvents="none"
|
65
|
+
importantForAccessibility="no-hide-descendants"
|
66
|
+
>
|
67
|
+
{isLeading && checkbox}
|
68
|
+
<Text
|
69
|
+
variant={labelVariant}
|
70
|
+
testID={`${testID}-text`}
|
71
|
+
maxFontSizeMultiplier={labelMaxFontSizeMultiplier}
|
72
|
+
style={[
|
73
|
+
styles.label,
|
74
|
+
!theme.isV3 && styles.font,
|
75
|
+
computedStyle,
|
76
|
+
labelStyle,
|
77
|
+
]}
|
78
|
+
>
|
79
|
+
{label}
|
80
|
+
</Text>
|
81
|
+
{!isLeading && checkbox}
|
82
|
+
</View>
|
83
|
+
</TouchableRipple>
|
84
|
+
);
|
85
|
+
};
|
86
|
+
|
87
|
+
CheckboxItem.displayName = 'Checkbox.Item';
|
88
|
+
|
89
|
+
export default CheckboxItem;
|
90
|
+
|
91
|
+
// @component-docs ignore-next-line
|
92
|
+
export { CheckboxItem };
|
93
|
+
|
94
|
+
const styles = StyleSheet.create({
|
95
|
+
container: {
|
96
|
+
flexDirection: 'row',
|
97
|
+
alignItems: 'center',
|
98
|
+
justifyContent: 'space-between',
|
99
|
+
paddingVertical: 8,
|
100
|
+
paddingHorizontal: 16,
|
101
|
+
},
|
102
|
+
label: {
|
103
|
+
flexShrink: 1,
|
104
|
+
flexGrow: 1,
|
105
|
+
},
|
106
|
+
font: {
|
107
|
+
fontSize: 16,
|
108
|
+
},
|
109
|
+
});
|
110
|
+
CheckboxItem.propTypes = {
|
111
|
+
status: PropTypes.oneOf(['checked','unchecked','indeterminate']),
|
112
|
+
/**
|
113
|
+
* Whether checkbox is disabled.
|
114
|
+
*/
|
115
|
+
disabled : PropTypes.bool,
|
116
|
+
/**
|
117
|
+
* Label to be displayed on the item.
|
118
|
+
*/
|
119
|
+
label: PropTypes.string,
|
120
|
+
/**
|
121
|
+
* Function to execute on press.
|
122
|
+
*/
|
123
|
+
onPress : PropTypes.func,//(e) => void;
|
124
|
+
/**
|
125
|
+
* Function to execute on long press.
|
126
|
+
*/
|
127
|
+
onLongPress : PropTypes.func,//(e) => void;
|
128
|
+
/**
|
129
|
+
* Type of background drawabale to display the feedback (Android).
|
130
|
+
* https://reactnative.dev/docs/pressable#rippleconfig
|
131
|
+
*/
|
132
|
+
background: PropTypes.any,
|
133
|
+
accessibilityLabel : PropTypes.string,
|
134
|
+
/**
|
135
|
+
* Custom color for unchecked checkbox.
|
136
|
+
*/
|
137
|
+
uncheckedColor : PropTypes.string,
|
138
|
+
/**
|
139
|
+
* Custom color for checkbox.
|
140
|
+
*/
|
141
|
+
color : PropTypes.string,
|
142
|
+
/**
|
143
|
+
* Color of the ripple effect.
|
144
|
+
*/
|
145
|
+
rippleColor : PropTypes.string,
|
146
|
+
/**
|
147
|
+
* Additional styles for container View.
|
148
|
+
*/
|
149
|
+
style : StyleProp,
|
150
|
+
/**
|
151
|
+
* Specifies the largest possible scale a label font can reach.
|
152
|
+
*/
|
153
|
+
labelMaxFontSizeMultiplier : PropTypes.number,
|
154
|
+
/**
|
155
|
+
* Style that is passed to Label element.
|
156
|
+
*/
|
157
|
+
labelStyle : StyleProp,
|
158
|
+
testID : PropTypes.string,
|
159
|
+
/**
|
160
|
+
* Checkbox control position.
|
161
|
+
*/
|
162
|
+
position : PropTypes.string,
|
163
|
+
/**
|
164
|
+
* Whether `<Checkbox.Android />` or `<Checkbox.IOS />` should be used.
|
165
|
+
* Left undefined `<Checkbox />` will be used.
|
166
|
+
*/
|
167
|
+
mode : PropTypes.oneOf(['android','ios'])
|
168
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Checkbox } from "react-native-paper";
|
2
|
+
import {forwardRef} from "react";
|
3
|
+
|
4
|
+
const CheckboxItemComponent = forwardRef((props,ref)=>{
|
5
|
+
return <Checkbox.Item
|
6
|
+
ref = {ref}
|
7
|
+
{...props}
|
8
|
+
/>
|
9
|
+
});
|
10
|
+
|
11
|
+
export default CheckboxItemComponent;
|
12
|
+
|
13
|
+
CheckboxItemComponent.displayName = "CheckboxItemComponent";
|
@@ -2,9 +2,11 @@ import { Checkbox } from 'react-native-paper';
|
|
2
2
|
import View from "$ecomponents/View";
|
3
3
|
import React from "$react";
|
4
4
|
import {isUndefined,defaultObj,defaultVal,defaultStr} from "$cutils";
|
5
|
-
import {isIos,isAndroid} from "$cplatform";
|
5
|
+
import {isIos,isAndroid,isMobileNative} from "$cplatform";
|
6
6
|
import theme,{Colors,DISABLED_OPACITY,ALPHA_OPACITY} from "$theme";
|
7
7
|
import { StyleSheet } from 'react-native';
|
8
|
+
import CheckboxItem from "./Item";
|
9
|
+
|
8
10
|
export const checkedStatus = 'checked';
|
9
11
|
export const uncheckedStatus = 'unchecked';
|
10
12
|
import PropTypes from "prop-types";
|
@@ -13,6 +15,7 @@ import HelperText from "$ecomponents/HelperText";
|
|
13
15
|
export const leftPosition = 'leading';
|
14
16
|
export const rightPosition = "trailing";
|
15
17
|
|
18
|
+
|
16
19
|
export const CHECKED_ICON_NAME = isIos()? 'check':'check';
|
17
20
|
|
18
21
|
export const UNCHECKED_ICON_NAME = isIos() ?'' : ''
|
@@ -119,8 +122,8 @@ const CheckboxComponent = React.forwardRef((props,ref)=>{
|
|
119
122
|
testID = defaultStr(testID,"RN_CheckboxComponent");
|
120
123
|
return <View testID={testID+"_Container"} {...containerProps} style={[containerProps.style,disabledStyle]} pointerEvents={pointerEvents}>
|
121
124
|
<Tooltip
|
122
|
-
Component = {Checkbox.Item}
|
123
125
|
{...p}
|
126
|
+
Component = {CheckboxItem}
|
124
127
|
testID = {testID}
|
125
128
|
disabled = {disabled}
|
126
129
|
readOnly = {!isEditable}
|
@@ -309,7 +309,13 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
309
309
|
return false;
|
310
310
|
}}
|
311
311
|
renderCustomPagination = {({context})=>{
|
312
|
-
if(!canPaginate())
|
312
|
+
if(!canPaginate()) {
|
313
|
+
return <View testID={testID+"_PaginationLabel"}>
|
314
|
+
<Label textBold primary style={{fontSize:15}}>
|
315
|
+
{total.formatNumber()}
|
316
|
+
</Label>
|
317
|
+
</View>
|
318
|
+
}
|
313
319
|
const page = pageRef.current, totalPages = getTotalPages(), prevPage = getPrevPage(),nextPage = getNextPage();
|
314
320
|
const iconProp = {
|
315
321
|
size : 25,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import PropTypes from "prop-types";
|
2
2
|
import KeyboardEventHandler from "../KeyboardEventHandler";
|
3
|
-
import { addMediaQueryUpdateStyeSubscription } from "$
|
3
|
+
import { addMediaQueryUpdateStyeSubscription } from "$econtext/hooks";
|
4
4
|
import Dimensions from "$cdimensions";
|
5
5
|
const {getActions,getFormFields,Forms} = require("../utils")
|
6
6
|
import TextField,{parseDecimal} from "$ecomponents/TextField";
|
@@ -58,7 +58,7 @@ export default function ImageComponent(props){
|
|
58
58
|
onChange,draw,round,drawText,drawLabel,rounded,defaultSrc,
|
59
59
|
createSignatureOnly,pickImageProps,width,height,cropProps,size,resizeProps,containerProps,
|
60
60
|
menuProps,pickUri,drawProps,imageProps,length,testID,withLabel,...rest} = props;
|
61
|
-
|
61
|
+
const pickedImageRef = React.useRef(null);
|
62
62
|
pickImageProps = defaultObj(pickImageProps);
|
63
63
|
cropProps = defaultObj(cropProps);
|
64
64
|
draw = defaultBool(draw,true);
|
@@ -144,6 +144,7 @@ export default function ImageComponent(props){
|
|
144
144
|
setSrc(imageSrc)
|
145
145
|
});
|
146
146
|
}
|
147
|
+
pickedImageRef.current = image;
|
147
148
|
setSrc(imageSrc);
|
148
149
|
return image;
|
149
150
|
}
|
@@ -184,11 +185,15 @@ export default function ImageComponent(props){
|
|
184
185
|
},
|
185
186
|
}
|
186
187
|
React.useEffect(()=>{
|
187
|
-
if(src === prevSrc)
|
188
|
+
if(src === prevSrc) {
|
189
|
+
pickedImageRef.current = null;
|
190
|
+
return;
|
191
|
+
}
|
188
192
|
if(typeof onChange =='function'){
|
189
|
-
onChange({context,src,deleted:src == null?true:false,dataURL:src,dataUrl:src})
|
193
|
+
onChange({context,...defaultObj(pickedImageRef.current),src,deleted:src == null?true:false,dataURL:src,dataUrl:src})
|
190
194
|
}
|
191
|
-
|
195
|
+
pickedImageRef.current = null;
|
196
|
+
},[src]);
|
192
197
|
React.useEffect(()=>{
|
193
198
|
if(typeof onMount =='function'){
|
194
199
|
onMount({context});
|
@@ -3,7 +3,7 @@ import PropTypes from "prop-types";
|
|
3
3
|
import React from "$react";
|
4
4
|
import {isMobileNative} from "$cplatform";
|
5
5
|
import {debounce,isNumber,isNonNullString} from "$cutils";
|
6
|
-
import {useMediaQueryUpdateStyle} from "$
|
6
|
+
import {useMediaQueryUpdateStyle} from "$econtext/hooks";
|
7
7
|
|
8
8
|
|
9
9
|
const ViewComponent = React.forwardRef(({onRender,onLayoutTimeout,pointerEvents,onLayout,autoHeight,autoWidth,elevation,...props},ref)=>{
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import PermText from "./PermText";
|
2
2
|
import React from "$react";
|
3
3
|
import Expandable from "$ecomponents/Expandable";
|
4
|
-
import {defaultObj,defaultStr,
|
4
|
+
import {defaultObj,defaultStr,isNonNullString,defaultVal} from "$cutils";
|
5
5
|
import PropTypes from "prop-types";
|
6
6
|
import {hasResource} from "./utils";
|
7
7
|
import { StyleSheet } from "react-native";
|
@@ -55,12 +55,16 @@ const PermLine = ({text,cellProps,isUserMasterAdmin,withGrid,defaultActions,reso
|
|
55
55
|
isUserMasterAdmin = !!isUserMasterAdmin;
|
56
56
|
let checked = isUserMasterAdmin;
|
57
57
|
const onToggleSingle = ({resource,checked,action})=>{
|
58
|
+
if(!resource){
|
59
|
+
console.error("Invalid resource toggle ",resource,checked,action);
|
60
|
+
return;
|
61
|
+
}
|
58
62
|
if(isUserMasterAdmin || !isNonNullString(action) || !isNonNullString(resource) || !isNonNullString(allPerms[resource])){
|
59
63
|
return;
|
60
64
|
}
|
61
65
|
const data = {...state.data};
|
62
66
|
const allAction = defaultStr(allPerms[resource]);
|
63
|
-
if(allAction
|
67
|
+
if(allAction === "all"){
|
64
68
|
if(checked){
|
65
69
|
data[resource] = allAction;
|
66
70
|
} else delete data[resource];
|
@@ -68,10 +72,10 @@ const PermLine = ({text,cellProps,isUserMasterAdmin,withGrid,defaultActions,reso
|
|
68
72
|
data[resource] = defaultStr(data[resource]).toLowerCase();
|
69
73
|
let spl = data[resource].split("2");
|
70
74
|
if(checked){
|
71
|
-
if(action !== 'read' &&
|
75
|
+
if(action !== 'read' && allAction.toLowerCase().split("2").includes('read') && !spl.includes('read')){
|
72
76
|
spl.push('read');
|
73
77
|
}
|
74
|
-
if(!
|
78
|
+
if(!spl.includes(action)){
|
75
79
|
spl.push(action);
|
76
80
|
}
|
77
81
|
} else {
|
@@ -108,40 +112,43 @@ const PermLine = ({text,cellProps,isUserMasterAdmin,withGrid,defaultActions,reso
|
|
108
112
|
onChange({data:state.data,resource,table});
|
109
113
|
}
|
110
114
|
},[state.data])
|
111
|
-
const content =
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
if(!
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
115
|
+
const content = React.useStableMemo(()=>{
|
116
|
+
const content = [];
|
117
|
+
Object.map(perms,(perm,i)=>{
|
118
|
+
const pText = defaultStr(perm.text,perm.label);
|
119
|
+
if(!isObj(perm.actions)){
|
120
|
+
if(!isNonNullString(pText)) return null;
|
121
|
+
allPerms[i] = "all";
|
122
|
+
checked = isUserMasterAdmin? true : isNonNullString(state.data[i]);
|
123
|
+
if(!checked){
|
124
|
+
allChecked = false;
|
125
|
+
}
|
126
|
+
content.push(<PermText isUserMasterAdmin={isUserMasterAdmin} key = {i} table={table} tooltip={defaultStr(perm.tooltip,perm.title,perm.desc)} onToggle={onToggleSingle} text={pText} checked ={checked} resource={i} action ={'all'}/>);
|
127
|
+
return;
|
128
|
+
}
|
129
|
+
allPerms[i] = "";
|
130
|
+
const splitP = defaultStr(state.data[i]).toLowerCase().split("2");
|
131
|
+
const pContent = []
|
132
|
+
const hasS = isNonNullString(text) && isNonNullString(pText) && pText.toLowerCase() != text.toLowerCase()
|
133
|
+
Object.map(perm.actions,(p,j)=>{
|
134
|
+
if(!isObj(p) || !isNonNullString(p.text)) return null;
|
135
|
+
allPerms[i] = (isNonNullString(allPerms[i])?(allPerms[i]+"2"):"")+j;
|
136
|
+
checked = isUserMasterAdmin? true : splitP.includes(j);
|
137
|
+
if(!checked){
|
138
|
+
allChecked = false;
|
139
|
+
}
|
140
|
+
pContent.push(<PermText labelStyle ={hasS? styles.permChildren : undefined} isUserMasterAdmin={isUserMasterAdmin} key={j} table={table} onToggle={onToggleSingle} tooltip={defaultStr(p.tooltip,p.title,p.desc)} text = {p.text} checked ={checked} actions={perm.actions} resource={i} action ={j}/>)
|
141
|
+
});
|
142
|
+
if(pContent.length){
|
143
|
+
content.push(<View key={i} style={{backgroundColor:theme.colors.surface}} testID={testID+"_Content_"+i}>
|
144
|
+
{hasS ? <Label testID={testID+'_Label'}>{pText}</Label> : null}
|
145
|
+
{pContent}
|
146
|
+
</View>)
|
134
147
|
}
|
135
|
-
|
148
|
+
|
136
149
|
});
|
137
|
-
|
138
|
-
|
139
|
-
{hasS ? <Label testID={testID+'_Label'}>{pText}</Label> : null}
|
140
|
-
{pContent}
|
141
|
-
</View>)
|
142
|
-
}
|
143
|
-
|
144
|
-
});
|
150
|
+
return content;
|
151
|
+
},[perms,state.data,state.expanded]);
|
145
152
|
if(!content.length) return null;
|
146
153
|
return <Cell testID={testID+"_Cell"} tabletSize={6} desktopSize={4} phoneSize={12} {...cellProps}>
|
147
154
|
<Expandable
|
@@ -162,7 +169,8 @@ const PermLine = ({text,cellProps,isUserMasterAdmin,withGrid,defaultActions,reso
|
|
162
169
|
labelStyle = {false}
|
163
170
|
checked = {allChecked}
|
164
171
|
disabled = {disabled}
|
165
|
-
resource={resource}
|
172
|
+
resource={resource}
|
173
|
+
action={allPerms[resource]}
|
166
174
|
text={text}
|
167
175
|
testID = {testID+"_"+table}
|
168
176
|
isUserMasterAdmin = {isUserMasterAdmin}
|
@@ -7,6 +7,10 @@ import theme from "$theme";
|
|
7
7
|
|
8
8
|
const PermText = React.forwardRef(({isUserMasterAdmin,disabled,assignPerm,testID,text,title,label,checked,labelStyle,table,type,onToggle,actions,action,resource,tooltip,...props},ref)=>{
|
9
9
|
testID = defaultStr(testID,"RN_AuthPermTextComponent");
|
10
|
+
if(!resource){
|
11
|
+
console.error("invalid resource for perm text : resource = ",resource,action,type,text,title," table = ",table,tooltip,props);
|
12
|
+
return null;
|
13
|
+
}
|
10
14
|
return <Checkbox
|
11
15
|
title = {tooltip || title}
|
12
16
|
ref = {ref}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module.exports = {
|
2
2
|
"@fto-consult/expo-ui": {
|
3
3
|
"name": "@fto-consult/expo-ui",
|
4
|
-
"version": "8.5
|
4
|
+
"version": "8.14.5",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
7
7
|
"url": "git+https://github.com/borispipo/expo-ui.git"
|
@@ -34,7 +34,7 @@ module.exports = {
|
|
34
34
|
"license": "MIT"
|
35
35
|
},
|
36
36
|
"@fto-consult/common": {
|
37
|
-
"version": "4.
|
37
|
+
"version": "4.15.56",
|
38
38
|
"url": "https://github.com/borispipo/common#readme",
|
39
39
|
"license": "ISC"
|
40
40
|
},
|
@@ -67,11 +67,6 @@ module.exports = {
|
|
67
67
|
"url": "https://github.com/crypto-browserify/crypto-browserify",
|
68
68
|
"license": "MIT"
|
69
69
|
},
|
70
|
-
"expo": {
|
71
|
-
"version": "50.0.2",
|
72
|
-
"url": "https://github.com/expo/expo/tree/main/packages/expo",
|
73
|
-
"license": "MIT"
|
74
|
-
},
|
75
70
|
"file-saver": {
|
76
71
|
"version": "2.0.5",
|
77
72
|
"url": "https://github.com/eligrey/FileSaver.js#readme",
|
@@ -82,6 +77,11 @@ module.exports = {
|
|
82
77
|
"url": "https://ruimarinho.github.io/google-libphonenumber/",
|
83
78
|
"license": "(MIT AND Apache-2.0)"
|
84
79
|
},
|
80
|
+
"html2canvas": {
|
81
|
+
"version": "1.4.1",
|
82
|
+
"url": "https://html2canvas.hertzen.com",
|
83
|
+
"license": "MIT"
|
84
|
+
},
|
85
85
|
"htmlparser2-without-node-native": {
|
86
86
|
"version": "3.9.2",
|
87
87
|
"url": "git://github.com/fb55/htmlparser2.git",
|
@@ -95,6 +95,11 @@ module.exports = {
|
|
95
95
|
"version": "3.7.6",
|
96
96
|
"license": "BSD-3-Clause"
|
97
97
|
},
|
98
|
+
"jsbarcode": {
|
99
|
+
"version": "3.11.6",
|
100
|
+
"url": "https://github.com/lindell/JsBarcode#readme",
|
101
|
+
"license": "MIT"
|
102
|
+
},
|
98
103
|
"prop-types": {
|
99
104
|
"version": "15.8.1",
|
100
105
|
"url": "https://facebook.github.io/react/",
|
@@ -129,7 +134,7 @@ module.exports = {
|
|
129
134
|
"license": "MIT"
|
130
135
|
},
|
131
136
|
"react-native-paper": {
|
132
|
-
"version": "5.12.
|
137
|
+
"version": "5.12.3",
|
133
138
|
"url": "https://callstack.github.io/react-native-paper",
|
134
139
|
"license": "MIT"
|
135
140
|
},
|
@@ -1,23 +0,0 @@
|
|
1
|
-
import "../utils";
|
2
|
-
import DateTimePicker from '@react-native-community/datetimepicker';
|
3
|
-
import DateLib from "$lib/date";
|
4
|
-
export default function DateTimePickerComponent(props){
|
5
|
-
const {visible,date,onDateChange,startDate,endDate,onCancel,...rest} = props;
|
6
|
-
const value = DateLib.isDateObj(date)?date:new Date();
|
7
|
-
return visible? <DateTimePicker
|
8
|
-
mode = {"date"}
|
9
|
-
{...rest}
|
10
|
-
value = {value}
|
11
|
-
minimumDate = {startDate}
|
12
|
-
maximumDate = {endDate}
|
13
|
-
onChange = {(e,selectedDate)=>{
|
14
|
-
if(!selectedDate){
|
15
|
-
if(typeof onCancel ==='function'){
|
16
|
-
onCancel((date?value:undefined))
|
17
|
-
}
|
18
|
-
return;
|
19
|
-
}
|
20
|
-
onDateChange(selectedDate);
|
21
|
-
}}
|
22
|
-
/> : null;
|
23
|
-
}
|