@momo-kits/foundation 0.168.1-rn862.1 → 0.169.1

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 (100) hide show
  1. package/Application/BottomSheet.hooks.ts +215 -0
  2. package/Application/BottomSheet.parts.tsx +231 -0
  3. package/Application/BottomSheet.styles.ts +59 -0
  4. package/Application/BottomSheet.tsx +114 -265
  5. package/Application/BottomTab/BottomTabBar.styles.ts +60 -0
  6. package/Application/BottomTab/BottomTabBar.tsx +7 -60
  7. package/Application/BottomTab/CustomBottomTabItem.tsx +5 -5
  8. package/Application/BottomTab/DuoRailTabBar.tsx +149 -0
  9. package/Application/BottomTab/DuoTabBar.parts.tsx +202 -0
  10. package/Application/BottomTab/DuoTabBar.styles.ts +123 -0
  11. package/Application/BottomTab/DuoTabBar.tsx +78 -464
  12. package/Application/BottomTab/TabScreen.tsx +177 -0
  13. package/Application/BottomTab/badge.ts +41 -0
  14. package/Application/BottomTab/hooks.ts +358 -0
  15. package/Application/BottomTab/index.styles.ts +30 -0
  16. package/Application/BottomTab/index.tsx +9 -236
  17. package/Application/Components/DuoGlassBackground.tsx +7 -9
  18. package/Application/Components/HeaderAnimated.tsx +1 -1
  19. package/Application/Components/HeaderBackground.tsx +1 -1
  20. package/Application/Components/HeaderExtendHeader.tsx +17 -11
  21. package/Application/Components/HeaderRight.styles.ts +144 -0
  22. package/Application/Components/HeaderRight.tsx +6 -528
  23. package/Application/Components/HeaderTitle.shared.ts +43 -0
  24. package/Application/Components/HeaderTitle.styles.ts +125 -0
  25. package/Application/Components/HeaderTitle.tsx +12 -576
  26. package/Application/Components/HeaderToolkitAction.tsx +208 -0
  27. package/Application/Components/NavigationButton.tsx +9 -6
  28. package/Application/Components/SearchHeader.tsx +1 -1
  29. package/Application/Components/SwipeBackHaptic.tsx +95 -0
  30. package/Application/Components/TitleJourney.tsx +110 -0
  31. package/Application/Components/TitleLocation.tsx +73 -0
  32. package/Application/Components/TitleUser.tsx +304 -0
  33. package/Application/Components/useToolkitActions.tsx +233 -0
  34. package/Application/ModalScreen.tsx +14 -10
  35. package/Application/Navigation.ts +1 -1
  36. package/Application/NavigationContainer.tsx +7 -8
  37. package/Application/StackScreen.tracking.ts +158 -0
  38. package/Application/StackScreen.tsx +10 -137
  39. package/Application/WidgetContainer.tsx +10 -3
  40. package/Application/hooks.ts +137 -0
  41. package/Application/index.ts +3 -1
  42. package/Application/navigationOptions.tsx +217 -0
  43. package/Application/types.header.ts +116 -0
  44. package/Application/types.tabs.ts +43 -0
  45. package/Application/types.theme.ts +87 -0
  46. package/Application/types.ts +12 -244
  47. package/Application/utils.ts +143 -0
  48. package/Badge/BadgeRibbon.tsx +3 -3
  49. package/Badge/styles.ts +2 -0
  50. package/Button/index.tsx +16 -136
  51. package/Button/styles.ts +1 -1
  52. package/Button/utils.ts +139 -0
  53. package/CheckBox/index.tsx +1 -6
  54. package/Divider/DashDivider.tsx +10 -11
  55. package/Divider/index.tsx +18 -8
  56. package/Image/index.tsx +1 -46
  57. package/Input/Input.tsx +7 -8
  58. package/Input/InputDropDown.tsx +3 -4
  59. package/Input/InputMoney.tsx +38 -164
  60. package/Input/InputMoneyView.tsx +187 -0
  61. package/Input/InputOTP.tsx +1 -1
  62. package/Input/InputPhoneNumber.tsx +5 -1
  63. package/Input/InputSearch.tsx +2 -108
  64. package/Input/InputTextArea.tsx +1 -5
  65. package/Input/SearchTextTyping.tsx +104 -0
  66. package/Input/common.tsx +4 -4
  67. package/Input/moneyUtils.ts +17 -0
  68. package/Input/styles.ts +26 -2
  69. package/Layout/FloatingButton.tsx +22 -21
  70. package/Layout/Screen.tsx +62 -667
  71. package/Layout/Section.tsx +1 -2
  72. package/Layout/index.ts +8 -4
  73. package/Layout/layoutMetrics.ts +58 -0
  74. package/Layout/layoutTypes.ts +86 -0
  75. package/Layout/screenContent.tsx +90 -0
  76. package/Layout/screenFooter.tsx +53 -0
  77. package/Layout/screenHeader.tsx +315 -0
  78. package/Layout/screenQuickReturn.tsx +67 -0
  79. package/Layout/screenScroll.ts +110 -0
  80. package/Layout/screenTypes.ts +134 -0
  81. package/Layout/styles.ts +2 -0
  82. package/Layout/utils.ts +10 -144
  83. package/Loader/DotLoader.tsx +7 -3
  84. package/Loader/ProgressBar.tsx +2 -6
  85. package/Loader/Spinner.tsx +7 -3
  86. package/Loader/styles.ts +4 -0
  87. package/Popup/PopupNotify.tsx +47 -11
  88. package/Popup/types.ts +7 -0
  89. package/Popup/utils.ts +61 -14
  90. package/Radio/index.tsx +2 -10
  91. package/Radio/styles.ts +6 -0
  92. package/Skeleton/index.tsx +1 -9
  93. package/Skeleton/styles.ts +1 -0
  94. package/Tag/index.tsx +3 -3
  95. package/Text/index.tsx +11 -2
  96. package/Title/index.tsx +2 -9
  97. package/Title/styles.ts +6 -0
  98. package/package.json +20 -22
  99. package/Application/device.ts +0 -29
  100. package/Application/utils.tsx +0 -497
