@momo-kits/foundation 0.167.1-duo.1 → 0.167.1-duo.2
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/Application/BottomSheet.tsx +4 -4
- package/Application/BottomTab/index.tsx +10 -11
- package/Application/Components/HeaderExtendHeader.tsx +40 -27
- package/Application/Components/HeaderLeft.tsx +17 -0
- package/Application/Components/HeaderRight.tsx +59 -9
- package/Application/Components/HeaderTitle.tsx +53 -17
- package/Application/Components/SearchHeader.tsx +15 -14
- package/Application/Components/SideBarButton.tsx +128 -0
- package/Application/ModalScreen.tsx +2 -2
- package/Application/NavigationContainer.tsx +22 -32
- package/Application/Navigator.ts +1 -3
- package/Application/StackScreen.tsx +2 -5
- package/Application/WidgetContainer.tsx +9 -7
- package/Application/types.ts +5 -1
- package/Application/utils.tsx +10 -3
- package/Consts/index.ts +0 -1
- package/Consts/theme.ts +5 -6
- package/Input/Input.tsx +3 -4
- package/Input/InputMoney.tsx +31 -51
- package/Input/InputPhoneNumber.tsx +3 -4
- package/Input/InputSearch.tsx +3 -4
- package/Input/InputTextArea.tsx +3 -4
- package/Layout/Card.tsx +8 -26
- package/Layout/FloatingButton.tsx +3 -3
- package/Layout/Item.tsx +1 -10
- package/Layout/Screen.tsx +39 -12
- package/Layout/Section.tsx +5 -18
- package/Layout/index.ts +4 -4
- package/Layout/utils.ts +280 -5
- package/Popup/PopupNotify.tsx +2 -2
- package/Text/index.tsx +2 -11
- package/Text/utils.ts +1 -2
- package/package.json +4 -3
- package/Consts/designSystemFont.ts +0 -38
- package/Layout/GridSystem.tsx +0 -137
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import React, { ReactNode, useContext } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
StyleProp,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
View,
|
|
7
|
+
ViewStyle,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
import { NavigationButtonProps } from '../types';
|
|
10
|
+
import { ApplicationContext } from '../../Context';
|
|
11
|
+
import { Colors, Radius, Shadow, Spacing } from '../../Consts';
|
|
12
|
+
import { Icon } from '../../Icon';
|
|
13
|
+
import { BadgeDot } from '../../Badge';
|
|
14
|
+
import { DuoMetrics } from '../../Layout/utils';
|
|
15
|
+
|
|
16
|
+
const SIDE_BAR_ICON_SIZE = 24;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* glass material for side bar controls: dark glass under light icons (banner headers),
|
|
20
|
+
* light glass otherwise
|
|
21
|
+
*/
|
|
22
|
+
const getGlassStyle = (tintColor?: string) =>
|
|
23
|
+
tintColor === Colors.black_01 || tintColor === 'white'
|
|
24
|
+
? styles.glassDark
|
|
25
|
+
: styles.glassLight;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 48pt glass circle used for a single control in the iPhone Duo side bar
|
|
29
|
+
*/
|
|
30
|
+
const SideBarButton: React.FC<NavigationButtonProps> = ({
|
|
31
|
+
icon,
|
|
32
|
+
tintColor,
|
|
33
|
+
showBadge = false,
|
|
34
|
+
style,
|
|
35
|
+
...props
|
|
36
|
+
}) => {
|
|
37
|
+
const { theme } = useContext(ApplicationContext);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<View>
|
|
41
|
+
<TouchableOpacity
|
|
42
|
+
{...props}
|
|
43
|
+
style={[styles.control, getGlassStyle(tintColor), style]}
|
|
44
|
+
>
|
|
45
|
+
<Icon
|
|
46
|
+
source={icon}
|
|
47
|
+
color={tintColor ?? theme.colors.text.default}
|
|
48
|
+
size={SIDE_BAR_ICON_SIZE}
|
|
49
|
+
/>
|
|
50
|
+
</TouchableOpacity>
|
|
51
|
+
{showBadge && <BadgeDot size={'small'} style={styles.badgeDot} />}
|
|
52
|
+
</View>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 48pt wide glass capsule grouping related controls, one item per 50pt
|
|
58
|
+
*/
|
|
59
|
+
const SideBarGroup: React.FC<{
|
|
60
|
+
tintColor?: string;
|
|
61
|
+
style?: StyleProp<ViewStyle>;
|
|
62
|
+
children: ReactNode;
|
|
63
|
+
}> = ({ tintColor, style, children }) => {
|
|
64
|
+
const count = React.Children.toArray(children).length;
|
|
65
|
+
const height =
|
|
66
|
+
count > 1 ? count * DuoMetrics.itemPitch : DuoMetrics.controlSize;
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<View style={[styles.control, getGlassStyle(tintColor), { height }, style]}>
|
|
70
|
+
{children}
|
|
71
|
+
</View>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* icon item inside a SideBarGroup
|
|
77
|
+
*/
|
|
78
|
+
const SideBarGroupItem: React.FC<NavigationButtonProps> = ({
|
|
79
|
+
icon,
|
|
80
|
+
tintColor,
|
|
81
|
+
...props
|
|
82
|
+
}) => {
|
|
83
|
+
const { theme } = useContext(ApplicationContext);
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<TouchableOpacity {...props} style={styles.groupItem}>
|
|
87
|
+
<Icon
|
|
88
|
+
source={icon}
|
|
89
|
+
color={tintColor ?? theme.colors.text.default}
|
|
90
|
+
size={SIDE_BAR_ICON_SIZE}
|
|
91
|
+
/>
|
|
92
|
+
</TouchableOpacity>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const styles = StyleSheet.create({
|
|
97
|
+
control: {
|
|
98
|
+
width: DuoMetrics.controlSize,
|
|
99
|
+
height: DuoMetrics.controlSize,
|
|
100
|
+
borderRadius: Radius.XL,
|
|
101
|
+
justifyContent: 'center',
|
|
102
|
+
alignItems: 'center',
|
|
103
|
+
},
|
|
104
|
+
glassLight: {
|
|
105
|
+
backgroundColor: Colors.black_01 + 'D9',
|
|
106
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
107
|
+
borderColor: Colors.black_20 + '14',
|
|
108
|
+
...Shadow.Light,
|
|
109
|
+
},
|
|
110
|
+
glassDark: {
|
|
111
|
+
backgroundColor: Colors.black_20 + '80',
|
|
112
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
113
|
+
borderColor: Colors.black_01 + '33',
|
|
114
|
+
},
|
|
115
|
+
groupItem: {
|
|
116
|
+
flex: 1,
|
|
117
|
+
alignSelf: 'stretch',
|
|
118
|
+
justifyContent: 'center',
|
|
119
|
+
alignItems: 'center',
|
|
120
|
+
},
|
|
121
|
+
badgeDot: {
|
|
122
|
+
position: 'absolute',
|
|
123
|
+
top: Spacing.XXS,
|
|
124
|
+
right: Spacing.XXS,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
export { SideBarButton, SideBarGroup, SideBarGroupItem };
|
|
@@ -16,7 +16,7 @@ import { Styles } from '../Consts';
|
|
|
16
16
|
import Navigation from './Navigation';
|
|
17
17
|
import { ModalParams } from './types';
|
|
18
18
|
import BottomSheet from './BottomSheet';
|
|
19
|
-
import {
|
|
19
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
20
20
|
|
|
21
21
|
const ModalScreen: React.FC<any> = props => {
|
|
22
22
|
if (props.route?.params?.isBottomSheet) {
|
|
@@ -106,7 +106,7 @@ const Modal: React.FC<ModalParams> = props => {
|
|
|
106
106
|
}),
|
|
107
107
|
]).start(() => {
|
|
108
108
|
navigator?.pop();
|
|
109
|
-
|
|
109
|
+
scheduleOnRN(callback);
|
|
110
110
|
});
|
|
111
111
|
},
|
|
112
112
|
[navigator, opacity, scale],
|
|
@@ -2,7 +2,6 @@ import React, { useContext, useEffect, useRef, useState } from 'react';
|
|
|
2
2
|
import {
|
|
3
3
|
SafeAreaInsetsContext,
|
|
4
4
|
SafeAreaProvider,
|
|
5
|
-
useSafeAreaInsets,
|
|
6
5
|
} from 'react-native-safe-area-context';
|
|
7
6
|
import {
|
|
8
7
|
NavigationContainer as ReactNavigationContainer,
|
|
@@ -13,14 +12,17 @@ import {
|
|
|
13
12
|
StackNavigationOptions,
|
|
14
13
|
TransitionPresets,
|
|
15
14
|
} from '@react-navigation/stack';
|
|
16
|
-
import { DeviceEventEmitter } from 'react-native';
|
|
17
15
|
import StackScreen from './StackScreen';
|
|
18
16
|
import ModalScreen from './ModalScreen';
|
|
19
17
|
import Navigator from './Navigator';
|
|
20
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
getModalOptions,
|
|
20
|
+
getStackOptions,
|
|
21
|
+
isWhiteListDesignSystem,
|
|
22
|
+
useNativeCanGoBack,
|
|
23
|
+
} from './utils';
|
|
21
24
|
import { NavigationContainerProps } from './types';
|
|
22
25
|
import { ApplicationContext, MiniAppContext } from '../Context';
|
|
23
|
-
import { useDefaultRegularFontFamily } from '../Consts/designSystemFont';
|
|
24
26
|
import Localize from './Localize';
|
|
25
27
|
import { Colors, defaultTheme } from '../Consts';
|
|
26
28
|
import { HeaderLeft } from './Components/HeaderLeft';
|
|
@@ -28,6 +30,7 @@ import { HeaderRight } from './Components/HeaderRight';
|
|
|
28
30
|
import { HeaderTitle } from './Components/HeaderTitle';
|
|
29
31
|
import { HeaderBackground } from './Components/HeaderBackground';
|
|
30
32
|
import { type EdgeInsets } from 'react-native-safe-area-context';
|
|
33
|
+
import { useScreenLayout } from '../Layout';
|
|
31
34
|
|
|
32
35
|
const Stack = createStackNavigator();
|
|
33
36
|
|
|
@@ -101,10 +104,11 @@ const Navigation: React.FC<any> = ({
|
|
|
101
104
|
const navigationRef = useRef<any>(null);
|
|
102
105
|
const isReady = useRef(false);
|
|
103
106
|
const navigator = useRef(new Navigator(navigationRef, isReady));
|
|
104
|
-
const
|
|
105
|
-
const insets = useSafeAreaInsets();
|
|
106
|
-
const defaultRegularFontFamily = useDefaultRegularFontFamily();
|
|
107
|
+
const { headerHeight, headerStatusBarHeight } = useScreenLayout();
|
|
107
108
|
const syncCanGoBack = useNativeCanGoBack();
|
|
109
|
+
const isWhiteList = isWhiteListDesignSystem(context);
|
|
110
|
+
const fontFamily = isWhiteList ? 'MomoTrustSans' : 'SFProText';
|
|
111
|
+
const navigationFontFamily = isWhiteList ? 'MomoTrustSans-Regular' : 'SFProText';
|
|
108
112
|
let headerBackground = context?.designSystemConfig?.config?.headerBar;
|
|
109
113
|
let headerGradient = theme.colors?.gradient;
|
|
110
114
|
|
|
@@ -120,23 +124,6 @@ const Navigation: React.FC<any> = ({
|
|
|
120
124
|
*/
|
|
121
125
|
navigator.current.maxApi = maxApi;
|
|
122
126
|
|
|
123
|
-
/**
|
|
124
|
-
* handle mini language & listen change
|
|
125
|
-
* engine only shake to enable grid view
|
|
126
|
-
*/
|
|
127
|
-
useEffect(() => {
|
|
128
|
-
const subscription = DeviceEventEmitter.addListener(
|
|
129
|
-
'onChangeGrid',
|
|
130
|
-
enable => {
|
|
131
|
-
setShowGrid(!!enable);
|
|
132
|
-
},
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
return () => {
|
|
136
|
-
subscription?.remove?.();
|
|
137
|
-
};
|
|
138
|
-
}, []);
|
|
139
|
-
|
|
140
127
|
/**
|
|
141
128
|
* translate context method
|
|
142
129
|
* @param data
|
|
@@ -156,6 +143,7 @@ const Navigation: React.FC<any> = ({
|
|
|
156
143
|
navigator: navigator.current,
|
|
157
144
|
theme: {
|
|
158
145
|
...theme,
|
|
146
|
+
font: fontFamily,
|
|
159
147
|
colors: {
|
|
160
148
|
...theme.colors,
|
|
161
149
|
gradient: headerGradient,
|
|
@@ -165,7 +153,6 @@ const Navigation: React.FC<any> = ({
|
|
|
165
153
|
headerBackground,
|
|
166
154
|
},
|
|
167
155
|
},
|
|
168
|
-
showGrid,
|
|
169
156
|
translate,
|
|
170
157
|
}}
|
|
171
158
|
>
|
|
@@ -183,19 +170,19 @@ const Navigation: React.FC<any> = ({
|
|
|
183
170
|
},
|
|
184
171
|
fonts: {
|
|
185
172
|
regular: {
|
|
186
|
-
fontFamily:
|
|
173
|
+
fontFamily: navigationFontFamily,
|
|
187
174
|
fontWeight: '400',
|
|
188
175
|
},
|
|
189
176
|
medium: {
|
|
190
|
-
fontFamily:
|
|
177
|
+
fontFamily: navigationFontFamily,
|
|
191
178
|
fontWeight: '400',
|
|
192
179
|
},
|
|
193
180
|
bold: {
|
|
194
|
-
fontFamily:
|
|
181
|
+
fontFamily: navigationFontFamily,
|
|
195
182
|
fontWeight: '400',
|
|
196
183
|
},
|
|
197
184
|
heavy: {
|
|
198
|
-
fontFamily:
|
|
185
|
+
fontFamily: navigationFontFamily,
|
|
199
186
|
fontWeight: '400',
|
|
200
187
|
},
|
|
201
188
|
},
|
|
@@ -215,8 +202,9 @@ const Navigation: React.FC<any> = ({
|
|
|
215
202
|
headerTitleAlign: 'center',
|
|
216
203
|
headerTintColor: theme.colors.text.default,
|
|
217
204
|
headerStyle: {
|
|
218
|
-
height:
|
|
205
|
+
height: headerHeight,
|
|
219
206
|
},
|
|
207
|
+
headerStatusBarHeight,
|
|
220
208
|
}}
|
|
221
209
|
>
|
|
222
210
|
<Stack.Screen
|
|
@@ -239,11 +227,13 @@ const Navigation: React.FC<any> = ({
|
|
|
239
227
|
cardStyle: {
|
|
240
228
|
backgroundColor: theme.colors.background.default,
|
|
241
229
|
},
|
|
242
|
-
headerLeft: (props: any) => <HeaderLeft {...props} />,
|
|
230
|
+
headerLeft: (props: any) => <HeaderLeft {...props} floating />,
|
|
243
231
|
headerBackground: (props: any) => (
|
|
244
232
|
<HeaderBackground {...props} />
|
|
245
233
|
),
|
|
246
|
-
headerRight: (props: any) =>
|
|
234
|
+
headerRight: (props: any) => (
|
|
235
|
+
<HeaderRight {...props} floating />
|
|
236
|
+
),
|
|
247
237
|
headerTintColor: Colors.black_17,
|
|
248
238
|
...TransitionPresets.ModalTransition,
|
|
249
239
|
}}
|
package/Application/Navigator.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { useHeaderHeight } from '@react-navigation/elements';
|
|
|
4
4
|
import { ScreenTrackingParams } from './types';
|
|
5
5
|
import Navigation from './Navigation';
|
|
6
6
|
import { ApplicationContext, MiniAppContext, ScreenContext } from '../Context';
|
|
7
|
-
import { GridSystem } from '../Layout';
|
|
8
7
|
import { version } from '../package.json';
|
|
9
8
|
import { SwipeBackHaptic, useAppState } from './utils';
|
|
10
9
|
import { TooltipPortalHost, TooltipPortalProvider } from './TooltipPortal';
|
|
@@ -17,7 +16,7 @@ const runAfterInteractions = InteractionManager.runAfterInteractions;
|
|
|
17
16
|
* @constructor
|
|
18
17
|
*/
|
|
19
18
|
const StackScreen: React.FC<any> = props => {
|
|
20
|
-
const {
|
|
19
|
+
const { navigator } = useContext(ApplicationContext);
|
|
21
20
|
const tracking = useRef<any>({
|
|
22
21
|
mounted: false,
|
|
23
22
|
timeoutLoad: undefined,
|
|
@@ -42,6 +41,7 @@ const StackScreen: React.FC<any> = props => {
|
|
|
42
41
|
});
|
|
43
42
|
const widgets = useRef<any>([]);
|
|
44
43
|
const context = useContext<any>(MiniAppContext);
|
|
44
|
+
|
|
45
45
|
const {
|
|
46
46
|
screen: Component,
|
|
47
47
|
options,
|
|
@@ -411,10 +411,7 @@ const StackScreen: React.FC<any> = props => {
|
|
|
411
411
|
>
|
|
412
412
|
<TooltipPortalProvider>
|
|
413
413
|
<Component heightHeader={heightHeader} {...data} />
|
|
414
|
-
{showGrid && <GridSystem />}
|
|
415
414
|
<TooltipPortalHost />
|
|
416
|
-
{/* a leaf on purpose: it subscribes to CardAnimationContext, which changes on every
|
|
417
|
-
Card render, and must not pull this screen into those renders */}
|
|
418
415
|
<SwipeBackHaptic />
|
|
419
416
|
</TooltipPortalProvider>
|
|
420
417
|
</ScreenContext.Provider>
|
|
@@ -3,7 +3,6 @@ import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
|
3
3
|
import Navigator from './Navigator';
|
|
4
4
|
import { WidgetContainerProps } from './types';
|
|
5
5
|
import { ApplicationContext, MiniAppContext } from '../Context';
|
|
6
|
-
import { useDefaultRegularFontFamily } from '../Consts/designSystemFont';
|
|
7
6
|
import Localize from './Localize';
|
|
8
7
|
import { defaultTheme } from '../Consts';
|
|
9
8
|
import {
|
|
@@ -11,7 +10,7 @@ import {
|
|
|
11
10
|
NavigationContainerRef,
|
|
12
11
|
NavigationIndependentTree,
|
|
13
12
|
} from '@react-navigation/native';
|
|
14
|
-
import { getModalOptions } from './utils';
|
|
13
|
+
import { getModalOptions, isWhiteListDesignSystem } from './utils';
|
|
15
14
|
import { createStackNavigator } from '@react-navigation/stack';
|
|
16
15
|
import ModalScreen from './ModalScreen';
|
|
17
16
|
import { View } from 'react-native';
|
|
@@ -43,7 +42,6 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
43
42
|
const isReady = useRef(false);
|
|
44
43
|
const navigator = useRef(new Navigator(navigationRef, isReady, true));
|
|
45
44
|
const [currentContext, setCurrentContext] = useState({});
|
|
46
|
-
const defaultRegularFontFamily = useDefaultRegularFontFamily();
|
|
47
45
|
|
|
48
46
|
useEffect(() => {
|
|
49
47
|
const sub = maxApi?.observer?.('font_scale_config', (data: any) => {
|
|
@@ -80,6 +78,9 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
80
78
|
...context,
|
|
81
79
|
...currentContext,
|
|
82
80
|
};
|
|
81
|
+
const isWhiteList = isWhiteListDesignSystem(mergedContext);
|
|
82
|
+
const fontFamily = isWhiteList ? 'MomoTrustSans' : 'SFProText';
|
|
83
|
+
const navigationFontFamily = isWhiteList ? 'MomoTrustSans-Regular' : 'SFProText';
|
|
83
84
|
|
|
84
85
|
return (
|
|
85
86
|
<View style={{ height: height ?? '100%', minHeight: 1 }}>
|
|
@@ -90,6 +91,7 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
90
91
|
navigator: navigator.current,
|
|
91
92
|
theme: {
|
|
92
93
|
...theme,
|
|
94
|
+
font: fontFamily,
|
|
93
95
|
colors: {
|
|
94
96
|
...theme.colors,
|
|
95
97
|
gradient: headerGradient,
|
|
@@ -116,19 +118,19 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
116
118
|
},
|
|
117
119
|
fonts: {
|
|
118
120
|
regular: {
|
|
119
|
-
fontFamily:
|
|
121
|
+
fontFamily: navigationFontFamily,
|
|
120
122
|
fontWeight: '400',
|
|
121
123
|
},
|
|
122
124
|
medium: {
|
|
123
|
-
fontFamily:
|
|
125
|
+
fontFamily: navigationFontFamily,
|
|
124
126
|
fontWeight: '400',
|
|
125
127
|
},
|
|
126
128
|
bold: {
|
|
127
|
-
fontFamily:
|
|
129
|
+
fontFamily: navigationFontFamily,
|
|
128
130
|
fontWeight: '400',
|
|
129
131
|
},
|
|
130
132
|
heavy: {
|
|
131
|
-
fontFamily:
|
|
133
|
+
fontFamily: navigationFontFamily,
|
|
132
134
|
fontWeight: '400',
|
|
133
135
|
},
|
|
134
136
|
},
|
package/Application/types.ts
CHANGED
|
@@ -117,7 +117,6 @@ export type Context = {
|
|
|
117
117
|
[key: string]: any;
|
|
118
118
|
theme: Theme;
|
|
119
119
|
navigator?: NavigatorProps;
|
|
120
|
-
showGrid?: boolean;
|
|
121
120
|
translate?: (data: string | { vi: string; en: string }) => string;
|
|
122
121
|
};
|
|
123
122
|
|
|
@@ -258,6 +257,11 @@ export interface HeaderBackProps extends NavigationButtonProps {
|
|
|
258
257
|
preventBack?: PopupNotifyProps;
|
|
259
258
|
onPressLeftHeader?: () => void;
|
|
260
259
|
onBackHandler?: (goBack: () => void) => void;
|
|
260
|
+
/**
|
|
261
|
+
* Optional. If `true`, the button floats into the iPhone Duo side bar while the
|
|
262
|
+
* device shows one. Set when the button is rendered by the navigation header.
|
|
263
|
+
*/
|
|
264
|
+
floating?: boolean;
|
|
261
265
|
}
|
|
262
266
|
|
|
263
267
|
export type HeaderBackgroundProps = {
|
package/Application/utils.tsx
CHANGED
|
@@ -73,8 +73,8 @@ const getStackOptions = (): StackNavigationOptions => {
|
|
|
73
73
|
left: Spacing.S,
|
|
74
74
|
},
|
|
75
75
|
headerBackground: (props: any) => <HeaderBackground {...props} />,
|
|
76
|
-
headerLeft: (props: any) => <HeaderLeft {...props} />,
|
|
77
|
-
headerRight: (props: any) => <HeaderRight {...props} />,
|
|
76
|
+
headerLeft: (props: any) => <HeaderLeft {...props} floating />,
|
|
77
|
+
headerRight: (props: any) => <HeaderRight {...props} floating />,
|
|
78
78
|
headerTintColor: Colors.black_17,
|
|
79
79
|
gestureEnabled: Platform.OS === 'ios',
|
|
80
80
|
...TransitionPresets.SlideFromRightIOS,
|
|
@@ -129,6 +129,7 @@ const getOptions = (
|
|
|
129
129
|
preventBack={params.preventBack}
|
|
130
130
|
onPressLeftHeader={params.onPressLeftHeader}
|
|
131
131
|
onBackHandler={params.onBackHandler}
|
|
132
|
+
floating
|
|
132
133
|
/>
|
|
133
134
|
);
|
|
134
135
|
if (params.hiddenBack) {
|
|
@@ -167,7 +168,9 @@ const getOptions = (
|
|
|
167
168
|
...options,
|
|
168
169
|
...{
|
|
169
170
|
headerRight: (props: any) => {
|
|
170
|
-
return
|
|
171
|
+
return (
|
|
172
|
+
<HeaderRight {...props} headerRight={params.headerRight} floating />
|
|
173
|
+
);
|
|
171
174
|
},
|
|
172
175
|
},
|
|
173
176
|
};
|
|
@@ -475,6 +478,9 @@ const SwipeBackHaptic = () => {
|
|
|
475
478
|
return null;
|
|
476
479
|
};
|
|
477
480
|
|
|
481
|
+
const isWhiteListDesignSystem = (context: any): boolean =>
|
|
482
|
+
context?.designSystemConfig?.isWhiteListDesignSystem === true;
|
|
483
|
+
|
|
478
484
|
export {
|
|
479
485
|
getStackOptions,
|
|
480
486
|
getModalOptions,
|
|
@@ -487,4 +493,5 @@ export {
|
|
|
487
493
|
useNativeCanGoBack,
|
|
488
494
|
useNormalizedSharedValue,
|
|
489
495
|
SwipeBackHaptic,
|
|
496
|
+
isWhiteListDesignSystem,
|
|
490
497
|
};
|
package/Consts/index.ts
CHANGED
package/Consts/theme.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {Context, Theme} from '../Application/types';
|
|
2
|
-
import {Colors} from './colors+spacing+radius';
|
|
1
|
+
import type { Context, Theme } from '../Application/types';
|
|
2
|
+
import { Colors } from './colors+spacing+radius';
|
|
3
3
|
|
|
4
4
|
const defaultTheme: Theme = {
|
|
5
5
|
dark: false,
|
|
@@ -51,7 +51,7 @@ const defaultTheme: Theme = {
|
|
|
51
51
|
container: Colors.blue_08,
|
|
52
52
|
},
|
|
53
53
|
},
|
|
54
|
-
font: '
|
|
54
|
+
font: 'SFProText',
|
|
55
55
|
assets: {},
|
|
56
56
|
};
|
|
57
57
|
|
|
@@ -105,17 +105,16 @@ const defaultDarkTheme: Theme = {
|
|
|
105
105
|
container: Colors.blue_08,
|
|
106
106
|
},
|
|
107
107
|
},
|
|
108
|
-
font: '
|
|
108
|
+
font: 'SFProText',
|
|
109
109
|
assets: {},
|
|
110
110
|
};
|
|
111
111
|
|
|
112
112
|
const defaultContext: Context = {
|
|
113
113
|
theme: defaultTheme,
|
|
114
114
|
navigator: undefined,
|
|
115
|
-
showGrid: false,
|
|
116
115
|
translate: () => {
|
|
117
116
|
return '';
|
|
118
117
|
},
|
|
119
118
|
};
|
|
120
119
|
|
|
121
|
-
export {defaultContext, defaultTheme, defaultDarkTheme};
|
|
120
|
+
export { defaultContext, defaultTheme, defaultDarkTheme };
|
package/Input/Input.tsx
CHANGED
|
@@ -6,9 +6,8 @@ import React, {
|
|
|
6
6
|
useState,
|
|
7
7
|
} from 'react';
|
|
8
8
|
import {
|
|
9
|
-
NativeSyntheticEvent,
|
|
10
9
|
TextInput,
|
|
11
|
-
|
|
10
|
+
TextInputFocusEvent,
|
|
12
11
|
TouchableOpacity,
|
|
13
12
|
View,
|
|
14
13
|
} from 'react-native';
|
|
@@ -102,12 +101,12 @@ const Input = forwardRef(
|
|
|
102
101
|
onChangeText?.(text);
|
|
103
102
|
};
|
|
104
103
|
|
|
105
|
-
const _onFocus = (e:
|
|
104
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
106
105
|
setFocused(true);
|
|
107
106
|
onFocus?.(e);
|
|
108
107
|
};
|
|
109
108
|
|
|
110
|
-
const _onBlur = (e:
|
|
109
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
111
110
|
setFocused(false);
|
|
112
111
|
onBlur?.(e);
|
|
113
112
|
};
|
package/Input/InputMoney.tsx
CHANGED
|
@@ -9,11 +9,9 @@ import React, {
|
|
|
9
9
|
useState,
|
|
10
10
|
} from 'react';
|
|
11
11
|
import {
|
|
12
|
-
NativeSyntheticEvent,
|
|
13
|
-
Platform,
|
|
14
12
|
TextInput,
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
TextInputFocusEvent,
|
|
14
|
+
TextInputSelectionChangeEvent,
|
|
17
15
|
TouchableOpacity,
|
|
18
16
|
View,
|
|
19
17
|
} from 'react-native';
|
|
@@ -57,13 +55,10 @@ const caretFromDigitIndex = (display: string, digitIndex: number) => {
|
|
|
57
55
|
return 0;
|
|
58
56
|
};
|
|
59
57
|
|
|
60
|
-
// Finds which range of `old` was replaced to produce `next`. `selection` is
|
|
61
|
-
// the pre-edit selection on iOS and already the post-edit caret on Android,
|
|
62
|
-
// where onSelectionChange fires before onChangeText.
|
|
63
58
|
const detectEdit = (old: string, next: string, selection: Selection): Edit => {
|
|
64
59
|
const { start, end } = selection;
|
|
65
60
|
const removed = old.length - next.length;
|
|
66
|
-
const
|
|
61
|
+
const candidates: Edit[] = [
|
|
67
62
|
{
|
|
68
63
|
start,
|
|
69
64
|
end,
|
|
@@ -72,26 +67,6 @@ const detectEdit = (old: string, next: string, selection: Selection): Edit => {
|
|
|
72
67
|
{ start: start - removed, end: start, inserted: '' },
|
|
73
68
|
{ start, end: start + removed, inserted: '' },
|
|
74
69
|
];
|
|
75
|
-
const postEdit: Edit[] = [];
|
|
76
|
-
const tail = next.length - start;
|
|
77
|
-
if (start === end && tail <= old.length) {
|
|
78
|
-
let prefix = 0;
|
|
79
|
-
while (
|
|
80
|
-
prefix < Math.min(start, old.length - tail) &&
|
|
81
|
-
old[prefix] === next[prefix]
|
|
82
|
-
) {
|
|
83
|
-
prefix += 1;
|
|
84
|
-
}
|
|
85
|
-
postEdit.push({
|
|
86
|
-
start: prefix,
|
|
87
|
-
end: old.length - tail,
|
|
88
|
-
inserted: next.slice(prefix, start),
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
const candidates =
|
|
92
|
-
Platform.OS === 'android'
|
|
93
|
-
? [...postEdit, ...preEdit]
|
|
94
|
-
: [...preEdit, ...postEdit];
|
|
95
70
|
const match = candidates.find(
|
|
96
71
|
e =>
|
|
97
72
|
e.start >= 0 &&
|
|
@@ -196,9 +171,8 @@ const InputMoney = forwardRef(
|
|
|
196
171
|
const selectionRef = useRef<Selection>({ start: 0, end: 0 });
|
|
197
172
|
// Caret to push to native once the committed text is rendered.
|
|
198
173
|
const pendingCaretRef = useRef<number | null>(null);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const rawCaretRef = useRef<number | null>(null);
|
|
174
|
+
const pendingSelectionRef = useRef<Selection | null>(null);
|
|
175
|
+
const editingRef = useRef(false);
|
|
202
176
|
const inputRef = useRef<TextInput>(null);
|
|
203
177
|
const componentName = 'InputMoney';
|
|
204
178
|
|
|
@@ -265,10 +239,13 @@ const InputMoney = forwardRef(
|
|
|
265
239
|
const _onChangeText = (text: string) => {
|
|
266
240
|
let digits = '';
|
|
267
241
|
let caretDigit = 0;
|
|
268
|
-
|
|
242
|
+
pendingSelectionRef.current = null;
|
|
243
|
+
editingRef.current = true;
|
|
244
|
+
setTimeout(() => {
|
|
245
|
+
editingRef.current = false;
|
|
246
|
+
});
|
|
269
247
|
if (text) {
|
|
270
248
|
const edit = detectEdit(displayRef.current, text, selectionRef.current);
|
|
271
|
-
rawCaretRef.current = edit.start + edit.inserted.length;
|
|
272
249
|
({ digits, caretDigit } = applyEdit(
|
|
273
250
|
displayRef.current,
|
|
274
251
|
edit,
|
|
@@ -281,31 +258,34 @@ const InputMoney = forwardRef(
|
|
|
281
258
|
};
|
|
282
259
|
|
|
283
260
|
// Keeps the caret out of the currency suffix.
|
|
284
|
-
const _onSelectionChange = (
|
|
285
|
-
e: NativeSyntheticEvent<TextInputSelectionChangeEventData>,
|
|
286
|
-
) => {
|
|
261
|
+
const _onSelectionChange = (e: TextInputSelectionChangeEvent) => {
|
|
287
262
|
props.onSelectionChange?.(e);
|
|
288
|
-
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
return;
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
263
|
+
if (editingRef.current) return;
|
|
264
|
+
const selection = e.nativeEvent.selection;
|
|
265
|
+
pendingSelectionRef.current = selection;
|
|
266
|
+
setTimeout(() => {
|
|
267
|
+
if (pendingSelectionRef.current !== selection) return;
|
|
268
|
+
pendingSelectionRef.current = null;
|
|
269
|
+
const { start, end } = selection;
|
|
270
|
+
const display = displayRef.current;
|
|
271
|
+
const max = display ? display.length - currency.length : 0;
|
|
272
|
+
const clamped = {
|
|
273
|
+
start: Math.min(start, max),
|
|
274
|
+
end: Math.min(end, max),
|
|
275
|
+
};
|
|
276
|
+
selectionRef.current = clamped;
|
|
277
|
+
if (clamped.start !== start || clamped.end !== end) {
|
|
278
|
+
inputRef.current?.setSelection(clamped.start, clamped.end);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
301
281
|
};
|
|
302
282
|
|
|
303
|
-
const _onFocus = (e:
|
|
283
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
304
284
|
setFocused(true);
|
|
305
285
|
onFocus?.(e);
|
|
306
286
|
};
|
|
307
287
|
|
|
308
|
-
const _onBlur = (e:
|
|
288
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
309
289
|
setFocused(false);
|
|
310
290
|
onBlur?.(e);
|
|
311
291
|
};
|