@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.
Files changed (131) hide show
  1. package/Application/BottomSheet.hooks.ts +8 -8
  2. package/Application/BottomSheet.parts.tsx +44 -34
  3. package/Application/BottomSheet.tsx +35 -26
  4. package/Application/BottomTab/ActiveIndicator.tsx +15 -14
  5. package/Application/BottomTab/BottomTabBar.tsx +49 -62
  6. package/Application/BottomTab/BottomTabInset.tsx +8 -4
  7. package/Application/BottomTab/CurvedContainer.tsx +14 -12
  8. package/Application/BottomTab/CustomBottomTabItem.tsx +13 -13
  9. package/Application/BottomTab/DuoBarCompression.tsx +13 -19
  10. package/Application/BottomTab/DuoRailTabBar.tsx +20 -24
  11. package/Application/BottomTab/DuoTabBar.tsx +8 -10
  12. package/Application/BottomTab/TabBarIcon.tsx +15 -29
  13. package/Application/BottomTab/TabScreen.tsx +1 -5
  14. package/Application/BottomTab/index.tsx +33 -30
  15. package/Application/BottomTab/metrics.ts +23 -23
  16. package/Application/BottomTab/tabItems.ts +1 -1
  17. package/Application/BottomTab/usePressLift.ts +2 -2
  18. package/Application/Components/BackgroundImageView.tsx +4 -0
  19. package/Application/Components/DuoGlassBackground.tsx +5 -4
  20. package/Application/Components/HeaderAnimated.tsx +40 -12
  21. package/Application/Components/HeaderBackground.tsx +19 -2
  22. package/Application/Components/HeaderExtendHeader.tsx +51 -37
  23. package/Application/Components/HeaderLeft.tsx +5 -18
  24. package/Application/Components/HeaderRight.styles.ts +15 -13
  25. package/Application/Components/HeaderRight.tsx +2 -1
  26. package/Application/Components/HeaderTitle.shared.ts +17 -16
  27. package/Application/Components/HeaderTitle.tsx +4 -3
  28. package/Application/Components/HeaderToolkitAction.tsx +29 -57
  29. package/Application/Components/NavigationButton.tsx +10 -6
  30. package/Application/Components/SearchHeader.tsx +37 -17
  31. package/Application/Components/TitleJourney.tsx +2 -2
  32. package/Application/Components/TitleLocation.tsx +2 -2
  33. package/Application/Components/TitleUser.tsx +2 -2
  34. package/Application/Components/useToolkitActions.tsx +17 -32
  35. package/Application/Localize.ts +7 -0
  36. package/Application/ModalScreen.tsx +9 -3
  37. package/Application/Navigation.ts +14 -16
  38. package/Application/NavigationContainer.tsx +19 -16
  39. package/Application/Navigator.ts +20 -48
  40. package/Application/ScaleSizeProvider.tsx +13 -6
  41. package/Application/StackScreen.tracking.ts +11 -26
  42. package/Application/StackScreen.tsx +17 -35
  43. package/Application/TooltipPortal.tsx +12 -5
  44. package/Application/WidgetContainer.tsx +10 -4
  45. package/Application/headerLayout.ts +158 -0
  46. package/Application/index.ts +11 -1
  47. package/Application/modalLayout.ts +13 -14
  48. package/Application/navigationOptions.tsx +27 -32
  49. package/Application/types.header.ts +7 -2
  50. package/Application/types.ts +7 -0
  51. package/Badge/Badge.tsx +5 -0
  52. package/Badge/BadgeDot.tsx +1 -0
  53. package/Badge/BadgeDotAnimation.tsx +15 -7
  54. package/Badge/BadgeRibbon.tsx +46 -38
  55. package/Badge/Shape.tsx +2 -0
  56. package/Badge/types.ts +2 -2
  57. package/Button/index.tsx +5 -16
  58. package/Button/utils.ts +9 -15
  59. package/CheckBox/index.tsx +4 -0
  60. package/Consts/theme.ts +10 -10
  61. package/Context/index.ts +5 -1
  62. package/Divider/DashDivider.tsx +1 -0
  63. package/Divider/index.tsx +4 -0
  64. package/FoundationList/index.tsx +4 -0
  65. package/Icon/index.tsx +6 -6
  66. package/Icon/types.ts +1 -1
  67. package/IconButton/index.tsx +4 -12
  68. package/Image/index.tsx +9 -7
  69. package/Input/Input.tsx +8 -9
  70. package/Input/InputDropDown.tsx +10 -12
  71. package/Input/InputMoney.tsx +12 -8
  72. package/Input/InputMoneyView.tsx +14 -7
  73. package/Input/InputOTP.tsx +35 -33
  74. package/Input/InputPhoneNumber.tsx +8 -9
  75. package/Input/InputSearch.tsx +22 -8
  76. package/Input/InputTextArea.tsx +4 -0
  77. package/Input/SearchTextTyping.tsx +4 -0
  78. package/Input/SystemTextInput.tsx +7 -2
  79. package/Input/TextTyping.tsx +4 -0
  80. package/Input/common.tsx +26 -12
  81. package/Input/index.tsx +24 -21
  82. package/Input/moneyUtils.ts +10 -4
  83. package/Input/styles.ts +0 -5
  84. package/Input/utils.ts +14 -12
  85. package/Layout/Card.tsx +7 -4
  86. package/Layout/FloatingButton.tsx +4 -0
  87. package/Layout/Item.tsx +6 -2
  88. package/Layout/ItemList.tsx +9 -7
  89. package/Layout/ItemSectionList.tsx +2 -1
  90. package/Layout/ReservedRegions.tsx +25 -25
  91. package/Layout/Screen.tsx +59 -58
  92. package/Layout/Section.tsx +8 -5
  93. package/Layout/TrackingScope.tsx +1 -0
  94. package/Layout/screenContent.tsx +4 -2
  95. package/Layout/screenFooter.tsx +28 -18
  96. package/Layout/screenHeader.tsx +88 -82
  97. package/Layout/screenQuickReturn.tsx +17 -20
  98. package/Layout/screenScroll.ts +4 -7
  99. package/Layout/screenTypes.ts +13 -4
  100. package/Layout/types.ts +2 -4
  101. package/Layout/utils.ts +31 -37
  102. package/Loader/DotLoader.tsx +4 -0
  103. package/Loader/Loader.tsx +4 -0
  104. package/Loader/ProgressBar.tsx +1 -0
  105. package/Loader/Spinner.tsx +4 -0
  106. package/Loader/utils.ts +11 -7
  107. package/Pagination/Dot.tsx +4 -0
  108. package/Pagination/PaginationDot.tsx +1 -0
  109. package/Pagination/PaginationNumber.tsx +5 -3
  110. package/Pagination/PaginationScroll.tsx +5 -0
  111. package/Pagination/PaginationWhiteDot.tsx +1 -0
  112. package/Pagination/index.tsx +4 -0
  113. package/Pagination/types.ts +2 -2
  114. package/Popup/PopupNotify.tsx +44 -48
  115. package/Popup/PopupPromotion.tsx +4 -7
  116. package/Popup/types.ts +4 -4
  117. package/Popup/utils.ts +4 -0
  118. package/Radio/index.tsx +4 -0
  119. package/Skeleton/index.tsx +8 -0
  120. package/Switch/index.tsx +1 -0
  121. package/Tag/index.tsx +5 -1
  122. package/Tag/types.ts +3 -3
  123. package/Text/index.tsx +14 -3
  124. package/Text/styles.ts +1 -1
  125. package/Text/types.ts +1 -6
  126. package/Text/utils.ts +20 -4
  127. package/Title/index.tsx +41 -32
  128. package/ViewBoundary/index.tsx +4 -2
  129. package/index.ts +0 -6
  130. package/package.json +37 -37
  131. 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