@@ -6,64 +6,61 @@ import React, {
6
6
  useState,
7
7
  } from 'react';
8
8
  import {
9
- BackHandler,
10
- Dimensions,
11
- Keyboard,
12
9
  KeyboardAvoidingView,
13
- KeyboardEvent,
14
- LayoutAnimation,
15
10
  Modal,
16
11
  PanResponder,
17
12
  Platform,
18
13
  Pressable,
14
+ StatusBar,
19
15
  StyleSheet,
20
- TouchableOpacity,
21
- useWindowDimensions,
22
16
  View,
23
17
  } from 'react-native';
24
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
25
18
  import { ApplicationContext, MiniAppContext } from '../Context';
26
19
  import { BottomSheetParams } from './types';
27
- import { Colors, Radius, Spacing, Styles } from '../Consts';
28
- import { Text } from '../Text';
29
- import { Icon } from '../Icon';
30
- import { useHeaderHeight } from '@react-navigation/elements';
20
+ import { Spacing } from '../Consts';
31
21
  import Animated, {
32
22
  Easing,
33
- Extrapolation,
34
- interpolate,
35
- useAnimatedStyle,
36
23
  useSharedValue,
37
24
  withSpring,
38
25
  withTiming,
39
26
  } from 'react-native-reanimated';
40
27
  import { scheduleOnRN } from 'react-native-worklets';
41
- import layoutStyles from '../Layout/styles';
42
- import { getDuoTopInset, isIPhoneDuo } from './device';
43
-
44
- // iPhone Duo inner display: center the sheet instead of spanning the width
45
- const DUO_REGULAR_MIN_WIDTH = 600;
28
+ import { DuoMetrics } from '../Layout/utils';
29
+ import { DUO_ORIENTATIONS, styles } from './BottomSheet.styles';
30
+ import {
31
+ useBottomSheetLayout,
32
+ useDuoKeyboardLift,
33
+ useSheetDismiss,
34
+ useSheetAnimatedStyles,
35
+ } from './BottomSheet.hooks';
36
+ import {
37
+ getSheetStyle,
38
+ renderSheetFooter,
39
+ renderSheetHeader,
40
+ renderSheetSideColumn,
41
+ } from './BottomSheet.parts';
46
42
 
