@momo-kits/foundation 0.167.1-beta.7 → 0.167.1-duo.12

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 (46) hide show
  1. package/Application/BottomSheet.tsx +115 -14
  2. package/Application/BottomTab/BottomTabBar.tsx +6 -3
  3. package/Application/BottomTab/DuoBarCompression.tsx +135 -0
  4. package/Application/BottomTab/DuoTabBar.tsx +462 -0
  5. package/Application/BottomTab/index.tsx +155 -134
  6. package/Application/Components/DuoGlassBackground.tsx +179 -0
  7. package/Application/Components/DuoQuickReturnHeader.tsx +42 -0
  8. package/Application/Components/HeaderExtendHeader.tsx +65 -28
  9. package/Application/Components/HeaderLeft.tsx +23 -0
  10. package/Application/Components/HeaderRight.tsx +104 -9
  11. package/Application/Components/HeaderTitle.tsx +47 -21
  12. package/Application/Components/OptionalGlassView.ts +11 -0
  13. package/Application/Components/SearchHeader.tsx +15 -14
  14. package/Application/Components/SideBarButton.tsx +128 -0
  15. package/Application/ModalScreen.tsx +16 -2
  16. package/Application/NavigationContainer.tsx +36 -48
  17. package/Application/Navigator.ts +1 -3
  18. package/Application/StackScreen.tsx +2 -5
  19. package/Application/WidgetContainer.tsx +9 -15
  20. package/Application/device.ts +29 -0
  21. package/Application/types.ts +10 -1
  22. package/Application/utils.tsx +10 -3
  23. package/Consts/index.ts +0 -1
  24. package/Consts/theme.ts +3 -4
  25. package/Input/Input.tsx +3 -4
  26. package/Input/InputMoney.tsx +31 -51
  27. package/Input/InputPhoneNumber.tsx +3 -4
  28. package/Input/InputSearch.tsx +3 -4
  29. package/Input/InputTextArea.tsx +3 -4
  30. package/Layout/Card.tsx +8 -26
  31. package/Layout/FloatingButton.tsx +3 -3
  32. package/Layout/Item.tsx +1 -10
  33. package/Layout/ReservedRegions.tsx +47 -0
  34. package/Layout/Screen.tsx +240 -48
  35. package/Layout/Section.tsx +5 -18
  36. package/Layout/index.ts +4 -4
  37. package/Layout/styles.ts +5 -0
  38. package/Layout/utils.ts +375 -5
  39. package/Popup/PopupNotify.tsx +33 -22
  40. package/Popup/PopupPromotion.tsx +20 -8
  41. package/Popup/utils.ts +32 -0
  42. package/Text/index.tsx +5 -15
  43. package/Text/utils.ts +1 -2
  44. package/package.json +3 -2
  45. package/Consts/designSystemFont.ts +0 -25
  46. package/Layout/GridSystem.tsx +0 -137
@@ -1,6 +1,6 @@
1
1
  import React, { Ref, useContext } from 'react';
2
2
  import LinearGradient from 'react-native-linear-gradient';
3
- import { Dimensions, Platform, StyleSheet, View } from 'react-native';
3
+ import { Platform, StyleSheet, View } from 'react-native';
4
4
  import Animated, {
5
5
  Extrapolation,
6
6
  interpolate,
@@ -14,21 +14,19 @@ 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
- AnimatedCompatValue,
19
- useNormalizedSharedValue,
20
- } from '../utils';
17
+ import { AnimatedCompatValue, useNormalizedSharedValue } from '../utils';
18
+ import { useScreenLayout } from '../../Layout';
19
+ import { HeaderMetrics } from '../../Layout/utils';
21
20
 
22
21
  const SCREEN_PADDING = 12;
23
22
  const BACK_WIDTH = 28;
24
-
25
- const { width: screenWidth } = Dimensions.get('window');
23
+ const TOOLKIT_WIDTH = 73;
26
24
 
