@fto-consult/expo-ui 6.26.2 → 6.26.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/Dialog/AppBarDialog.js +2 -1
- package/src/components/ErrorBoundary/ErrorMessage.js +3 -2
- package/src/components/ErrorBoundary/Provider.js +4 -3
- package/src/components/ErrorBoundary/index.js +1 -0
- package/src/components/Icon/Icon.js +1 -1
- package/src/components/List/Virtuoso/index.js +1 -2
- package/src/components/Logo/Progress.js +9 -5
- package/src/components/Menu/Menu.js +113 -97
- package/src/components/Portal/Portal.js +88 -0
- package/src/components/Portal/PortalHost.js +31 -0
- package/src/components/Portal/PortalProvider.js +31 -0
- package/src/components/Portal/constants.js +15 -0
- package/src/components/Portal/context.js +10 -0
- package/src/components/Portal/hooks.js +75 -0
- package/src/components/Portal/index.js +11 -3
- package/src/components/Portal/index.old.js +4 -0
- package/src/components/Portal/reducer.js +92 -0
- package/src/components/Portal/usePortalState.js +19 -0
- package/src/components/Preloader/index.js +1 -1
- package/src/components/ScrollView/index.js +1 -0
- package/src/components/SplashScreen/index.js +2 -2
- package/src/components/StatusBar/Component/index.web.js +0 -1
- package/src/components/Table/EmptyPlaceholder/index.js +41 -0
- package/src/components/Table/EmptyPlaceholder/index.native.js +3 -0
- package/src/components/Table/hooks.js +1 -1
- package/src/components/Table/index.js +11 -5
- package/src/context/Provider.js +7 -0
- package/src/index.js +34 -41
- package/src/navigation/index.js +2 -1
- package/src/screens/Help/openLibraries.js +1 -1
- package/src/components/Icon/IconButton.js +0 -155
package/package.json
CHANGED
|
@@ -9,8 +9,9 @@ const AppBarDialogComponent = React.forwardRef((props,ref)=>{
|
|
|
9
9
|
const forceRender = React.useForceRender();
|
|
10
10
|
React.useEffect(()=>{
|
|
11
11
|
const onResize = ()=>{
|
|
12
|
+
return;
|
|
12
13
|
forceRender();
|
|
13
|
-
|
|
14
|
+
}
|
|
14
15
|
if(responsive){
|
|
15
16
|
APP.on(APP.EVENTS.RESIZE_PAGE,onResize);
|
|
16
17
|
}
|
|
@@ -13,6 +13,7 @@ import {isWeb} from "$cplatform";
|
|
|
13
13
|
|
|
14
14
|
const ErrorMessage = React.forwardRef(function(props,ref){
|
|
15
15
|
const { error,resetError,onGoBack, info } = props
|
|
16
|
+
const testID = defaultStr(props.testID,"RN_ErrorBoundaryMessage");
|
|
16
17
|
const goToHome = ()=> {
|
|
17
18
|
if(navigationRef){
|
|
18
19
|
navigationRef.navigate(homeRoute);
|
|
@@ -26,8 +27,8 @@ const ErrorMessage = React.forwardRef(function(props,ref){
|
|
|
26
27
|
const pointerEvents = 'auto';
|
|
27
28
|
const {width,height} = useWindowDimensions();
|
|
28
29
|
return <Portal>
|
|
29
|
-
<View ref={ref} testID=
|
|
30
|
-
<View style={styles.content} pointerEvents={pointerEvents}>
|
|
30
|
+
<View ref={ref} testID={`${testID}_ErrorMessageContainer`} pointerEvents={pointerEvents} style={[styles.container,isWeb()?{position:'fixed'}:null,{backgroundColor:theme.colors.surface,width,height}]}>
|
|
31
|
+
<View style={styles.content} testID={`${testID}_ErrorMessageContentContainer`} pointerEvents={pointerEvents}>
|
|
31
32
|
<Label style={styles.title}>Oops!</Label>
|
|
32
33
|
<Label style={styles.subtitle}>{'Une erreur est survenue'}</Label>
|
|
33
34
|
<Label style={styles.error}>{error.toString()}</Label>
|
|
@@ -4,6 +4,7 @@ let providerRef = null;
|
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import useForceRender from "$react/useForceRender";
|
|
6
6
|
import setRef from "$react/setRef";
|
|
7
|
+
import {defaultStr} from "$cutils";
|
|
7
8
|
|
|
8
9
|
const providerState = {};
|
|
9
10
|
|
|
@@ -38,9 +39,9 @@ const Provider = React.forwardRef((_props,innerRef)=>{
|
|
|
38
39
|
},
|
|
39
40
|
});
|
|
40
41
|
setRef(ref,context);
|
|
41
|
-
|
|
42
|
-
return <Portal>
|
|
43
|
-
<ErrorMessage {...propRef.current} ref={el=>{
|
|
42
|
+
const testID = defaultStr(propRef.current?.testID,_props.testID,"RN_ErrorBoundaryProvider");
|
|
43
|
+
return <Portal testID={testID}>
|
|
44
|
+
<ErrorMessage {...propRef.current} testID={testID+"_ErrorBoundaryPortalContent"} ref={el=>{
|
|
44
45
|
messageRef.current = el;
|
|
45
46
|
setRef(propRef.current.messageRef);
|
|
46
47
|
}}/>
|
|
@@ -3,7 +3,7 @@ import PropTypes from "prop-types";
|
|
|
3
3
|
import Tooltip from "$ecomponents/Tooltip";
|
|
4
4
|
import theme,{flattenStyle,Colors} from "$theme";
|
|
5
5
|
import React from "$react";
|
|
6
|
-
import {IconButton} from "react-native-paper"
|
|
6
|
+
import {IconButton} from "react-native-paper";
|
|
7
7
|
|
|
8
8
|
const IconComponentRef = React.forwardRef((props,ref)=>{
|
|
9
9
|
let {icon,style,Component,button,color,name,containerColor,...rest} = props;
|
|
@@ -58,8 +58,7 @@ const VirtuosoListComponent = React.forwardRef(({onRender,id,fixedHeaderContent,
|
|
|
58
58
|
const containerId = `${id}-container`;
|
|
59
59
|
const headId = `${id}-table-head`;
|
|
60
60
|
testID = defaultStr(testID,containerProps.testID,"RN_VirtuosoListComponent");
|
|
61
|
-
const
|
|
62
|
-
const listId = listIdRef.current;
|
|
61
|
+
const listId = `${id}-list`;
|
|
63
62
|
const listRef = React.useRef(null);
|
|
64
63
|
const sizeRef = React.useRef({width:0,height:0});
|
|
65
64
|
const listSize = sizeRef.current;
|
|
@@ -5,15 +5,19 @@ import { ActivityIndicator, Colors } from 'react-native-paper';
|
|
|
5
5
|
import theme,{defaultDarkTheme} from "$theme";
|
|
6
6
|
import {isIos} from "$cplatform";
|
|
7
7
|
import appConfig from "$capp/config";
|
|
8
|
+
import {defaultStr} from "$cutils";
|
|
8
9
|
|
|
9
|
-
export default function LogoProgress (
|
|
10
|
+
export default function LogoProgress ({testID}){
|
|
11
|
+
testID = defaultStr(testID,"RN_LogoProgress");
|
|
10
12
|
let containerStyle = {width:(Logo.width?Logo.width:undefined),height:(Logo.height?(Logo.height+100):undefined),flex:1,alignItems:"center",justifyContent:"center"};
|
|
11
13
|
const primaryColor = theme.colors.primaryOnSurface,
|
|
12
14
|
secondaryColor = theme.colors.secondaryOnSurface;
|
|
13
|
-
return <View style={[containerStyle]}>
|
|
14
|
-
<Logo key='logo' style={{marginBottom:0}} color={primaryColor}/>
|
|
15
|
-
<
|
|
16
|
-
|
|
15
|
+
return <View style={[containerStyle]} testID={testID+"_ProgressLogoContainer"}>
|
|
16
|
+
<Logo key='logo' style={{marginBottom:0}} color={primaryColor} testID={testID+"_ProgressLogo"}/>
|
|
17
|
+
<View style={{marginTop:20}} testID={testID+"_LogoProgressActivityIndicatorContainer"}>
|
|
18
|
+
<ActivityIndicator size = {isIos()?'large':40} animating={true} color={secondaryColor} />
|
|
19
|
+
</View>
|
|
20
|
+
<View key={'app-version'} style={{flex:1}} testID={testID+"_LogoProgressVersion"}>
|
|
17
21
|
<Label style={[{marginTop:10, fontWeight:'bold',color:secondaryColor}]}>version {appConfig.version}</Label>
|
|
18
22
|
</View>
|
|
19
23
|
</View>
|
|
@@ -94,12 +94,16 @@ class _Menu extends AppComponent {
|
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
updateVisibility = async () => {
|
|
97
|
+
// _Menu is rendered in Portal, which updates items asynchronously
|
|
98
|
+
// We need to do the same here so that the ref is up-to-date
|
|
99
|
+
await Promise.resolve();
|
|
100
|
+
|
|
97
101
|
if (this.props.visible) {
|
|
98
102
|
this.show();
|
|
99
103
|
} else {
|
|
100
104
|
this.hide();
|
|
101
105
|
}
|
|
102
|
-
}
|
|
106
|
+
};
|
|
103
107
|
|
|
104
108
|
isBrowser = () => Platform.OS === 'web' && 'document' in global;
|
|
105
109
|
|
|
@@ -157,62 +161,69 @@ class _Menu extends AppComponent {
|
|
|
157
161
|
document.removeEventListener('keyup', this.handleKeypress);
|
|
158
162
|
};
|
|
159
163
|
|
|
160
|
-
show (){
|
|
164
|
+
show = async () => {
|
|
161
165
|
if(!this._isMounted()) return;
|
|
162
|
-
|
|
166
|
+
const windowLayout = Dimensions.get('window');
|
|
167
|
+
const [menuLayout, anchorLayout] = await Promise.all([
|
|
163
168
|
this.measureMenuLayout(),
|
|
164
169
|
this.measureAnchorLayout(),
|
|
165
|
-
])
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
// When visible is true for first render
|
|
173
|
+
// native views can be still not rendered and
|
|
174
|
+
// measureMenuLayout/measureAnchorLayout functions
|
|
175
|
+
// return wrong values e.g { x:0, y: 0, width: 0, height: 0 }
|
|
176
|
+
// so we have to wait until views are ready
|
|
177
|
+
// and rerun this function to show menu
|
|
178
|
+
if (
|
|
179
|
+
!windowLayout.width ||
|
|
180
|
+
!windowLayout.height ||
|
|
181
|
+
!menuLayout.width ||
|
|
182
|
+
!menuLayout.height ||
|
|
183
|
+
(!anchorLayout.width) ||
|
|
184
|
+
(!anchorLayout.height)
|
|
185
|
+
) {
|
|
186
|
+
requestAnimationFrame(this.show);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
this.setState(
|
|
191
|
+
() => ({
|
|
192
|
+
left: anchorLayout.x,
|
|
193
|
+
top: anchorLayout.y,
|
|
194
|
+
anchorLayout: {
|
|
195
|
+
height: anchorLayout.height,
|
|
196
|
+
width: anchorLayout.width,
|
|
190
197
|
},
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
})
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
198
|
+
menuLayout: {
|
|
199
|
+
width: menuLayout.width,
|
|
200
|
+
height: menuLayout.height,
|
|
201
|
+
},
|
|
202
|
+
}),
|
|
203
|
+
() => {
|
|
204
|
+
this.attachListeners();
|
|
205
|
+
|
|
206
|
+
const animation = theme.animation;
|
|
207
|
+
Animated.parallel([
|
|
208
|
+
Animated.timing(this.state.scaleAnimation, {
|
|
209
|
+
toValue: { x: menuLayout.width, y: menuLayout.height },
|
|
210
|
+
duration: ANIMATION_DURATION * animation.scale,
|
|
211
|
+
easing: EASING,
|
|
212
|
+
useNativeDriver: true,
|
|
213
|
+
}),
|
|
214
|
+
Animated.timing(this.state.opacityAnimation, {
|
|
215
|
+
toValue: 1,
|
|
216
|
+
duration: ANIMATION_DURATION * animation.scale,
|
|
217
|
+
easing: EASING,
|
|
218
|
+
useNativeDriver: true,
|
|
219
|
+
}),
|
|
220
|
+
]).start(({ finished }) => {
|
|
221
|
+
if (finished) {
|
|
222
|
+
this.focusFirstDOMNode(this.menu);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
);
|
|
216
227
|
};
|
|
217
228
|
|
|
218
229
|
hide = (cb) => {
|
|
@@ -226,7 +237,7 @@ class _Menu extends AppComponent {
|
|
|
226
237
|
useNativeDriver: true,
|
|
227
238
|
}).start(({ finished }) => {
|
|
228
239
|
if (finished) {
|
|
229
|
-
this.setState({
|
|
240
|
+
this.setState({ menuLayout: { width: 0, height: 0 }},(e)=>{if(typeof cb ==='function') cb();});
|
|
230
241
|
this.state.scaleAnimation.setValue({ x: 0, y: 0 });
|
|
231
242
|
this.focusFirstDOMNode(this.anchor);
|
|
232
243
|
}
|
|
@@ -283,7 +294,7 @@ class _Menu extends AppComponent {
|
|
|
283
294
|
|
|
284
295
|
// We need to translate menu while animating scale to imitate transform origin for scale animation
|
|
285
296
|
const positionTransforms = [];
|
|
286
|
-
|
|
297
|
+
|
|
287
298
|
// Check if menu fits horizontally and if not align it to right.
|
|
288
299
|
if (left <= windowLayout.width - menuLayout.width - SCREEN_INDENT) {
|
|
289
300
|
positionTransforms.push({
|
|
@@ -304,7 +315,9 @@ class _Menu extends AppComponent {
|
|
|
304
315
|
outputRange: [menuLayout.width / 2, 0],
|
|
305
316
|
}),
|
|
306
317
|
});
|
|
318
|
+
|
|
307
319
|
left += anchorLayout.width - menuLayout.width;
|
|
320
|
+
|
|
308
321
|
const right = left + menuLayout.width;
|
|
309
322
|
// Check if menu position has enough space from right side
|
|
310
323
|
if (right > windowLayout.width - SCREEN_INDENT) {
|
|
@@ -312,6 +325,7 @@ class _Menu extends AppComponent {
|
|
|
312
325
|
}
|
|
313
326
|
}
|
|
314
327
|
const handleScroll = canHandleScroll !== false? true : false;
|
|
328
|
+
|
|
315
329
|
// If the menu is larger than available vertical space,
|
|
316
330
|
// calculate the height of scrollable view
|
|
317
331
|
let scrollableMenuHeight = 0;
|
|
@@ -455,48 +469,50 @@ class _Menu extends AppComponent {
|
|
|
455
469
|
style = {{backgroundColor:'transparent'}}
|
|
456
470
|
>
|
|
457
471
|
{anchor}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
472
|
+
{true ? (
|
|
473
|
+
<Portal>
|
|
474
|
+
{rendered ? <TouchableWithoutFeedback
|
|
475
|
+
testID={testID+"_Menu_TouchableWithoutFeedBack"}
|
|
476
|
+
accessibilityLabel={overlayAccessibilityLabel}
|
|
477
|
+
role="button"
|
|
478
|
+
onPress={onDismiss}
|
|
479
|
+
style = {[hiddenStyle]}
|
|
480
|
+
>
|
|
481
|
+
<View style={[StyleSheet.absoluteFill,{flex:1,backgroundColor:'transparent'}]} testID={testID+"_Backdrop"} />
|
|
482
|
+
</TouchableWithoutFeedback>:null}
|
|
483
|
+
<View
|
|
484
|
+
testID = {testID+"_MenuContentContainer"}
|
|
485
|
+
ref={(ref) => {
|
|
486
|
+
this.menu = ref;
|
|
487
|
+
}}
|
|
488
|
+
collapsable={false}
|
|
489
|
+
accessibilityViewIsModal={visible}
|
|
490
|
+
style={[styles.wrapper, positionStyle, style,hiddenStyle]}
|
|
491
|
+
pointerEvents={visible ? 'box-none' : 'none'}
|
|
492
|
+
onAccessibilityEscape={onDismiss}
|
|
493
|
+
>
|
|
494
|
+
{rendered?<Animated.View style={{ transform: positionTransforms }} testID={testID+"_Animated"}>
|
|
495
|
+
<Surface
|
|
496
|
+
elevation = {5}
|
|
497
|
+
testID= {testID+"_MenuContent"}
|
|
498
|
+
style={
|
|
499
|
+
[
|
|
500
|
+
styles.shadowMenuContainer,
|
|
501
|
+
shadowMenuContainerStyle,
|
|
502
|
+
contentStyle,
|
|
503
|
+
{backgroundColor : theme.colors.surface},
|
|
504
|
+
minWidth && {minWidth : Math.max(minWidth,MIN_WIDTH)},
|
|
505
|
+
sameWidth && anchorLayout.width ? {width:Math.max(anchorLayout.width,minWidth,MIN_WIDTH)} : undefined,
|
|
506
|
+
]
|
|
507
|
+
}
|
|
508
|
+
>
|
|
509
|
+
{((scrollableMenuHeight|| contentContainerStyle) && (<ScrollView contentContainerStyle={contentContainerStyle} testID={testID+"_ScrollView"}>{children}</ScrollView>
|
|
510
|
+
)) || children}
|
|
511
|
+
</Surface>
|
|
512
|
+
</Animated.View> : null}
|
|
513
|
+
</View>
|
|
514
|
+
</Portal>
|
|
515
|
+
) : null}
|
|
500
516
|
</View>
|
|
501
517
|
);
|
|
502
518
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* MIT License
|
|
3
|
+
Copyright (c) 2020 Mo Gorhom
|
|
4
|
+
@see : https://github.com/gorhom/react-native-portal
|
|
5
|
+
*/
|
|
6
|
+
import { memo, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
7
|
+
import {uniqid} from "$utils";
|
|
8
|
+
import { usePortal } from './hooks';
|
|
9
|
+
|
|
10
|
+
const PortalComponent = ({
|
|
11
|
+
name: _providedName,
|
|
12
|
+
hostName,
|
|
13
|
+
handleOnMount: _providedHandleOnMount,
|
|
14
|
+
handleOnUnmount: _providedHandleOnUnmount,
|
|
15
|
+
handleOnUpdate: _providedHandleOnUpdate,
|
|
16
|
+
children,
|
|
17
|
+
}) => {
|
|
18
|
+
//#region hooks
|
|
19
|
+
const { addPortal: addUpdatePortal, removePortal } = usePortal(hostName);
|
|
20
|
+
//#endregion
|
|
21
|
+
|
|
22
|
+
//#region variables
|
|
23
|
+
const name = useMemo(() => _providedName || uniqid("portal-component"), [_providedName]);
|
|
24
|
+
//#endregion
|
|
25
|
+
|
|
26
|
+
//#region refs
|
|
27
|
+
const handleOnMountRef = useRef();
|
|
28
|
+
const handleOnUnmountRef = useRef();
|
|
29
|
+
const handleOnUpdateRef = useRef();
|
|
30
|
+
//#endregion
|
|
31
|
+
|
|
32
|
+
//#region callbacks
|
|
33
|
+
const handleOnMount = useCallback(() => {
|
|
34
|
+
if (_providedHandleOnMount) {
|
|
35
|
+
_providedHandleOnMount(() => addUpdatePortal(name, children));
|
|
36
|
+
} else {
|
|
37
|
+
addUpdatePortal(name, children);
|
|
38
|
+
}
|
|
39
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
|
+
}, [_providedHandleOnMount, addUpdatePortal]);
|
|
41
|
+
handleOnMountRef.current = handleOnMount;
|
|
42
|
+
|
|
43
|
+
const handleOnUnmount = useCallback(() => {
|
|
44
|
+
if (_providedHandleOnUnmount) {
|
|
45
|
+
_providedHandleOnUnmount(() => removePortal(name));
|
|
46
|
+
} else {
|
|
47
|
+
removePortal(name);
|
|
48
|
+
}
|
|
49
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
50
|
+
}, [_providedHandleOnUnmount, removePortal]);
|
|
51
|
+
handleOnUnmountRef.current = handleOnUnmount;
|
|
52
|
+
|
|
53
|
+
const handleOnUpdate = useCallback(() => {
|
|
54
|
+
if (_providedHandleOnUpdate) {
|
|
55
|
+
_providedHandleOnUpdate(() => addUpdatePortal(name, children));
|
|
56
|
+
} else {
|
|
57
|
+
addUpdatePortal(name, children);
|
|
58
|
+
}
|
|
59
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
60
|
+
}, [_providedHandleOnUpdate, addUpdatePortal, children]);
|
|
61
|
+
handleOnUpdateRef.current = handleOnUpdate;
|
|
62
|
+
//#endregion
|
|
63
|
+
|
|
64
|
+
//#region effects
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
handleOnMountRef.current?.();
|
|
67
|
+
return () => {
|
|
68
|
+
handleOnUnmountRef.current?.();
|
|
69
|
+
|
|
70
|
+
// remove callbacks refs
|
|
71
|
+
handleOnMountRef.current = undefined;
|
|
72
|
+
handleOnUnmountRef.current = undefined;
|
|
73
|
+
handleOnUpdateRef.current = undefined;
|
|
74
|
+
};
|
|
75
|
+
}, []);
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
handleOnUpdateRef.current?.();
|
|
78
|
+
}, [children]);
|
|
79
|
+
//#endregion
|
|
80
|
+
|
|
81
|
+
return null;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const Portal = memo(PortalComponent);
|
|
85
|
+
Portal.displayName = 'Portal';
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
export default Portal;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* MIT License
|
|
3
|
+
Copyright (c) 2020 Mo Gorhom
|
|
4
|
+
@see : https://github.com/gorhom/react-native-portal
|
|
5
|
+
*/
|
|
6
|
+
import React, { memo, useEffect } from 'react';
|
|
7
|
+
import { usePortal,usePortalState} from './hooks';
|
|
8
|
+
|
|
9
|
+
const PortalHostComponent = ({ name }) => {
|
|
10
|
+
const state = usePortalState(name);
|
|
11
|
+
const { registerHost, deregisterHost } = usePortal(name);
|
|
12
|
+
|
|
13
|
+
//#region effects
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
registerHost();
|
|
16
|
+
return () => {
|
|
17
|
+
deregisterHost();
|
|
18
|
+
};
|
|
19
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
20
|
+
}, []);
|
|
21
|
+
//#endregion
|
|
22
|
+
|
|
23
|
+
//#region render
|
|
24
|
+
return <>{state.map(item => item.node)}</>;
|
|
25
|
+
//#endregion
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const PortalHost = memo(PortalHostComponent);
|
|
29
|
+
PortalHost.displayName = 'PortalHost';
|
|
30
|
+
|
|
31
|
+
export default PortalHost;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* MIT License
|
|
3
|
+
Copyright (c) 2020 Mo Gorhom
|
|
4
|
+
@see : https://github.com/gorhom/react-native-portal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { memo, useReducer } from 'react';
|
|
8
|
+
import PortalHost from './PortalHost';
|
|
9
|
+
import {PortalDispatchContext,PortalStateContext} from './context';
|
|
10
|
+
import { INITIAL_STATE } from './constants';
|
|
11
|
+
import { reducer } from './reducer';
|
|
12
|
+
|
|
13
|
+
const PortalProviderComponent = ({
|
|
14
|
+
rootHostName = 'root',
|
|
15
|
+
shouldAddRootHost = true,
|
|
16
|
+
children,
|
|
17
|
+
}) => {
|
|
18
|
+
const [state, dispatch] = useReducer(reducer, INITIAL_STATE);
|
|
19
|
+
return (
|
|
20
|
+
<PortalDispatchContext.Provider value={dispatch}>
|
|
21
|
+
<PortalStateContext.Provider value={state}>
|
|
22
|
+
{children}
|
|
23
|
+
{shouldAddRootHost && <PortalHost name={rootHostName} />}
|
|
24
|
+
</PortalStateContext.Provider>
|
|
25
|
+
</PortalDispatchContext.Provider>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const PortalProvider = memo(PortalProviderComponent);
|
|
30
|
+
PortalProvider.displayName = 'PortalProvider';
|
|
31
|
+
export default PortalProvider;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* MIT License
|
|
3
|
+
Copyright (c) 2020 Mo Gorhom
|
|
4
|
+
@see : https://github.com/gorhom/react-native-portal
|
|
5
|
+
*/
|
|
6
|
+
const ACTIONS = {
|
|
7
|
+
REGISTER_HOST :"REGISTER_HOST",
|
|
8
|
+
DEREGISTER_HOST:"DEREGISTER_HOST",
|
|
9
|
+
ADD_UPDATE_PORTAL:"ADD_UPDATE_PORTAL",
|
|
10
|
+
REMOVE_PORTAL:"REMOVE_PORTAL",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const INITIAL_STATE = {};
|
|
14
|
+
|
|
15
|
+
export { ACTIONS, INITIAL_STATE };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* MIT License
|
|
3
|
+
Copyright (c) 2020 Mo Gorhom
|
|
4
|
+
@see : https://github.com/gorhom/react-native-portal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createContext } from 'react';
|
|
8
|
+
|
|
9
|
+
export const PortalStateContext = createContext(null);
|
|
10
|
+
export const PortalDispatchContext = createContext(null);
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* MIT License
|
|
3
|
+
Copyright (c) 2020 Mo Gorhom
|
|
4
|
+
@see : https://github.com/gorhom/react-native-portal
|
|
5
|
+
*/
|
|
6
|
+
import { useCallback, useContext } from 'react';
|
|
7
|
+
import { ACTIONS } from './constants';
|
|
8
|
+
import { PortalDispatchContext,PortalStateContext } from './context';
|
|
9
|
+
|
|
10
|
+
export const usePortal = (hostName = 'root') => {
|
|
11
|
+
const dispatch = useContext(PortalDispatchContext);
|
|
12
|
+
|
|
13
|
+
if (dispatch === null) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
"'PortalDispatchContext' cannot be null, please add 'PortalProvider' to the root component."
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//#region methods
|
|
20
|
+
const registerHost = useCallback(() => {
|
|
21
|
+
dispatch({
|
|
22
|
+
type: ACTIONS.REGISTER_HOST,
|
|
23
|
+
hostName: hostName,
|
|
24
|
+
});
|
|
25
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26
|
+
}, []);
|
|
27
|
+
|
|
28
|
+
const deregisterHost = useCallback(() => {
|
|
29
|
+
dispatch({
|
|
30
|
+
type: ACTIONS.DEREGISTER_HOST,
|
|
31
|
+
hostName: hostName,
|
|
32
|
+
});
|
|
33
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
const addUpdatePortal = useCallback((name, node) => {
|
|
37
|
+
dispatch({
|
|
38
|
+
type: ACTIONS.ADD_UPDATE_PORTAL,
|
|
39
|
+
hostName,
|
|
40
|
+
portalName: name,
|
|
41
|
+
node,
|
|
42
|
+
});
|
|
43
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
44
|
+
}, []);
|
|
45
|
+
|
|
46
|
+
const removePortal = useCallback((name) => {
|
|
47
|
+
dispatch({
|
|
48
|
+
type: ACTIONS.REMOVE_PORTAL,
|
|
49
|
+
hostName,
|
|
50
|
+
portalName: name,
|
|
51
|
+
});
|
|
52
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
53
|
+
}, []);
|
|
54
|
+
//#endregion
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
registerHost,
|
|
58
|
+
deregisterHost,
|
|
59
|
+
addPortal: addUpdatePortal,
|
|
60
|
+
updatePortal: addUpdatePortal,
|
|
61
|
+
removePortal,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const usePortalState = (hostName) => {
|
|
66
|
+
const state = useContext(PortalStateContext);
|
|
67
|
+
|
|
68
|
+
if (state === null) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
"'PortalStateContext' cannot be null, please add 'PortalProvider' to the root component."
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return state[hostName] || [];
|
|
75
|
+
};
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
/***
|
|
2
|
+
* MIT License
|
|
3
|
+
Copyright (c) 2020 Mo Gorhom
|
|
4
|
+
@see : https://github.com/gorhom/react-native-portal
|
|
5
|
+
*/
|
|
2
6
|
|
|
3
|
-
export
|
|
7
|
+
export {default} from "./Portal";
|
|
4
8
|
|
|
5
|
-
export default
|
|
9
|
+
export {default as PortalHost} from "./PortalHost";
|
|
10
|
+
|
|
11
|
+
export {default as PortalProvider} from "./PortalProvider";
|
|
12
|
+
|
|
13
|
+
export * from "./hooks";
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* MIT License
|
|
3
|
+
Copyright (c) 2020 Mo Gorhom
|
|
4
|
+
@see : https://github.com/gorhom/react-native-portal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ACTIONS } from './constants';
|
|
8
|
+
|
|
9
|
+
const registerHost = (state,hostName) => {
|
|
10
|
+
if (!(hostName in state)) {
|
|
11
|
+
state[hostName] = [];
|
|
12
|
+
}
|
|
13
|
+
return state;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const deregisterHost = (
|
|
17
|
+
state,
|
|
18
|
+
hostName
|
|
19
|
+
) => {
|
|
20
|
+
delete state[hostName];
|
|
21
|
+
return state;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const addUpdatePortal = (
|
|
25
|
+
state,
|
|
26
|
+
hostName,
|
|
27
|
+
portalName,
|
|
28
|
+
node
|
|
29
|
+
) => {
|
|
30
|
+
if (!(hostName in state)) {
|
|
31
|
+
state = registerHost(state, hostName);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* updated portal, if it was already added.
|
|
36
|
+
*/
|
|
37
|
+
const index = state[hostName].findIndex(item => item.name === portalName);
|
|
38
|
+
if (index !== -1) {
|
|
39
|
+
state[hostName][index].node = node;
|
|
40
|
+
} else {
|
|
41
|
+
state[hostName].push({
|
|
42
|
+
name: portalName,
|
|
43
|
+
node,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return state;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const removePortal = (
|
|
50
|
+
state,
|
|
51
|
+
hostName,
|
|
52
|
+
portalName
|
|
53
|
+
) => {
|
|
54
|
+
if (!(hostName in state)) {
|
|
55
|
+
console.warn({
|
|
56
|
+
component: reducer.name,
|
|
57
|
+
method: removePortal.name,
|
|
58
|
+
params: `Failed to remove portal '${portalName}', '${hostName}' was not registered!`,
|
|
59
|
+
});
|
|
60
|
+
return state;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const index = state[hostName].findIndex(item => item.name === portalName);
|
|
64
|
+
if (index !== -1) state[hostName].splice(index, 1);
|
|
65
|
+
return state;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const reducer = (state,action) => {
|
|
69
|
+
const { type } = action;
|
|
70
|
+
let clonedState = { ...state };
|
|
71
|
+
switch (type) {
|
|
72
|
+
case ACTIONS.REGISTER_HOST:
|
|
73
|
+
return registerHost(clonedState, action.hostName);
|
|
74
|
+
case ACTIONS.DEREGISTER_HOST:
|
|
75
|
+
return deregisterHost(clonedState, action.hostName);
|
|
76
|
+
case ACTIONS.ADD_UPDATE_PORTAL:
|
|
77
|
+
return addUpdatePortal(
|
|
78
|
+
clonedState,
|
|
79
|
+
action.hostName,
|
|
80
|
+
(action).portalName,
|
|
81
|
+
(action).node
|
|
82
|
+
);
|
|
83
|
+
case ACTIONS.REMOVE_PORTAL:
|
|
84
|
+
return removePortal(
|
|
85
|
+
clonedState,
|
|
86
|
+
action.hostName,
|
|
87
|
+
(action).portalName
|
|
88
|
+
);
|
|
89
|
+
default:
|
|
90
|
+
return state;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* MIT License
|
|
3
|
+
Copyright (c) 2020 Mo Gorhom
|
|
4
|
+
@see : https://github.com/gorhom/react-native-portal
|
|
5
|
+
*/
|
|
6
|
+
import { useContext } from 'react';
|
|
7
|
+
import { PortalStateContext } from './context';
|
|
8
|
+
|
|
9
|
+
export const usePortalState = (hostName) => {
|
|
10
|
+
const state = useContext(PortalStateContext);
|
|
11
|
+
|
|
12
|
+
if (state === null) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
"'PortalStateContext' cannot be null, please add 'PortalProvider' to the root component."
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return state[hostName] || [];
|
|
19
|
+
};
|
|
@@ -158,7 +158,7 @@ export function PreloaderProvider({ children }) {
|
|
|
158
158
|
return ()=>{ unlinkPreloader();}
|
|
159
159
|
},[])
|
|
160
160
|
return (<PreloaderContext.Provider value={{subscribe,unsubscribe}}>
|
|
161
|
-
<PreloaderComponent id={MAIN_PRELOADER_ID} visible = {false}/>
|
|
161
|
+
<PreloaderComponent id={MAIN_PRELOADER_ID} testID={"RN_MainPreloaderProviderComponent"} visible = {false}/>
|
|
162
162
|
{children}
|
|
163
163
|
</PreloaderContext.Provider>);
|
|
164
164
|
}
|
|
@@ -5,6 +5,7 @@ import {defaultStr,defaultObj} from "$cutils";
|
|
|
5
5
|
import {Vertical as AutoSizeVertical} from "$ecomponents/AutoSizer";
|
|
6
6
|
|
|
7
7
|
const ScrollViewComponent = React.forwardRef(({withAutoSizer,autoSizerProps,testID,...rest},ref) => {
|
|
8
|
+
return <ScrollView testID={testID} {...rest} ref={ref}/>
|
|
8
9
|
testID = defaultStr(testID,'RN_ScrollViewComponent');
|
|
9
10
|
const autoSize = React.useRef(withAutoSizer).current;
|
|
10
11
|
if(!autoSize || rest.horizontal === true || rest.vertical === false){
|
|
@@ -98,7 +98,7 @@ const SplashScreenComponent = ({isLoaded,children , duration, delay,logoWidth,lo
|
|
|
98
98
|
],
|
|
99
99
|
}
|
|
100
100
|
const child = (animationDone && isLoaded)? React.isValidElement(children) && children : null;
|
|
101
|
-
if(animationDone) return child;
|
|
101
|
+
if(animationDone && isLoaded) return child;
|
|
102
102
|
return <View style={[styles.container]} testID={testID} id={testID}>
|
|
103
103
|
{!animationDone ? <View style={StyleSheet.absoluteFill} testID={testID+"_Animation"}/> : null}
|
|
104
104
|
<View style={styles.containerGlue} testID={testID+"_ContainerGlue"}>
|
|
@@ -108,7 +108,7 @@ const SplashScreenComponent = ({isLoaded,children , duration, delay,logoWidth,lo
|
|
|
108
108
|
testID={testID+"_AnimationDone"}
|
|
109
109
|
/>
|
|
110
110
|
)}
|
|
111
|
-
{(animationDone || isNative) && child}
|
|
111
|
+
{false && (animationDone || isNative) && child}
|
|
112
112
|
{!animationDone && (
|
|
113
113
|
<View testID={testID+"_LogoContainer"} style={[StyleSheet.absoluteFill, styles.logoStyle]}>
|
|
114
114
|
{(
|
|
@@ -53,7 +53,6 @@ export default function StatusBarComponent(props){
|
|
|
53
53
|
}
|
|
54
54
|
},[]);
|
|
55
55
|
return null;
|
|
56
|
-
return <StatusBar {...styles} {...props}></StatusBar>
|
|
57
56
|
}
|
|
58
57
|
const updateThemeName = (theme)=>{
|
|
59
58
|
if(typeof document ==="undefined" || !document || !isDOMElement(document.body)) return null;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {useEffect} from "react";
|
|
2
|
+
import { StyleSheet } from "react-native";
|
|
3
|
+
import View from "$ecomponents/View";
|
|
4
|
+
import {defaultStr,defaultNumber,uniqid,classNames} from "$cutils";
|
|
5
|
+
import { useWindowDimensions } from "react-native";
|
|
6
|
+
import {useTable} from "../hooks";
|
|
7
|
+
|
|
8
|
+
export default function EmptyPlaceholderComponent({testID,content}){
|
|
9
|
+
testID = defaultStr(testID,"RN_VirtuosoTableEmptyPlaceholder");
|
|
10
|
+
const {id : tableId,visibleColsNames} = useTable();
|
|
11
|
+
const id = `${tableId}-empty-placeholder`;
|
|
12
|
+
const listID = `${tableId}-list`;
|
|
13
|
+
const clx = "virtuoso-table-empty-placehoder";
|
|
14
|
+
const {width:dimW} = useWindowDimensions();
|
|
15
|
+
useEffect(()=>{
|
|
16
|
+
const list = document.querySelector(`#${listID}`),content = document.querySelector(`#${id}-content`);
|
|
17
|
+
if(!list || !content || !list.offsetWidth) return;
|
|
18
|
+
const width = list.offsetWidth || list.clientWidth;
|
|
19
|
+
content.style.width = `${width}px`;
|
|
20
|
+
},[dimW]);
|
|
21
|
+
return <tbody id={`${id}-tbody`} data-test-id={`${testID}-tbody`} className={`${clx}-tbody`} style={wStyle}>
|
|
22
|
+
<tr id={`${id}-tr`} data-test-id={`${testID}-tr`} className={`${clx}-tr`} style={wStyle}>
|
|
23
|
+
<td colSpan={visibleColsNames.length} id={`${id}-td`} width={"100%"} height={"100%"} data-test-id={`${testID}-td`} style={wStyle}>
|
|
24
|
+
<View testID={testID} id={`${id}-content`} style={styles.content}>{content}</View>
|
|
25
|
+
</td>
|
|
26
|
+
</tr>
|
|
27
|
+
</tbody>
|
|
28
|
+
}
|
|
29
|
+
const wStyle = {
|
|
30
|
+
width : "100%",
|
|
31
|
+
height : "100%",
|
|
32
|
+
position : "relative"
|
|
33
|
+
}
|
|
34
|
+
const styles = StyleSheet.create({
|
|
35
|
+
content : {
|
|
36
|
+
alignItems:"center",
|
|
37
|
+
justifyContent : "center",
|
|
38
|
+
height : "100%",
|
|
39
|
+
width : "100%",
|
|
40
|
+
},
|
|
41
|
+
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import View from "$ecomponents/View";
|
|
2
|
-
import {defaultObj,defaultStr,debounce,defaultNumber,isObj,defaultVal} from "$cutils";
|
|
2
|
+
import {defaultObj,defaultStr,debounce,defaultNumber,uniqid,isObj,defaultVal} from "$cutils";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import React from "$react";
|
|
5
5
|
import { StyleSheet,View as RNView,ScrollView,Dimensions} from "react-native";
|
|
@@ -15,6 +15,7 @@ import {useIsRowSelected} from "$ecomponents/Datagrid/hooks";
|
|
|
15
15
|
import {getRowStyle} from "$ecomponents/Datagrid/utils";
|
|
16
16
|
import ScrollNative from "./ScrollNative";
|
|
17
17
|
import VirtuosoTableComponent from "./VirtuosoTable";
|
|
18
|
+
import EmptyPlaceholder from "./EmptyPlaceholder";
|
|
18
19
|
export {styles};
|
|
19
20
|
|
|
20
21
|
const isSCrollingRef = React.createRef();
|
|
@@ -257,6 +258,9 @@ const TableComponent = React.forwardRef(({containerProps,listContainerStyle,onRe
|
|
|
257
258
|
return <TableRowComponent {...props} style={[getRowStyle(args),props.style]}/>
|
|
258
259
|
},
|
|
259
260
|
Table: VirtuosoTableComponent,
|
|
261
|
+
EmptyPlaceholder : (props)=>{
|
|
262
|
+
return <EmptyPlaceholder testID={testID+"_VirtuosoEmptyPlaceholder"} {...props} content={emptyContent}/>
|
|
263
|
+
}
|
|
260
264
|
}}
|
|
261
265
|
/>
|
|
262
266
|
{isNative ? <AbsoluteScrollView
|
|
@@ -334,20 +338,22 @@ TableComponent.popTypes = {
|
|
|
334
338
|
|
|
335
339
|
TableComponent.displayName = "TableComponent";
|
|
336
340
|
|
|
337
|
-
const TableComponentProvider = React.forwardRef(({children,renderCell,testID,withDatagridContext,getRowKey,filter,data,...props},ref)=>{
|
|
341
|
+
const TableComponentProvider = React.forwardRef(({children,id,renderCell,testID,withDatagridContext,getRowKey,filter,data,...props},ref)=>{
|
|
338
342
|
testID = props.testID = defaultStr(testID,"RN_TableComponent");
|
|
339
|
-
const
|
|
343
|
+
const idRef = React.useRef(defaultStr(id,uniqid("virtuoso-table-list-id")));
|
|
344
|
+
id = idRef.current;
|
|
345
|
+
const prepatedColumns = usePrepareColumns({...props,id});
|
|
340
346
|
const keyExtractor = typeof getRowKey =='function'? getRowKey : React.getKey;
|
|
341
347
|
const items = React.useMemo(()=>{
|
|
342
348
|
filter = typeof filter =='function'? filter : x=>true;
|
|
343
349
|
return data.filter((i,...rest)=>isObj(i) && !!filter(i,...rest));
|
|
344
350
|
},[data]);
|
|
345
351
|
const getItem = (index)=>items[index]||null;
|
|
346
|
-
return <TableContext.Provider value={{...props,...prepatedColumns,getItem,getRowByIndex:getItem,testID,data,withDatagridContext,keyExtractor,
|
|
352
|
+
return <TableContext.Provider value={{...props,...prepatedColumns,id,getItem,getRowByIndex:getItem,testID,data,withDatagridContext,keyExtractor,
|
|
347
353
|
renderCell,
|
|
348
354
|
items
|
|
349
355
|
}}>
|
|
350
|
-
<TableComponent {...props} ref={ref}/>
|
|
356
|
+
<TableComponent {...props} id={id} ref={ref}/>
|
|
351
357
|
</TableContext.Provider>
|
|
352
358
|
});
|
|
353
359
|
TableComponentProvider.displayName = "TableComponentProvider";
|
package/src/context/Provider.js
CHANGED
|
@@ -85,6 +85,13 @@ const Provider = ({children,getTableData,navigation,components,convertFiltersToS
|
|
|
85
85
|
get customCSS(){
|
|
86
86
|
const prevCSS = defaultStr(typeof customCSS ==='function'? customCSS(theme) : customCSS);
|
|
87
87
|
return `
|
|
88
|
+
#root {
|
|
89
|
+
overflow:hidden!important;
|
|
90
|
+
width : 100%!important;
|
|
91
|
+
height : 100%important;
|
|
92
|
+
left : 0!important;
|
|
93
|
+
top : 0!important;
|
|
94
|
+
}
|
|
88
95
|
.virtuoso-table-component,
|
|
89
96
|
.virtuoso-table-component th,
|
|
90
97
|
.virtuoso-table-component tr,
|
package/src/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import SimpleSelect from '$ecomponents/SimpleSelect';
|
|
|
28
28
|
import {Provider as AlertProvider} from '$ecomponents/Dialog/confirm/Alert';
|
|
29
29
|
import { DialogProvider as FormDataDialogProvider } from '$eform/FormData';
|
|
30
30
|
import {Portal } from 'react-native-paper';
|
|
31
|
-
import {PortalProvider} from '$ecomponents/Portal';
|
|
31
|
+
import {PortalProvider,CustomPortal} from '$ecomponents/Portal';
|
|
32
32
|
import ErrorBoundaryProvider from "$ecomponents/ErrorBoundary/Provider";
|
|
33
33
|
import notify, {notificationRef} from "$notify";
|
|
34
34
|
import DropdownAlert from '$ecomponents/Dialog/DropdownAlert';
|
|
@@ -40,9 +40,6 @@ import StatusBar from "$ecomponents/StatusBar";
|
|
|
40
40
|
import {Provider as PaperProvider } from 'react-native-paper';
|
|
41
41
|
import FontIcon from "$ecomponents/Icon/Font";
|
|
42
42
|
import useContext from "$econtext/hooks";
|
|
43
|
-
import {GestureHandlerRootView} from "react-native-gesture-handler";
|
|
44
|
-
import KeyboardAvoidingViewComponent from '$ecomponents/KeyboardAvoidingView';
|
|
45
|
-
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
46
43
|
export * from "./context";
|
|
47
44
|
|
|
48
45
|
let MAX_BACK_COUNT = 1;
|
|
@@ -256,59 +253,55 @@ function App({init:initApp,initialRouteName:appInitialRouteName,render,onMount})
|
|
|
256
253
|
onMountRef.current = true;
|
|
257
254
|
}
|
|
258
255
|
},[isLoaded])
|
|
259
|
-
const child = isLoaded ? <
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
256
|
+
const child = isLoaded ? <NavigationContainer
|
|
257
|
+
ref={navigationRef}
|
|
258
|
+
initialState={initialState}
|
|
259
|
+
onStateChange={(state) =>{
|
|
260
|
+
setSession(NAVIGATION_PERSISTENCE_KEY,decycle(state),false);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
>
|
|
264
|
+
<Navigation
|
|
265
|
+
initialRouteName = {defaultStr(hasGetStarted ? appInitialRouteName : getStartedRouteName,"Home")}
|
|
266
|
+
state = {state}
|
|
267
|
+
hasGetStarted = {hasGetStarted}
|
|
268
|
+
isInitialized = {isInitialized}
|
|
269
|
+
onGetStart = {(e)=>{
|
|
270
|
+
setState({...state,hasGetStarted:true})
|
|
271
|
+
}}
|
|
272
|
+
/>
|
|
273
|
+
</NavigationContainer> : null;
|
|
268
274
|
const content = isLoaded ? typeof render == 'function'? render({children:child,appConfig,config:appConfig}) : child : null;
|
|
269
275
|
return <AuthProvider>
|
|
270
|
-
|
|
271
|
-
ref={navigationRef}
|
|
272
|
-
initialState={initialState}
|
|
273
|
-
onStateChange={(state) =>{
|
|
274
|
-
if(!isLoaded) return;
|
|
275
|
-
setSession(NAVIGATION_PERSISTENCE_KEY,decycle(state),false);
|
|
276
|
-
}}
|
|
277
|
-
>
|
|
278
|
-
<PaperProvider
|
|
276
|
+
<PaperProvider
|
|
279
277
|
theme={theme}
|
|
280
278
|
settings={{
|
|
281
279
|
icon: (props) => {
|
|
282
280
|
return <FontIcon {...props}/>
|
|
283
281
|
},
|
|
284
282
|
}}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
>
|
|
284
|
+
<PortalProvider>
|
|
285
|
+
<ErrorBoundaryProvider/>
|
|
288
286
|
<PreloaderProvider/>
|
|
289
|
-
<DialogProvider responsive/>
|
|
287
|
+
<DialogProvider responsive testID={"RN_MainAppDialogProvider"}/>
|
|
290
288
|
<AlertProvider SimpleSelect={SimpleSelect}/>
|
|
291
289
|
<FormDataDialogProvider/>
|
|
292
290
|
<BottomSheetProvider/>
|
|
293
291
|
<DropdownAlert ref={notificationRef}/>
|
|
294
|
-
<
|
|
295
|
-
|
|
296
|
-
|
|
292
|
+
<Portal.Host testID="RN_NativePaperPortalHost">
|
|
293
|
+
<ErrorBoundary>
|
|
294
|
+
<StatusBar/>
|
|
297
295
|
<SplashScreen isLoaded={isLoaded}>
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
{React.isValidElement(content) && content || child}
|
|
302
|
-
</PreferencesContext.Provider>
|
|
303
|
-
</ErrorBoundary>
|
|
296
|
+
<PreferencesContext.Provider value={preferences}>
|
|
297
|
+
{React.isValidElement(content) && content || child}
|
|
298
|
+
</PreferencesContext.Provider>
|
|
304
299
|
</SplashScreen>
|
|
305
|
-
</
|
|
306
|
-
</
|
|
307
|
-
</
|
|
308
|
-
</PortalProvider>
|
|
300
|
+
</ErrorBoundary>
|
|
301
|
+
</Portal.Host>
|
|
302
|
+
</PortalProvider>
|
|
309
303
|
</PaperProvider>
|
|
310
|
-
|
|
311
|
-
</AuthProvider>
|
|
304
|
+
</AuthProvider>;
|
|
312
305
|
}
|
|
313
306
|
|
|
314
307
|
export default App;
|
package/src/navigation/index.js
CHANGED
|
@@ -15,7 +15,8 @@ export * from "./utils";
|
|
|
15
15
|
* lorsque hasGetStarted est à false, celle-ci rend l'écran Start permettant de rendre le contenu GetStarted
|
|
16
16
|
*/
|
|
17
17
|
export default function NavigationComponent (props){
|
|
18
|
-
let {state,hasGetStarted,onGetStart,initialRouteName,...rest} = props;
|
|
18
|
+
let {state,hasGetStarted,isLoading,onGetStart,initialRouteName,...rest} = props;
|
|
19
|
+
if(isLoading) return null;
|
|
19
20
|
const {navigation:{screens}} = useContext();
|
|
20
21
|
const allScreens = initScreens({Factory:Stack,screens,ModalFactory:Stack,filter:({name})=>{
|
|
21
22
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports = {"@fto-consult/expo-ui":{"name":"@fto-consult/expo-ui","version":"6.
|
|
1
|
+
module.exports = {"@fto-consult/expo-ui":{"name":"@fto-consult/expo-ui","version":"6.26.2","repository":{"type":"git","url":"git+https://github.com/borispipo/expo-ui.git"},"homepage":"https://github.com/borispipo/expo-ui#readme"},"@emotion/native":{"version":"11.11.0","url":"https://emotion.sh","license":"MIT"},"@emotion/react":{"version":"11.11.1","url":"https://github.com/emotion-js/emotion/tree/main/packages/react","license":"MIT"},"@expo/html-elements":{"version":"0.5.1","url":"https://github.com/expo/expo/tree/main/packages/html-elements","license":"MIT"},"@expo/metro-config":{"version":"0.10.7","url":"https://github.com/expo/expo.git","license":"MIT"},"@expo/vector-icons":{"version":"13.0.0","url":"https://expo.github.io/vector-icons","license":"MIT"},"@expo/webpack-config":{"version":"18.1.2","url":"https://github.com/expo/expo-cli.git","license":"MIT"},"@faker-js/faker":{"version":"8.0.2","url":"https://github.com/faker-js/faker.git","license":"MIT"},"@fto-consult/common":{"version":"3.28.4","url":"https://github.com/borispipo/common#readme","license":"ISC"},"@gorhom/portal":{"version":"1.0.14","url":"https://github.com/gorhom/react-native-portal#readme","license":"MIT"},"@pchmn/expo-material3-theme":{"version":"1.3.1","url":"https://github.com/pchmn/expo-material3-theme#readme","license":"MIT"},"@react-native-async-storage/async-storage":{"version":"1.18.2","url":"https://github.com/react-native-async-storage/async-storage#readme","license":"MIT"},"@react-native-community/datetimepicker":{"version":"7.2.0","url":"https://github.com/react-native-community/datetimepicker#readme","license":"MIT"},"@react-native-community/netinfo":{"version":"9.3.10","url":"https://github.com/react-native-netinfo/react-native-netinfo#readme","license":"MIT"},"@react-native/assets-registry":{"version":"0.72.0","url":"git@github.com:facebook/react-native.git","license":"MIT"},"@react-navigation/native":{"version":"6.1.7","url":"https://reactnavigation.org","license":"MIT"},"@react-navigation/native-stack":{"version":"6.9.13","url":"https://github.com/software-mansion/react-native-screens#readme","license":"MIT"},"@shopify/flash-list":{"version":"1.4.3","url":"https://shopify.github.io/flash-list/","license":"MIT"},"apexcharts":{"version":"3.41.1","url":"https://apexcharts.com","license":"MIT"},"babel-plugin-inline-dotenv":{"version":"1.7.0","url":"https://github.com/brysgo/babel-plugin-inline-dotenv#readme","license":"ISC"},"babel-plugin-module-resolver":{"version":"5.0.0","url":"https://github.com/tleunen/babel-plugin-module-resolver.git","license":"MIT"},"expo":{"version":"49.0.7","url":"https://github.com/expo/expo/tree/main/packages/expo","license":"MIT"},"expo-camera":{"version":"13.4.2","url":"https://docs.expo.dev/versions/latest/sdk/camera/","license":"MIT"},"expo-clipboard":{"version":"4.3.1","url":"https://docs.expo.dev/versions/latest/sdk/clipboard","license":"MIT"},"expo-font":{"version":"11.4.0","url":"https://docs.expo.dev/versions/latest/sdk/font/","license":"MIT"},"expo-image-picker":{"version":"14.3.2","url":"https://docs.expo.dev/versions/latest/sdk/imagepicker/","license":"MIT"},"expo-linking":{"version":"5.0.2","url":"https://docs.expo.dev/versions/latest/sdk/linking","license":"MIT"},"expo-sqlite":{"version":"11.3.2","url":"https://docs.expo.dev/versions/latest/sdk/sqlite/","license":"MIT"},"expo-status-bar":{"version":"1.6.0","url":"https://docs.expo.dev/versions/latest/sdk/status-bar/","license":"MIT"},"expo-system-ui":{"version":"2.4.0","url":"https://docs.expo.dev/versions/latest/sdk/system-ui","license":"MIT"},"expo-web-browser":{"version":"12.3.2","url":"https://docs.expo.dev/versions/latest/sdk/webbrowser/","license":"MIT"},"file-saver":{"version":"2.0.5","url":"https://github.com/eligrey/FileSaver.js#readme","license":"MIT"},"fs-extra":{"version":"11.1.1","url":"https://github.com/jprichardson/node-fs-extra","license":"MIT"},"google-libphonenumber":{"version":"3.2.33","url":"https://ruimarinho.github.io/google-libphonenumber/","license":"(MIT AND Apache-2.0)"},"htmlparser2-without-node-native":{"version":"3.9.2","url":"git://github.com/fb55/htmlparser2.git","license":"MIT"},"pdfmake":{"version":"0.2.7","url":"http://pdfmake.org","license":"MIT"},"process":{"version":"0.11.10","url":"git://github.com/shtylman/node-process.git","license":"MIT"},"prop-types":{"version":"15.8.1","url":"https://facebook.github.io/react/","license":"MIT"},"react":{"version":"18.2.0","url":"https://reactjs.org/","license":"MIT"},"react-content-loader":{"version":"6.2.1","url":"https://github.com/danilowoz/react-content-loader","license":"MIT"},"react-dom":{"version":"18.2.0","url":"https://reactjs.org/","license":"MIT"},"react-native":{"version":"0.72.3","license":"MIT"},"react-native-big-list":{"version":"1.6.1","url":"https://marcocesarato.github.io/react-native-big-list-docs/","license":"GPL-3.0-or-later"},"react-native-blob-util":{"version":"0.18.6","url":"https://github.com/RonRadtke/react-native-blob-util","license":"MIT"},"react-native-gesture-handler":{"version":"2.12.1","url":"https://github.com/software-mansion/react-native-gesture-handler#readme","license":"MIT"},"react-native-iphone-x-helper":{"version":"1.3.1","url":"https://github.com/ptelad/react-native-iphone-x-helper#readme","license":"MIT"},"react-native-mime-types":{"version":"2.4.0","license":"MIT"},"react-native-paper":{"version":"5.10.1","url":"https://callstack.github.io/react-native-paper","license":"MIT"},"react-native-paper-dates":{"version":"0.18.14","url":"https://github.com/web-ridge/react-native-paper-dates#readme","license":"MIT"},"react-native-reanimated":{"version":"3.3.0","url":"https://github.com/software-mansion/react-native-reanimated#readme","license":"MIT"},"react-native-safe-area-context":{"version":"4.6.3","url":"https://github.com/th3rdwave/react-native-safe-area-context#readme","license":"MIT"},"react-native-screens":{"version":"3.22.1","url":"https://github.com/software-mansion/react-native-screens#readme","license":"MIT"},"react-native-svg":{"version":"13.9.0","url":"https://github.com/react-native-community/react-native-svg","license":"MIT"},"react-native-web":{"version":"0.19.7","url":"git://github.com/necolas/react-native-web.git","license":"MIT"},"react-native-webview":{"version":"13.2.2","url":"https://github.com/react-native-webview/react-native-webview#readme","license":"MIT"},"react-virtuoso":{"version":"4.5.0","url":"https://virtuoso.dev/","license":"MIT"},"sharp-cli":{"version":"4.1.1","url":"https://github.com/vseventer/sharp-cli","license":"MIT"},"tippy.js":{"version":"6.3.7","url":"https://atomiks.github.io/tippyjs/","license":"MIT"},"uninstall":{"version":"0.0.0","license":"MIT"},"websql":{"version":"2.0.3","url":"git://github.com/nolanlawson/node-websql.git","license":"Apache-2.0"},"xlsx":{"version":"0.18.5","url":"https://sheetjs.com/","license":"Apache-2.0"}};
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
StyleSheet,
|
|
4
|
-
} from 'react-native';
|
|
5
|
-
import {TouchableRipple} from "react-native-paper";
|
|
6
|
-
import CrossFadeIcon from 'react-native-paper/lib/commonjs/components/CrossFadeIcon';
|
|
7
|
-
import Surface from '$ecomponents/Surface';
|
|
8
|
-
import { IconButton } from 'react-native-paper';
|
|
9
|
-
import PropTypes from "prop-types";
|
|
10
|
-
import theme,{StyleProp,Colors} from "$theme";
|
|
11
|
-
import {defaultStr} from "$cutils";
|
|
12
|
-
|
|
13
|
-
const IconButtonComponent = ({
|
|
14
|
-
icon,
|
|
15
|
-
iconColor: customIconColor,
|
|
16
|
-
containerColor,
|
|
17
|
-
size = 24,
|
|
18
|
-
accessibilityLabel,
|
|
19
|
-
disabled,
|
|
20
|
-
onPress,
|
|
21
|
-
selected = false,
|
|
22
|
-
animated = false,
|
|
23
|
-
mode,
|
|
24
|
-
containerProps,
|
|
25
|
-
style,
|
|
26
|
-
testID,
|
|
27
|
-
color,
|
|
28
|
-
...rest
|
|
29
|
-
}) => {
|
|
30
|
-
const IconComponent = animated ? CrossFadeIcon : IconButton;
|
|
31
|
-
testID = defaultStr(testID,"RN_IconButtonComponent");
|
|
32
|
-
containerProps = defaultObj(containerProps);
|
|
33
|
-
const containerStyle = StyleSheet.flatten(containerProps.style) || {};
|
|
34
|
-
const backgroundColor = Colors.isValid(containerColor)? containerColor : Colors.isValid(containerStyle.color) ? containerStyle.color : undefined;
|
|
35
|
-
const iconColor = Colors.isValid(customIconColor)? customIconColor : Colors.isValid(color)? color : theme.colors.text;
|
|
36
|
-
const borderColor = theme.colors.outline || theme.colors.divider;
|
|
37
|
-
const rippleColor = Colors.setAlpha(iconColor,0.32);
|
|
38
|
-
const buttonSize = size * 1.5;
|
|
39
|
-
const borderStyles = {
|
|
40
|
-
borderWidth: 0,
|
|
41
|
-
borderRadius: buttonSize / 2,
|
|
42
|
-
borderColor,
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<Surface
|
|
47
|
-
testID = {testID+"_Container"}
|
|
48
|
-
style={
|
|
49
|
-
[
|
|
50
|
-
{
|
|
51
|
-
backgroundColor,
|
|
52
|
-
width: buttonSize,
|
|
53
|
-
height: buttonSize,
|
|
54
|
-
},
|
|
55
|
-
styles.container,
|
|
56
|
-
borderStyles,
|
|
57
|
-
disabled && styles.disabled,
|
|
58
|
-
style,
|
|
59
|
-
]
|
|
60
|
-
}
|
|
61
|
-
>
|
|
62
|
-
<TouchableRipple
|
|
63
|
-
borderless
|
|
64
|
-
centered
|
|
65
|
-
onPress={onPress}
|
|
66
|
-
rippleColor={rippleColor}
|
|
67
|
-
accessibilityLabel={accessibilityLabel}
|
|
68
|
-
style={styles.touchable}
|
|
69
|
-
// @ts-expect-error We keep old a11y props for backwards compat with old RN versions
|
|
70
|
-
accessibilityTraits={disabled ? ['button', 'disabled'] : 'button'}
|
|
71
|
-
accessibilityComponentType="button"
|
|
72
|
-
role="button"
|
|
73
|
-
accessibilityState={{ disabled }}
|
|
74
|
-
disabled={disabled}
|
|
75
|
-
hitSlop={
|
|
76
|
-
TouchableRipple.supported
|
|
77
|
-
? { top: 10, left: 10, bottom: 10, right: 10 }
|
|
78
|
-
: { top: 6, left: 6, bottom: 6, right: 6 }
|
|
79
|
-
}
|
|
80
|
-
{...rest}
|
|
81
|
-
testID = {testID}
|
|
82
|
-
>
|
|
83
|
-
<IconComponent testID={testID+"_Icon"} color={iconColor} source={icon} size={size} />
|
|
84
|
-
</TouchableRipple>
|
|
85
|
-
</Surface>
|
|
86
|
-
);
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const styles = StyleSheet.create({
|
|
90
|
-
container: {
|
|
91
|
-
overflow: 'hidden',
|
|
92
|
-
margin: 6,
|
|
93
|
-
elevation: 0,
|
|
94
|
-
},
|
|
95
|
-
touchable: {
|
|
96
|
-
flexGrow: 1,
|
|
97
|
-
justifyContent: 'center',
|
|
98
|
-
alignItems: 'center',
|
|
99
|
-
},
|
|
100
|
-
disabled: {
|
|
101
|
-
opacity: 0.32,
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
IconButtonComponent.propTypes = {
|
|
106
|
-
/**
|
|
107
|
-
* Icon to display.
|
|
108
|
-
*/
|
|
109
|
-
icon: PropTypes.oneOfType(PropTypes.string,PropTypes.object),
|
|
110
|
-
/**
|
|
111
|
-
* @supported Available in v5.x
|
|
112
|
-
* Mode of the icon button. By default there is no specified mode - only pressable icon will be rendered.
|
|
113
|
-
*/
|
|
114
|
-
mode : PropTypes.oneOf([
|
|
115
|
-
'outlined','contained' ,'contained-tonal'
|
|
116
|
-
]),
|
|
117
|
-
/**
|
|
118
|
-
* @renamed Renamed from 'color' to 'iconColor' in v5.x
|
|
119
|
-
* Color of the icon.
|
|
120
|
-
*/
|
|
121
|
-
iconColor: PropTypes.string,
|
|
122
|
-
/**
|
|
123
|
-
* @supported Available in v5.x
|
|
124
|
-
* Background color of the icon container.
|
|
125
|
-
*/
|
|
126
|
-
containerColor: PropTypes.string,
|
|
127
|
-
/**
|
|
128
|
-
* @supported Available in v5.x
|
|
129
|
-
* Whether icon button is selected. A selected button receives alternative combination of icon and container colors.
|
|
130
|
-
*/
|
|
131
|
-
selected: PropTypes.bool,
|
|
132
|
-
/**
|
|
133
|
-
* Size of the icon.
|
|
134
|
-
*/
|
|
135
|
-
size : PropTypes.number,
|
|
136
|
-
/**
|
|
137
|
-
* Whether the button is disabled. A disabled button is greyed out and `onPress` is not called on touch.
|
|
138
|
-
*/
|
|
139
|
-
disabled: PropTypes.bool,
|
|
140
|
-
/**
|
|
141
|
-
* Whether an icon change is animated.
|
|
142
|
-
*/
|
|
143
|
-
animated: PropTypes.bool,
|
|
144
|
-
/**
|
|
145
|
-
* Accessibility label for the button. This is read by the screen reader when the user taps the button.
|
|
146
|
-
*/
|
|
147
|
-
accessibilityLabel: PropTypes.string,
|
|
148
|
-
/**
|
|
149
|
-
* Function to execute on press.
|
|
150
|
-
*/
|
|
151
|
-
onPress : PropTypes.func,//(e: GestureResponderEvent) => void;
|
|
152
|
-
style : StyleProp,
|
|
153
|
-
ref : PropTypes.object,
|
|
154
|
-
}
|
|
155
|
-
export default theme.withStyles(IconButtonComponent,{displayName:"IconButtonComponent"});
|