- {children ?? (
67
- <Image
68
- source={{
69
- uri: image,
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 style={styles.extendedHeader}>
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={styles.headerBackground}
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 { DuoMetrics, HeaderMetrics } from '../../Layout/utils';
20
+ import { HeaderMetrics } from '../../Layout/utils';
21
+ import {
22
+ HeaderBarMetrics,
23
+ type HeaderContentLayout,
24
+ useHeaderLayout,
25
+ } from '../headerLayout';
21
26
 
22
- const SCREEN_PADDING = 12;
23
- const BACK_WIDTH = 28;
24
- const TOOLKIT_WIDTH = 73;
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
- // the iPhone Duo status bar row keeps side bar sized back and toolkit
56
- const isStatusBarRow = !!layout.statusBarClearance;
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 : toolkitWidth;
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 collapsedLeft =
68
- layout.insetLeft + leftPosition + (layout.statusBarClearance?.left ?? 0);
69
- const collapsedRight = contentRight - (layout.statusBarClearance?.right ?? 0);
70
- const searchWidth = layout.contentWidth - SCREEN_PADDING * 2;
71
- const collapsedSearchWidth =
72
- collapsedRight - collapsedLeft - SCREEN_PADDING - headerRightWidth;
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 collapsedRaise =
75
- (layout.headerHeight -
76
- layout.headerStatusBarHeight -
77
- HeaderMetrics.barHeight) /
78
- 2;
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={styles.headerBackground}
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={styles.headerBackground}
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 { useScreenLayout, useSideBarItemStyle } from '../../Layout/utils';
9
+ import { useSideBarItemStyle } from '../../Layout/utils';
10
10
  import { useSideBarCounterStyle } from './DuoQuickReturnHeader';
11
+ import { HeaderBarMetrics } from '../headerLayout';
11
12
 
12
13
  /**
13
- * default header left used for nav
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: 12,
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: 28,
7
- width: 28,
8
- borderRadius: 14,
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: Spacing.M,
51
+ paddingRight: sidePadding,
49
52
  },
50
53
  toolkitContainer: {
51
- height: 28,
52
- borderRadius: 14,
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
- padding: 4,
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: 65,
141
+ width: pillWidth,
140
142
  },
141
143
  toolkitNarrow: {
142
- width: 28,
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
- * main component for header right
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 and toolkit sharing the navigation bar with the title
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 STATUS_BAR_ROW_ACTIONS_EXTRA = 55;
23
+ const HEADER_ACTIONS_WIDTH =
24
+ sidePadding * 2 + buttonSize + titleGap * 2 + clusterWidth;
21
25
 
22
26
  /**
23
- * max title width, the iPhone Duo side bar takes back and toolkit out of the bar
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 { width, contentWidth, sideBar, statusBarClearance } =
27
- useScreenLayout();
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
- * default header title used for nav
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
- * Title custom for header
104
- * @constructor
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) {