@momo-kits/foundation 0.167.1-beta.7 → 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/BottomTabBar.tsx +6 -3
- 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 +47 -21
- 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 -37
- package/Application/Navigator.ts +1 -3
- package/Application/StackScreen.tsx +2 -5
- package/Application/WidgetContainer.tsx +9 -15
- package/Application/types.ts +5 -1
- package/Application/utils.tsx +10 -3
- package/Consts/index.ts +0 -1
- package/Consts/theme.ts +3 -4
- 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 +5 -15
- package/Text/utils.ts +1 -2
- package/package.json +3 -2
- package/Consts/designSystemFont.ts +0 -25
- 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,17 +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 {
|
|
24
|
-
useDefaultRegularFontFamily,
|
|
25
|
-
useResolvedFontFamily,
|
|
26
|
-
} from '../Consts/designSystemFont';
|
|
27
26
|
import Localize from './Localize';
|
|
28
27
|
import { Colors, defaultTheme } from '../Consts';
|
|
29
28
|
import { HeaderLeft } from './Components/HeaderLeft';
|
|
@@ -31,6 +30,7 @@ import { HeaderRight } from './Components/HeaderRight';
|
|
|
31
30
|
import { HeaderTitle } from './Components/HeaderTitle';
|
|
32
31
|
import { HeaderBackground } from './Components/HeaderBackground';
|
|
33
32
|
import { type EdgeInsets } from 'react-native-safe-area-context';
|
|
33
|
+
import { useScreenLayout } from '../Layout';
|
|
34
34
|
|
|
35
35
|
const Stack = createStackNavigator();
|
|
36
36
|
|
|
@@ -104,11 +104,11 @@ const Navigation: React.FC<any> = ({
|
|
|
104
104
|
const navigationRef = useRef<any>(null);
|
|
105
105
|
const isReady = useRef(false);
|
|
106
106
|
const navigator = useRef(new Navigator(navigationRef, isReady));
|
|
107
|
-
const
|
|
108
|
-
const insets = useSafeAreaInsets();
|
|
109
|
-
const defaultRegularFontFamily = useDefaultRegularFontFamily();
|
|
110
|
-
const themeFont = useResolvedFontFamily(theme.font);
|
|
107
|
+
const { headerHeight, headerStatusBarHeight } = useScreenLayout();
|
|
111
108
|
const syncCanGoBack = useNativeCanGoBack();
|
|
109
|
+
const isWhiteList = isWhiteListDesignSystem(context);
|
|
110
|
+
const fontFamily = isWhiteList ? 'MomoTrustSans' : 'SFProText';
|
|
111
|
+
const navigationFontFamily = isWhiteList ? 'MomoTrustSans-Regular' : 'SFProText';
|
|
112
112
|
let headerBackground = context?.designSystemConfig?.config?.headerBar;
|
|
113
113
|
let headerGradient = theme.colors?.gradient;
|
|
114
114
|
|
|
@@ -124,23 +124,6 @@ const Navigation: React.FC<any> = ({
|
|
|
124
124
|
*/
|
|
125
125
|
navigator.current.maxApi = maxApi;
|
|
126
126
|
|
|
127
|
-
/**
|
|
128
|
-
* handle mini language & listen change
|
|
129
|
-
* engine only shake to enable grid view
|
|
130
|
-
*/
|
|
131
|
-
useEffect(() => {
|
|
132
|
-
const subscription = DeviceEventEmitter.addListener(
|
|
133
|
-
'onChangeGrid',
|
|
134
|
-
enable => {
|
|
135
|
-
setShowGrid(!!enable);
|
|
136
|
-
},
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
return () => {
|
|
140
|
-
subscription?.remove?.();
|
|
141
|
-
};
|
|
142
|
-
}, []);
|
|
143
|
-
|
|
144
127
|
/**
|
|
145
128
|
* translate context method
|
|
146
129
|
* @param data
|
|
@@ -160,7 +143,7 @@ const Navigation: React.FC<any> = ({
|
|
|
160
143
|
navigator: navigator.current,
|
|
161
144
|
theme: {
|
|
162
145
|
...theme,
|
|
163
|
-
font:
|
|
146
|
+
font: fontFamily,
|
|
164
147
|
colors: {
|
|
165
148
|
...theme.colors,
|
|
166
149
|
gradient: headerGradient,
|
|
@@ -170,7 +153,6 @@ const Navigation: React.FC<any> = ({
|
|
|
170
153
|
headerBackground,
|
|
171
154
|
},
|
|
172
155
|
},
|
|
173
|
-
showGrid,
|
|
174
156
|
translate,
|
|
175
157
|
}}
|
|
176
158
|
>
|
|
@@ -188,19 +170,19 @@ const Navigation: React.FC<any> = ({
|
|
|
188
170
|
},
|
|
189
171
|
fonts: {
|
|
190
172
|
regular: {
|
|
191
|
-
fontFamily:
|
|
173
|
+
fontFamily: navigationFontFamily,
|
|
192
174
|
fontWeight: '400',
|
|
193
175
|
},
|
|
194
176
|
medium: {
|
|
195
|
-
fontFamily:
|
|
177
|
+
fontFamily: navigationFontFamily,
|
|
196
178
|
fontWeight: '400',
|
|
197
179
|
},
|
|
198
180
|
bold: {
|
|
199
|
-
fontFamily:
|
|
181
|
+
fontFamily: navigationFontFamily,
|
|
200
182
|
fontWeight: '400',
|
|
201
183
|
},
|
|
202
184
|
heavy: {
|
|
203
|
-
fontFamily:
|
|
185
|
+
fontFamily: navigationFontFamily,
|
|
204
186
|
fontWeight: '400',
|
|
205
187
|
},
|
|
206
188
|
},
|
|
@@ -220,8 +202,9 @@ const Navigation: React.FC<any> = ({
|
|
|
220
202
|
headerTitleAlign: 'center',
|
|
221
203
|
headerTintColor: theme.colors.text.default,
|
|
222
204
|
headerStyle: {
|
|
223
|
-
height:
|
|
205
|
+
height: headerHeight,
|
|
224
206
|
},
|
|
207
|
+
headerStatusBarHeight,
|
|
225
208
|
}}
|
|
226
209
|
>
|
|
227
210
|
<Stack.Screen
|
|
@@ -244,11 +227,13 @@ const Navigation: React.FC<any> = ({
|
|
|
244
227
|
cardStyle: {
|
|
245
228
|
backgroundColor: theme.colors.background.default,
|
|
246
229
|
},
|
|
247
|
-
headerLeft: (props: any) => <HeaderLeft {...props} />,
|
|
230
|
+
headerLeft: (props: any) => <HeaderLeft {...props} floating />,
|
|
248
231
|
headerBackground: (props: any) => (
|
|
249
232
|
<HeaderBackground {...props} />
|
|
250
233
|
),
|
|
251
|
-
headerRight: (props: any) =>
|
|
234
|
+
headerRight: (props: any) => (
|
|
235
|
+
<HeaderRight {...props} floating />
|
|
236
|
+
),
|
|
252
237
|
headerTintColor: Colors.black_17,
|
|
253
238
|
...TransitionPresets.ModalTransition,
|
|
254
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,10 +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 {
|
|
7
|
-
resolveFontFamily,
|
|
8
|
-
useDefaultRegularFontFamily,
|
|
9
|
-
} from '../Consts/designSystemFont';
|
|
10
6
|
import Localize from './Localize';
|
|
11
7
|
import { defaultTheme } from '../Consts';
|
|
12
8
|
import {
|
|
@@ -14,7 +10,7 @@ import {
|
|
|
14
10
|
NavigationContainerRef,
|
|
15
11
|
NavigationIndependentTree,
|
|
16
12
|
} from '@react-navigation/native';
|
|
17
|
-
import { getModalOptions } from './utils';
|
|
13
|
+
import { getModalOptions, isWhiteListDesignSystem } from './utils';
|
|
18
14
|
import { createStackNavigator } from '@react-navigation/stack';
|
|
19
15
|
import ModalScreen from './ModalScreen';
|
|
20
16
|
import { View } from 'react-native';
|
|
@@ -46,7 +42,6 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
46
42
|
const isReady = useRef(false);
|
|
47
43
|
const navigator = useRef(new Navigator(navigationRef, isReady, true));
|
|
48
44
|
const [currentContext, setCurrentContext] = useState({});
|
|
49
|
-
const defaultRegularFontFamily = useDefaultRegularFontFamily();
|
|
50
45
|
|
|
51
46
|
useEffect(() => {
|
|
52
47
|
const sub = maxApi?.observer?.('font_scale_config', (data: any) => {
|
|
@@ -83,6 +78,9 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
83
78
|
...context,
|
|
84
79
|
...currentContext,
|
|
85
80
|
};
|
|
81
|
+
const isWhiteList = isWhiteListDesignSystem(mergedContext);
|
|
82
|
+
const fontFamily = isWhiteList ? 'MomoTrustSans' : 'SFProText';
|
|
83
|
+
const navigationFontFamily = isWhiteList ? 'MomoTrustSans-Regular' : 'SFProText';
|
|
86
84
|
|
|
87
85
|
return (
|
|
88
86
|
<View style={{ height: height ?? '100%', minHeight: 1 }}>
|
|
@@ -93,11 +91,7 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
93
91
|
navigator: navigator.current,
|
|
94
92
|
theme: {
|
|
95
93
|
...theme,
|
|
96
|
-
font:
|
|
97
|
-
theme.font,
|
|
98
|
-
mergedContext?.designSystemConfig?.isWhiteListDesignSystem ===
|
|
99
|
-
true,
|
|
100
|
-
),
|
|
94
|
+
font: fontFamily,
|
|
101
95
|
colors: {
|
|
102
96
|
...theme.colors,
|
|
103
97
|
gradient: headerGradient,
|
|
@@ -124,19 +118,19 @@ const WidgetContainer: React.FC<WidgetContainerProps> = ({
|
|
|
124
118
|
},
|
|
125
119
|
fonts: {
|
|
126
120
|
regular: {
|
|
127
|
-
fontFamily:
|
|
121
|
+
fontFamily: navigationFontFamily,
|
|
128
122
|
fontWeight: '400',
|
|
129
123
|
},
|
|
130
124
|
medium: {
|
|
131
|
-
fontFamily:
|
|
125
|
+
fontFamily: navigationFontFamily,
|
|
132
126
|
fontWeight: '400',
|
|
133
127
|
},
|
|
134
128
|
bold: {
|
|
135
|
-
fontFamily:
|
|
129
|
+
fontFamily: navigationFontFamily,
|
|
136
130
|
fontWeight: '400',
|
|
137
131
|
},
|
|
138
132
|
heavy: {
|
|
139
|
-
fontFamily:
|
|
133
|
+
fontFamily: navigationFontFamily,
|
|
140
134
|
fontWeight: '400',
|
|
141
135
|
},
|
|
142
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,
|
|
@@ -112,10 +112,9 @@ const defaultDarkTheme: Theme = {
|
|
|
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
|
};
|