47
43
  const BottomSheet: React.FC<BottomSheetParams> = props => {
48
44
  const { theme, navigator } = useContext(ApplicationContext);
49
45
  const context = useContext<any>(MiniAppContext);
50
- const windowSize = useWindowDimensions();
51
- const isDuo = isIPhoneDuo();
52
- const isDuoCentered = isDuo && windowSize.width >= DUO_REGULAR_MIN_WIDTH;
53
- const isPortrait = windowSize.height > windowSize.width;
54
- // 'screen' is the outer display on iPhone Duo, even when unfolded
55
- const screenHeight = Dimensions.get('screen').height;
56
- const heightDevice = isDuo ? windowSize.height : screenHeight;
46
+ const {
47
+ windowSize,
48
+ isDuo,
49
+ isDuoCentered,
50
+ isDuoFloating,
51
+ sideColumn,
52
+ sideColumnWidth,
53
+ hasSideColumn,
54
+ heightDevice,
55
+ insets,
56
+ topGap,
57
+ sideInsetLeft,
58
+ sideInsetRight,
59
+ indicatorShift,
60
+ bottomInset,
61
+ keyboardOffset,
62
+ } = useBottomSheetLayout();
57
63
  const action = useRef<undefined | string>(undefined);
58
- const insets = useSafeAreaInsets();
59
- const heightHeader = useHeaderHeight();
60
- const topGap = Math.max(
61
- getDuoTopInset(insets, windowSize.width, windowSize.height),
62
- Spacing.XL,
63
- );
64
- const isIOS = Platform.OS === 'ios';
65
- const bottomInset = isIOS ? Math.min(insets.bottom, 21) : insets.bottom;
66
- const keyboardOffset = heightHeader - bottomInset;
67
64
 
68
65
  const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
69
66
 
@@ -83,43 +80,16 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
83
80
  }: BottomSheetParams = props.route.params;
84
81
 
85
82
  const translateY = useSharedValue(heightDevice);
86
- const [keyboardLift, setKeyboardLift] = useState(0);
87
-
88
- // KeyboardAvoidingView lifts the whole sheet past the top on iPhone Duo,
89
- // so lift it here and shrink maxHeight by the same amount instead
90
- useEffect(() => {
91
- if (!isDuo || !useKeyboardAvoidingView) {
92
- return;
93
- }
94
- const onKeyboardChange = (e: KeyboardEvent) => {
95
- const overlap = windowSize.height - e.endCoordinates.screenY;
96
- const lift = Math.max(
97
- overlap - bottomInset - (keyboardVerticalOffset ?? 0),
98
- 0,
99
- );
100
- if (e.duration) {
101
- LayoutAnimation.configureNext({
102
- duration: e.duration,
103
- update: {
104
- duration: e.duration,
105
- type: LayoutAnimation.Types[e.easing] || 'keyboard',
106
- },
107
- });
108
- }
109
- setKeyboardLift(lift);
110
- };
111
- const subscriptions = [
112
- Keyboard.addListener('keyboardWillChangeFrame', onKeyboardChange),
113
- Keyboard.addListener('keyboardWillHide', onKeyboardChange),
114
- ];
115
- return () => subscriptions.forEach(sub => sub.remove());
116
- }, [
117
- bottomInset,
83
+ const onDismissRef = useRef(props.route.params?.onDismiss);
84
+ onDismissRef.current = props.route.params?.onDismiss;
85
+ const [sheetTop, setSheetTop] = useState(windowSize.height);
86
+ const keyboardLift = useDuoKeyboardLift(
118
87
  isDuo,
119
- keyboardVerticalOffset,
120
88
  useKeyboardAvoidingView,
121
89
  windowSize.height,
122
- ]);
90
+ bottomInset,
91
+ keyboardVerticalOffset,
92
+ );
123
93
 
