@fto-consult/expo-ui 6.1.6 → 6.2.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/appConfig.txt +1 -4
- package/babel.config.alias.js +4 -0
- package/index.js +4 -2
- package/package.json +3 -3
- package/src/App.js +8 -43
- package/src/components/AppBar/index.js +8 -11
- package/src/components/Datagrid/Common/Common.js +1 -1
- package/src/components/Datagrid/SWRDatagrid.js +5 -6
- package/src/components/ErrorBoundary/Provider.js +1 -2
- package/src/components/Form/Fields/SelectTableData/Component.js +9 -7
- package/src/components/TextField/index.js +12 -13
- package/src/context/index.js +74 -0
- package/src/index.js +7 -6
- package/src/components/AppBar/Content2.js +0 -132
- package/src/components/ContentLoader/index copy.js +0 -148
package/appConfig.txt
CHANGED
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
/*** le nombre maximal de courbes qu'on peut afficher sur le même graphe***/
|
|
10
10
|
maxSupportedChartSeries {number}
|
|
11
|
-
|
|
12
|
-
///fonction de rappel appelée avant d'exit l'application, doit retourner une promesse que lorsque résolue, exit l'application
|
|
13
|
-
beforeExit : ()=><Promise>
|
|
11
|
+
|
|
14
12
|
|
|
15
13
|
/***les fonctions d'aggregations du datagrid**/
|
|
16
14
|
datagridAggregatorFunctions : {objectOf({code:{string},label:{string},eval:{function}})|| arrayOf({code:{string},label:{string},eval:{function}})}
|
|
@@ -19,7 +17,6 @@
|
|
|
19
17
|
"&libele&" : selectLabel,
|
|
20
18
|
}
|
|
21
19
|
getTableData : {function(tableName)=>table} retourne l'ojet table data,
|
|
22
|
-
swrRefreshTimeout : {number} le délai d'inactivité auquel, une fois l'application active, les données de type listData sont rafraichies
|
|
23
20
|
handleHelpScreen : {boolean}, //if Help screen will be added on navigation's main drawer
|
|
24
21
|
|
|
25
22
|
checkNavigationPermsOnTableOrStructData : {boolean}, si le test de la permission sur la table data où sur la struct data sera effectuée lorsqu'on appelera la fonction navigateToTableData ou navigateToStructData
|
package/babel.config.alias.js
CHANGED
|
@@ -133,6 +133,10 @@ module.exports = (opts)=>{
|
|
|
133
133
|
//le chemin ver le repertoire electron
|
|
134
134
|
r.$eelectron = r["$e-electron"] = $electron;
|
|
135
135
|
r.$electron = r.$electron || r.$eelectron;
|
|
136
|
+
r.$econtext = path.resolve(expo,"context");
|
|
137
|
+
if(!r.$context){
|
|
138
|
+
r.$context = r.$econtext;
|
|
139
|
+
}
|
|
136
140
|
const electronAssetsPath = path.resolve(dir,"electron","assets");
|
|
137
141
|
if($assets){
|
|
138
142
|
const l1 = path.resolve($assets,"logo.png"), l2 = path.resolve($assets,"logo.png");
|
package/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { registerRootComponent } from "expo";
|
|
2
2
|
import {Platform } from 'react-native';
|
|
3
3
|
import App from "./src/App";
|
|
4
|
+
import { Provider } from "$econtext";
|
|
4
5
|
const isWeb = Platform.OS === "web";
|
|
6
|
+
import {isObj} from "$cutils";
|
|
5
7
|
|
|
6
8
|
/****
|
|
7
9
|
* les options sont de la forme :
|
|
@@ -16,9 +18,9 @@ const isWeb = Platform.OS === "web";
|
|
|
16
18
|
* }
|
|
17
19
|
*/
|
|
18
20
|
export default function registerApp (options){
|
|
19
|
-
|
|
21
|
+
const {onMount,onUnmount,onRender,swrConfig,...rest} = isObj(options)? options : {};
|
|
20
22
|
registerRootComponent(function(props){
|
|
21
|
-
return <
|
|
23
|
+
return <Provider {...props} {...rest} swrConfig={isObj(swrConfig) && swrConfig || {}} children={<App onMount={onMount} onUnmount={onUnmount} onRender={onRender}/>}/>
|
|
22
24
|
});
|
|
23
25
|
}
|
|
24
26
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fto-consult/expo-ui",
|
|
3
|
-
"version": "6.1
|
|
3
|
+
"version": "6.2.1",
|
|
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.11.0",
|
|
62
62
|
"@expo/html-elements": "^0.5.1",
|
|
63
63
|
"@expo/vector-icons": "^13.0.0",
|
|
64
|
-
"@fto-consult/common": "^3.
|
|
64
|
+
"@fto-consult/common": "^3.19.0",
|
|
65
65
|
"@gorhom/portal": "^1.0.14",
|
|
66
66
|
"@pchmn/expo-material3-theme": "^1.0.1",
|
|
67
67
|
"@react-native-async-storage/async-storage": "1.18.2",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@react-navigation/native-stack": "^6.9.12",
|
|
73
73
|
"@shopify/flash-list": "1.4.3",
|
|
74
74
|
"apexcharts": "^3.41.0",
|
|
75
|
-
"expo": "^49.0.
|
|
75
|
+
"expo": "^49.0.3",
|
|
76
76
|
"expo-camera": "~13.4.2",
|
|
77
77
|
"expo-clipboard": "~4.3.0",
|
|
78
78
|
"expo-font": "~11.4.0",
|
package/src/App.js
CHANGED
|
@@ -9,7 +9,6 @@ import {GestureHandlerRootView} from "react-native-gesture-handler";
|
|
|
9
9
|
import APP from "$app";
|
|
10
10
|
import {isMobileNative} from "$cplatform";
|
|
11
11
|
import {setDeviceIdRef} from "$capp";
|
|
12
|
-
import appConfig from "$capp/config";
|
|
13
12
|
import {showPrompt} from "$ecomponents/Dialog/confirm";
|
|
14
13
|
import { AppState } from 'react-native'
|
|
15
14
|
import {canFetchOffline} from "$capi/utils";
|
|
@@ -18,51 +17,18 @@ import { timeout as SWR_REFRESH_TIMEOUT} from '$ecomponents/Datagrid/SWRDatagrid
|
|
|
18
17
|
import { Dimensions,Keyboard } from 'react-native';
|
|
19
18
|
import {isTouchDevice} from "$platform";
|
|
20
19
|
import * as Utils from "$cutils";
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import { useColorScheme } from 'react-native';
|
|
24
|
-
import {colorsAlias,Colors} from "$theme";
|
|
20
|
+
import useContext from "$econtext";
|
|
21
|
+
import appConfig from "$capp/config";
|
|
25
22
|
|
|
26
|
-
import { configureFonts} from 'react-native-paper';
|
|
27
23
|
Object.map(Utils,(v,i)=>{
|
|
28
24
|
if(typeof v =='function' && typeof window !='undefined' && window && !window[i]){
|
|
29
25
|
window[i] = v;
|
|
30
26
|
}
|
|
31
27
|
});
|
|
32
|
-
|
|
33
|
-
export default function getIndex({onMount,onUnmount,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
//const colorScheme = useColorScheme();
|
|
37
|
-
appConfig.extendAppTheme = (theme)=>{
|
|
38
|
-
if(!isObj(theme)) return;
|
|
39
|
-
const newTheme = theme.dark || theme.isDark ? { ...MD3DarkTheme, colors: pTheme.dark } : { ...MD3LightTheme, colors: pTheme.light };
|
|
40
|
-
for(let i in newTheme){
|
|
41
|
-
if(i !== 'colors' && !(i in theme)){
|
|
42
|
-
theme[i] = newTheme[i];
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if(isObj(theme.colors)){
|
|
46
|
-
colorsAlias.map((color)=>{
|
|
47
|
-
color = color.trim();
|
|
48
|
-
const cUpper = color.ucFirst();
|
|
49
|
-
//math theme colors to material desgin V3
|
|
50
|
-
const textA = `${color}Text`,onColor=`on${cUpper}`//,containerA = `${color}Container`,onColorContainer=`on${cUpper}Container`;
|
|
51
|
-
const c = Colors.isValid(theme.colors[onColor])? theme.colors[onColor] : (theme.colors[textA]) || undefined;
|
|
52
|
-
if(c){
|
|
53
|
-
theme.colors[onColor] = c;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
for(let i in newTheme.colors){
|
|
57
|
-
if(!(i in theme.colors)){
|
|
58
|
-
theme.colors[i] = newTheme.colors[i];
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
theme.fonts = newTheme.fonts;
|
|
63
|
-
return typeof extendAppTheme == 'function'? extendAppTheme(theme) : theme;
|
|
64
|
-
}
|
|
65
|
-
const isScreenFocusedRef = React.useRef(true);
|
|
28
|
+
|
|
29
|
+
export default function getIndex({onMount,onUnmount,onRender}){
|
|
30
|
+
const {swrConfig} = useContext();
|
|
31
|
+
const isScreenFocusedRef = React.useRef(true);
|
|
66
32
|
///garde pour chaque écran sa date de dernière activité
|
|
67
33
|
const screensRef = React.useRef({});//la liste des écrans actifs
|
|
68
34
|
const activeScreenRef = React.useRef('');
|
|
@@ -70,7 +36,6 @@ export default function getIndex({onMount,onUnmount,swrConfig,onRender,...rest})
|
|
|
70
36
|
const appStateRef = React.useRef({});
|
|
71
37
|
const isKeyboardOpenRef = React.useRef(false);
|
|
72
38
|
React.useOnRender(onRender);
|
|
73
|
-
swrConfig = defaultObj(swrConfig);
|
|
74
39
|
React.useEffect(()=>{
|
|
75
40
|
///la fonction de rappel lorsque le composant est monté
|
|
76
41
|
const onScreenFocus = ({sanitizedName})=>{
|
|
@@ -144,7 +109,7 @@ export default function getIndex({onMount,onUnmount,swrConfig,onRender,...rest})
|
|
|
144
109
|
}
|
|
145
110
|
const date = screensRef.current[screen];
|
|
146
111
|
const diff = new Date().getTime() - date.getTime();
|
|
147
|
-
const timeout = defaultNumber(
|
|
112
|
+
const timeout = defaultNumber(swrConfig.refreshTimeout,SWR_REFRESH_TIMEOUT)
|
|
148
113
|
screensRef.current[screen] = new Date();
|
|
149
114
|
return diff >= timeout ? true : false;
|
|
150
115
|
},
|
|
@@ -174,7 +139,7 @@ export default function getIndex({onMount,onUnmount,swrConfig,onRender,...rest})
|
|
|
174
139
|
}
|
|
175
140
|
}}
|
|
176
141
|
>
|
|
177
|
-
|
|
142
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
178
143
|
<SafeAreaProvider>
|
|
179
144
|
<Index {...rest} onMount={onMount}/>
|
|
180
145
|
</SafeAreaProvider>
|
|
@@ -114,15 +114,6 @@ const AppBarComponent = React.forwardRef((props,ref)=> {
|
|
|
114
114
|
titleProps = defaultObj(titleProps);
|
|
115
115
|
React.setRef(ref,context);
|
|
116
116
|
testID = defaultStr(testID,"RN_AppBarComponent")
|
|
117
|
-
const renderedActions = renderSplitedActions(splitedActions,{
|
|
118
|
-
...defaultObj(menuProps,appBarProps.menuProps),
|
|
119
|
-
anchorProps : {
|
|
120
|
-
style : anchorStyle,
|
|
121
|
-
color : anchorStyle.color,
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
const renderedRight = React.isValidElement(rightContent) && rightContent || right;
|
|
125
|
-
const hasRight = React.isValidElement(renderedActions) || React.isValidElement(renderedRight);
|
|
126
117
|
return (
|
|
127
118
|
<Appbar.Header elevation={elevation} {...appBarProps} testID={testID} style={[styles.header,{backgroundColor},elevStyle,appBarProps.style]} onLayout={onPageResize}>
|
|
128
119
|
{backAction}
|
|
@@ -132,8 +123,14 @@ const AppBarComponent = React.forwardRef((props,ref)=> {
|
|
|
132
123
|
subtitle = {defaultVal(subtitle,params.subtitle,options.subtitle)}
|
|
133
124
|
subtitleProps = {subtitleProps}
|
|
134
125
|
/>
|
|
135
|
-
{
|
|
136
|
-
|
|
126
|
+
{renderSplitedActions(splitedActions,{
|
|
127
|
+
...defaultObj(menuProps,appBarProps.menuProps),
|
|
128
|
+
anchorProps : {
|
|
129
|
+
style : anchorStyle,
|
|
130
|
+
color : anchorStyle.color,
|
|
131
|
+
}
|
|
132
|
+
})}
|
|
133
|
+
{React.isValidElement(rightContent) && rightContent || React.isValidElement(right) && right || null}
|
|
137
134
|
</Appbar.Header>
|
|
138
135
|
);
|
|
139
136
|
});
|
|
@@ -3371,7 +3371,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
3371
3371
|
fetchOptions.dataSources = this.currentDataSources;
|
|
3372
3372
|
fetchOptions.selector = fetchFilters;
|
|
3373
3373
|
fetchOptions.sort = this.getSort();
|
|
3374
|
-
const canIncludeField = typeof this.props.includeFieldsInFetchOptions =='boolean'? this.props.includeFieldsInFetchOptions : defaultBool(appConfig.get("includeFieldsInDatagridFetchOptions")
|
|
3374
|
+
const canIncludeField = typeof this.props.includeFieldsInFetchOptions =='boolean'? this.props.includeFieldsInFetchOptions : defaultBool(appConfig.get("includeFieldsInDatagridFetchOptions")) !== false;
|
|
3375
3375
|
if(canIncludeField){
|
|
3376
3376
|
const ff = this.getFilterableColumnsNames();
|
|
3377
3377
|
let fields = ff;
|
|
@@ -25,6 +25,7 @@ import {getRowsPerPagesLimits} from "./Common/utils";
|
|
|
25
25
|
import PropTypes from "prop-types";
|
|
26
26
|
import {Menu} from "$ecomponents/BottomSheet";
|
|
27
27
|
import session from "$session";
|
|
28
|
+
import useContext from "$econtext";
|
|
28
29
|
|
|
29
30
|
export const getSessionKey = ()=>{
|
|
30
31
|
return Auth.getSessionKey("swrDatagrid");
|
|
@@ -48,8 +49,8 @@ export const setSessionData = (key,value)=>{
|
|
|
48
49
|
export const timeout = 5000*60;//5 minutes
|
|
49
50
|
/***@see : https://swr.vercel.app/docs/api */
|
|
50
51
|
|
|
51
|
-
export const getSWROptions = ()=>{
|
|
52
|
-
const delay = defaultNumber(
|
|
52
|
+
export const getSWROptions = (defTimeout)=>{
|
|
53
|
+
const delay = defaultNumber(defTimeout,timeout);
|
|
53
54
|
return {
|
|
54
55
|
dedupingInterval : delay,
|
|
55
56
|
errorRetryInterval : Math.max(delay*2,timeout),
|
|
@@ -101,6 +102,7 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
101
102
|
defaultSortOrder,
|
|
102
103
|
...rest
|
|
103
104
|
} = props;
|
|
105
|
+
const {swrConfig} = useContext();
|
|
104
106
|
rest = defaultObj(rest);
|
|
105
107
|
rest.exportTableProps = defaultObj(rest.exportTableProps)
|
|
106
108
|
const firstPage = 1;
|
|
@@ -227,10 +229,7 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
227
229
|
});
|
|
228
230
|
},
|
|
229
231
|
showError : false,
|
|
230
|
-
swrOptions :
|
|
231
|
-
...getSWROptions(),
|
|
232
|
-
...defaultObj(appConfig.swr),
|
|
233
|
-
},
|
|
232
|
+
swrOptions : getSWROptions(swrConfig.refreshTimeout)
|
|
234
233
|
});
|
|
235
234
|
const isLoading = isLoadingRef.current && customIsLoading || false;
|
|
236
235
|
/*React.useEffect(()=>{
|
|
@@ -34,8 +34,7 @@ const Provider = React.forwardRef((_props,innerRef)=>{
|
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
isOpen : x=> {
|
|
37
|
-
|
|
38
|
-
return messageRef.current && messageRef.current.setNativeProps ? true : false
|
|
37
|
+
return messageRef.current && messageRef.current? true : false
|
|
39
38
|
},
|
|
40
39
|
});
|
|
41
40
|
setRef(ref,context);
|
|
@@ -11,7 +11,7 @@ import {getFetchOptions,prepareFilters} from "$cutils/filters";
|
|
|
11
11
|
import fetch from "$capi"
|
|
12
12
|
import {willConvertFiltersToSQL} from "$ecomponents/Datagrid/utils";
|
|
13
13
|
import React from "$react";
|
|
14
|
-
import
|
|
14
|
+
import useApp from "$econtext";
|
|
15
15
|
|
|
16
16
|
/*** la tabledataSelectField permet de faire des requêtes distantes pour rechercher les données
|
|
17
17
|
* Elle doit prendre en paramètre et de manière requis : les props suivante :
|
|
@@ -19,8 +19,9 @@ import appConfig from "$appConfig";
|
|
|
19
19
|
* foreignKeyTable : la tableData dans laquelle effectuer les donées de la requêtes
|
|
20
20
|
* foreignKeyLabel : Le libélé dans la table étrangère
|
|
21
21
|
*/
|
|
22
|
-
const TableDataSelectField = React.forwardRef(({foreignKeyColumn,prepareFilters:cPrepareFilters,bindUpsert2RemoveEvents,onAdd,showAdd:customShowAdd,canShowAdd,foreignKeyTable,fetchItemsPath,foreignKeyLabel,foreignKeyLabelIndex,dropdownActions,fields,fetchItems:customFetchItem,convertFiltersToSQL,mutateFetchedItems,
|
|
22
|
+
const TableDataSelectField = React.forwardRef(({foreignKeyColumn,prepareFilters:cPrepareFilters,bindUpsert2RemoveEvents,onAdd,showAdd:customShowAdd,canShowAdd,foreignKeyTable,fetchItemsPath,foreignKeyLabel,foreignKeyLabelIndex,dropdownActions,fields,fetchItems:customFetchItem,convertFiltersToSQL,mutateFetchedItems,onFetchItems,isFilter,isUpdate,isDocEditing,items,onAddProps,fetchOptions,...props},ref)=>{
|
|
23
23
|
props.data = defaultObj(props.data);
|
|
24
|
+
const {getTableData:getForeignKeyTable} = useApp();
|
|
24
25
|
if(!foreignKeyColumn && isNonNullString(props.field)){
|
|
25
26
|
foreignKeyColumn = props.field;
|
|
26
27
|
}
|
|
@@ -32,11 +33,13 @@ const TableDataSelectField = React.forwardRef(({foreignKeyColumn,prepareFilters:
|
|
|
32
33
|
foreignKeyLabel = foreignKeyLabel.ltrim("[").rtrim("]").split(",");
|
|
33
34
|
}
|
|
34
35
|
convertFiltersToSQL = defaultVal(convertFiltersToSQL,willConvertFiltersToSQL());
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const foreignKeyTableStr = defaultStr(foreignKeyTable,props.tableName,props.table);
|
|
37
|
+
if(typeof getForeignKeyTable !=='function'){
|
|
38
|
+
console.error("la fonction getTableData non définie des les paramètres d'initialisation de l'application!!! Rassurez vous d'avoir définier cette fonction!!, options : foreignKeyTable:",foreignKeyTable,"foreignKeyColumn:",foreignKeyColumn,props)
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
let fKeyTable = getForeignKeyTable(foreignKeyTableStr,props);
|
|
38
42
|
fetchItemsPath = defaultStr(fetchItemsPath).trim();
|
|
39
|
-
|
|
40
43
|
if(!fetchItemsPath && (!isObj(fKeyTable) || !(defaultStr(fKeyTable.tableName,fKeyTable.table)))){
|
|
41
44
|
console.error("type de données invalide pour la foreignKeyTable ",foreignKeyTable," label : ",foreignKeyLabel,fKeyTable," composant SelectTableData",foreignKeyColumn,foreignKeyTable,props);
|
|
42
45
|
return null;
|
|
@@ -306,7 +309,6 @@ TableDataSelectField.propTypes = {
|
|
|
306
309
|
canShowAdd : PropTypes.func, //({foreignKeyTable,foreignKeyColumn})=><boolean> la fonction permettant de spécifier si l'on peut afficher le bouton showAdd
|
|
307
310
|
mutateFetchedItems : PropTypes.func, //la fonction permettant d'effectuer une mutation sur l'ensemble des donnéees récupérées à distance
|
|
308
311
|
fetchItems : PropTypes.func,//la fonction de rappel à utiliser pour faire une requête fetch permettant de selectionner les données à distance
|
|
309
|
-
getForeignKeyTable : PropTypes.func, //la fonction permettant de récupérer la fKeyTable data dont fait référence le champ
|
|
310
312
|
foreignKeyTable : PropTypes.string, //le nom de la fKeyTable data à laquelle se reporte le champ
|
|
311
313
|
fetchItemsPath : PropTypes.string, //le chemin d'api pour récupérer les items des données étrangères en utilisant la fonction fetch
|
|
312
314
|
beforeFetchItems : PropTypes.func, //appelée immédiatement avant l'exécution de la requête fetch
|
|
@@ -124,6 +124,7 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
|
|
|
124
124
|
}
|
|
125
125
|
const isSecureText = type =="password"?true : false;
|
|
126
126
|
const [secureTextEntry,setSecureTextEntry] = React.useState(isSecureText);
|
|
127
|
+
const [toggle,setToggle] = React.useState(false);
|
|
127
128
|
const prevSecureTextEntry = React.usePrevious(secureTextEntry);
|
|
128
129
|
containerProps = defaultObj(containerProps);
|
|
129
130
|
mode = defaultStr(mode,theme.textFieldMode);
|
|
@@ -271,10 +272,8 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
|
|
|
271
272
|
}
|
|
272
273
|
}
|
|
273
274
|
let hasLabel = label && (isShadowMode || isNormalMode || alwaysUseLabel || text || (isFocused || (!usePlaceholderWhenEmpty && canValueBeFormattable)))? true : labelText !== placeholder;
|
|
274
|
-
const innerRef = (
|
|
275
|
-
|
|
276
|
-
React.setRef(inputRef,el,setRef);
|
|
277
|
-
};
|
|
275
|
+
const innerRef = React.useRef(null);
|
|
276
|
+
const componentRef = React.useMergeRefs(innerRef,ref,setRef);
|
|
278
277
|
validType = defaultStr(validType,validRule).toLowerCase();
|
|
279
278
|
multiline = isFilter ? false : defaultBool(multiline,multiple,!!numberOfLines);
|
|
280
279
|
let inputColor = (isFocused || error) ? labelColor : Colors.isValid(color)?color : theme.colors.text;
|
|
@@ -304,7 +303,7 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
|
|
|
304
303
|
keyboardAppearance : theme.isDark()? 'dark': 'default',
|
|
305
304
|
caretHidden : false,
|
|
306
305
|
...props,
|
|
307
|
-
innerRef,
|
|
306
|
+
innerRef:componentRef,
|
|
308
307
|
placeholder : (isFocused || isShadowMode || isNormalMode) && labelText ? "":placeholder,
|
|
309
308
|
placeholderTextColor : error ? theme.colors.error : placeholderColor,
|
|
310
309
|
selectionColor,
|
|
@@ -377,12 +376,12 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
|
|
|
377
376
|
text2 = "0"+text2;
|
|
378
377
|
}
|
|
379
378
|
if(multiline){
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
379
|
+
if(!text2 || text2.length < 30){
|
|
380
|
+
heightRef.current = HEIGHT;
|
|
381
|
+
setToggle(!toggle);
|
|
382
|
+
} else if(target.scrollHeight > heightRef.current){
|
|
383
|
+
heightRef.current = target.scrollHeight;
|
|
384
|
+
setToggle(!toggle);
|
|
386
385
|
}
|
|
387
386
|
}
|
|
388
387
|
const tVal = toCase(text2);
|
|
@@ -475,7 +474,7 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
|
|
|
475
474
|
} else affix = undefined;
|
|
476
475
|
}
|
|
477
476
|
elevation = defaultNumber(contentContainerProps.elevation,elevation,isShadowMode?4:0);
|
|
478
|
-
const paddingVertical = (hasRight || hasLeft)? isMob?5 : 0 : 10;
|
|
477
|
+
const paddingVertical = multiline ? 0 : (hasRight || hasLeft)? isMob?5 : 0 : 10;
|
|
479
478
|
const contentContainerStyle = isOutlinedMode ? {
|
|
480
479
|
borderColor,
|
|
481
480
|
borderWidth,
|
|
@@ -540,7 +539,7 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
|
|
|
540
539
|
typeof render ==="function"? render(inputProps):
|
|
541
540
|
<RNTextInput
|
|
542
541
|
{...inputProps}
|
|
543
|
-
ref = {
|
|
542
|
+
ref = {componentRef}
|
|
544
543
|
/>
|
|
545
544
|
}
|
|
546
545
|
</KeyboardAvoidingView>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from "$react";
|
|
2
|
+
import appConfig from "$capp/config";
|
|
3
|
+
import {MD3LightTheme,MD3DarkTheme} from "react-native-paper";
|
|
4
|
+
import { useMaterial3Theme } from '@pchmn/expo-material3-theme';
|
|
5
|
+
import {colorsAlias,Colors} from "$theme";
|
|
6
|
+
import {isObj} from "$cutils";
|
|
7
|
+
|
|
8
|
+
const ExpoUIContext = React.createContext(null);
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
export const useExpoUI = ()=> React.useContext(ExpoUIContext);
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/*****
|
|
15
|
+
les utilitaires disponibles à passer au provider :
|
|
16
|
+
FontsIconsFilter : (font{object},fontName{string},fontNameLower{string})=><boolean> //porte le nom de la props de appConfig dans lequel définir les filtres à utiliser pour charger l'iconSet désirée pour l'appication
|
|
17
|
+
///fonction de rappel appelée avant d'exit l'application, doit retourner une promesse que lorsque résolue, exit l'application
|
|
18
|
+
beforeExit : ()=><Promise>
|
|
19
|
+
getTableData : ()=>{object|array}
|
|
20
|
+
getStructData : ()=>{object|array}
|
|
21
|
+
tablesData : {object}, la liste des tables de données
|
|
22
|
+
strucsData : {object}, la liste des données de structures
|
|
23
|
+
*/
|
|
24
|
+
export const Provider = ({children,getTableData,getStructData,tablesData,structsData,...props})=>{
|
|
25
|
+
const {extendAppTheme,structsData,getTableData} = appConfig;
|
|
26
|
+
const { theme : pTheme } = useMaterial3Theme();
|
|
27
|
+
structsData = isObj(structsData)? structsData : null;
|
|
28
|
+
tablesData = isObj(tablesData) ? tablesData : null;
|
|
29
|
+
if(!isObj(appConfig.tablesData)){
|
|
30
|
+
appConfig.tablesData = tablesData;
|
|
31
|
+
}
|
|
32
|
+
if(!isObj(appConfig.structsData)){
|
|
33
|
+
appConfig.structsData = structsData;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
appConfig.getTableData = getTableData = typeof getTableData =='function'? getTableData : undefined;
|
|
37
|
+
appConfig.getStructData = getStructData = typeof getStructData =='function' ? getStructData : undefined;
|
|
38
|
+
//const colorScheme = useColorScheme();
|
|
39
|
+
appConfig.extendAppTheme = (theme)=>{
|
|
40
|
+
if(!isObj(theme)) return;
|
|
41
|
+
const newTheme = theme.dark || theme.isDark ? { ...MD3DarkTheme, colors: pTheme.dark } : { ...MD3LightTheme, colors: pTheme.light };
|
|
42
|
+
for(let i in newTheme){
|
|
43
|
+
if(i !== 'colors' && !(i in theme)){
|
|
44
|
+
theme[i] = newTheme[i];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if(isObj(theme.colors)){
|
|
48
|
+
colorsAlias.map((color)=>{
|
|
49
|
+
color = color.trim();
|
|
50
|
+
const cUpper = color.ucFirst();
|
|
51
|
+
//math theme colors to material desgin V3
|
|
52
|
+
const textA = `${color}Text`,onColor=`on${cUpper}`//,containerA = `${color}Container`,onColorContainer=`on${cUpper}Container`;
|
|
53
|
+
const c = Colors.isValid(theme.colors[onColor])? theme.colors[onColor] : (theme.colors[textA]) || undefined;
|
|
54
|
+
if(c){
|
|
55
|
+
theme.colors[onColor] = c;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
for(let i in newTheme.colors){
|
|
59
|
+
if(!(i in theme.colors)){
|
|
60
|
+
theme.colors[i] = newTheme.colors[i];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
theme.fonts = newTheme.fonts;
|
|
65
|
+
return typeof extendAppTheme == 'function'? extendAppTheme(theme) : theme;
|
|
66
|
+
}
|
|
67
|
+
return <ExpoUIContext.Provider value={{...props,getTableData,getStructData,tablesData,structsData,appConfig}} children={children}/>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default useExpoUI;
|
|
71
|
+
|
|
72
|
+
export const useContext = useExpoUI;
|
|
73
|
+
|
|
74
|
+
export const useApp = useContext;
|
package/src/index.js
CHANGED
|
@@ -39,6 +39,7 @@ import {updateTheme,defaultTheme} from "$theme";
|
|
|
39
39
|
import StatusBar from "$ecomponents/StatusBar";
|
|
40
40
|
import {Provider as PaperProvider } from 'react-native-paper';
|
|
41
41
|
import FontIcon from "$ecomponents/Icon/Font";
|
|
42
|
+
import useContext from "$econtext";
|
|
42
43
|
|
|
43
44
|
let MAX_BACK_COUNT = 1;
|
|
44
45
|
let countBack = 0;
|
|
@@ -58,17 +59,17 @@ const NAVIGATION_PERSISTENCE_KEY = 'NAVIGATION_STATE';
|
|
|
58
59
|
*/
|
|
59
60
|
function App({init:initApp,initialRouteName:appInitialRouteName,render,onMount,preferences:appPreferences,getStartedRouteName}) {
|
|
60
61
|
AppStateService.init();
|
|
62
|
+
const {FontsIconsFilter,beforeExit} = useContext();
|
|
61
63
|
const [initialState, setInitialState] = React.useState(undefined);
|
|
62
64
|
const appReadyRef = React.useRef(true);
|
|
63
65
|
const [state,setState] = React.useState({
|
|
64
66
|
isLoading : true,
|
|
65
67
|
isInitialized:false,
|
|
66
68
|
});
|
|
67
|
-
|
|
69
|
+
React.useEffect(() => {
|
|
68
70
|
const loadResources = ()=>{
|
|
69
71
|
return new Promise((resolve)=>{
|
|
70
|
-
|
|
71
|
-
loadFonts(appConfig.get("FontsIconsFilter")).catch((e)=>{
|
|
72
|
+
loadFonts(FontsIconsFilter).catch((e)=>{
|
|
72
73
|
console.warn(e," ierror loading app resources fonts");
|
|
73
74
|
}).finally(()=>{
|
|
74
75
|
resolve(true);
|
|
@@ -111,10 +112,10 @@ function App({init:initApp,initialRouteName:appInitialRouteName,render,onMount,p
|
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
const exit = ()=>{
|
|
114
|
-
if(typeof
|
|
115
|
-
const r2 =
|
|
115
|
+
if(typeof beforeExit =='function'){
|
|
116
|
+
const r2 = beforeExit()
|
|
116
117
|
if(!isPromise(r2)){
|
|
117
|
-
throw {message:'La fonction before exit
|
|
118
|
+
throw {message:'La fonction before exit du contexte doit retourner une promesse',returnedResult:r2}
|
|
118
119
|
}
|
|
119
120
|
return r2.then(foreceExit).catch(reject);
|
|
120
121
|
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import React from '$react';
|
|
2
|
-
import {Platform,StyleSheet,Pressable,View} from 'react-native';
|
|
3
|
-
import Label from "$ecomponents/Label";
|
|
4
|
-
import theme,{Colors,StyleProp} from "$theme";
|
|
5
|
-
import PropTypes from "prop-types";
|
|
6
|
-
import {defaultObj,defaultStr} from "$cutils";
|
|
7
|
-
import {isIos,isAndroid,isWeb} from "$cplatform";
|
|
8
|
-
|
|
9
|
-
const AppbarContent = React.forwardRef(({
|
|
10
|
-
color: titleColor,
|
|
11
|
-
subtitle,
|
|
12
|
-
subtitleProps,
|
|
13
|
-
subtitleStyle,
|
|
14
|
-
onPress,
|
|
15
|
-
style,
|
|
16
|
-
titleProps,
|
|
17
|
-
titleRef,
|
|
18
|
-
titleStyle,
|
|
19
|
-
title,
|
|
20
|
-
testID,
|
|
21
|
-
containerProps,
|
|
22
|
-
...rest
|
|
23
|
-
},ref) => {
|
|
24
|
-
|
|
25
|
-
const titleTextColor = titleColor ? titleColor : theme.colors.primaryText;
|
|
26
|
-
titleProps = defaultObj(titleProps);
|
|
27
|
-
subtitleProps = defaultObj(subtitleProps);
|
|
28
|
-
testID = defaultStr(testID,"RN_AppBarContentComponent")
|
|
29
|
-
subtitle = subtitle === false ? null : subtitle;
|
|
30
|
-
const subtitleColor = Colors.setAlpha(titleTextColor,0.7);
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<Pressable testID={testID+"_Container"} {...defaultObj(containerProps)} onPress={onPress} disabled={!onPress}>
|
|
34
|
-
<View
|
|
35
|
-
pointerEvents="box-none"
|
|
36
|
-
style={[styles.container, style]}
|
|
37
|
-
{...rest}
|
|
38
|
-
testID = {testID}
|
|
39
|
-
ref = {ref}
|
|
40
|
-
>
|
|
41
|
-
<Label
|
|
42
|
-
ref={titleRef}
|
|
43
|
-
testID = {testID+"_Title"}
|
|
44
|
-
{...titleProps}
|
|
45
|
-
style={[
|
|
46
|
-
{
|
|
47
|
-
color: titleTextColor,
|
|
48
|
-
...(isIos()? theme.fonts.regular: theme.fonts.medium),
|
|
49
|
-
},
|
|
50
|
-
isWeb() && theme.styles.webFontFamilly,
|
|
51
|
-
titleProps.style,
|
|
52
|
-
titleStyle,
|
|
53
|
-
]}
|
|
54
|
-
numberOfLines={1}
|
|
55
|
-
accessible
|
|
56
|
-
// @ts-ignore Type '"heading"' is not assignable to type ...
|
|
57
|
-
role={Platform.OS === 'web' ? 'heading' : 'header'}
|
|
58
|
-
>
|
|
59
|
-
{title}
|
|
60
|
-
</Label>
|
|
61
|
-
{subtitle ? (
|
|
62
|
-
<Label
|
|
63
|
-
testID = {testID+"_Subtitle"}
|
|
64
|
-
{...subtitleProps}
|
|
65
|
-
style={[styles.subtitle, { color: subtitleColor }, subtitleProps.style, subtitleStyle]}
|
|
66
|
-
numberOfLines={1}
|
|
67
|
-
>
|
|
68
|
-
{subtitle}
|
|
69
|
-
</Label>
|
|
70
|
-
) : null}
|
|
71
|
-
</View>
|
|
72
|
-
</Pressable>
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
AppbarContent.displayName = 'Appbar.Content';
|
|
77
|
-
|
|
78
|
-
const styles = StyleSheet.create({
|
|
79
|
-
container: {
|
|
80
|
-
flex: 1,
|
|
81
|
-
paddingHorizontal: 5,
|
|
82
|
-
justifyContent : 'center',
|
|
83
|
-
alignItems : 'flex-start',
|
|
84
|
-
},
|
|
85
|
-
title: {
|
|
86
|
-
fontSize: Platform.OS === 'ios' ? 17 : 20,
|
|
87
|
-
},
|
|
88
|
-
subtitle: {
|
|
89
|
-
fontSize: Platform.OS === 'ios' ? 11 : 14,
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
export default AppbarContent;
|
|
94
|
-
const titleType = PropTypes.oneOfType([
|
|
95
|
-
PropTypes.string,
|
|
96
|
-
PropTypes.node,
|
|
97
|
-
PropTypes.bool,
|
|
98
|
-
])
|
|
99
|
-
|
|
100
|
-
AppbarContent.propTypes = {
|
|
101
|
-
/**
|
|
102
|
-
* Custom StyleProp for the text.
|
|
103
|
-
*/
|
|
104
|
-
StyleProp: PropTypes.string,
|
|
105
|
-
/**
|
|
106
|
-
* Text for the title.
|
|
107
|
-
*/
|
|
108
|
-
title: titleType,
|
|
109
|
-
/**
|
|
110
|
-
* Style for the title.
|
|
111
|
-
*/
|
|
112
|
-
titleStyle: StyleProp,
|
|
113
|
-
/**
|
|
114
|
-
* Reference for the title.
|
|
115
|
-
*/
|
|
116
|
-
titleRef : PropTypes.any,
|
|
117
|
-
/**
|
|
118
|
-
* @deprecated Deprecated in v5.x
|
|
119
|
-
* Text for the subtitle.
|
|
120
|
-
*/
|
|
121
|
-
subtitle : titleType,
|
|
122
|
-
/**
|
|
123
|
-
* @deprecated Deprecated in v5.x
|
|
124
|
-
* Style for the subtitle.
|
|
125
|
-
*/
|
|
126
|
-
subtitleStyle: StyleProp,
|
|
127
|
-
/**
|
|
128
|
-
* Function to execute on press.
|
|
129
|
-
*/
|
|
130
|
-
onPress : PropTypes.func,
|
|
131
|
-
style : StyleProp
|
|
132
|
-
}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/**** see : https://github.com/danilowoz/react-content-loader */
|
|
2
|
-
import {defaultObj} from "$cutils";
|
|
3
|
-
import View from "$ecomponents/View";
|
|
4
|
-
import {StyleSheet,Dimensions,useWindowDimensions} from "react-native";
|
|
5
|
-
import React from "react";
|
|
6
|
-
import ContentLoaderF, {Facebook as CLFacebook,Instagram as CLInstagram} from './Loader';
|
|
7
|
-
import PropTypes from "prop-types";
|
|
8
|
-
import BarcharComponent from "./BarChar";
|
|
9
|
-
import PieChartComponent from "./PieChart";
|
|
10
|
-
import FormComponent,{HEIGHT as formHeight} from "./Form";
|
|
11
|
-
import DatagridContentLoader,{HEIGHT as datagridHeight} from "./Datagrid";
|
|
12
|
-
import ProfileComponent from "./Profile";
|
|
13
|
-
import { getBackgroundColor } from "./utils";
|
|
14
|
-
import TaskListComponent from "./TaskList";
|
|
15
|
-
import theme,{Colors} from "$theme"
|
|
16
|
-
import Rect from "./Rect";
|
|
17
|
-
import Circle from "./Circle";
|
|
18
|
-
|
|
19
|
-
export * from "./utils";
|
|
20
|
-
|
|
21
|
-
export {Rect};
|
|
22
|
-
|
|
23
|
-
export {Circle};
|
|
24
|
-
|
|
25
|
-
export {default as Table} from "./Table";
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export default function ContentLoaderWrapper (props){
|
|
29
|
-
let {instance,containerProps,mediaQueryUpdateNativeProps,instances,Component,count,...rest} = props;
|
|
30
|
-
const innerRef = React.useRef(null);
|
|
31
|
-
Component = defaultVal(Component,ContentLoaderF);
|
|
32
|
-
containerProps = defaultObj(containerProps);
|
|
33
|
-
const getChildren = ({width,height,count})=>{
|
|
34
|
-
const dimensions = Dimensions.get("window");
|
|
35
|
-
width = width || dimensions.width;
|
|
36
|
-
height = height || dimensions.height;
|
|
37
|
-
rest = {...defaultObj(rest),width,height}
|
|
38
|
-
const r = [];
|
|
39
|
-
rest = defaultObj(rest);
|
|
40
|
-
count = Math.ceil(defaultNumber(instances,instance,count,3))
|
|
41
|
-
rest.backgroundColor = Colors.isValid(rest.backgroundColor)? rest.backgroundColor : Colors.darken(theme.colors.background);
|
|
42
|
-
rest.backgroundColor= getBackgroundColor(rest.backgroundColor)// '#cecece';
|
|
43
|
-
if(count <= 1) count = 1;
|
|
44
|
-
for(let i = 1; i<= count; i++){
|
|
45
|
-
r.push(<Component {...rest} key={i+""} />)
|
|
46
|
-
}
|
|
47
|
-
return r;
|
|
48
|
-
}
|
|
49
|
-
const children = getChildren({count});
|
|
50
|
-
return <View ref={innerRef} onLayout = {React.mediaQueryUpdateNativePropsCallback(({target,...args})=>{
|
|
51
|
-
args.layout = args.nativeEvent.layout;
|
|
52
|
-
if(typeof mediaQueryUpdateNativeProps ==='function'){
|
|
53
|
-
const children = getChildren(defaultObj(mediaQueryUpdateNativeProps(args)));
|
|
54
|
-
console.log("will update target ",target,children);
|
|
55
|
-
target.setNativeProps({children});
|
|
56
|
-
}
|
|
57
|
-
},innerRef)} {...containerProps}
|
|
58
|
-
style={[styles.container,styles.fullWidth,containerProps.style]}
|
|
59
|
-
>
|
|
60
|
-
{children}
|
|
61
|
-
</View>
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
ContentLoaderWrapper.propTypes = {
|
|
65
|
-
//le nombre d'instance du content loader
|
|
66
|
-
instances : PropTypes.number,
|
|
67
|
-
instance : PropTypes.number,
|
|
68
|
-
count : PropTypes.number,
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function Facebook (props){
|
|
72
|
-
return <ContentLoaderWrapper {...props} Component={CLFacebook}/>
|
|
73
|
-
}
|
|
74
|
-
export function Instagram (props){
|
|
75
|
-
return <ContentLoaderWrapper {...props} Component={CLInstagram}/>
|
|
76
|
-
}
|
|
77
|
-
export function ContentLoader (props){
|
|
78
|
-
return <ContentLoaderWrapper {...props} Component={ContentLoaderF}/>
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function BarChart (props){
|
|
82
|
-
return <ContentLoaderWrapper {...props} Component={BarcharComponent}/>
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function PieChart (props){
|
|
86
|
-
return <ContentLoaderWrapper {...props} Component={PieChartComponent}/>
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function Form (props){
|
|
90
|
-
const {height} = Dimensions.get("window");
|
|
91
|
-
return <ContentLoaderWrapper
|
|
92
|
-
mediaQueryUpdateNativeProps = {({layout:{width,height}})=>{
|
|
93
|
-
width = Math.max(width-50,200);
|
|
94
|
-
return {width,count:Math.max(Math.trunc(height/formHeight),2)}
|
|
95
|
-
}}
|
|
96
|
-
{...props}
|
|
97
|
-
count = {Math.max(Math.trunc(height/formHeight),2)}
|
|
98
|
-
Component={FormComponent}
|
|
99
|
-
/>
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function Profile (props){
|
|
103
|
-
let {containerProps,...rest} = props;
|
|
104
|
-
containerProps = Object.assign({},containerProps);
|
|
105
|
-
containerProps.style = [styles.taskListContainer,containerProps.style];
|
|
106
|
-
return <ContentLoaderWrapper count={3} {...props} Component={ProfileComponent}/>
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function TaskList (props){
|
|
110
|
-
return <ContentLoaderWrapper count={3} {...props} Component={TaskListComponent}/>
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function Datagrid (props){
|
|
114
|
-
const {height} = Dimensions.get("window");
|
|
115
|
-
return <ContentLoaderWrapper
|
|
116
|
-
name = "ddddd"
|
|
117
|
-
mediaQueryUpdateNativeProps ={({layout:{width,height}})=>{
|
|
118
|
-
width = Math.max(props.width-50,200);
|
|
119
|
-
return {width,count:Math.max(Math.trunc((height-100)/datagridHeight),2)}
|
|
120
|
-
}}
|
|
121
|
-
{...props}
|
|
122
|
-
Component={DatagridContentLoader}
|
|
123
|
-
count = {Math.max(Math.trunc((height-100)/datagridHeight),2)}
|
|
124
|
-
/>
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const styles = StyleSheet.create({
|
|
129
|
-
fullWidth : {
|
|
130
|
-
width : '100%'
|
|
131
|
-
},
|
|
132
|
-
center : {
|
|
133
|
-
flex : 1,
|
|
134
|
-
justifyContent: 'center',
|
|
135
|
-
alignItems :'center',
|
|
136
|
-
},
|
|
137
|
-
container : {
|
|
138
|
-
marginHorizontal : 0,
|
|
139
|
-
paddingHorizontal : 0,
|
|
140
|
-
marginTop : 10,
|
|
141
|
-
alignItems : 'center',
|
|
142
|
-
justifyContent : 'flex-start'
|
|
143
|
-
},
|
|
144
|
-
taskListContainer : {
|
|
145
|
-
alignItems : 'flex-end',
|
|
146
|
-
alignSelf : 'flex-start',
|
|
147
|
-
},
|
|
148
|
-
})
|