27
25
  const HeaderExtendHeader: React.FC<{
28
26
  headerType?: HeaderType;
29
27
  animatedValue: AnimatedCompatValue;
30
28
  heightHeader: number;
31
- headerRightWidth: number;
29
+ headerRightWidth?: number;
32
30
  inputSearchProps?: SearchHeaderProps;
33
31
  inputSearchRef?: Ref<InputRef>;
34
32
  navigation?: Navigation;
@@ -39,7 +37,7 @@ const HeaderExtendHeader: React.FC<{
39
37
  headerType = 'default',
40
38
  animatedValue,
41
39
  heightHeader,
42
- headerRightWidth = 73,
40
+ headerRightWidth: customHeaderRightWidth,
43
41
  inputSearchProps,
44
42
  inputSearchRef,
45
43
  useShadowHeader: useShadowHeaderProp = true,
@@ -51,7 +49,25 @@ const HeaderExtendHeader: React.FC<{
51
49
  const sharedValue = useNormalizedSharedValue(animatedValue);
52
50
  const gradientColor = customGradientColor ?? theme.colors.gradient;
53
51
  const headerBackground = customBackground ?? theme.assets?.headerBackground;
54
- const leftPosition = inputSearchProps?.leftPosition || BACK_WIDTH + 20;
52
+ const layout = useScreenLayout();
53
+
54
+ const leftPosition =
55
+ inputSearchProps?.leftPosition ||
56
+ (layout.sideBar ? SCREEN_PADDING : BACK_WIDTH + 20);
57
+ const headerRightWidth =
58
+ customHeaderRightWidth ?? (layout.sideBar ? 0 : TOOLKIT_WIDTH);
59
+ const contentLeft = layout.insetLeft + SCREEN_PADDING;
60
+ const contentRight = layout.insetLeft + layout.contentWidth;
61
+ const collapsedLeft = layout.insetLeft + leftPosition;
62
+ const searchWidth = layout.contentWidth - SCREEN_PADDING * 2;
63
+ const collapsedSearchWidth =
64
+ contentRight - collapsedLeft - SCREEN_PADDING - headerRightWidth;
65
+ // a row taller than barHeight (iPhone Duo) centers the collapsed search on the title
66
+ const collapsedRaise =
67
+ (layout.headerHeight -
68
+ layout.headerStatusBarHeight -
69
+ HeaderMetrics.barHeight) /
70
+ 2;
55
71
 
56
72
  let useShadowHeader = useShadowHeaderProp;
57
73
  if (inputSearchProps && Platform.OS === 'android') {
@@ -70,7 +86,12 @@ const HeaderExtendHeader: React.FC<{
70
86
  }));
71
87
 
72
88
  const gradientOpacityStyle = useAnimatedStyle(() => ({
73
- opacity: interpolate(sharedValue.value, [0, 52], [1, 0], Extrapolation.CLAMP),
89
+ opacity: interpolate(
90
+ sharedValue.value,
91
+ [0, 52],
92
+ [1, 0],
93
+ Extrapolation.CLAMP,
94
+ ),
74
95
  }));
75
96
 
76
97
  const searchTranslateStyle = useAnimatedStyle(() => ({
@@ -79,7 +100,15 @@ const HeaderExtendHeader: React.FC<{
79
100
  translateX: interpolate(
80
101
  sharedValue.value,
81
102
  [0, 100],
82
- [SCREEN_PADDING, leftPosition],
103
+ [contentLeft, collapsedLeft],
104
+ Extrapolation.CLAMP,
105
+ ),
106
+ },
107
+ {
108
+ translateY: interpolate(
109
+ sharedValue.value,
110
+ [0, 100],
111
+ [0, -collapsedRaise],
83
112
  Extrapolation.CLAMP,
84
113
  ),
85
114
  },
@@ -87,19 +116,19 @@ const HeaderExtendHeader: React.FC<{
87
116
  width: interpolate(
88
117
  sharedValue.value,
89
118
  [0, 100],
90
- [
91
- screenWidth - SCREEN_PADDING * 2,
92
- screenWidth - leftPosition - 12 - headerRightWidth,
93
- ],
119
+ [searchWidth, collapsedSearchWidth],
94
120
  Extrapolation.CLAMP,
95
121
  ),
96
122
  }));
97
123
 
98
124
  const searchBackgroundStyle = useAnimatedStyle(() => {
99
125
  const t = Math.min(Math.max(sharedValue.value / 100, 0), 1);
100
- return { backgroundColor: t === 0
101
- ? theme.colors.background.surface
102
- : theme.colors.background.default };
126
+ return {
127
+ backgroundColor:
128
+ t === 0
129
+ ? theme.colors.background.surface
130
+ : theme.colors.background.default,
131
+ };
103
132
  });
104
133
 
105
134
  const extendedHeightStyle = useAnimatedStyle(() => ({
@@ -124,14 +153,17 @@ const HeaderExtendHeader: React.FC<{
124
153
  <Animated.View
125
154
  style={[
126
155
  styles.headerBox,
127
- headerType === 'extended'
128
- ? heightStyle
129
- : { height: heightHeader },
156
+ headerType === 'extended' ? heightStyle : { height: heightHeader },
130
157
  ]}
131
158
  >
132
159
  {!!gradientColor && (
133
160
  <Animated.View
134
- style={[styles.extendedHeader, gradientOpacityStyle]}
161
+ style={[
162
+ styles.extendedHeader,
163
+ // fade out within the header box, as DuoScrollGradient does
164
+ !!layout.sideBar && styles.fillHeaderBox,
165
+ gradientOpacityStyle,
166
+ ]}
135
167
  >
136
168
  <LinearGradient
137
169
  colors={[gradientColor, gradientColor + '00']}
@@ -162,10 +194,7 @@ const HeaderExtendHeader: React.FC<{
162
194
  style={[{ marginVertical: Spacing.S }, searchTranslateStyle]}
163
195
  >
164
196
  <Animated.View
165
- style={[
166
- { borderRadius: Radius.XL },
167
- searchBackgroundStyle,
168
- ]}
197
+ style={[{ borderRadius: Radius.XL }, searchBackgroundStyle]}
169
198
  >
170
199
  <InputSearch
171
200
  {...inputSearchProps}
@@ -191,7 +220,11 @@ const HeaderExtendHeader: React.FC<{
191
220
  />
192
221
  {!!gradientColor && (
193
222
  <Animated.View
194
- style={[styles.extendedHeader, gradientOpacityStyle, extendedHeightStyle]}
223
+ style={[
224
+ styles.extendedHeader,
225
+ gradientOpacityStyle,
226
+ extendedHeightStyle,
227
+ ]}
195
228
  >
196
229
  <LinearGradient
197
230
  colors={[gradientColor, gradientColor + '00']}
@@ -227,6 +260,10 @@ const styles = StyleSheet.create({
227
260
  position: 'absolute',
228
261
  width: '100%',
229
262
  },
263
+ fillHeaderBox: {
264
+ aspectRatio: undefined,
265
+ height: '100%',
266
+ },
230
267
  headerBox: {
231
268
  width: '100%',
232
269
  position: 'absolute',
@@ -4,6 +4,10 @@ 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 Animated from 'react-native-reanimated';
9
+ import { useSideBarItemStyle } from '../../Layout/utils';
10
+ import { useSideBarCounterStyle } from './DuoQuickReturnHeader';
7
11
 
8
12
  /**
9
13
  * default header left used for nav
@@ -13,9 +17,12 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
13
17
  preventBack,
14
18
  onPressLeftHeader,
15
19
  onBackHandler,
20
+ floating = false,
16
21
  }) => {
17
22
  const context = useContext<any>(MiniAppContext);
18
23
  const { navigator } = useContext(ApplicationContext);
24
+ const sideBarStyle = useSideBarItemStyle('left', 0);
25
+ const counterStyle = useSideBarCounterStyle();
19
26
 
20
27
  const goBack = useCallback(() => {
21
28
  const canGoBack = navigator?.ref?.current?.canGoBack?.();
@@ -72,6 +79,22 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
72
79
  return () => backHandler.remove();
73
80
  }, [goBackSafe]);
74
81
 
82
+ if (floating && sideBarStyle) {
83
+ return (
84
+ <Animated.View
85
+ style={[sideBarStyle, counterStyle]}
86
+ pointerEvents={'box-none'}
87
+ >
88
+ <SideBarButton
89
+ accessibilityLabel="btn_navigation_back"
90
+ icon="arrow-back"
91
+ tintColor={tintColor}
92
+ onPress={goBackSafe}
93
+ />
94
+ </Animated.View>
95
+ );
96
+ }
97
+
75
98
  return (
76
99
  <View style={styles.headerLeft}>
77
100
  <NavigationButton
@@ -13,6 +13,12 @@ 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 Animated from 'react-native-reanimated';
17
+ import { useSideBarItemStyle } from '../../Layout/utils';
18
+ import { useSideBarCounterStyle } from './DuoQuickReturnHeader';
19
+ import { SideBarButton, SideBarGroup, SideBarGroupItem } from './SideBarButton';
20
+ import { useDuoBarCompression } from '../BottomTab/DuoBarCompression';
21
+ import { DuoMetrics } from '../../Layout/utils';
16
22
 
17
23
  const DID_SYNC_NEW_HOME = 'did_sync_new_home';
18
24
 
@@ -21,8 +27,10 @@ const DID_SYNC_NEW_HOME = 'did_sync_new_home';
21
27
  */
22
28
  const HeaderRight: React.FC<any> = props => {
23
29
  const { translate } = useContext(ApplicationContext);
24
- const { headerRight = {} } = props;
30
+ const { headerRight = {}, floating = false } = props;
25
31
  const { useOnBoarding = false, buttonOnBoarding, onPress } = headerRight;
32
+ const sideBarStyle = useSideBarItemStyle('right', 1);
33
+ const counterStyle = useSideBarCounterStyle();
26
34
 
27
35
  if (typeof props.headerRight === 'function') {
28
36
  return props.headerRight(props);
@@ -38,6 +46,21 @@ const HeaderRight: React.FC<any> = props => {
38
46
  );
39
47
  }
40
48
 
49
+ if (floating && sideBarStyle) {
50
+ return (
51
+ <Animated.View
52
+ style={[sideBarStyle, counterStyle]}
53
+ pointerEvents={'box-none'}
54
+ >
55
+ <HeaderToolkitAction
56
+ {...props.headerRight}
57
+ tintColor={props.tintColor}
58
+ vertical
59
+ />
60
+ </Animated.View>
61
+ );
62
+ }
63
+
41
64
  return (
42
65
  <View style={styles.headerRightButton}>
43
66
  <HeaderToolkitAction {...props.headerRight} tintColor={props.tintColor} />
@@ -56,9 +79,12 @@ const HeaderToolkitAction: React.FC<any> = ({
56
79
  useMore = false,
57
80
  tools = [],
58
81
  useCloseIcon = false,
82
+ vertical = false,
59
83
  }) => {
60
84
  const { navigator } = useContext(ApplicationContext);
61
85
  const context = useContext<any>(MiniAppContext);
86
+ const { toolbarCompressed, toolbarHidden, expandToolbar, setToolbarHeight } =
87
+ useDuoBarCompression();
62
88
 
63
89
  const [isFavorite, setIsFavorite] = useState<boolean>(false);
64
90
  const [isLoading, setIsLoading] = useState(false);
@@ -260,6 +286,78 @@ const HeaderToolkitAction: React.FC<any> = ({
260
286
  group?.items?.some?.(tool => tool?.showBadge),
261
287
  );
262
288
 
289
+ const useHelpCenter = context.appId !== 'vn.momo.helpcenter';
290
+ const closeIcon = useCloseIcon
291
+ ? '16_navigation_close_circle'
292
+ : '16_basic_home';
293
+
294
+ const groupCount = useHelpCenter ? 2 : 1;
295
+ // Back slot, the optional shortcut, then the help/home capsule
296
+ const fullToolbarHeight =
297
+ DuoMetrics.controlSize +
298
+ Spacing.M +
299
+ (useShortcut ? DuoMetrics.controlSize + Spacing.M : 0) +
300
+ (groupCount > 1
301
+ ? groupCount * DuoMetrics.itemPitch
302
+ : DuoMetrics.controlSize);
303
+
304
+ useEffect(() => {
305
+ if (vertical) {
306
+ setToolbarHeight?.(fullToolbarHeight);
307
+ }
308
+ }, [vertical, fullToolbarHeight, setToolbarHeight]);
309
+
310
+ // an open tab rail takes this slot for a moment
311
+ if (vertical && toolbarHidden) {
312
+ return null;
313
+ }
314
+
315
+ // HIG "Toolbar compressed": tools fold into one button; tapping it expands the
316
+ // toolbar and compresses the tab bar instead. Not the useMore icon, to tell them apart
317
+ if (vertical && toolbarCompressed) {
318
+ return (
319
+ <SideBarButton
320
+ accessibilityLabel={'btn_navigation_toolbar'}
321
+ icon={'navigation_menu'}
322
+ tintColor={tintColor}
323
+ showBadge={showBadge}
324
+ onPress={expandToolbar}
325
+ />
326
+ );
327
+ }
328
+
329
+ if (vertical) {
330
+ return (
331
+ <View style={styles.sideBarColumn}>
332
+ {useShortcut && (
333
+ <SideBarButton
334
+ disabled={isLoading}
335
+ icon={iconShortcut}
336
+ onPress={shortcutOnPress}
337
+ tintColor={tintColor}
338
+ showBadge={showBadge}
339
+ />
340
+ )}
341
+ <SideBarGroup tintColor={tintColor}>
342
+ {useHelpCenter && (
343
+ <SideBarGroupItem
344
+ accessibilityLabel={'btn_navigation_help_center'}
345
+ icon={'help_center'}
346
+ tintColor={tintColor}
347
+ onPress={onPressHelpCenter}
348
+ />
349
+ )}
350
+ <SideBarGroupItem
351
+ accessibilityLabel={'btn_navigation_close'}
352
+ icon={closeIcon}
353
+ tintColor={tintColor}
354
+ onPress={onClose}
355
+ />
356
+ </SideBarGroup>
357
+ </View>
358
+ );
359
+ }
360
+
263
361
  return (
264
362
  <View style={Styles.row}>
265
363
  {useShortcut && (
@@ -280,7 +378,7 @@ const HeaderToolkitAction: React.FC<any> = ({
280
378
  },
281
379
  ]}
282
380
  >
283
- {context.appId !== 'vn.momo.helpcenter' && (
381
+ {useHelpCenter && (
284
382
  <>
285
383
  <TouchableOpacity
286
384
  accessibilityLabel={'btn_navigation_help_center'}
@@ -299,13 +397,7 @@ const HeaderToolkitAction: React.FC<any> = ({
299
397
  style={styles.toolkitButton}
300
398
  hitSlop={{ top: 7, bottom: 7, left: 0, right: 7 }}
301
399
  >
302
- <Icon
303
- color={tintColor}
304
- source={
305
- useCloseIcon ? '16_navigation_close_circle' : '16_basic_home'
306
- }
307
- size={20}
308
- />
400
+ <Icon color={tintColor} source={closeIcon} size={20} />
309
401
  </TouchableOpacity>
310
402
  </View>
311
403
  </View>
@@ -376,6 +468,9 @@ const styles = StyleSheet.create({
376
468
  width: 0.5,
377
469
  height: 12,
378
470
  },
471
+ sideBarColumn: {
472
+ gap: Spacing.M,
473
+ },
379
474
  headerLeft: {
380
475
  marginLeft: 12,
381
476
  },
@@ -7,13 +7,7 @@ import Animated, {
7
7
  } from 'react-native-reanimated';
8
8
  import { ApplicationContext, MiniAppContext } from '../../Context';
9
9
  import { exportFontFamily, Text, useScaleSize } from '../../Text';
10
- import {
11
- Colors,
12
- Radius,
13
- Spacing,
14
- Styles,
15
- useHeaderFontFamily,
16
- } from '../../Consts';
10
+ import { Colors, Radius, Spacing, Styles } from '../../Consts';
17
11
  import {
18
12
  TitleJourneyProps,
19
13
  TitleLocationProps,
@@ -22,7 +16,33 @@ import {
22
16
  import { Image } from '../../Image';
23
17
  import { Icon } from '../../Icon';
24
18
  import { Skeleton } from '../../Skeleton';
25
- import { AnimatedCompatValue, useNormalizedSharedValue } from '../utils';
19
+ import {
20
+ AnimatedCompatValue,
21
+ isWhiteListDesignSystem,
22
+ useNormalizedSharedValue,
23
+ } from '../utils';
24
+ import { useScreenLayout } from '../../Layout';
25
+
26
+ const useHeaderFontFamily = (): string => {
27
+ const context = useContext<any>(MiniAppContext);
28
+ return isWhiteListDesignSystem(context) ? 'MoMoTrustDisplay' : 'SFProText';
29
+ };
30
+
31
+ /**
32
+ * back button and toolkit sharing the navigation bar with the title
33
+ */
34
+ const HEADER_ACTIONS_WIDTH = 172;
35
+
36
+ /**
37
+ * max title width, the iPhone Duo side bar takes back and toolkit out of the bar
38
+ */
39
+ const useTitleMaxWidth = () => {
40
+ const { width, contentWidth, sideBar } = useScreenLayout();
41
+ if (sideBar) {
42
+ return contentWidth - Spacing.M * 2;
43
+ }
44
+ return width - HEADER_ACTIONS_WIDTH;
45
+ };
26
46
 
27
47
  type HeaderTitleInterpolate = {
28
48
  inputRange: number[];
@@ -44,6 +64,7 @@ const HeaderTitle: React.FC<
44
64
  > = props => {
45
65
  const context = useContext<any>(MiniAppContext);
46
66
  const headerFontFamily = useHeaderFontFamily();
67
+ const maxWidth = useTitleMaxWidth();
47
68
 
48
69
  const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
49
70
 
@@ -74,7 +95,7 @@ const HeaderTitle: React.FC<
74
95
  style={[
75
96
  {
76
97
  justifyContent: 'center',
77
- maxWidth: Dimensions.get('window').width - 172,
98
+ maxWidth,
78
99
  },
79
100
  showBaseLineDebug && styles.debugBaseLine,
80
101
  ]}
@@ -138,7 +159,7 @@ const TitleUser: React.FC<TitleUserProps> = ({
138
159
  }) => {
139
160
  const { theme } = useContext(ApplicationContext);
140
161
  const headerFontFamily = useHeaderFontFamily();
141
- const maxWidth = Dimensions.get('window').width - 172;
162
+ const maxWidth = useTitleMaxWidth();
142
163
  const getShortName = (name: string) => {
143
164
  const words = name.split(' ');
144
165
  const lastTwoWords = words.slice(-2);
@@ -421,7 +442,7 @@ const TitleLocation: React.FC<TitleLocationProps> = ({
421
442
  isLoading,
422
443
  }) => {
423
444
  const headerFontFamily = useHeaderFontFamily();
424
- const maxWidth = Dimensions.get('window').width - 172;
445
+ const maxWidth = useTitleMaxWidth();
425
446
  const renderShimmer = () => {
426
447
  return (
427
448
  <View style={Styles.flex}>
@@ -457,9 +478,12 @@ const TitleLocation: React.FC<TitleLocationProps> = ({
457
478
  </Text>
458
479
  )}
459
480
  <View style={Styles.row}>
460
- <Text typography="action_xs_bold"
481
+ <Text
482
+ typography="action_xs_bold"
461
483
  fontFamily={headerFontFamily}
462
- color={tintColor} numberOfLines={1}>
484
+ color={tintColor}
485
+ numberOfLines={1}
486
+ >
463
487
  {location}
464
488
  </Text>
465
489
  <Icon
@@ -487,10 +511,14 @@ const TitleJourney: React.FC<TitleJourneyProps> = ({
487
511
  isLoading,
488
512
  }) => {
489
513
  const headerFontFamily = useHeaderFontFamily();
490
- const { width } = Dimensions.get('screen');
491
- const maxWidth = Dimensions.get('window').width - 172;
492
- const startWidth = width * 0.25;
493
- const endWidth = width * 0.75 - 212;
514
+ const maxWidth = useTitleMaxWidth();
515
+ const { sideBar } = useScreenLayout();
516
+ // journey split is tuned against the whole bar width
517
+ const barWidth = sideBar
518
+ ? maxWidth + HEADER_ACTIONS_WIDTH
519
+ : Dimensions.get('screen').width;
520
+ const startWidth = barWidth * 0.25;
521
+ const endWidth = barWidth * 0.75 - 212;
494
522
  const renderShimmer = () => {
495
523
  return (
496
524
  <View style={Styles.flex}>
@@ -522,8 +550,7 @@ const TitleJourney: React.FC<TitleJourneyProps> = ({
522
550
  style={{ maxWidth: startWidth }}
523
551
  color={tintColor}
524
552
  numberOfLines={1}
525
- fontFamily={headerFontFamily}
526
-
553
+ fontFamily={headerFontFamily}
527
554
  >
528
555
  {start}
529
556
  </Text>
@@ -539,8 +566,7 @@ const TitleJourney: React.FC<TitleJourneyProps> = ({
539
566
  typography="action_xs_bold"
540
567
  color={tintColor}
541
568
  numberOfLines={1}
542
- fontFamily={headerFontFamily}
543
-
569
+ fontFamily={headerFontFamily}
544
570
  >
545
571
  {end}
546
572
  </Text>
@@ -0,0 +1,11 @@
1
+ import type React from 'react';
2
+
3
+ // native glass is optional so apps without @momo-kits/glass-view still bundle
4
+ let GlassView: React.ComponentType<any> | undefined;
5
+ try {
6
+ GlassView = require('@momo-kits/glass-view').GlassView;
7
+ } catch {
8
+ GlassView = undefined;
9
+ }
10
+
11
+ export { GlassView };
@@ -1,17 +1,13 @@
1
1
  import { Colors, Radius, Spacing, Styles } from '../../Consts';
2
2
  import { InputRef, InputSearch } from '../../Input';
3
- import {
4
- Dimensions,
5
- StyleSheet,
6
- TouchableOpacity,
7
- View,
8
- } from 'react-native';
3
+ import { StyleSheet, TouchableOpacity, View } from 'react-native';
9
4
  import Animated, { useAnimatedStyle } from 'react-native-reanimated';
10
5
  import React, { useContext } from 'react';
11
6
  import { SearchHeaderProps } from '../types';
12
7
  import { ApplicationContext, MiniAppContext } from '../../Context';
13
8
  import { Text } from '../../Text';
14
9
  import { useNormalizedSharedValue } from '../utils';
10
+ import { useScreenLayout } from '../../Layout';
15
11
 
16
12
  const SearchHeader = React.forwardRef<InputRef, SearchHeaderProps>(
17
13
  (
@@ -27,18 +23,25 @@ const SearchHeader = React.forwardRef<InputRef, SearchHeaderProps>(
27
23
  const { theme, navigator } = useContext(ApplicationContext);
28
24
  const context = useContext<any>(MiniAppContext);
29
25
  const BACK_WIDTH = 28;
30
- const { width: screenWidth } = Dimensions.get('window');
26
+ const layout = useScreenLayout();
31
27
 
32
28
  const sharedValue = useNormalizedSharedValue(animatedValue);
33
29
  const leftPosition = props?.leftPosition ?? BACK_WIDTH + 20;
34
30
  const headerRightWidth = props?.headerRightWidth ?? 73;
35
31
 
32
+ // iPhone Duo side bar holds back: the search shares the content width with the buttons only
33
+ let searchMaxWidth = layout.width - leftPosition - 12 - headerRightWidth;
34
+ if (layout.sideBar) {
35
+ searchMaxWidth = layout.contentWidth - Spacing.M * 2 - headerRightWidth;
36
+ }
37
+
36
38
  const backgroundStyle = useAnimatedStyle(() => {
37
39
  const t = Math.min(Math.max(sharedValue.value / 100, 0), 1);
38
40
  return {
39
- backgroundColor: t === 0
40
- ? theme.colors.background.surface
41
- : theme.colors.background.default,
41
+ backgroundColor:
42
+ t === 0
43
+ ? theme.colors.background.surface
44
+ : theme.colors.background.default,
42
45
  };
43
46
  });
44
47
 
@@ -77,13 +80,11 @@ const SearchHeader = React.forwardRef<InputRef, SearchHeaderProps>(
77
80
  style={[
78
81
  Styles.flex,
79
82
  renderButtons && {
80
- maxWidth: screenWidth - leftPosition - 12 - headerRightWidth,
83
+ maxWidth: searchMaxWidth,
81
84
  },
82
85
  ]}
83
86
  >
84
- <Animated.View
85
- style={[{ borderRadius: Radius.XL }, backgroundStyle]}
86
- >
87
+ <Animated.View style={[{ borderRadius: Radius.XL }, backgroundStyle]}>
87
88
  <InputSearch
88
89
  ref={ref}
89
90
  {...props}