@momo-kits/foundation 0.169.7-beta.4 → 0.169.7-beta.6
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 +40 -37
- 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 +56 -34
- package/Application/Components/HeaderLeft.tsx +4 -2
- package/Application/Components/HeaderRight.styles.ts +15 -9
- package/Application/Components/HeaderRight.tsx +2 -1
- package/Application/Components/HeaderTitle.shared.ts +19 -12
- package/Application/Components/HeaderTitle.tsx +4 -3
- package/Application/Components/HeaderToolkitAction.tsx +28 -22
- package/Application/Components/NavigationButton.tsx +10 -6
- package/Application/Components/SearchHeader.tsx +41 -15
- 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 +10 -10
- package/Application/Navigation.ts +14 -16
- package/Application/NavigationContainer.tsx +19 -18
- package/Application/Navigator.ts +20 -48
- package/Application/ScaleSizeProvider.tsx +13 -6
- package/Application/StackScreen.tracking.ts +11 -33
- package/Application/StackScreen.tsx +19 -54
- 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 +1 -1
- package/Application/KitAdoption/AdoptionBadge.tsx +0 -119
- package/Application/KitAdoption/AdoptionProbe.tsx +0 -166
- package/Application/KitAdoption/AdoptionStore.ts +0 -80
- package/Application/KitAdoption/Authorship/utils.ts +0 -137
- package/Application/KitAdoption/Slots/utils.ts +0 -68
- package/Application/KitAdoption/constants.ts +0 -120
- package/Application/KitAdoption/index.ts +0 -12
- package/Application/KitAdoption/styles.ts +0 -55
- package/Application/KitAdoption/types.ts +0 -61
- package/Application/KitAdoption/utils.ts +0 -376
- package/Application/__tests__/KitAdoption.integration.test.tsx +0 -253
- package/Application/__tests__/KitAdoption.test.ts +0 -283
- package/Application/__tests__/KitAdoptionAuthorship.test.ts +0 -132
- package/Application/__tests__/KitAdoptionStore.test.ts +0 -110
- package/Application/__tests__/KitAdoptionStructural.test.ts +0 -193
- 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
|
|
|
@@ -18,11 +18,20 @@ import { type AnimatedCompatValue } from '../utils';
|
|
|
18
18
|
import { useNormalizedSharedValue } from '../hooks';
|
|
19
19
|
import { useScreenLayout } from '../../Layout';
|
|
20
20
|
import { DuoMetrics, 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,39 @@ 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
|
|
|
69
|
+
let backWidth = buttonSize;
|
|
70
|
+
let toolkitWidth = TOOLKIT_WIDTH;
|
|
55
71
|
// the iPhone Duo status bar row keeps side bar sized back and toolkit
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
72
|
+
if (layout.statusBarClearance) {
|
|
73
|
+
backWidth = DuoMetrics.controlSize;
|
|
74
|
+
toolkitWidth = DuoMetrics.itemPitch * 2 + SCREEN_PADDING;
|
|
75
|
+
}
|
|
76
|
+
const backLeft = backWidth + sidePadding + titleGap;
|
|
77
|
+
const defaultLeft = layout.sideBar ? SCREEN_PADDING : backLeft;
|
|
61
78
|
const leftPosition = inputSearchProps?.leftPosition || defaultLeft;
|
|
62
79
|
const defaultRightWidth = layout.sideBar ? 0 : toolkitWidth;
|
|
63
80
|
const headerRightWidth = customHeaderRightWidth ?? defaultRightWidth;
|
|
64
|
-
const contentLeft = layout.insetLeft + SCREEN_PADDING;
|
|
65
|
-
const contentRight = layout.insetLeft + layout.contentWidth;
|
|
81
|
+
const contentLeft = layout.insetLeft + SCREEN_PADDING + frameShift;
|
|
82
|
+
const contentRight = layout.insetLeft + layout.contentWidth - frameShift;
|
|
66
83
|
// collapsed on the status bar row, the search stays between its clusters
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
|
|
84
|
+
const clearanceLeft = layout.statusBarClearance?.left ?? 0;
|
|
85
|
+
const clearanceRight = layout.statusBarClearance?.right ?? 0;
|
|
86
|
+
const searchLeft = leftPosition + clearanceLeft + frameShift;
|
|
87
|
+
const collapsedLeft = layout.insetLeft + searchLeft;
|
|
88
|
+
const collapsedRight = contentRight - clearanceRight - headerRightWidth;
|
|
89
|
+
const searchWidth = contentRight - contentLeft - SCREEN_PADDING;
|
|
90
|
+
const collapsedSearchWidth = collapsedRight - collapsedLeft - SCREEN_PADDING;
|
|
73
91
|
// a row taller than barHeight (iPhone Duo) centers the collapsed search on the title
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
92
|
+
const titleRowHeight = layout.headerHeight - layout.headerStatusBarHeight;
|
|
93
|
+
const collapsedRaise = (titleRowHeight - HeaderMetrics.barHeight) / 2;
|
|
94
|
+
|
|
95
|
+
// the iPhone Duo side bar and status bar row keep the content search size
|
|
96
|
+
const isDuoRow = !!layout.sideBar || !!layout.statusBarClearance;
|
|
97
|
+
const searchSize = isDuoRow ? 'default' : 'header';
|
|
79
98
|
|
|
80
99
|
let useShadowHeader = useShadowHeaderProp;
|
|
81
100
|
if (inputSearchProps && Platform.OS === 'android') {
|
|
@@ -168,6 +187,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
168
187
|
<Animated.View
|
|
169
188
|
style={[
|
|
170
189
|
styles.extendedHeader,
|
|
190
|
+
headerLayout.isWide && styles.phoneHeight,
|
|
171
191
|
// fade out within the header box, as DuoScrollGradient does
|
|
172
192
|
!!layout.sideBar && styles.fillHeaderBox,
|
|
173
193
|
gradientOpacityStyle,
|
|
@@ -179,7 +199,10 @@ const HeaderExtendHeader: React.FC<{
|
|
|
179
199
|
>
|
|
180
200
|
{!!theme.assets?.headerBackground && (
|
|
181
201
|
<Image
|
|
182
|
-
style={
|
|
202
|
+
style={[
|
|
203
|
+
styles.headerBackground,
|
|
204
|
+
headerLayout.isWide && styles.phoneHeight,
|
|
205
|
+
]}
|
|
183
206
|
source={{ uri: theme.assets?.headerBackground }}
|
|
184
207
|
loading={false}
|
|
185
208
|
/>
|
|
@@ -188,9 +211,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
188
211
|
</Animated.View>
|
|
189
212
|
)}
|
|
190
213
|
</Animated.View>
|
|
191
|
-
<Animated.View
|
|
192
|
-
style={[styles.searchContainer, heightStyle]}
|
|
193
|
-
>
|
|
214
|
+
<Animated.View style={[styles.searchContainer, heightStyle]}>
|
|
194
215
|
<Animated.View
|
|
195
216
|
style={[{ marginVertical: Spacing.S }, searchTranslateStyle]}
|
|
196
217
|
>
|
|
@@ -200,6 +221,7 @@ const HeaderExtendHeader: React.FC<{
|
|
|
200
221
|
<InputSearch
|
|
201
222
|
{...inputSearchProps}
|
|
202
223
|
ref={inputSearchRef}
|
|
224
|
+
size={searchSize}
|
|
203
225
|
backgroundColor={'transparent'}
|
|
204
226
|
showButtonText={false}
|
|
205
227
|
/>
|
|
@@ -235,7 +257,10 @@ const HeaderExtendHeader: React.FC<{
|
|
|
235
257
|
>
|
|
236
258
|
{!!headerBackground && (
|
|
237
259
|
<Image
|
|
238
|
-
style={
|
|
260
|
+
style={[
|
|
261
|
+
styles.headerBackground,
|
|
262
|
+
headerLayout.isWide && styles.phoneHeight,
|
|
263
|
+
]}
|
|
239
264
|
source={{ uri: headerBackground }}
|
|
240
265
|
loading={false}
|
|
241
266
|
/>
|
|
@@ -263,6 +288,11 @@ const styles = StyleSheet.create({
|
|
|
263
288
|
position: 'absolute',
|
|
264
289
|
width: '100%',
|
|
265
290
|
},
|
|
291
|
+
// wide windows keep the phone gradient height instead of scaling with the width
|
|
292
|
+
phoneHeight: {
|
|
293
|
+
aspectRatio: undefined,
|
|
294
|
+
height: HeaderBarMetrics.gradientHeight,
|
|
295
|
+
},
|
|
266
296
|
fillHeaderBox: {
|
|
267
297
|
aspectRatio: undefined,
|
|
268
298
|
height: '100%',
|
|
@@ -272,14 +302,6 @@ const styles = StyleSheet.create({
|
|
|
272
302
|
position: 'absolute',
|
|
273
303
|
overflow: 'hidden',
|
|
274
304
|
},
|
|
275
|
-
verifiedDot: {
|
|
276
|
-
width: 4,
|
|
277
|
-
height: 4,
|
|
278
|
-
borderRadius: 2,
|
|
279
|
-
backgroundColor: Colors.green_03,
|
|
280
|
-
position: 'absolute',
|
|
281
|
-
alignSelf: 'center',
|
|
282
|
-
},
|
|
283
305
|
debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
|
|
284
306
|
container: {
|
|
285
307
|
zIndex: 0,
|
|
@@ -8,9 +8,11 @@ import { SideBarButton } from './SideBarButton';
|
|
|
8
8
|
import Animated from 'react-native-reanimated';
|
|
9
9
|
import { useScreenLayout, 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 layouts use the 48pt side bar button.
|
|
14
16
|
*/
|
|
15
17
|
const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
16
18
|
tintColor,
|
|
@@ -124,7 +126,7 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
124
126
|
|
|
125
127
|
const styles = StyleSheet.create({
|
|
126
128
|
headerLeft: {
|
|
127
|
-
marginLeft:
|
|
129
|
+
marginLeft: HeaderBarMetrics.sidePadding,
|
|
128
130
|
},
|
|
129
131
|
});
|
|
130
132
|
|
|
@@ -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,
|
|
@@ -136,9 +142,9 @@ export const styles = StyleSheet.create({
|
|
|
136
142
|
marginRight: Spacing.M,
|
|
137
143
|
},
|
|
138
144
|
toolkitWide: {
|
|
139
|
-
width:
|
|
145
|
+
width: pillWidth,
|
|
140
146
|
},
|
|
141
147
|
toolkitNarrow: {
|
|
142
|
-
width:
|
|
148
|
+
width: buttonSize,
|
|
143
149
|
},
|
|
144
150
|
});
|
|
@@ -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,41 +3,48 @@ 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
|
|
20
|
+
* side paddings, back button, title gaps and right cluster sharing the
|
|
21
|
+
* navigation bar with the title
|
|
14
22
|
*/
|
|
15
|
-
const HEADER_ACTIONS_WIDTH =
|
|
23
|
+
const HEADER_ACTIONS_WIDTH =
|
|
24
|
+
sidePadding * 2 + buttonSize + titleGap * 2 + clusterWidth;
|
|
16
25
|
|
|
17
26
|
/**
|
|
18
27
|
* extra width the 48pt back and toolkit take on the iPhone Duo status bar row
|
|
19
28
|
*/
|
|
20
|
-
const STATUS_BAR_ROW_ACTIONS_EXTRA =
|
|
29
|
+
const STATUS_BAR_ROW_ACTIONS_EXTRA = 43;
|
|
21
30
|
|
|
22
31
|
/**
|
|
23
|
-
*
|
|
32
|
+
* Max header title width. The iPhone Duo side bar takes back and toolkit out of
|
|
33
|
+
* the bar, so the title gets the content width; otherwise it shares the bar with them.
|
|
24
34
|
*/
|
|
25
35
|
const useTitleMaxWidth = () => {
|
|
26
|
-
const
|
|
27
|
-
|
|
36
|
+
const layout = useScreenLayout();
|
|
37
|
+
const { width, contentWidth, sideBar, statusBarClearance } = layout;
|
|
28
38
|
let clearance = 0;
|
|
39
|
+
let rowActionsExtra = 0;
|
|
29
40
|
if (statusBarClearance) {
|
|
30
41
|
clearance = statusBarClearance.left + statusBarClearance.right;
|
|
42
|
+
rowActionsExtra = STATUS_BAR_ROW_ACTIONS_EXTRA;
|
|
31
43
|
}
|
|
32
44
|
if (sideBar) {
|
|
33
45
|
return contentWidth - Spacing.M * 2 - clearance;
|
|
34
46
|
}
|
|
35
|
-
return
|
|
36
|
-
width -
|
|
37
|
-
HEADER_ACTIONS_WIDTH -
|
|
38
|
-
(statusBarClearance ? STATUS_BAR_ROW_ACTIONS_EXTRA : 0) -
|
|
39
|
-
clearance
|
|
40
|
-
);
|
|
47
|
+
return width - HEADER_ACTIONS_WIDTH - rowActionsExtra - clearance;
|
|
41
48
|
};
|
|
42
49
|
|
|
43
50
|
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) {
|
|
@@ -9,12 +9,14 @@ import { SideBarButton, SideBarGroup, SideBarGroupItem } from './SideBarButton';
|
|
|
9
9
|
import { useDuoBarCompression } from '../BottomTab/DuoBarCompression';
|
|
10
10
|
import { styles } from './HeaderRight.styles';
|
|
11
11
|
import { useToolkitActions } from './useToolkitActions';
|
|
12
|
+
import { HeaderBarMetrics } from '../headerLayout';
|
|
12
13
|
|
|
13
14
|
const CLOSE_ICON = '16_navigation_close_circle';
|
|
14
15
|
const HOME_ICON = '16_basic_home';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
* Header toolkit
|
|
18
|
+
* Header toolkit: optional shortcut plus the help center / close capsule. When
|
|
19
|
+
* `vertical` (iPhone Duo side bar) it reports its height and may fold into one button.
|
|
18
20
|
*/
|
|
19
21
|
const HeaderToolkitAction: React.FC<any> = ({
|
|
20
22
|
tintColor,
|
|
@@ -27,8 +29,9 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
27
29
|
vertical = false,
|
|
28
30
|
}) => {
|
|
29
31
|
const context = useContext<any>(MiniAppContext);
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
+
const compression = useDuoBarCompression();
|
|
33
|
+
const { toolbarCompressed, toolbarHidden } = compression;
|
|
34
|
+
const { expandToolbar, setToolbarHeight } = compression;
|
|
32
35
|
const { statusBarClearance } = useScreenLayout();
|
|
33
36
|
const {
|
|
34
37
|
isLoading,
|
|
@@ -56,18 +59,22 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
56
59
|
|
|
57
60
|
const useHelpCenter = context.appId !== 'vn.momo.helpcenter';
|
|
58
61
|
const closeIcon = useCloseIcon ? CLOSE_ICON : HOME_ICON;
|
|
62
|
+
let toolkitWidthStyle: ViewStyle = styles.toolkitNarrow;
|
|
63
|
+
if (useHelpCenter) {
|
|
64
|
+
toolkitWidthStyle = styles.toolkitWide;
|
|
65
|
+
}
|
|
59
66
|
|
|
60
67
|
const groupCount = useHelpCenter ? 2 : 1;
|
|
61
68
|
let capsuleHeight = DuoMetrics.controlSize;
|
|
62
69
|
if (groupCount > 1) {
|
|
63
70
|
capsuleHeight = groupCount * DuoMetrics.itemPitch;
|
|
64
71
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Spacing.M
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
const backSlotHeight = DuoMetrics.controlSize + Spacing.M;
|
|
73
|
+
let shortcutHeight = 0;
|
|
74
|
+
if (useShortcut) {
|
|
75
|
+
shortcutHeight = DuoMetrics.controlSize + Spacing.M;
|
|
76
|
+
}
|
|
77
|
+
const fullToolbarHeight = backSlotHeight + shortcutHeight + capsuleHeight;
|
|
71
78
|
|
|
72
79
|
useEffect(() => {
|
|
73
80
|
if (vertical) {
|
|
@@ -80,8 +87,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
80
87
|
return null;
|
|
81
88
|
}
|
|
82
89
|
|
|
83
|
-
// HIG "Toolbar compressed":
|
|
84
|
-
// toolbar and compresses the tab bar instead. Not the useMore icon, to tell them apart
|
|
90
|
+
// HIG "Toolbar compressed": a menu icon (not the "more" one) that expands the toolbar
|
|
85
91
|
if (vertical && toolbarCompressed) {
|
|
86
92
|
return (
|
|
87
93
|
<SideBarButton
|
|
@@ -170,15 +176,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
170
176
|
showBadge={showBadge}
|
|
171
177
|
/>
|
|
172
178
|
)}
|
|
173
|
-
<View
|
|
174
|
-
style={[
|
|
175
|
-
styles.toolkitContainer,
|
|
176
|
-
buttonStyle,
|
|
177
|
-
context.appId !== 'vn.momo.helpcenter'
|
|
178
|
-
? styles.toolkitWide
|
|
179
|
-
: styles.toolkitNarrow,
|
|
180
|
-
]}
|
|
181
|
-
>
|
|
179
|
+
<View style={[styles.toolkitContainer, buttonStyle, toolkitWidthStyle]}>
|
|
182
180
|
{useHelpCenter && (
|
|
183
181
|
<>
|
|
184
182
|
<TouchableOpacity
|
|
@@ -187,7 +185,11 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
187
185
|
onPress={onPressHelpCenter}
|
|
188
186
|
hitSlop={{ top: 7, bottom: 7, left: 7, right: 0 }}
|
|
189
187
|
>
|
|
190
|
-
<Icon
|
|
188
|
+
<Icon
|
|
189
|
+
color={tintColor}
|
|
190
|
+
source={'help_center'}
|
|
191
|
+
size={HeaderBarMetrics.iconSize}
|
|
192
|
+
/>
|
|
191
193
|
</TouchableOpacity>
|
|
192
194
|
<View style={[styles.divider, { backgroundColor: tintColor }]} />
|
|
193
195
|
</>
|
|
@@ -198,7 +200,11 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
198
200
|
style={styles.toolkitButton}
|
|
199
201
|
hitSlop={{ top: 7, bottom: 7, left: 0, right: 7 }}
|
|
200
202
|
>
|
|
201
|
-
<Icon
|
|
203
|
+
<Icon
|
|
204
|
+
color={tintColor}
|
|
205
|
+
source={closeIcon}
|
|
206
|
+
size={HeaderBarMetrics.iconSize}
|
|
207
|
+
/>
|
|
202
208
|
</TouchableOpacity>
|
|
203
209
|
</View>
|
|
204
210
|
</View>
|
|
@@ -5,9 +5,13 @@ import { StyleSheet, TouchableOpacity, View, ViewStyle } from 'react-native';
|
|
|
5
5
|
import { Colors, Spacing } from '../../Consts';
|
|
6
6
|
import { Icon } from '../../Icon';
|
|
7
7
|
import { BadgeDot } from '../../Badge';
|
|
8
|
+
import { HeaderBarMetrics } from '../headerLayout';
|
|
9
|
+
|
|
10
|
+
const { buttonSize, iconSize } = HeaderBarMetrics;
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
|
-
*
|
|
13
|
+
* Round 32pt icon button of the header (back, shortcut) with an optional badge
|
|
14
|
+
* dot; switches to a dark fill under a white tint so the icon stays readable.
|
|
11
15
|
*/
|
|
12
16
|
const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
13
17
|
icon,
|
|
@@ -34,7 +38,7 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
34
38
|
<Icon
|
|
35
39
|
source={icon}
|
|
36
40
|
color={tintColor ?? theme.colors.text.default}
|
|
37
|
-
size={
|
|
41
|
+
size={iconSize}
|
|
38
42
|
/>
|
|
39
43
|
</TouchableOpacity>
|
|
40
44
|
{showBadge && <BadgeDot size={'small'} style={styles.badgeDot} />}
|
|
@@ -44,12 +48,12 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
44
48
|
|
|
45
49
|
const styles = StyleSheet.create({
|
|
46
50
|
container: {
|
|
47
|
-
width:
|
|
51
|
+
width: buttonSize,
|
|
48
52
|
},
|
|
49
53
|
navigationButton: {
|
|
50
|
-
height:
|
|
51
|
-
width:
|
|
52
|
-
borderRadius:
|
|
54
|
+
height: buttonSize,
|
|
55
|
+
width: buttonSize,
|
|
56
|
+
borderRadius: buttonSize / 2,
|
|
53
57
|
justifyContent: 'center',
|
|
54
58
|
alignItems: 'center',
|
|
55
59
|
backgroundColor: Colors.black_01 + '99',
|