124
94
  const openAnimation = useCallback(() => {
125
95
  translateY.value = withTiming(0, {
@@ -179,143 +149,71 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
179
149
  }
180
150
 
181
151
  /**
182
- * emit dismiss event
152
+ * emit dismiss event, once: folding or rotating iPhone Duo changes the
153
+ * window height while the sheet stays open
183
154
  */
184
155
  useEffect(() => {
185
- translateY.value = heightDevice;
186
156
  openAnimation();
187
157
  return () => {
188
- props.route.params?.onDismiss?.(action.current);
158
+ onDismissRef.current?.(action.current);
189
159
  };
190
- }, [heightDevice, openAnimation, props.route.params, translateY]);
160
+ }, [openAnimation]);
191
161
 
192
- /**
193
- * handler dismiss
194
- */
195
- const onDismiss = useCallback(
196
- (force = false, callback?: () => void) => {
197
- if (barrierDismissible && !force) {
198
- return;
199
- }
200
- closeAnimation(() => {
201
- navigator?.pop();
202
- scheduleOnRN(() => {
203
- callback?.();
204
- });
205
- });
206
- },
207
- [barrierDismissible, closeAnimation, navigator],
208
- );
162
+ const { onDismiss, onRequestClose, onPressBack, onPressClose } =
163
+ useSheetDismiss({
164
+ barrierDismissible,
165
+ closeAnimation,
166
+ navigator,
167
+ leftOptions,
168
+ action,
169
+ });
209
170
 
210
- /**
211
- * on request close
212
- */
213
- const onRequestClose = useCallback(
214
- (callback?: () => void) => {
215
- onDismiss(true, callback);
216
- },
217
- [onDismiss],
218
- );
171
+ const showBack = !!leftOptions?.onPressIconLeft;
172
+ const iconBack = leftOptions?.iconLeft ?? 'ic_back';
173
+ const sideColumnCount = showBack ? 2 : 1;
174
+ const sideColumnHeight =
175
+ sideColumnCount * DuoMetrics.controlSize +
176
+ (sideColumnCount - 1) * Spacing.M;
177
+ const coversStatusBar = !!sideColumn && sheetTop < sideColumn.top;
219
178
 
220
179
  useEffect(() => {
221
- const backHandler = BackHandler.addEventListener(
222
- 'hardwareBackPress',
223
- () => {
224
- onDismiss();
225
- return true;
226
- },
227
- );
228
- return () => backHandler.remove();
229
- }, [barrierDismissible, onDismiss]);
230
-
231
- /**
232
- * render header
233
- */
234
- const renderHeader = useCallback(() => {
235
- return (
236
- <View {...panResponder.panHandlers}>
237
- <View style={{ height: 16 }}>
238
- <View style={styles.indicator} />
239
- </View>
240
- <View
241
- style={[
242
- styles.header,
243
- useDivider && {
244
- borderBottomColor: theme.colors.border.default,
245
- borderBottomWidth: 1,
246
- },
247
- ]}
248
- >
249
- {leftOptions?.onPressIconLeft ? (
250
- <TouchableOpacity
251
- style={styles.iconButton}
252
- onPress={() => {
253
- onDismiss(true, leftOptions.onPressIconLeft);
254
- }}
255
- >
256
- <Icon source={leftOptions.iconLeft ?? 'ic_back'} />
257
- </TouchableOpacity>
258
- ) : null}
180
+ if (!coversStatusBar) {
181
+ return;
182
+ }
183
+ const entry = StatusBar.pushStackEntry({
184
+ barStyle: theme.dark ? 'light-content' : 'dark-content',
185
+ animated: true,
186
+ });
187
+ return () => StatusBar.popStackEntry(entry);
188
+ }, [coversStatusBar, theme.dark]);
259
189
 
260
- {options.header ? (
261
- <View style={Styles.flex}>{options.header}</View>
262
- ) : (
263
- <>
264
- {!leftOptions ? <View style={styles.iconButton} /> : null}
265
- <Text
266
- style={[Styles.flex, { textAlign: 'center' }]}
267
- numberOfLines={1}
268
- typography="header_default_bold"
269
- >
270
- {options.title ?? ''}
271
- </Text>
272
- </>
273
- )}
274
- <TouchableOpacity
275
- style={styles.iconButton}
276
- onPress={() => {
277
- action.current = 'icon_close';
278
- onDismiss(true);
279
- }}
280
- >
281
- <Icon source="navigation_close" />
282
- </TouchableOpacity>
283
- </View>
284
- </View>
285
- );
286
- }, [
287
- onDismiss,
288
- leftOptions,
289
- options.header,
290
- options.title,
291
- panResponder.panHandlers,
292
- theme.colors.border.default,
190
+ const partsParams = {
191
+ panHandlers: panResponder.panHandlers,
192
+ indicatorShift,
293
193
  useDivider,
294
- ]);
295
-
296
- const animatedStyle = useAnimatedStyle(() => {
297
- return {
298
- transform: [{ translateY: translateY.value }],
299
- };
300
- });
194
+ theme,
195
+ hasSideColumn,
196
+ showBack,
197
+ onPressBack,
198
+ onPressClose,
199
+ iconBack,
200
+ options,
201
+ leftOptions,
202
+ sideColumn,
203
+ windowHeight: windowSize.height,
204
+ sheetTop,
205
+ sideColumnHeight,
206
+ sideColumnWidth,
207
+ };
301
208
 
