@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.
Files changed (32) hide show
  1. package/package.json +1 -1
  2. package/src/components/Dialog/AppBarDialog.js +2 -1
  3. package/src/components/ErrorBoundary/ErrorMessage.js +3 -2
  4. package/src/components/ErrorBoundary/Provider.js +4 -3
  5. package/src/components/ErrorBoundary/index.js +1 -0
  6. package/src/components/Icon/Icon.js +1 -1
  7. package/src/components/List/Virtuoso/index.js +1 -2
  8. package/src/components/Logo/Progress.js +9 -5
  9. package/src/components/Menu/Menu.js +113 -97
  10. package/src/components/Portal/Portal.js +88 -0
  11. package/src/components/Portal/PortalHost.js +31 -0
  12. package/src/components/Portal/PortalProvider.js +31 -0
  13. package/src/components/Portal/constants.js +15 -0
  14. package/src/components/Portal/context.js +10 -0
  15. package/src/components/Portal/hooks.js +75 -0
  16. package/src/components/Portal/index.js +11 -3
  17. package/src/components/Portal/index.old.js +4 -0
  18. package/src/components/Portal/reducer.js +92 -0
  19. package/src/components/Portal/usePortalState.js +19 -0
  20. package/src/components/Preloader/index.js +1 -1
  21. package/src/components/ScrollView/index.js +1 -0
  22. package/src/components/SplashScreen/index.js +2 -2
  23. package/src/components/StatusBar/Component/index.web.js +0 -1
  24. package/src/components/Table/EmptyPlaceholder/index.js +41 -0
  25. package/src/components/Table/EmptyPlaceholder/index.native.js +3 -0
  26. package/src/components/Table/hooks.js +1 -1
  27. package/src/components/Table/index.js +11 -5
  28. package/src/context/Provider.js +7 -0
  29. package/src/index.js +34 -41
  30. package/src/navigation/index.js +2 -1
  31. package/src/screens/Help/openLibraries.js +1 -1
  32. package/src/components/Icon/IconButton.js +0 -155
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "6.26.2",
3
+ "version": "6.26.3",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -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='RN_ErrorBoundary_Container' pointerEvents={pointerEvents} style={[styles.container,isWeb()?{position:'fixed'}:null,{backgroundColor:theme.colors.surface,width,height}]}>
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
  }}/>
