@momo-kits/foundation 0.167.1-duo.1 → 0.167.1-duo.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Application/BottomSheet.tsx +115 -14
- package/Application/BottomTab/DuoTabBar.tsx +410 -0
- package/Application/BottomTab/index.tsx +38 -28
- package/Application/Components/DuoGlassBackground.tsx +177 -0
- 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/OptionalGlassView.ts +11 -0
- package/Application/Components/SearchHeader.tsx +15 -14
- package/Application/Components/SideBarButton.tsx +128 -0
- package/Application/ModalScreen.tsx +16 -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/device.ts +29 -0
- 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 +146 -40
- package/Layout/Section.tsx +5 -18
- package/Layout/index.ts +4 -4
- package/Layout/utils.ts +280 -5
- package/Popup/PopupNotify.tsx +33 -22
- package/Popup/PopupPromotion.tsx +20 -8
- package/Popup/utils.ts +32 -0
- 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
|
@@ -27,7 +27,9 @@ import StackScreen from '../StackScreen';
|
|
|
27
27
|
import { BottomTabProps } from '../types';
|
|
28
28
|
import { getOptions, getStackOptions, useAppState } from '../utils';
|
|
29
29
|
import BottomTabBar from './BottomTabBar';
|
|
30
|
+
import { DuoTabBar } from './DuoTabBar';
|
|
30
31
|
import { ApplicationContext, MiniAppContext } from '../../Context';
|
|
32
|
+
import { useScreenLayout } from '../../Layout';
|
|
31
33
|
|
|
32
34
|
const Tab = createBottomTabNavigator();
|
|
33
35
|
const Stack = createStackNavigator();
|
|
@@ -36,7 +38,13 @@ const TabScreen: React.FC<any> = ({ route, navigation }) => {
|
|
|
36
38
|
const { navigator } = useContext(ApplicationContext);
|
|
37
39
|
const context = useContext<any>(MiniAppContext);
|
|
38
40
|
const { nested, options, screen, initialParams } = route?.params;
|
|
39
|
-
const
|
|
41
|
+
const { headerHeight, headerStatusBarHeight } = useScreenLayout();
|
|
42
|
+
const headerStyleOptions = {
|
|
43
|
+
headerStyle: {
|
|
44
|
+
height: headerHeight,
|
|
45
|
+
},
|
|
46
|
+
headerStatusBarHeight,
|
|
47
|
+
};
|
|
40
48
|
|
|
41
49
|
const opacityValue = 0.3;
|
|
42
50
|
const scaleValue = 0.97;
|
|
@@ -139,11 +147,7 @@ const TabScreen: React.FC<any> = ({ route, navigation }) => {
|
|
|
139
147
|
return (
|
|
140
148
|
<Animated.View style={[styles.container, tabAnimatedStyle]}>
|
|
141
149
|
<Stack.Navigator
|
|
142
|
-
screenOptions={
|
|
143
|
-
headerStyle: {
|
|
144
|
-
height: 52 + insets.top,
|
|
145
|
-
},
|
|
146
|
-
}}
|
|
150
|
+
screenOptions={headerStyleOptions}
|
|
147
151
|
>
|
|
148
152
|
<Stack.Screen
|
|
149
153
|
name="Stack"
|
|
@@ -174,11 +178,7 @@ const TabScreen: React.FC<any> = ({ route, navigation }) => {
|
|
|
174
178
|
<NavigationIndependentTree>
|
|
175
179
|
<NavigationContainer>
|
|
176
180
|
<Stack.Navigator
|
|
177
|
-
screenOptions={
|
|
178
|
-
headerStyle: {
|
|
179
|
-
height: 52 + insets.top,
|
|
180
|
-
},
|
|
181
|
-
}}
|
|
181
|
+
screenOptions={headerStyleOptions}
|
|
182
182
|
>
|
|
183
183
|
<Stack.Screen
|
|
184
184
|
name="Stack"
|
|
@@ -207,6 +207,7 @@ const BottomTab: React.FC<BottomTabProps> = ({
|
|
|
207
207
|
floatingButton,
|
|
208
208
|
}) => {
|
|
209
209
|
const { theme, navigator } = useContext(ApplicationContext);
|
|
210
|
+
const { isIPhoneDuo } = useScreenLayout();
|
|
210
211
|
const dimensions = useWindowDimensions();
|
|
211
212
|
const insets = useSafeAreaInsets();
|
|
212
213
|
const initialIndex = tabs.findIndex(i => i.name === initialRouteName);
|
|
@@ -306,23 +307,32 @@ const BottomTab: React.FC<BottomTabProps> = ({
|
|
|
306
307
|
</View>
|
|
307
308
|
),
|
|
308
309
|
}}
|
|
309
|
-
tabBar={props =>
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
310
|
+
tabBar={props =>
|
|
311
|
+
isIPhoneDuo ? (
|
|
312
|
+
<DuoTabBar
|
|
313
|
+
{...props}
|
|
314
|
+
floatingButton={floatingButton}
|
|
315
|
+
inactiveTintColor={theme.colors.text.default}
|
|
316
|
+
activeTintColor={theme.colors.primary}
|
|
317
|
+
/>
|
|
318
|
+
) : (
|
|
319
|
+
<BottomTabBar
|
|
320
|
+
{...props}
|
|
321
|
+
floatingButton={floatingButton}
|
|
322
|
+
inactiveTintColor={theme.colors.text.hint}
|
|
323
|
+
activeTintColor={theme.colors.primary}
|
|
324
|
+
style={[
|
|
325
|
+
{
|
|
326
|
+
height:
|
|
327
|
+
64 +
|
|
328
|
+
(Platform.OS === 'ios'
|
|
329
|
+
? Math.min(insets.bottom, 21)
|
|
330
|
+
: insets.bottom),
|
|
331
|
+
},
|
|
332
|
+
]}
|
|
333
|
+
/>
|
|
334
|
+
)
|
|
335
|
+
}
|
|
326
336
|
initialRouteName={initialRouteName}
|
|
327
337
|
>
|
|
328
338
|
{tabs.map((item, index) => {
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import React, { useContext, useState } from 'react';
|
|
2
|
+
import { StyleSheet, View } from 'react-native';
|
|
3
|
+
import LinearGradient from 'react-native-linear-gradient';
|
|
4
|
+
import Animated, {
|
|
5
|
+
Extrapolation,
|
|
6
|
+
interpolate,
|
|
7
|
+
runOnJS,
|
|
8
|
+
useAnimatedReaction,
|
|
9
|
+
useAnimatedStyle,
|
|
10
|
+
} from 'react-native-reanimated';
|
|
11
|
+
import { ApplicationContext } from '../../Context';
|
|
12
|
+
import { Shadow } from '../../Consts';
|
|
13
|
+
import { Image } from '../../Image';
|
|
14
|
+
import { AnimatedCompatValue, useNormalizedSharedValue } from '../utils';
|
|
15
|
+
import { GlassView } from './OptionalGlassView';
|
|
16
|
+
|
|
17
|
+
// extended headers run their gradient this far below the header, as off Duo
|
|
18
|
+
const EXTENDED_GRADIENT_EXTRA = 52;
|
|
19
|
+
// scroll distance over which the extended gradient collapses to the header
|
|
20
|
+
const EXTENDED_COLLAPSE_DISTANCE = 100;
|
|
21
|
+
// scroll distance over which the bar material fades in
|
|
22
|
+
const FADE_DISTANCE = 16;
|
|
23
|
+
const TRANSLUCENT_ALPHA = 'CC';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* iPhone Duo header background: glass running edge to edge, behind the status bar
|
|
27
|
+
* column too, shown once content scrolls under it
|
|
28
|
+
*/
|
|
29
|
+
const DuoGlassBackground: React.FC<{
|
|
30
|
+
animatedValue?: AnimatedCompatValue;
|
|
31
|
+
// scroll offset where the bar starts to show, e.g. below an animated banner
|
|
32
|
+
fadeStart?: number;
|
|
33
|
+
}> = ({ animatedValue, fadeStart = 0 }) => {
|
|
34
|
+
const { theme } = useContext(ApplicationContext);
|
|
35
|
+
const sharedValue = useNormalizedSharedValue(animatedValue);
|
|
36
|
+
const [scrolled, setScrolled] = useState(false);
|
|
37
|
+
|
|
38
|
+
useAnimatedReaction(
|
|
39
|
+
() => sharedValue.value > fadeStart,
|
|
40
|
+
(isScrolled, wasScrolled) => {
|
|
41
|
+
if (GlassView && isScrolled !== wasScrolled) {
|
|
42
|
+
runOnJS(setScrolled)(isScrolled);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
[fadeStart],
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const fadeStyle = useAnimatedStyle(() => ({
|
|
49
|
+
opacity: interpolate(
|
|
50
|
+
sharedValue.value,
|
|
51
|
+
[fadeStart, fadeStart + FADE_DISTANCE],
|
|
52
|
+
[0, 1],
|
|
53
|
+
Extrapolation.CLAMP,
|
|
54
|
+
),
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<View pointerEvents={'none'} style={StyleSheet.absoluteFill}>
|
|
59
|
+
{GlassView ? (
|
|
60
|
+
// UIVisualEffectView breaks under alpha, so glass toggles its effect instead
|
|
61
|
+
<GlassView
|
|
62
|
+
effect={scrolled ? 'glass' : 'none'}
|
|
63
|
+
useShadow
|
|
64
|
+
style={StyleSheet.absoluteFill}
|
|
65
|
+
/>
|
|
66
|
+
) : (
|
|
67
|
+
<Animated.View
|
|
68
|
+
style={[
|
|
69
|
+
StyleSheet.absoluteFill,
|
|
70
|
+
styles.translucentBar,
|
|
71
|
+
{
|
|
72
|
+
backgroundColor:
|
|
73
|
+
theme.colors.background.surface + TRANSLUCENT_ALPHA,
|
|
74
|
+
borderBottomColor: theme.colors.border.default,
|
|
75
|
+
},
|
|
76
|
+
fadeStyle,
|
|
77
|
+
]}
|
|
78
|
+
/>
|
|
79
|
+
)}
|
|
80
|
+
</View>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* pink header gradient drawn under the content: header-high for default headers
|
|
86
|
+
* (scrolls away), 52 taller for extended ones (collapses and fades, as off Duo)
|
|
87
|
+
*/
|
|
88
|
+
const DuoScrollGradient: React.FC<{
|
|
89
|
+
animatedValue?: AnimatedCompatValue;
|
|
90
|
+
gradientColor?: string;
|
|
91
|
+
headerBackground?: string;
|
|
92
|
+
heightHeader: number;
|
|
93
|
+
extended?: boolean;
|
|
94
|
+
}> = ({
|
|
95
|
+
animatedValue,
|
|
96
|
+
gradientColor,
|
|
97
|
+
headerBackground,
|
|
98
|
+
heightHeader,
|
|
99
|
+
extended,
|
|
100
|
+
}) => {
|
|
101
|
+
const { theme } = useContext(ApplicationContext);
|
|
102
|
+
const sharedValue = useNormalizedSharedValue(animatedValue);
|
|
103
|
+
const color = gradientColor ?? theme.colors.gradient;
|
|
104
|
+
const image = headerBackground ?? theme.assets?.headerBackground;
|
|
105
|
+
|
|
106
|
+
const scrollStyle = useAnimatedStyle(() => {
|
|
107
|
+
if (!extended) {
|
|
108
|
+
return {
|
|
109
|
+
height: heightHeader,
|
|
110
|
+
transform: [{ translateY: -Math.max(sharedValue.value, 0) }],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
height: interpolate(
|
|
115
|
+
sharedValue.value,
|
|
116
|
+
[0, EXTENDED_COLLAPSE_DISTANCE],
|
|
117
|
+
[heightHeader + EXTENDED_GRADIENT_EXTRA, heightHeader],
|
|
118
|
+
Extrapolation.CLAMP,
|
|
119
|
+
),
|
|
120
|
+
opacity: interpolate(
|
|
121
|
+
sharedValue.value,
|
|
122
|
+
[0, EXTENDED_GRADIENT_EXTRA],
|
|
123
|
+
[1, 0],
|
|
124
|
+
Extrapolation.CLAMP,
|
|
125
|
+
),
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (!color) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<Animated.View
|
|
135
|
+
pointerEvents={'none'}
|
|
136
|
+
style={[styles.gradient, scrollStyle]}
|
|
137
|
+
>
|
|
138
|
+
{/* extended squeezes the whole fade into its box like main; default clips it */}
|
|
139
|
+
<View style={extended ? StyleSheet.absoluteFill : styles.gradientFill}>
|
|
140
|
+
<LinearGradient
|
|
141
|
+
colors={[color, color + '00']}
|
|
142
|
+
style={StyleSheet.absoluteFill}
|
|
143
|
+
>
|
|
144
|
+
{!!image && (
|
|
145
|
+
<Image
|
|
146
|
+
style={styles.gradientFill}
|
|
147
|
+
source={{ uri: image }}
|
|
148
|
+
loading={false}
|
|
149
|
+
/>
|
|
150
|
+
)}
|
|
151
|
+
</LinearGradient>
|
|
152
|
+
</View>
|
|
153
|
+
</Animated.View>
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const styles = StyleSheet.create({
|
|
158
|
+
translucentBar: {
|
|
159
|
+
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
160
|
+
...Shadow.Light,
|
|
161
|
+
},
|
|
162
|
+
gradient: {
|
|
163
|
+
position: 'absolute',
|
|
164
|
+
top: 0,
|
|
165
|
+
left: 0,
|
|
166
|
+
right: 0,
|
|
167
|
+
overflow: 'hidden',
|
|
168
|
+
},
|
|
169
|
+
// default header gradient keeps the off-Duo 375:154 shape, the header clips it
|
|
170
|
+
gradientFill: {
|
|
171
|
+
width: '100%',
|
|
172
|
+
position: 'absolute',
|
|
173
|
+
aspectRatio: 375 / 154,
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
export { DuoGlassBackground, DuoScrollGradient };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { Ref, useContext } from 'react';
|
|
2
2
|
import LinearGradient from 'react-native-linear-gradient';
|
|
3
|
-
import {
|
|
3
|
+
import { Platform, StyleSheet, View } from 'react-native';
|
|
4
4
|
import Animated, {
|
|
5
5
|
Extrapolation,
|
|
6
6
|
interpolate,
|
|
@@ -14,21 +14,18 @@ import { Colors, Radius, Spacing } from '../../Consts';
|
|
|
14
14
|
import { Image } from '../../Image';
|
|
15
15
|
import { SearchHeaderProps } from '../types';
|
|
16
16
|
import BackgroundImageView from './BackgroundImageView';
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
useNormalizedSharedValue,
|
|
20
|
-
} from '../utils';
|
|
17
|
+
import { AnimatedCompatValue, useNormalizedSharedValue } from '../utils';
|
|
18
|
+
import { useScreenLayout } from '../../Layout';
|
|
21
19
|
|
|
22
20
|
const SCREEN_PADDING = 12;
|
|
23
21
|
const BACK_WIDTH = 28;
|
|
24
|
-
|
|
25
|
-
const { width: screenWidth } = Dimensions.get('window');
|
|
22
|
+
const TOOLKIT_WIDTH = 73;
|
|
26
23
|
|
|
27
24
|
const HeaderExtendHeader: React.FC<{
|
|
28
25
|
headerType?: HeaderType;
|
|
29
26
|
animatedValue: AnimatedCompatValue;
|
|
30
27
|
heightHeader: number;
|
|
31
|
-
headerRightWidth
|
|
28
|
+
headerRightWidth?: number;
|
|
32
29
|
inputSearchProps?: SearchHeaderProps;
|
|
33
30
|
inputSearchRef?: Ref<InputRef>;
|
|
34
31
|
navigation?: Navigation;
|
|
@@ -39,7 +36,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
39
36
|
headerType = 'default',
|
|
40
37
|
animatedValue,
|
|
41
38
|
heightHeader,
|
|
42
|
-
headerRightWidth
|
|
39
|
+
headerRightWidth: customHeaderRightWidth,
|
|
43
40
|
inputSearchProps,
|
|
44
41
|
inputSearchRef,
|
|
45
42
|
useShadowHeader: useShadowHeaderProp = true,
|
|
@@ -51,7 +48,19 @@ const HeaderExtendHeader: React.FC<{
|
|
|
51
48
|
const sharedValue = useNormalizedSharedValue(animatedValue);
|
|
52
49
|
const gradientColor = customGradientColor ?? theme.colors.gradient;
|
|
53
50
|
const headerBackground = customBackground ?? theme.assets?.headerBackground;
|
|
54
|
-
const
|
|
51
|
+
const layout = useScreenLayout();
|
|
52
|
+
|
|
53
|
+
const leftPosition =
|
|
54
|
+
inputSearchProps?.leftPosition ||
|
|
55
|
+
(layout.sideBar ? SCREEN_PADDING : BACK_WIDTH + 20);
|
|
56
|
+
const headerRightWidth =
|
|
57
|
+
customHeaderRightWidth ?? (layout.sideBar ? 0 : TOOLKIT_WIDTH);
|
|
58
|
+
const contentLeft = layout.insetLeft + SCREEN_PADDING;
|
|
59
|
+
const contentRight = layout.insetLeft + layout.contentWidth;
|
|
60
|
+
const collapsedLeft = layout.insetLeft + leftPosition;
|
|
61
|
+
const searchWidth = layout.contentWidth - SCREEN_PADDING * 2;
|
|
62
|
+
const collapsedSearchWidth =
|
|
63
|
+
contentRight - collapsedLeft - SCREEN_PADDING - headerRightWidth;
|
|
55
64
|
|
|
56
65
|
let useShadowHeader = useShadowHeaderProp;
|
|
57
66
|
if (inputSearchProps && Platform.OS === 'android') {
|
|
@@ -70,7 +79,12 @@ const HeaderExtendHeader: React.FC<{
|
|
|
70
79
|
}));
|
|
71
80
|
|
|
72
81
|
const gradientOpacityStyle = useAnimatedStyle(() => ({
|
|
73
|
-
opacity: interpolate(
|
|
82
|
+
opacity: interpolate(
|
|
83
|
+
sharedValue.value,
|
|
84
|
+
[0, 52],
|
|
85
|
+
[1, 0],
|
|
86
|
+
Extrapolation.CLAMP,
|
|
87
|
+
),
|
|
74
88
|
}));
|
|
75
89
|
|
|
76
90
|
const searchTranslateStyle = useAnimatedStyle(() => ({
|
|
@@ -79,7 +93,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
79
93
|
translateX: interpolate(
|
|
80
94
|
sharedValue.value,
|
|
81
95
|
[0, 100],
|
|
82
|
-
[
|
|
96
|
+
[contentLeft, collapsedLeft],
|
|
83
97
|
Extrapolation.CLAMP,
|
|
84
98
|
),
|
|
85
99
|
},
|
|
@@ -87,19 +101,19 @@ const HeaderExtendHeader: React.FC<{
|
|
|
87
101
|
width: interpolate(
|
|
88
102
|
sharedValue.value,
|
|
89
103
|
[0, 100],
|
|
90
|
-
[
|
|
91
|
-
screenWidth - SCREEN_PADDING * 2,
|
|
92
|
-
screenWidth - leftPosition - 12 - headerRightWidth,
|
|
93
|
-
],
|
|
104
|
+
[searchWidth, collapsedSearchWidth],
|
|
94
105
|
Extrapolation.CLAMP,
|
|
95
106
|
),
|
|
96
107
|
}));
|
|
97
108
|
|
|
98
109
|
const searchBackgroundStyle = useAnimatedStyle(() => {
|
|
99
110
|
const t = Math.min(Math.max(sharedValue.value / 100, 0), 1);
|
|
100
|
-
return {
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
return {
|
|
112
|
+
backgroundColor:
|
|
113
|
+
t === 0
|
|
114
|
+
? theme.colors.background.surface
|
|
115
|
+
: theme.colors.background.default,
|
|
116
|
+
};
|
|
103
117
|
});
|
|
104
118
|
|
|
105
119
|
const extendedHeightStyle = useAnimatedStyle(() => ({
|
|
@@ -124,9 +138,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
124
138
|
<Animated.View
|
|
125
139
|
style={[
|
|
126
140
|
styles.headerBox,
|
|
127
|
-
headerType === 'extended'
|
|
128
|
-
? heightStyle
|
|
129
|
-
: { height: heightHeader },
|
|
141
|
+
headerType === 'extended' ? heightStyle : { height: heightHeader },
|
|
130
142
|
]}
|
|
131
143
|
>
|
|
132
144
|
{!!gradientColor && (
|
|
@@ -162,10 +174,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
162
174
|
style={[{ marginVertical: Spacing.S }, searchTranslateStyle]}
|
|
163
175
|
>
|
|
164
176
|
<Animated.View
|
|
165
|
-
style={[
|
|
166
|
-
{ borderRadius: Radius.XL },
|
|
167
|
-
searchBackgroundStyle,
|
|
168
|
-
]}
|
|
177
|
+
style={[{ borderRadius: Radius.XL }, searchBackgroundStyle]}
|
|
169
178
|
>
|
|
170
179
|
<InputSearch
|
|
171
180
|
{...inputSearchProps}
|
|
@@ -191,7 +200,11 @@ const HeaderExtendHeader: React.FC<{
|
|
|
191
200
|
/>
|
|
192
201
|
{!!gradientColor && (
|
|
193
202
|
<Animated.View
|
|
194
|
-
style={[
|
|
203
|
+
style={[
|
|
204
|
+
styles.extendedHeader,
|
|
205
|
+
gradientOpacityStyle,
|
|
206
|
+
extendedHeightStyle,
|
|
207
|
+
]}
|
|
195
208
|
>
|
|
196
209
|
<LinearGradient
|
|
197
210
|
colors={[gradientColor, gradientColor + '00']}
|
|
@@ -4,6 +4,8 @@ import React, { useCallback, useContext, useEffect } from 'react';
|
|
|
4
4
|
import { ApplicationContext, MiniAppContext } from '../../Context';
|
|
5
5
|
import { PopupNotify } from '../../Popup';
|
|
6
6
|
import { NavigationButton } from './NavigationButton';
|
|
7
|
+
import { SideBarButton } from './SideBarButton';
|
|
8
|
+
import { useSideBarItemStyle } from '../../Layout/utils';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* default header left used for nav
|
|
@@ -13,9 +15,11 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
13
15
|
preventBack,
|
|
14
16
|
onPressLeftHeader,
|
|
15
17
|
onBackHandler,
|
|
18
|
+
floating = false,
|
|
16
19
|
}) => {
|
|
17
20
|
const context = useContext<any>(MiniAppContext);
|
|
18
21
|
const { navigator } = useContext(ApplicationContext);
|
|
22
|
+
const sideBarStyle = useSideBarItemStyle('left', 0);
|
|
19
23
|
|
|
20
24
|
const goBack = useCallback(() => {
|
|
21
25
|
const canGoBack = navigator?.ref?.current?.canGoBack?.();
|
|
@@ -72,6 +76,19 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
72
76
|
return () => backHandler.remove();
|
|
73
77
|
}, [goBackSafe]);
|
|
74
78
|
|
|
79
|
+
if (floating && sideBarStyle) {
|
|
80
|
+
return (
|
|
81
|
+
<View style={sideBarStyle} pointerEvents={'box-none'}>
|
|
82
|
+
<SideBarButton
|
|
83
|
+
accessibilityLabel="btn_navigation_back"
|
|
84
|
+
icon="arrow-back"
|
|
85
|
+
tintColor={tintColor}
|
|
86
|
+
onPress={goBackSafe}
|
|
87
|
+
/>
|
|
88
|
+
</View>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
75
92
|
return (
|
|
76
93
|
<View style={styles.headerLeft}>
|
|
77
94
|
<NavigationButton
|
|
@@ -13,6 +13,8 @@ import { PopupNotify } from '../../Popup';
|
|
|
13
13
|
import { Tool, ToolGroup } from '../types';
|
|
14
14
|
import { Icon } from '../../Icon';
|
|
15
15
|
import { Text } from '../../Text';
|
|
16
|
+
import { useSideBarItemStyle } from '../../Layout/utils';
|
|
17
|
+
import { SideBarButton, SideBarGroup, SideBarGroupItem } from './SideBarButton';
|
|
16
18
|
|
|
17
19
|
const DID_SYNC_NEW_HOME = 'did_sync_new_home';
|
|
18
20
|
|
|
@@ -21,8 +23,9 @@ const DID_SYNC_NEW_HOME = 'did_sync_new_home';
|
|
|
21
23
|
*/
|
|
22
24
|
const HeaderRight: React.FC<any> = props => {
|
|
23
25
|
const { translate } = useContext(ApplicationContext);
|
|
24
|
-
const { headerRight = {} } = props;
|
|
26
|
+
const { headerRight = {}, floating = false } = props;
|
|
25
27
|
const { useOnBoarding = false, buttonOnBoarding, onPress } = headerRight;
|
|
28
|
+
const sideBarStyle = useSideBarItemStyle('right', 1);
|
|
26
29
|
|
|
27
30
|
if (typeof props.headerRight === 'function') {
|
|
28
31
|
return props.headerRight(props);
|
|
@@ -38,6 +41,18 @@ const HeaderRight: React.FC<any> = props => {
|
|
|
38
41
|
);
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
if (floating && sideBarStyle) {
|
|
45
|
+
return (
|
|
46
|
+
<View style={sideBarStyle} pointerEvents={'box-none'}>
|
|
47
|
+
<HeaderToolkitAction
|
|
48
|
+
{...props.headerRight}
|
|
49
|
+
tintColor={props.tintColor}
|
|
50
|
+
vertical
|
|
51
|
+
/>
|
|
52
|
+
</View>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
return (
|
|
42
57
|
<View style={styles.headerRightButton}>
|
|
43
58
|
<HeaderToolkitAction {...props.headerRight} tintColor={props.tintColor} />
|
|
@@ -56,6 +71,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
56
71
|
useMore = false,
|
|
57
72
|
tools = [],
|
|
58
73
|
useCloseIcon = false,
|
|
74
|
+
vertical = false,
|
|
59
75
|
}) => {
|
|
60
76
|
const { navigator } = useContext(ApplicationContext);
|
|
61
77
|
const context = useContext<any>(MiniAppContext);
|
|
@@ -260,6 +276,43 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
260
276
|
group?.items?.some?.(tool => tool?.showBadge),
|
|
261
277
|
);
|
|
262
278
|
|
|
279
|
+
const useHelpCenter = context.appId !== 'vn.momo.helpcenter';
|
|
280
|
+
const closeIcon = useCloseIcon
|
|
281
|
+
? '16_navigation_close_circle'
|
|
282
|
+
: '16_basic_home';
|
|
283
|
+
|
|
284
|
+
if (vertical) {
|
|
285
|
+
return (
|
|
286
|
+
<View style={styles.sideBarColumn}>
|
|
287
|
+
{useShortcut && (
|
|
288
|
+
<SideBarButton
|
|
289
|
+
disabled={isLoading}
|
|
290
|
+
icon={iconShortcut}
|
|
291
|
+
onPress={shortcutOnPress}
|
|
292
|
+
tintColor={tintColor}
|
|
293
|
+
showBadge={showBadge}
|
|
294
|
+
/>
|
|
295
|
+
)}
|
|
296
|
+
<SideBarGroup tintColor={tintColor}>
|
|
297
|
+
{useHelpCenter && (
|
|
298
|
+
<SideBarGroupItem
|
|
299
|
+
accessibilityLabel={'btn_navigation_help_center'}
|
|
300
|
+
icon={'help_center'}
|
|
301
|
+
tintColor={tintColor}
|
|
302
|
+
onPress={onPressHelpCenter}
|
|
303
|
+
/>
|
|
304
|
+
)}
|
|
305
|
+
<SideBarGroupItem
|
|
306
|
+
accessibilityLabel={'btn_navigation_close'}
|
|
307
|
+
icon={closeIcon}
|
|
308
|
+
tintColor={tintColor}
|
|
309
|
+
onPress={onClose}
|
|
310
|
+
/>
|
|
311
|
+
</SideBarGroup>
|
|
312
|
+
</View>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
263
316
|
return (
|
|
264
317
|
<View style={Styles.row}>
|
|
265
318
|
{useShortcut && (
|
|
@@ -280,7 +333,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
280
333
|
},
|
|
281
334
|
]}
|
|
282
335
|
>
|
|
283
|
-
{
|
|
336
|
+
{useHelpCenter && (
|
|
284
337
|
<>
|
|
285
338
|
<TouchableOpacity
|
|
286
339
|
accessibilityLabel={'btn_navigation_help_center'}
|
|
@@ -299,13 +352,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
299
352
|
style={styles.toolkitButton}
|
|
300
353
|
hitSlop={{ top: 7, bottom: 7, left: 0, right: 7 }}
|
|
301
354
|
>
|
|
302
|
-
<Icon
|
|
303
|
-
color={tintColor}
|
|
304
|
-
source={
|
|
305
|
-
useCloseIcon ? '16_navigation_close_circle' : '16_basic_home'
|
|
306
|
-
}
|
|
307
|
-
size={20}
|
|
308
|
-
/>
|
|
355
|
+
<Icon color={tintColor} source={closeIcon} size={20} />
|
|
309
356
|
</TouchableOpacity>
|
|
310
357
|
</View>
|
|
311
358
|
</View>
|
|
@@ -376,6 +423,9 @@ const styles = StyleSheet.create({
|
|
|
376
423
|
width: 0.5,
|
|
377
424
|
height: 12,
|
|
378
425
|
},
|
|
426
|
+
sideBarColumn: {
|
|
427
|
+
gap: Spacing.M,
|
|
428
|
+
},
|
|
379
429
|
headerLeft: {
|
|
380
430
|
marginLeft: 12,
|
|
381
431
|
},
|