@momo-kits/foundation 0.168.1-beta.37 → 0.168.1-beta.39
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.hooks.ts +8 -8
- package/Application/BottomSheet.parts.tsx +44 -34
- package/Application/BottomSheet.tsx +35 -26
- package/Application/BottomTab/ActiveIndicator.tsx +15 -14
- package/Application/BottomTab/BottomTabBar.tsx +49 -62
- package/Application/BottomTab/BottomTabInset.tsx +8 -4
- package/Application/BottomTab/CurvedContainer.tsx +14 -12
- package/Application/BottomTab/CustomBottomTabItem.tsx +13 -13
- package/Application/BottomTab/DuoBarCompression.tsx +13 -19
- package/Application/BottomTab/DuoRailTabBar.tsx +20 -24
- package/Application/BottomTab/DuoTabBar.tsx +8 -10
- package/Application/BottomTab/TabBarIcon.tsx +15 -29
- package/Application/BottomTab/TabScreen.tsx +1 -5
- package/Application/BottomTab/index.tsx +33 -30
- package/Application/BottomTab/metrics.ts +23 -23
- package/Application/BottomTab/tabItems.ts +1 -1
- package/Application/BottomTab/usePressLift.ts +2 -2
- package/Application/Components/BackgroundImageView.tsx +4 -0
- package/Application/Components/DuoGlassBackground.tsx +5 -4
- package/Application/Components/HeaderAnimated.tsx +40 -12
- package/Application/Components/HeaderBackground.tsx +19 -2
- package/Application/Components/HeaderExtendHeader.tsx +51 -37
- package/Application/Components/HeaderLeft.tsx +5 -18
- package/Application/Components/HeaderRight.styles.ts +15 -13
- package/Application/Components/HeaderRight.tsx +2 -1
- package/Application/Components/HeaderTitle.shared.ts +17 -16
- package/Application/Components/HeaderTitle.tsx +4 -3
- package/Application/Components/HeaderToolkitAction.tsx +29 -57
- package/Application/Components/NavigationButton.tsx +10 -6
- package/Application/Components/SearchHeader.tsx +37 -17
- package/Application/Components/TitleJourney.tsx +2 -2
- package/Application/Components/TitleLocation.tsx +2 -2
- package/Application/Components/TitleUser.tsx +2 -2
- package/Application/Components/useToolkitActions.tsx +17 -32
- package/Application/Localize.ts +7 -0
- package/Application/ModalScreen.tsx +9 -3
- package/Application/Navigation.ts +14 -16
- package/Application/NavigationContainer.tsx +19 -16
- package/Application/Navigator.ts +20 -48
- package/Application/ScaleSizeProvider.tsx +13 -6
- package/Application/StackScreen.tracking.ts +11 -26
- package/Application/StackScreen.tsx +17 -35
- package/Application/TooltipPortal.tsx +12 -5
- package/Application/WidgetContainer.tsx +10 -4
- package/Application/headerLayout.ts +158 -0
- package/Application/index.ts +11 -1
- package/Application/modalLayout.ts +13 -14
- package/Application/navigationOptions.tsx +27 -32
- package/Application/types.header.ts +7 -2
- package/Application/types.ts +7 -0
- package/Badge/Badge.tsx +5 -0
- package/Badge/BadgeDot.tsx +1 -0
- package/Badge/BadgeDotAnimation.tsx +15 -7
- package/Badge/BadgeRibbon.tsx +46 -38
- package/Badge/Shape.tsx +2 -0
- package/Badge/types.ts +2 -2
- package/Button/index.tsx +5 -16
- package/Button/utils.ts +9 -15
- package/CheckBox/index.tsx +4 -0
- package/Consts/theme.ts +10 -10
- package/Context/index.ts +5 -1
- package/Divider/DashDivider.tsx +1 -0
- package/Divider/index.tsx +4 -0
- package/FoundationList/index.tsx +4 -0
- package/Icon/index.tsx +6 -6
- package/Icon/types.ts +1 -1
- package/IconButton/index.tsx +4 -12
- package/Image/index.tsx +9 -7
- package/Input/Input.tsx +8 -9
- package/Input/InputDropDown.tsx +10 -12
- package/Input/InputMoney.tsx +12 -8
- package/Input/InputMoneyView.tsx +14 -7
- package/Input/InputOTP.tsx +35 -33
- package/Input/InputPhoneNumber.tsx +8 -9
- package/Input/InputSearch.tsx +22 -8
- package/Input/InputTextArea.tsx +4 -0
- package/Input/SearchTextTyping.tsx +4 -0
- package/Input/SystemTextInput.tsx +7 -2
- package/Input/TextTyping.tsx +4 -0
- package/Input/common.tsx +26 -12
- package/Input/index.tsx +24 -21
- package/Input/moneyUtils.ts +10 -4
- package/Input/styles.ts +0 -5
- package/Input/utils.ts +14 -12
- package/Layout/Card.tsx +7 -4
- package/Layout/FloatingButton.tsx +4 -0
- package/Layout/Item.tsx +6 -2
- package/Layout/ItemList.tsx +9 -7
- package/Layout/ItemSectionList.tsx +2 -1
- package/Layout/ReservedRegions.tsx +25 -25
- package/Layout/Screen.tsx +59 -58
- package/Layout/Section.tsx +8 -5
- package/Layout/TrackingScope.tsx +1 -0
- package/Layout/screenContent.tsx +4 -2
- package/Layout/screenFooter.tsx +28 -18
- package/Layout/screenHeader.tsx +88 -82
- package/Layout/screenQuickReturn.tsx +17 -20
- package/Layout/screenScroll.ts +4 -7
- package/Layout/screenTypes.ts +13 -4
- package/Layout/types.ts +2 -4
- package/Layout/utils.ts +31 -37
- package/Loader/DotLoader.tsx +4 -0
- package/Loader/Loader.tsx +4 -0
- package/Loader/ProgressBar.tsx +1 -0
- package/Loader/Spinner.tsx +4 -0
- package/Loader/utils.ts +11 -7
- package/Pagination/Dot.tsx +4 -0
- package/Pagination/PaginationDot.tsx +1 -0
- package/Pagination/PaginationNumber.tsx +5 -3
- package/Pagination/PaginationScroll.tsx +5 -0
- package/Pagination/PaginationWhiteDot.tsx +1 -0
- package/Pagination/index.tsx +4 -0
- package/Pagination/types.ts +2 -2
- package/Popup/PopupNotify.tsx +44 -48
- package/Popup/PopupPromotion.tsx +4 -7
- package/Popup/types.ts +4 -4
- package/Popup/utils.ts +4 -0
- package/Radio/index.tsx +4 -0
- package/Skeleton/index.tsx +8 -0
- package/Switch/index.tsx +1 -0
- package/Tag/index.tsx +5 -1
- package/Tag/types.ts +3 -3
- package/Text/index.tsx +14 -3
- package/Text/styles.ts +1 -1
- package/Text/types.ts +1 -6
- package/Text/utils.ts +20 -4
- package/Title/index.tsx +41 -32
- package/ViewBoundary/index.tsx +4 -2
- package/index.ts +0 -6
- package/package.json +37 -37
- package/Application/__tests__/modalLayout.test.ts +0 -128
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { StyleSheet } from 'react-native';
|
|
1
|
+
import { StyleSheet, View } from 'react-native';
|
|
2
|
+
import LinearGradient from 'react-native-linear-gradient';
|
|
2
3
|
import Animated, {
|
|
3
4
|
Extrapolation,
|
|
4
5
|
interpolate,
|
|
@@ -9,6 +10,7 @@ import React from 'react';
|
|
|
9
10
|
import { Image } from '../../Image';
|
|
10
11
|
import { Colors } from '../../Consts';
|
|
11
12
|
import { useNormalizedSharedValue } from '../hooks';
|
|
13
|
+
import { HeaderBarMetrics, useHeaderLayout } from '../headerLayout';
|
|
12
14
|
|
|
13
15
|
const ASPECT_RATIOS: Record<
|
|
14
16
|
NonNullable<HeaderAnimatedProps['aspectRatio']>,
|
|
@@ -19,14 +21,21 @@ const ASPECT_RATIOS: Record<
|
|
|
19
21
|
'1/1': 1 / 1,
|
|
20
22
|
};
|
|
21
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Parallax header image (or `children`): stretches when pulled down and fades out
|
|
26
|
+
* as the content scrolls up. Wide windows keep it at phone size, centered.
|
|
27
|
+
*/
|
|
22
28
|
const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
|
|
23
29
|
animatedValue,
|
|
24
30
|
image,
|
|
25
31
|
useScale = true,
|
|
26
32
|
aspectRatio = '16/9',
|
|
33
|
+
bannerBackgroundColor,
|
|
27
34
|
children,
|
|
28
35
|
}) => {
|
|
29
36
|
const sharedValue = useNormalizedSharedValue(animatedValue);
|
|
37
|
+
const { isWide, bannerWidth } = useHeaderLayout();
|
|
38
|
+
const ratio = ASPECT_RATIOS[aspectRatio];
|
|
30
39
|
const animatedStyle = useAnimatedStyle(() => {
|
|
31
40
|
let scale = 1;
|
|
32
41
|
if (useScale) {
|
|
@@ -55,22 +64,36 @@ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
|
|
|
55
64
|
};
|
|
56
65
|
});
|
|
57
66
|
|
|
67
|
+
const content = children ?? (
|
|
68
|
+
<Image
|
|
69
|
+
source={{
|
|
70
|
+
uri: image,
|
|
71
|
+
}}
|
|
72
|
+
style={styles.full}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (!isWide) {
|
|
77
|
+
return (
|
|
78
|
+
<Animated.View
|
|
79
|
+
style={[styles.container, { aspectRatio: ratio }, animatedStyle]}
|
|
80
|
+
>
|
|
81
|
+
{content}
|
|
82
|
+
</Animated.View>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
58
86
|
return (
|
|
59
87
|
<Animated.View
|
|
60
|
-
style={[
|
|
61
|
-
styles.container,
|
|
62
|
-
{ aspectRatio: ASPECT_RATIOS[aspectRatio] },
|
|
63
|
-
animatedStyle,
|
|
64
|
-
]}
|
|
88
|
+
style={[styles.container, { height: bannerWidth / ratio }, animatedStyle]}
|
|
65
89
|
>
|
|
66
|
-
{
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}}
|
|
71
|
-
style={styles.full}
|
|
90
|
+
{!!bannerBackgroundColor && (
|
|
91
|
+
<LinearGradient
|
|
92
|
+
colors={[bannerBackgroundColor, bannerBackgroundColor + '00']}
|
|
93
|
+
style={StyleSheet.absoluteFill}
|
|
72
94
|
/>
|
|
73
95
|
)}
|
|
96
|
+
<View style={styles.phoneBanner}>{content}</View>
|
|
74
97
|
</Animated.View>
|
|
75
98
|
);
|
|
76
99
|
};
|
|
@@ -86,6 +109,11 @@ const styles = StyleSheet.create({
|
|
|
86
109
|
alignSelf: 'center',
|
|
87
110
|
},
|
|
88
111
|
full: { width: '100%', height: '100%' },
|
|
112
|
+
phoneBanner: {
|
|
113
|
+
width: HeaderBarMetrics.bannerWidth,
|
|
114
|
+
height: '100%',
|
|
115
|
+
alignSelf: 'center',
|
|
116
|
+
},
|
|
89
117
|
});
|
|
90
118
|
|
|
91
119
|
export { HeaderAnimated };
|
|
@@ -8,7 +8,13 @@ import { Colors, Styles } from '../../Consts';
|
|
|
8
8
|
import { Image } from '../../Image';
|
|
9
9
|
import BackgroundImageView from './BackgroundImageView';
|
|
10
10
|
import { useNormalizedSharedValue } from '../hooks';
|
|
11
|
+
import { HeaderBarMetrics, useHeaderLayout } from '../headerLayout';
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Header background: surface and image that fade in on scroll, with an optional
|
|
15
|
+
* gradient (custom or theme) on top, at phone height on wide windows. Outlined
|
|
16
|
+
* when `showBaseLineDebug` is on.
|
|
17
|
+
*/
|
|
12
18
|
const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
13
19
|
animatedValue,
|
|
14
20
|
useGradient = true,
|
|
@@ -21,6 +27,7 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
|
21
27
|
const gradientColor = customGradientColor ?? theme.colors.gradient;
|
|
22
28
|
const headerImage = headerBackground ?? theme.assets?.headerBackground;
|
|
23
29
|
const sharedValue = useNormalizedSharedValue(animatedValue);
|
|
30
|
+
const { isWide } = useHeaderLayout();
|
|
24
31
|
|
|
25
32
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
26
33
|
|
|
@@ -34,14 +41,19 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
|
34
41
|
/>
|
|
35
42
|
<View style={styles.gradientContainer}>
|
|
36
43
|
{useGradient && !!gradientColor && (
|
|
37
|
-
<Animated.View
|
|
44
|
+
<Animated.View
|
|
45
|
+
style={[styles.extendedHeader, isWide && styles.phoneHeight]}
|
|
46
|
+
>
|
|
38
47
|
<LinearGradient
|
|
39
48
|
colors={[gradientColor, gradientColor + '00']}
|
|
40
49
|
style={StyleSheet.absoluteFill}
|
|
41
50
|
>
|
|
42
51
|
{!!headerImage && (
|
|
43
52
|
<Image
|
|
44
|
-
style={
|
|
53
|
+
style={[
|
|
54
|
+
styles.headerBackground,
|
|
55
|
+
isWide && styles.phoneHeight,
|
|
56
|
+
]}
|
|
45
57
|
source={{ uri: headerImage }}
|
|
46
58
|
loading={false}
|
|
47
59
|
/>
|
|
@@ -71,6 +83,11 @@ const styles = StyleSheet.create({
|
|
|
71
83
|
position: 'absolute',
|
|
72
84
|
aspectRatio: 375 / 154,
|
|
73
85
|
},
|
|
86
|
+
// wide windows keep the phone gradient height instead of scaling with the width
|
|
87
|
+
phoneHeight: {
|
|
88
|
+
aspectRatio: undefined,
|
|
89
|
+
height: HeaderBarMetrics.gradientHeight,
|
|
90
|
+
},
|
|
74
91
|
debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
|
|
75
92
|
});
|
|
76
93
|
|
|
@@ -17,12 +17,21 @@ import BackgroundImageView from './BackgroundImageView';
|
|
|
17
17
|
import { type AnimatedCompatValue } from '../utils';
|
|
18
18
|
import { useNormalizedSharedValue } from '../hooks';
|
|
19
19
|
import { useScreenLayout } from '../../Layout';
|
|
20
|
-
import {
|
|
20
|
+
import { HeaderMetrics } from '../../Layout/utils';
|
|
21
|
+
import {
|
|
22
|
+
HeaderBarMetrics,
|
|
23
|
+
type HeaderContentLayout,
|
|
24
|
+
useHeaderLayout,
|
|
25
|
+
} from '../headerLayout';
|
|
21
26
|
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const TOOLKIT_WIDTH =
|
|
27
|
+
const { buttonSize, pillWidth, sidePadding, titleGap } = HeaderBarMetrics;
|
|
28
|
+
const SCREEN_PADDING = sidePadding;
|
|
29
|
+
const TOOLKIT_WIDTH = pillWidth + sidePadding;
|
|
25
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Extended header background: a gradient that collapses on scroll and, with
|
|
33
|
+
* `inputSearchProps`, a full-width search that slides into the bar beside back/toolkit.
|
|
34
|
+
*/
|
|
26
35
|
const HeaderExtendHeader: React.FC<{
|
|
27
36
|
headerType?: HeaderType;
|
|
28
37
|
animatedValue: AnimatedCompatValue;
|
|
@@ -34,6 +43,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
34
43
|
useShadowHeader?: boolean;
|
|
35
44
|
gradientColor?: string;
|
|
36
45
|
headerBackground?: string;
|
|
46
|
+
contentLayout?: HeaderContentLayout;
|
|
37
47
|
}> = ({
|
|
38
48
|
headerType = 'default',
|
|
39
49
|
animatedValue,
|
|
@@ -44,6 +54,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
44
54
|
useShadowHeader: useShadowHeaderProp = true,
|
|
45
55
|
gradientColor: customGradientColor,
|
|
46
56
|
headerBackground: customBackground,
|
|
57
|
+
contentLayout,
|
|
47
58
|
}) => {
|
|
48
59
|
const { theme } = useContext(ApplicationContext);
|
|
49
60
|
const context = useContext<any>(MiniAppContext);
|
|
@@ -51,31 +62,31 @@ const HeaderExtendHeader: React.FC<{
|
|
|
51
62
|
const gradientColor = customGradientColor ?? theme.colors.gradient;
|
|
52
63
|
const headerBackground = customBackground ?? theme.assets?.headerBackground;
|
|
53
64
|
const layout = useScreenLayout();
|
|
65
|
+
const headerLayout = useHeaderLayout(contentLayout);
|
|
66
|
+
// the stretch frame pulls the search in from both bar edges
|
|
67
|
+
const frameShift = headerLayout.frameInset - sidePadding;
|
|
54
68
|
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
const duoToolkitWidth = DuoMetrics.itemPitch * 2 + SCREEN_PADDING;
|
|
58
|
-
const backWidth = isStatusBarRow ? DuoMetrics.controlSize : BACK_WIDTH;
|
|
59
|
-
const toolkitWidth = isStatusBarRow ? duoToolkitWidth : TOOLKIT_WIDTH;
|
|
60
|
-
const defaultLeft = layout.sideBar ? SCREEN_PADDING : backWidth + 20;
|
|
69
|
+
const backLeft = buttonSize + sidePadding + titleGap;
|
|
70
|
+
const defaultLeft = layout.sideBar ? SCREEN_PADDING : backLeft;
|
|
61
71
|
const leftPosition = inputSearchProps?.leftPosition || defaultLeft;
|
|
62
|
-
const defaultRightWidth = layout.sideBar ? 0 :
|
|
72
|
+
const defaultRightWidth = layout.sideBar ? 0 : TOOLKIT_WIDTH;
|
|
63
73
|
const headerRightWidth = customHeaderRightWidth ?? defaultRightWidth;
|
|
64
|
-
const contentLeft = layout.insetLeft + SCREEN_PADDING;
|
|
65
|
-
const contentRight = layout.insetLeft + layout.contentWidth;
|
|
74
|
+
const contentLeft = layout.insetLeft + SCREEN_PADDING + frameShift;
|
|
75
|
+
const contentRight = layout.insetLeft + layout.contentWidth - frameShift;
|
|
66
76
|
// collapsed on the status bar row, the search stays between its clusters
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
|
|
77
|
+
const clearanceLeft = layout.statusBarClearance?.left ?? 0;
|
|
78
|
+
const clearanceRight = layout.statusBarClearance?.right ?? 0;
|
|
79
|
+
const searchLeft = leftPosition + clearanceLeft + frameShift;
|
|
80
|
+
const collapsedLeft = layout.insetLeft + searchLeft;
|
|
81
|
+
const collapsedRight = contentRight - clearanceRight - headerRightWidth;
|
|
82
|
+
const searchWidth = contentRight - contentLeft - SCREEN_PADDING;
|
|
83
|
+
const collapsedSearchWidth = collapsedRight - collapsedLeft - SCREEN_PADDING;
|
|
73
84
|
// a row taller than barHeight (iPhone Duo) centers the collapsed search on the title
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
const titleRowHeight = layout.headerHeight - layout.headerStatusBarHeight;
|
|
86
|
+
const collapsedRaise = (titleRowHeight - HeaderMetrics.barHeight) / 2;
|
|
87
|
+
|
|
88
|
+
// the iPhone Duo side bar keeps the content search size
|
|
89
|
+
const searchSize = layout.sideBar ? 'default' : 'header';
|
|
79
90
|
|
|
80
91
|
let useShadowHeader = useShadowHeaderProp;
|
|
81
92
|
if (inputSearchProps && Platform.OS === 'android') {
|
|
@@ -168,6 +179,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
168
179
|
<Animated.View
|
|
169
180
|
style={[
|
|
170
181
|
styles.extendedHeader,
|
|
182
|
+
headerLayout.isWide && styles.phoneHeight,
|
|
171
183
|
// fade out within the header box, as DuoScrollGradient does
|
|
172
184
|
!!layout.sideBar && styles.fillHeaderBox,
|
|
173
185
|
gradientOpacityStyle,
|
|
@@ -179,7 +191,10 @@ const HeaderExtendHeader: React.FC<{
|
|
|
179
191
|
>
|
|
180
192
|
{!!theme.assets?.headerBackground && (
|
|
181
193
|
<Image
|
|
182
|
-
style={
|
|
194
|
+
style={[
|
|
195
|
+
styles.headerBackground,
|
|
196
|
+
headerLayout.isWide && styles.phoneHeight,
|
|
197
|
+
]}
|
|
183
198
|
source={{ uri: theme.assets?.headerBackground }}
|
|
184
199
|
loading={false}
|
|
185
200
|
/>
|
|
@@ -188,9 +203,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
188
203
|
</Animated.View>
|
|
189
204
|
)}
|
|
190
205
|
</Animated.View>
|
|
191
|
-
<Animated.View
|
|
192
|
-
style={[styles.searchContainer, heightStyle]}
|
|
193
|
-
>
|
|
206
|
+
<Animated.View style={[styles.searchContainer, heightStyle]}>
|
|
194
207
|
<Animated.View
|
|
195
208
|
style={[{ marginVertical: Spacing.S }, searchTranslateStyle]}
|
|
196
209
|
>
|
|
@@ -200,6 +213,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
200
213
|
<InputSearch
|
|
201
214
|
{...inputSearchProps}
|
|
202
215
|
ref={inputSearchRef}
|
|
216
|
+
size={searchSize}
|
|
203
217
|
backgroundColor={'transparent'}
|
|
204
218
|
showButtonText={false}
|
|
205
219
|
/>
|
|
@@ -235,7 +249,10 @@ const HeaderExtendHeader: React.FC<{
|
|
|
235
249
|
>
|
|
236
250
|
{!!headerBackground && (
|
|
237
251
|
<Image
|
|
238
|
-
style={
|
|
252
|
+
style={[
|
|
253
|
+
styles.headerBackground,
|
|
254
|
+
headerLayout.isWide && styles.phoneHeight,
|
|
255
|
+
]}
|
|
239
256
|
source={{ uri: headerBackground }}
|
|
240
257
|
loading={false}
|
|
241
258
|
/>
|
|
@@ -263,6 +280,11 @@ const styles = StyleSheet.create({
|
|
|
263
280
|
position: 'absolute',
|
|
264
281
|
width: '100%',
|
|
265
282
|
},
|
|
283
|
+
// wide windows keep the phone gradient height instead of scaling with the width
|
|
284
|
+
phoneHeight: {
|
|
285
|
+
aspectRatio: undefined,
|
|
286
|
+
height: HeaderBarMetrics.gradientHeight,
|
|
287
|
+
},
|
|
266
288
|
fillHeaderBox: {
|
|
267
289
|
aspectRatio: undefined,
|
|
268
290
|
height: '100%',
|
|
@@ -272,14 +294,6 @@ const styles = StyleSheet.create({
|
|
|
272
294
|
position: 'absolute',
|
|
273
295
|
overflow: 'hidden',
|
|
274
296
|
},
|
|
275
|
-
verifiedDot: {
|
|
276
|
-
width: 4,
|
|
277
|
-
height: 4,
|
|
278
|
-
borderRadius: 2,
|
|
279
|
-
backgroundColor: Colors.green_03,
|
|
280
|
-
position: 'absolute',
|
|
281
|
-
alignSelf: 'center',
|
|
282
|
-
},
|
|
283
297
|
debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
|
|
284
298
|
container: {
|
|
285
299
|
zIndex: 0,
|
|
@@ -6,11 +6,13 @@ import { PopupNotify } from '../../Popup';
|
|
|
6
6
|
import { NavigationButton } from './NavigationButton';
|
|
7
7
|
import { SideBarButton } from './SideBarButton';
|
|
8
8
|
import Animated from 'react-native-reanimated';
|
|
9
|
-
import {
|
|
9
|
+
import { useSideBarItemStyle } from '../../Layout/utils';
|
|
10
10
|
import { useSideBarCounterStyle } from './DuoQuickReturnHeader';
|
|
11
|
+
import { HeaderBarMetrics } from '../headerLayout';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
+
* Header back button, also bound to the Android hardware back. `preventBack`
|
|
15
|
+
* confirms in a popup first; the iPhone Duo side bar uses the 48pt side bar button.
|
|
14
16
|
*/
|
|
15
17
|
const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
16
18
|
tintColor,
|
|
@@ -23,7 +25,6 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
23
25
|
const { navigator } = useContext(ApplicationContext);
|
|
24
26
|
const sideBarStyle = useSideBarItemStyle('left', 0);
|
|
25
27
|
const counterStyle = useSideBarCounterStyle();
|
|
26
|
-
const { statusBarClearance } = useScreenLayout();
|
|
27
28
|
|
|
28
29
|
const goBack = useCallback(() => {
|
|
29
30
|
const canGoBack = navigator?.ref?.current?.canGoBack?.();
|
|
@@ -96,20 +97,6 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
96
97
|
);
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
// on the status bar row the controls keep the side bar size
|
|
100
|
-
if (statusBarClearance) {
|
|
101
|
-
return (
|
|
102
|
-
<View style={styles.headerLeft}>
|
|
103
|
-
<SideBarButton
|
|
104
|
-
accessibilityLabel="btn_navigation_back"
|
|
105
|
-
icon="arrow-back"
|
|
106
|
-
tintColor={tintColor}
|
|
107
|
-
onPress={goBackSafe}
|
|
108
|
-
/>
|
|
109
|
-
</View>
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
100
|
return (
|
|
114
101
|
<View style={styles.headerLeft}>
|
|
115
102
|
<NavigationButton
|
|
@@ -124,7 +111,7 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
124
111
|
|
|
125
112
|
const styles = StyleSheet.create({
|
|
126
113
|
headerLeft: {
|
|
127
|
-
marginLeft:
|
|
114
|
+
marginLeft: HeaderBarMetrics.sidePadding,
|
|
128
115
|
},
|
|
129
116
|
});
|
|
130
117
|
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { Platform, StyleSheet } from 'react-native';
|
|
2
2
|
import { Colors, Spacing } from '../../Consts';
|
|
3
|
+
import { HeaderBarMetrics } from '../headerLayout';
|
|
4
|
+
|
|
5
|
+
const { buttonSize, pillWidth, pillHeight, sidePadding } = HeaderBarMetrics;
|
|
3
6
|
|
|
4
7
|
export const styles = StyleSheet.create({
|
|
5
8
|
navigationButton: {
|
|
6
|
-
height:
|
|
7
|
-
width:
|
|
8
|
-
borderRadius:
|
|
9
|
+
height: buttonSize,
|
|
10
|
+
width: buttonSize,
|
|
11
|
+
borderRadius: buttonSize / 2,
|
|
9
12
|
justifyContent: 'center',
|
|
10
13
|
alignItems: 'center',
|
|
11
14
|
backgroundColor: Colors.black_01 + '99',
|
|
@@ -45,11 +48,11 @@ export const styles = StyleSheet.create({
|
|
|
45
48
|
flexDirection: 'row',
|
|
46
49
|
justifyContent: 'center',
|
|
47
50
|
alignItems: 'center',
|
|
48
|
-
paddingRight:
|
|
51
|
+
paddingRight: sidePadding,
|
|
49
52
|
},
|
|
50
53
|
toolkitContainer: {
|
|
51
|
-
height:
|
|
52
|
-
borderRadius:
|
|
54
|
+
height: pillHeight,
|
|
55
|
+
borderRadius: pillHeight / 2,
|
|
53
56
|
justifyContent: 'center',
|
|
54
57
|
alignItems: 'center',
|
|
55
58
|
flexDirection: 'row',
|
|
@@ -59,7 +62,10 @@ export const styles = StyleSheet.create({
|
|
|
59
62
|
marginLeft: Spacing.S,
|
|
60
63
|
},
|
|
61
64
|
toolkitButton: {
|
|
62
|
-
|
|
65
|
+
flex: 1,
|
|
66
|
+
height: '100%',
|
|
67
|
+
justifyContent: 'center',
|
|
68
|
+
alignItems: 'center',
|
|
63
69
|
},
|
|
64
70
|
divider: {
|
|
65
71
|
width: 0.5,
|
|
@@ -68,10 +74,6 @@ export const styles = StyleSheet.create({
|
|
|
68
74
|
sideBarColumn: {
|
|
69
75
|
gap: Spacing.M,
|
|
70
76
|
},
|
|
71
|
-
sideBarRow: {
|
|
72
|
-
flexDirection: 'row',
|
|
73
|
-
gap: Spacing.M,
|
|
74
|
-
},
|
|
75
77
|
headerLeft: {
|
|
76
78
|
marginLeft: 12,
|
|
77
79
|
},
|
|
@@ -136,9 +138,9 @@ export const styles = StyleSheet.create({
|
|
|
136
138
|
marginRight: Spacing.M,
|
|
137
139
|
},
|
|
138
140
|
toolkitWide: {
|
|
139
|
-
width:
|
|
141
|
+
width: pillWidth,
|
|
140
142
|
},
|
|
141
143
|
toolkitNarrow: {
|
|
142
|
-
width:
|
|
144
|
+
width: buttonSize,
|
|
143
145
|
},
|
|
144
146
|
});
|
|
@@ -9,7 +9,8 @@ import { HeaderToolkitAction } from './HeaderToolkitAction';
|
|
|
9
9
|
import { styles } from './HeaderRight.styles';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Header right slot: a custom `headerRight` render function, the onboarding skip
|
|
13
|
+
* button, or the toolkit (stacked vertically in the floating iPhone Duo side bar).
|
|
13
14
|
*/
|
|
14
15
|
const HeaderRight: React.FC<any> = props => {
|
|
15
16
|
const { translate } = useContext(ApplicationContext);
|
|
@@ -3,28 +3,34 @@ import { MiniAppContext } from '../../Context';
|
|
|
3
3
|
import { Spacing } from '../../Consts';
|
|
4
4
|
import { isWhiteListDesignSystem } from '../utils';
|
|
5
5
|
import { useScreenLayout } from '../../Layout';
|
|
6
|
+
import { HeaderBarMetrics } from '../headerLayout';
|
|
6
7
|
|
|
8
|
+
const { sidePadding, buttonSize, titleGap, clusterWidth } = HeaderBarMetrics;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Header title font: MoMoTrustDisplay for design-system whitelisted mini apps,
|
|
12
|
+
* SFProText otherwise.
|
|
13
|
+
*/
|
|
7
14
|
const useHeaderFontFamily = (): string => {
|
|
8
15
|
const context = useContext<any>(MiniAppContext);
|
|
9
16
|
return isWhiteListDesignSystem(context) ? 'MoMoTrustDisplay' : 'SFProText';
|
|
10
17
|
};
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
|
-
* back button
|
|
14
|
-
|
|
15
|
-
const HEADER_ACTIONS_WIDTH = 172;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* extra width the 48pt back and toolkit take on the iPhone Duo status bar row
|
|
20
|
+
* side paddings, back button, title gaps and right cluster sharing the
|
|
21
|
+
* navigation bar with the title
|
|
19
22
|
*/
|
|
20
|
-
const
|
|
23
|
+
const HEADER_ACTIONS_WIDTH =
|
|
24
|
+
sidePadding * 2 + buttonSize + titleGap * 2 + clusterWidth;
|
|
21
25
|
|
|
22
26
|
/**
|
|
23
|
-
*
|
|
27
|
+
* Max header title width. The iPhone Duo side bar takes back and toolkit out of
|
|
28
|
+
* the bar, so the title gets the content width; otherwise it shares the bar with
|
|
29
|
+
* them, minus the status bar clusters on the iPhone Duo inner portrait row.
|
|
24
30
|
*/
|
|
25
31
|
const useTitleMaxWidth = () => {
|
|
26
|
-
const
|
|
27
|
-
|
|
32
|
+
const layout = useScreenLayout();
|
|
33
|
+
const { width, contentWidth, sideBar, statusBarClearance } = layout;
|
|
28
34
|
let clearance = 0;
|
|
29
35
|
if (statusBarClearance) {
|
|
30
36
|
clearance = statusBarClearance.left + statusBarClearance.right;
|
|
@@ -32,12 +38,7 @@ const useTitleMaxWidth = () => {
|
|
|
32
38
|
if (sideBar) {
|
|
33
39
|
return contentWidth - Spacing.M * 2 - clearance;
|
|
34
40
|
}
|
|
35
|
-
return
|
|
36
|
-
width -
|
|
37
|
-
HEADER_ACTIONS_WIDTH -
|
|
38
|
-
(statusBarClearance ? STATUS_BAR_ROW_ACTIONS_EXTRA : 0) -
|
|
39
|
-
clearance
|
|
40
|
-
);
|
|
41
|
+
return width - HEADER_ACTIONS_WIDTH - clearance;
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
export { useHeaderFontFamily, HEADER_ACTIONS_WIDTH, useTitleMaxWidth };
|
|
@@ -33,7 +33,8 @@ type HeaderTitleExtraProps = {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Default navigation header title. With `animatedValue` its opacity follows the
|
|
37
|
+
* scroll through `interpolate` (0 to 1 over the first 200pt by default).
|
|
37
38
|
*/
|
|
38
39
|
const HeaderTitle: React.FC<
|
|
39
40
|
HeaderTitleExtraProps & { [key: string]: any }
|
|
@@ -100,8 +101,8 @@ const HeaderTitle: React.FC<
|
|
|
100
101
|
};
|
|
101
102
|
|
|
102
103
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
104
|
+
* Header title picked by `type` (user, location or journey) with `data` as its
|
|
105
|
+
* props; an empty view for an unknown type.
|
|
105
106
|
*/
|
|
106
107
|
const TitleCustom: React.FC<any> = ({ type, data, ...props }) => {
|
|
107
108
|
switch (type) {
|