@@ -38,6 +38,7 @@ class ErrorBoundary extends React.Component {
38
38
  } else {
39
39
  return (
40
40
  <ErrorMessage
41
+ testID={"RN_ErrorBoundaryErrorMessage"}
41
42
  error={error}
42
43
  info={info}
43
44
  resetError={this.resetError}
@@ -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 listIdRef = React.useRef(uniqid("virtuoso-list-id"));
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 (props){
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
- <ActivityIndicator size = {isIos()?'large':40} animating={true} color={secondaryColor} />
16
- <View key={'app-version'} style={{flex:1}}>
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
- return Promise.all([
166
+ const windowLayout = Dimensions.get('window');
167
+ const [menuLayout, anchorLayout] = await Promise.all([
163
168
  this.measureMenuLayout(),
164
169
  this.measureAnchorLayout(),
165
- ]).then(([menuLayout, anchorLayout])=>{
166
- const windowLayout = Dimensions.get('window');
167
- if (
168
- !windowLayout.width ||
169
- !windowLayout.height ||
170
- !menuLayout.width ||
171
- !menuLayout.height ||
172
- (!anchorLayout.width) ||
173
- (!anchorLayout.height)
174
- ) {
175
- requestAnimationFrame(this.show.bind(this));
176
- return;
177
- }
178
- this.setState({
179
- left: anchorLayout.x,
180
- top: anchorLayout.y,
181
- rendered : true,
182
- anchorLayout: {
183
- height: anchorLayout.height,
184
- width: anchorLayout.width,
185
- },
186
- menuLayout: {
187
- width: menuLayout.width,
188
- height: menuLayout.height,
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
- this.attachListeners();
193
-
194
- const animation = theme.animation;
195
- Animated.parallel([
196
- Animated.timing(this.state.scaleAnimation, {
197
- toValue: { x: menuLayout.width, y: menuLayout.height },
198
- duration: ANIMATION_DURATION * animation.scale,
199
- easing: EASING,
200
- useNativeDriver: true,
201
- }),
202
- Animated.timing(this.state.opacityAnimation, {
203
- toValue: 1,
204
- duration: ANIMATION_DURATION * animation.scale,
205
- easing: EASING,
206
- useNativeDriver: true,
207
- }),
208
- ]).start(({ finished }) => {
209
- if (finished) {
210
- this.focusFirstDOMNode(this.menu);
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({ rendered:false,menuLayout: { width: 0, height: 0 }},(e)=>{if(typeof cb ==='function') cb();});
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
- <Portal>
459
- {rendered ? <TouchableWithoutFeedback
460
- testID={testID+"_MenuTouchableWithoutFeedBack"}
461
- accessibilityLabel={overlayAccessibilityLabel}
462
- role="button"
463
- onPress={onDismiss}
464
- style = {[hiddenStyle]}
465
- >
466
- <View style={[StyleSheet.absoluteFill,{flex:1,backgroundColor:'transparent'}]} testID={testID+"_Backdrop"} />
467
- </TouchableWithoutFeedback>:null}
468
- <View
469
- testID = {testID+"_MenuContentContainer"}
470
- ref={(ref) => {
471
- this.menu = ref;
472
- }}
473
- collapsable={false}
474
- accessibilityViewIsModal={visible}
475
- style={[styles.wrapper, positionStyle, style,hiddenStyle]}
476
- pointerEvents={visible ? 'box-none' : 'none'}
477
- onAccessibilityEscape={onDismiss}
478
- >
479
- {rendered?<Animated.View style={{ transform: positionTransforms }} testID={testID+"_Animated"}>
480
- <Surface
481
- elevation = {5}
482
- testID= {testID+"_MenuContent"}
483
- style={
484
- [
485
- styles.shadowMenuContainer,
486
- shadowMenuContainerStyle,
487
- contentStyle,
488
- {backgroundColor : theme.colors.surface},
489
- minWidth && {minWidth : Math.max(minWidth,MIN_WIDTH)},
490
- sameWidth && anchorLayout.width ? {width:Math.max(anchorLayout.width,minWidth,MIN_WIDTH)} : undefined,
491
- ]
492
- }
493
- >
494
- {((scrollableMenuHeight|| contentContainerStyle) && (<ScrollView contentContainerStyle={contentContainerStyle} testID={testID+"_ScrollView"}>{children}</ScrollView>
495
- )) || children}
496
- </Surface>
497
- </Animated.View> : null}
498
- </View>
499
- </Portal>
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
- import { Portal } from "@gorhom/portal";
1
+ /***
2
+ * MIT License
3
+ Copyright (c) 2020 Mo Gorhom
4
+ @see : https://github.com/gorhom/react-native-portal
5
+ */
2
6
 
3
- export * from "@gorhom/portal";
7
+ export {default} from "./Portal";
4
8
 
5
- export default Portal;
9
+ export {default as PortalHost} from "./PortalHost";
10
+
11
+ export {default as PortalProvider} from "./PortalProvider";
12
+
13
+ export * from "./hooks";
@@ -0,0 +1,4 @@
1
+ import { Portal } from "@gorhom/portal";
2
+ export * from "@gorhom/portal";
3
+
4
+ export default Portal;
@@ -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
+ })
@@ -0,0 +1,3 @@
1
+ export default function EmptyPlaceholderComponent({emptyContent}){
2
+ return null;
3
+ }
@@ -1,5 +1,5 @@
1
1
  import React,{useMemo} from "$react";
2
- import {defaultStr,isObj} from "$cutils";
2
+ import {defaultStr,isObj,uniqid} from "$cutils";
3
3
  import {DEFAULT_COLUMN_WIDTH} from "./utils";
4
4
  import Label from "$ecomponents/Label";
5
5
  import HeaderCell from "./Header/Cell";
@@ -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 prepatedColumns = usePrepareColumns(props);
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";
@@ -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 ? <Navigation
260
- initialRouteName = {defaultStr(hasGetStarted ? appInitialRouteName : getStartedRouteName,"Home")}
261
- state = {state}
262
- hasGetStarted = {hasGetStarted}
263
- isInitialized = {isInitialized}
264
- onGetStart = {(e)=>{
265
- setState({...state,hasGetStarted:true})
266
- }}
267
- />: null;
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
- <NavigationContainer
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
- <PortalProvider>
287
- <Portal.Host>
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
- <ErrorBoundaryProvider/>
295
- <GestureHandlerRootView style={{ flex: 1,flexGrow:1,flexShrink:1}} testID={"RN_GestureHandlerRootView"}>
296
- <SafeAreaProvider testID={"RN_AppSafeAreaProvider"}>
292
+ <Portal.Host testID="RN_NativePaperPortalHost">
293
+ <ErrorBoundary>
294
+ <StatusBar/>
297
295
  <SplashScreen isLoaded={isLoaded}>
298
- <ErrorBoundary>
299
- <StatusBar/>
300
- <PreferencesContext.Provider value={preferences}>
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
- </SafeAreaProvider>
306
- </GestureHandlerRootView>
307
- </Portal.Host>
308
- </PortalProvider>
300
+ </ErrorBoundary>
301
+ </Portal.Host>
302
+ </PortalProvider>
309
303
  </PaperProvider>
310
- </NavigationContainer>
311
- </AuthProvider>
304
+ </AuthProvider>;
312
305
  }
313
306
 
314
307
  export default App;
@@ -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.25.1","repository":{"type":"git","url":"git+https://github.com/borispipo/expo-ui.git"},"homepage":"https://github.com/borispipo/expo-ui#readme"}};
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"});