302
- const animatedOverlayStyle = useAnimatedStyle(() => {
303
- return {
304
- opacity: interpolate(
305
- translateY.value,
306
- [0, heightDevice],
307
- [1, 0],
308
- Extrapolation.CLAMP,
309
- ),
310
- };
311
- });
209
+ const { animatedStyle, animatedOverlayStyle } = useSheetAnimatedStyles(
210
+ translateY,
211
+ heightDevice,
212
+ );
312
213
 
313
- // landscape side buttons span the full height, so inset the content; in
314
- // portrait the side status bar only covers the top corner
315
- const needsSideInset = isDuo && !isDuoCentered && !isPortrait;
316
- const sideInsetStyle = needsSideInset && {
317
- paddingLeft: insets.left,
318
- paddingRight: insets.right,
214
+ const sideInsetStyle = isDuoFloating && {
215
+ paddingLeft: sideInsetLeft,
216
+ paddingRight: sideInsetRight,
319
217
  };
320
218
 
321
219
  const screen = (
@@ -333,8 +231,9 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
333
231
  onRequestClose={() => {
334
232
  onDismiss();
335
233
  }}
336
- style={StyleSheet.absoluteFill}
234
+ style={StyleSheet.absoluteFillObject}
337
235
  isModalKit={true}
236
+ supportedOrientations={isDuo ? DUO_ORIENTATIONS : undefined}
338
237
  >
339
238
  <KeyboardAvoidingView
340
239
  behavior={Platform.select({
@@ -347,7 +246,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
347
246
  style={styles.container}
348
247
  >
349
248
  <Pressable
350
- style={StyleSheet.absoluteFill}
249
+ style={StyleSheet.absoluteFillObject}
351
250
  onPress={() => {
352
251
  action.current = 'touch';
353
252
  onDismiss();
@@ -357,56 +256,39 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
357
256
  </Pressable>
358
257
 
359
258
  <Animated.View
259
+ onLayout={
260
+ isDuoFloating ? e => setSheetTop(e.nativeEvent.layout.y) : undefined
261
+ }
360
262
  style={[
361
263
  animatedStyle,
362
- {
264
+ getSheetStyle({
363
265
  backgroundColor,
364
- borderTopLeftRadius: Radius.M,
365
- borderTopRightRadius: Radius.M,
366
- overflow: 'hidden',
367
- },
368
- isDuo && {
369
- maxHeight: windowSize.height - topGap - keyboardLift,
370
- marginBottom: keyboardLift,
371
- },
372
- isDuoCentered && {
373
- // keeps the portrait width in landscape, like system sheets
374
- width: Math.min(
375
- Math.min(windowSize.width, windowSize.height) - Spacing.L * 2,
376
- windowSize.width -
377
- Math.max(insets.left, insets.right, Spacing.L) * 2,
378
- ),
379
- alignSelf: 'center',
380
- },
381
- showBaseLineDebug && styles.debugBaseLine,
266
+ isDuo,
267
+ isDuoFloating,
268
+ isDuoCentered,
269
+ windowSize,
270
+ topGap,
271
+ keyboardLift,
272
+ sideColumn,
273
+ sideColumnHeight,
274
+ insets,
275
+ showBaseLineDebug,
276
+ }),
382
277
  ]}
383
278
  >
384
279
  {isDuo ? (
385
280
  // content shrinks so a tall sheet keeps its header and footer
386
281
  <View style={[styles.shrink, sideInsetStyle]}>
387
- {renderHeader()}
282
+ {renderSheetHeader(partsParams)}
388
283
  <View style={styles.shrink}>{screen}</View>
389
284
  </View>
390
285
  ) : (
391
286
  <>
392
- {renderHeader()}
287
+ {renderSheetHeader(partsParams)}
393
288
  {screen}
394
289
  </>
395
290
  )}
396
- {footerComponent && (
397
- <View
398
- style={[
399
- layoutStyles.shadow,
400
- {
401
- paddingBottom: Spacing.S,
402
- backgroundColor: theme.colors.background.surface,
403
- },
404
- sideInsetStyle,
405
- ]}
406
- >
407
- {footerComponent}
408
- </View>
409
- )}
291
+ {renderSheetFooter({ footerComponent, theme, sideInsetStyle })}
410
292
  {useBottomInset && (
411
293
  <View
412
294
  style={{
@@ -415,44 +297,11 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
415
297
  }}
416
298
  />
417
299
  )}
300
+ {renderSheetSideColumn(partsParams)}
418
301
  </Animated.View>
419
302
  </KeyboardAvoidingView>
420
303
  </Container>
421
304
  );
422
305
  };
423
306
 
424
- const styles = StyleSheet.create({
425
- container: {
426
- flex: 1,
427
- justifyContent: 'flex-end',
428
- },
429
- overlay: {
430
- flex: 1,
431
- backgroundColor: 'rgba(0, 0, 0, 0.6)',
432
- },
433
- indicator: {
434
- width: 40,
435
- height: 4,
436
- borderRadius: Radius.S,
437
- backgroundColor: Colors.black_06,
438
- position: 'absolute',
439
- alignSelf: 'center',
440
- top: Spacing.S,
441
- },
442
- header: {
443
- height: 56,
444
- flexDirection: 'row',
445
- alignItems: 'center',
446
- },
447
- iconButton: {
448
- width: 24,
449
- height: 24,
450
- alignItems: 'center',
451
- justifyContent: 'center',
452
- marginHorizontal: Spacing.M,
453
- },
454
- shrink: { flexShrink: 1 },
455
- debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
456
- });
457
-
458
307
  export default BottomSheet;
@@ -0,0 +1,60 @@
1
+ import { Platform, StyleSheet } from 'react-native';
2
+ import { Colors, Radius } from '../../Consts';
3
+
4
+ export const styles = StyleSheet.create({
5
+ content: {
6
+ flex: 1,
7
+ flexDirection: 'row',
8
+ },
9
+ tabBar: {
10
+ left: 0,
11
+ right: 0,
12
+ bottom: 0,
13
+ borderTopWidth: StyleSheet.hairlineWidth,
14
+ elevation: 8,
15
+ },
16
+ tabBarFloatingButton: {
17
+ left: 0,
18
+ right: 0,
19
+ bottom: 0,
20
+ zIndex: 1,
21
+ shadowColor: Colors.black_20,
22
+ shadowOffset: { width: 0, height: -2 },
23
+ shadowOpacity: 0.05,
24
+ shadowRadius: 3,
25
+ elevation: 8,
26
+ },
27
+ floatingContainer: {
28
+ position: 'absolute',
29
+ alignItems: 'center',
30
+ left: 0,
31
+ right: 0,
32
+ top: -2,
33
+ bottom: Platform.OS === 'ios' ? -6 : 4,
34
+ },
35
+ floatingContent: {
36
+ alignItems: 'center',
37
+ justifyContent: 'center',
38
+ height: 48,
39
+ width: 48,
40
+ borderRadius: 24,
41
+ top: -10,
42
+ },
43
+ indicator: {
44
+ height: 2,
45
+ width: 44,
46
+ alignSelf: 'center',
47
+ borderBottomLeftRadius: 1,
48
+ borderBottomRightRadius: 1,
49
+ },
50
+ debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
51
+ floatingLabel: {
52
+ top: -4,
53
+ borderRadius: Radius.XL,
54
+ paddingHorizontal: 6,
55
+ },
56
+ indicatorContainer: {
57
+ position: 'absolute',
58
+ top: 0,
59
+ },
60
+ });
@@ -3,7 +3,6 @@ import { CommonActions, Route } from '@react-navigation/native';
3
3
  import React, { useCallback, useContext } from 'react';
4
4
  import {
5
5
  Platform,
6
- StyleSheet,
7
6
  TouchableOpacity,
8
7
  useWindowDimensions,
9
8
  View,
@@ -14,12 +13,13 @@ import Animated, {
14
13
  withTiming,
15
14
  } from 'react-native-reanimated';
16
15
  import { EdgeInsets, useSafeAreaInsets } from 'react-native-safe-area-context';
17
- import { Colors, Radius, Styles } from '../../Consts';
16
+ import { Styles } from '../../Consts';
18
17
  import { Icon } from '../../Icon';
19
18
  import { Text } from '../../Text';
20
19
  import { FloatingButtonProps } from '../types';
21
20
  import CustomBottomTabItem from './CustomBottomTabItem';
22
21
  import { ApplicationContext, MiniAppContext } from '../../Context';
22
+ import { styles } from './BottomTabBar.styles';
23
23
 
24
24
  type Props = BottomTabBarProps & {
25
25
  activeTintColor?: string;
@@ -175,12 +175,10 @@ export default function BottomTabBar({
175
175
  {renderFloatingIcon()}
176
176
  </View>
177
177
  <View
178
- style={{
179
- top: -4,
180
- backgroundColor: activeTintColor ?? theme.colors.primary,
181
- borderRadius: Radius.XL,
182
- paddingHorizontal: 6,
183
- }}
178
+ style={[
179
+ styles.floatingLabel,
180
+ { backgroundColor: activeTintColor ?? theme.colors.primary },
181
+ ]}
184
182
  >
185
183
  <Text
186
184
  numberOfLines={1}
@@ -257,9 +255,7 @@ export default function BottomTabBar({
257
255
  >
258
256
  <View style={styles.content} accessibilityLabel={'bottom_tab_bar'}>
259
257
  {useFloating && floatingButton?.container}
260
- <Animated.View
261
- style={[{ position: 'absolute', top: 0 }, indicatorStyle]}
262
- >
258
+ <Animated.View style={[styles.indicatorContainer, indicatorStyle]}>
263
259
  <View
264
260
  style={[
265
261
  styles.indicator,
@@ -272,52 +268,3 @@ export default function BottomTabBar({
272
268
  </View>
273
269
  );
274
270
  }
275
-
276
- const styles = StyleSheet.create({
277
- content: {
278
- flex: 1,
279
- flexDirection: 'row',
280
- },
281
- tabBar: {
282
- left: 0,
283
- right: 0,
284
- bottom: 0,
285
- borderTopWidth: StyleSheet.hairlineWidth,
286
- elevation: 8,
287
- },
288
- tabBarFloatingButton: {
289
- left: 0,
290
- right: 0,
291
- bottom: 0,
292
- zIndex: 1,
293
- shadowColor: Colors.black_20,
294
- shadowOffset: { width: 0, height: -2 },
295
- shadowOpacity: 0.05,
296
- shadowRadius: 3,
297
- elevation: 8,
298
- },
299
- floatingContainer: {
300
- position: 'absolute',
301
- alignItems: 'center',
302
- left: 0,
303
- right: 0,
304
- top: -2,
305
- bottom: Platform.OS === 'ios' ? -6 : 4
306
- },
307
- floatingContent: {
308
- alignItems: 'center',
309
- justifyContent: 'center',
310
- height: 48,
311
- width: 48,
312
- borderRadius: 24,
313
- top: -10,
314
- },
315
- indicator: {
316
- height: 2,
317
- width: 44,
318
- alignSelf: 'center',
319
- borderBottomLeftRadius: 1,
320
- borderBottomRightRadius: 1,
321
- },
322
- debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
323
- });
@@ -87,20 +87,20 @@ const CustomBottomTabItem: React.FC<CustomBottomTabItemProps> = ({
87
87
  );
88
88
  };
89
89
 
90
- const renderLabel = ({ focused }: { focused: boolean }) => {
90
+ const renderLabel = ({ focused: isFocused }: { focused: boolean }) => {
91
91
  if (showLabel === false) {
92
92
  return null;
93
93
  }
94
94
 
95
- const color = focused ? activeTintColor : inactiveTintColor;
95
+ const color = isFocused ? activeTintColor : inactiveTintColor;
96
96
 
97
97
  if (typeof label === 'string') {
98
98
  return (
99
99
  <Text
100
100
  numberOfLines={1}
101
101
  style={[styles.label, labelStyle]}
102
- color={focused ? activeTintColor : inactiveTintColor}
103
- typography={focused ? 'label_xs_medium' : 'description_xs_regular'}
102
+ color={isFocused ? activeTintColor : inactiveTintColor}
103
+ typography={isFocused ? 'label_xs_medium' : 'description_xs_regular'}
104
104
  allowFontScaling={allowFontScaling}
105
105
  >
106
106
  {label}
@@ -109,7 +109,7 @@ const CustomBottomTabItem: React.FC<CustomBottomTabItemProps> = ({
109
109
  }
110
110
 
111
111
  return label({
112
- focused,
112
+ focused: isFocused,
113
113
  color,
114
114
  children: route.name,
115
115
  position: 'below-icon',