@momo-kits/tab-view 0.89.5 → 0.89.6-rc.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.
package/index.tsx CHANGED
@@ -1,30 +1,51 @@
1
- import React, {FC, useCallback, useRef, useState} from 'react';
2
- import {LayoutChangeEvent, View} from 'react-native';
3
- import {Tab, TabViewProps} from './types';
1
+ import React, {
2
+ forwardRef,
3
+ ForwardRefRenderFunction,
4
+ useCallback,
5
+ useContext,
6
+ useImperativeHandle,
7
+ useRef,
8
+ useState,
9
+ } from 'react';
10
+ import {Animated, LayoutChangeEvent, View} from 'react-native';
11
+ import {Tab, TabViewProps, TabViewRef} from './types';
4
12
  import TabBar from './tabBar/TabBar';
5
13
  import styles from './styles';
6
14
  import CardTabBar from './tabBar/CardTabBar';
7
15
  import ScrollableTabBar from './tabBar/SrollableTabBar';
8
16
  import PagerView from 'react-native-pager-view';
17
+ import {ApplicationContext} from '@momo-kits/foundation';
9
18
 
10
- const TabView: FC<TabViewProps> = ({
11
- scrollable = false,
12
- tabs = [],
13
- onPressTabItem,
14
- type = 'default',
15
- initialPage = 0,
16
- pagerProps,
17
- }) => {
19
+ const TabComponent: ForwardRefRenderFunction<TabViewRef, TabViewProps> = (
20
+ {
21
+ scrollable = false,
22
+ tabs = [],
23
+ onPressTabItem,
24
+ type = 'default',
25
+ initialPage = 0,
26
+ pagerProps,
27
+ direction,
28
+ selectedColor,
29
+ unselectedColor,
30
+ },
31
+ ref
32
+ ) => {
18
33
  const startPage =
19
34
  initialPage > tabs.length - 1 ? tabs.length - 1 : initialPage;
20
35
  const [selectedIndex, setSelectedIndex] = useState(startPage);
21
36
  const [tabBarWidth, setTabBarWidth] = useState(0);
22
37
  const isCardTab = type === 'card';
23
38
  const pagerRef = useRef<PagerView>(null);
24
- const [scrollX, setScrollX] = useState(0);
39
+ const scrollX = useRef(new Animated.Value(startPage));
40
+ const lazy = useRef([selectedIndex]).current;
41
+ const {theme} = useContext(ApplicationContext);
25
42
  const _onPressTabItem = (index: number) => {
26
- pagerRef.current?.setPage(index);
27
43
  onPressTabItem?.(index);
44
+ pagerRef.current?.setPage(index);
45
+
46
+ if (!lazy.includes(index)) {
47
+ lazy.push(index);
48
+ }
28
49
  setSelectedIndex(index);
29
50
  };
30
51
 
@@ -32,10 +53,12 @@ const TabView: FC<TabViewProps> = ({
32
53
  setTabBarWidth(e.nativeEvent.layout.width);
33
54
  };
34
55
 
35
- const onPageSelected = (e: {
36
- nativeEvent: {position: React.SetStateAction<number>};
37
- }) => {
38
- setSelectedIndex(e.nativeEvent.position);
56
+ const onPageSelected = (e: {nativeEvent: {position: number}}) => {
57
+ const {position} = e.nativeEvent;
58
+ if (!lazy.includes(position)) {
59
+ lazy.push(position);
60
+ }
61
+ setSelectedIndex(position);
39
62
  };
40
63
 
41
64
  let TabBarComponent = scrollable ? ScrollableTabBar : TabBar;
@@ -46,16 +69,23 @@ const TabView: FC<TabViewProps> = ({
46
69
 
47
70
  const onPageScroll = (e: {nativeEvent: {position: any; offset: any}}) => {
48
71
  const {position, offset} = e.nativeEvent;
49
- setScrollX(position + offset);
72
+ scrollX.current.setValue(position + offset);
50
73
  };
51
74
 
52
75
  const renderScreen = useCallback(
53
- (tab: Tab) => {
76
+ (tab: Tab, index: number) => {
77
+ if (!lazy.includes(index)) return <View />;
54
78
  return <View>{tab.component}</View>;
55
79
  },
56
- [tabs],
80
+ [tabs]
57
81
  );
58
82
 
83
+ useImperativeHandle(ref, () => ({
84
+ goToPage: (page: number) => {
85
+ if (page >= 0 && page <= tabs.length) pagerRef.current?.setPage(page);
86
+ },
87
+ }));
88
+
59
89
  return (
60
90
  <View onLayout={onLayout} style={[styles.tabView, {flex: 1}]}>
61
91
  <View>
@@ -64,7 +94,10 @@ const TabView: FC<TabViewProps> = ({
64
94
  selectedIndex={selectedIndex}
65
95
  tabs={tabs}
66
96
  containerWidth={tabBarWidth}
67
- scrollX={scrollX}
97
+ scrollX={scrollX.current}
98
+ direction={direction}
99
+ selectedColor={selectedColor ?? theme.colors.primary}
100
+ unselectedColor={unselectedColor ?? theme.colors.text.default}
68
101
  />
69
102
  </View>
70
103
 
@@ -75,11 +108,13 @@ const TabView: FC<TabViewProps> = ({
75
108
  onPageSelected={onPageSelected}
76
109
  style={styles.pagerView}
77
110
  initialPage={startPage}>
78
- {tabs.map(tab => renderScreen(tab))}
111
+ {tabs.map((tab, index) => renderScreen(tab, index))}
79
112
  </PagerView>
80
113
  </View>
81
114
  );
82
115
  };
83
116
 
117
+ const TabView = forwardRef(TabComponent);
118
+
84
119
  export {CardTabBar, ScrollableTabBar, TabBar, TabView};
85
120
  export type {TabViewProps, Tab};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/tab-view",
3
- "version": "0.89.5",
3
+ "version": "0.89.6-rc.1",
4
4
  "private": false,
5
5
  "main": "index.tsx",
6
6
  "dependencies": {},
@@ -14,4 +14,4 @@
14
14
  "@momo-platform/versions": "4.1.11"
15
15
  },
16
16
  "license": "MoMo"
17
- }
17
+ }
package/publish.sh CHANGED
@@ -1,29 +1,27 @@
1
1
  #!/bin/bash
2
+
3
+ # Prepare dist files
2
4
  rm -rf dist
3
5
  mkdir dist
4
-
5
- cp . ./dist
6
-
7
- # GET VERSION from mck_package.json
8
- VERSIONSTRING=( v$(jq .version package.json) )
9
- VERSION=(${VERSIONSTRING//[\"]/})
10
- echo VERSION: $VERSION
11
-
12
- rsync -r --verbose --exclude '*.mdx' --exclude '*Demo.js' --exclude 'props-type.js' --exclude 'prop-types.js' ./* dist
13
-
14
- # #babel component to dist
15
- #babel ./dist -d dist --copy-files
16
-
17
- #copy option
18
- #cp -r ./src/ dist
19
-
20
-
21
- #npm login
22
- #publish dist to npm
6
+ rsync -r --exclude=/dist ./* dist
23
7
  cd dist
24
- npm publish --tag beta --access=public
8
+
9
+ if [ "$1" == "stable" ]; then
10
+ npm version $(npm view @momo-kits/foundation@stable version)
11
+ npm version patch
12
+ npm publish --tag stable --access=public
13
+ elif [ "$1" == "latest" ]; then
14
+ npm version $(npm view @momo-kits/foundation@latest version)
15
+ npm publish --tag latest --access=public
16
+ else
17
+ npm version $(npm view @momo-kits/tab-view@beta version)
18
+ npm version prerelease --preid=beta
19
+ npm publish --tag beta --access=public
20
+ fi
21
+
22
+ PACKAGE_NAME=$(npm pkg get name)
23
+ NEW_PACKAGE_VERSION=$(npm pkg get version)
24
+
25
+ # Clean up
25
26
  cd ..
26
27
  rm -rf dist
27
-
28
-
29
- ##curl -X POST -H 'Content-Type: application/json' 'https://chat.googleapis.com/v1/spaces/AAAAbP8987c/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=UGSFRvk_oYb9uGsAgs31bVvMm6jDkmD8zihGm3eyaQA%3D&threadKey=JoaXTEYaNNkl' -d '{"text": "@momo-kits/tab-view new version release: '*"$VERSION"*' https://www.npmjs.com/package/@momo-kits/tab-view"}'
package/styles.ts CHANGED
@@ -14,7 +14,6 @@ export default StyleSheet.create({
14
14
  borderBottomWidth: 1,
15
15
  },
16
16
  tabItem: {
17
- padding: Spacing.M,
18
17
  alignItems: 'center',
19
18
  justifyContent: 'center',
20
19
  },
@@ -26,9 +25,15 @@ export default StyleSheet.create({
26
25
  bottom: 0,
27
26
  },
28
27
  icon: {
28
+ borderRadius: Radius.XS,
29
+ },
30
+ iconHolder: {
31
+ marginRight: Spacing.XS,
29
32
  width: 24,
30
33
  height: 24,
31
- borderRadius: Radius.XS,
34
+ justifyContent: 'center',
35
+ alignItems: 'center',
36
+ overflow: 'hidden',
32
37
  },
33
38
  tabItemWrapper: {
34
39
  paddingHorizontal: Spacing.XS,
@@ -47,6 +52,9 @@ export default StyleSheet.create({
47
52
  flexDirection: 'row',
48
53
  justifyContent: 'center',
49
54
  alignItems: 'center',
55
+ paddingHorizontal: Spacing.S,
56
+ paddingTop: Spacing.S,
57
+ paddingBottom: Spacing.M,
50
58
  },
51
59
  cardTabOverlay: {
52
60
  flexDirection: 'row',
@@ -60,19 +68,26 @@ export default StyleSheet.create({
60
68
  height: '100%',
61
69
  alignItems: 'center',
62
70
  justifyContent: 'center',
63
- paddingTop: Spacing.XS,
71
+ paddingVertical: Spacing.M,
72
+ paddingHorizontal: Spacing.S,
64
73
  flexDirection: 'row',
65
74
  },
66
75
  dotSmall: {
67
76
  position: 'absolute',
68
- top: -Spacing.XXS,
69
- right: -Spacing.XXS,
77
+ top: -Spacing.XS,
78
+ right: -Spacing.XS,
70
79
  zIndex: 2,
71
80
  },
72
81
  dot: {
73
82
  position: 'absolute',
74
83
  top: -Spacing.S,
75
- right: -Spacing.XS,
84
+ right: -Spacing.S,
85
+ zIndex: 2,
86
+ },
87
+ badge: {
88
+ position: 'absolute',
89
+ top: -Spacing.S,
90
+ left: Spacing.S,
76
91
  zIndex: 2,
77
92
  },
78
93
  });
@@ -4,7 +4,9 @@ import {TabBarProps} from '../types';
4
4
  import styles from '../styles';
5
5
  import {
6
6
  ApplicationContext,
7
- Image,
7
+ Badge,
8
+ BadgeDot,
9
+ Icon,
8
10
  Radius,
9
11
  Shadow,
10
12
  Spacing,
@@ -18,6 +20,8 @@ const CardTabBar: FC<TabBarProps> = ({
18
20
  onPressTabItem,
19
21
  containerWidth,
20
22
  selectedIndex,
23
+ selectedColor,
24
+ unselectedColor,
21
25
  }) => {
22
26
  const {theme} = useContext(ApplicationContext);
23
27
  const itemWidth = containerWidth / tabs.length;
@@ -36,6 +40,8 @@ const CardTabBar: FC<TabBarProps> = ({
36
40
  onPressTabItem?.(index);
37
41
  }}
38
42
  width={itemWidth}
43
+ selectedColor={selectedColor}
44
+ unselectedColor={unselectedColor}
39
45
  />
40
46
  );
41
47
  })}
@@ -52,6 +58,7 @@ const CardTabBar: FC<TabBarProps> = ({
52
58
  <PathSvg style={{transform: [{rotateY: '180deg'}], left: 8}} />
53
59
  )}
54
60
  <View
61
+ accessibilityLabel={tabs[selectedIndex]?.accessibilityLabel}
55
62
  style={[
56
63
  styles.overlayTextWrapper,
57
64
  {
@@ -59,21 +66,50 @@ const CardTabBar: FC<TabBarProps> = ({
59
66
  width: containerWidth / tabs.length,
60
67
  borderTopRightRadius: Radius.M,
61
68
  borderTopLeftRadius: Radius.M,
69
+ paddingHorizontal: tabs.length === 3 ? Spacing.S : Spacing.M,
62
70
  },
63
71
  ]}>
64
- {!!tabs[selectedIndex]?.icon && (
65
- <Image
66
- source={{uri: tabs[selectedIndex]?.icon}}
72
+ {!!tabs[selectedIndex]?.renderIcon &&
73
+ typeof tabs[selectedIndex]?.renderIcon === 'function' && (
74
+ <View
75
+ style={[
76
+ styles.icon,
77
+ styles.iconHolder,
78
+ {marginRight: Spacing.XS},
79
+ ]}>
80
+ {tabs[selectedIndex]?.renderIcon?.(true)}
81
+ </View>
82
+ )}
83
+ {!tabs[selectedIndex]?.renderIcon && !!tabs[selectedIndex]?.icon && (
84
+ <Icon
85
+ color={selectedColor}
86
+ source={tabs[selectedIndex]?.icon as string}
67
87
  style={[styles.icon, {marginRight: Spacing.XS}]}
68
88
  />
69
89
  )}
70
90
  <Text
71
- color={theme.colors.primary}
91
+ color={selectedColor}
72
92
  numberOfLines={1}
73
- style={styles.textCenter}
93
+ style={[styles.textCenter, {flexShrink: 1}]}
74
94
  typography={'header_s_semibold'}>
75
95
  {tabs[selectedIndex]?.title || ''}
76
96
  </Text>
97
+ {tabs[selectedIndex]?.showDot && (
98
+ <BadgeDot
99
+ size={tabs[selectedIndex]?.dotSize ?? 'small'}
100
+ style={{
101
+ marginLeft: Spacing.XS,
102
+ }}
103
+ />
104
+ )}
105
+ {!tabs[selectedIndex]?.showDot && tabs[selectedIndex]?.badgeValue && (
106
+ <View>
107
+ <Badge
108
+ label={tabs[selectedIndex]?.badgeValue}
109
+ style={{marginLeft: Spacing.XS}}
110
+ />
111
+ </View>
112
+ )}
77
113
  </View>
78
114
  {!isLast && <PathSvg style={{right: 8}} />}
79
115
  </View>
@@ -9,12 +9,16 @@ const ScrollableTabBar: FC<TabBarProps> = ({
9
9
  tabs = [],
10
10
  onPressTabItem,
11
11
  selectedIndex,
12
+ selectedColor,
13
+ unselectedColor,
14
+ direction,
12
15
  }) => {
13
16
  const {theme} = useContext(ApplicationContext);
14
17
  const [itemWidthMap, setItemWidthMap] = useState<
15
18
  {width: number; x: number}[]
16
19
  >([]);
17
20
  const animatedWidth = useRef(new Animated.Value(0)).current;
21
+ const animX = useRef(new Animated.Value(0)).current;
18
22
  const scrollViewRef = useRef<ScrollView>(null);
19
23
 
20
24
  useEffect(() => {
@@ -22,11 +26,18 @@ const ScrollableTabBar: FC<TabBarProps> = ({
22
26
  scrollToIndex(selectedIndex);
23
27
  }, [selectedIndex, itemWidthMap]);
24
28
  const moveIndicator = () => {
25
- Animated.timing(animatedWidth, {
26
- toValue: itemWidthMap[selectedIndex]?.width || 0,
27
- duration: 250,
28
- useNativeDriver: false,
29
- }).start();
29
+ Animated.parallel([
30
+ Animated.timing(animatedWidth, {
31
+ toValue: itemWidthMap[selectedIndex]?.width || 0,
32
+ duration: 250,
33
+ useNativeDriver: false,
34
+ }),
35
+ Animated.timing(animX, {
36
+ toValue: itemWidthMap[selectedIndex]?.x || 0,
37
+ duration: 250,
38
+ useNativeDriver: false,
39
+ }),
40
+ ]).start();
30
41
  };
31
42
 
32
43
  const onLayout = (e: LayoutChangeEvent, index: number) => {
@@ -62,6 +73,9 @@ const ScrollableTabBar: FC<TabBarProps> = ({
62
73
  }}
63
74
  active={isActive}
64
75
  tab={item}
76
+ selectedColor={selectedColor}
77
+ unselectedColor={unselectedColor}
78
+ direction={direction}
65
79
  />
66
80
  </View>
67
81
  );
@@ -84,9 +98,9 @@ const ScrollableTabBar: FC<TabBarProps> = ({
84
98
  style={[
85
99
  styles.indicator,
86
100
  {
87
- left: itemWidthMap[selectedIndex]?.x || 0,
101
+ left: animX,
88
102
  width: animatedWidth,
89
- backgroundColor: theme.colors.primary,
103
+ backgroundColor: selectedColor,
90
104
  },
91
105
  ]}
92
106
  />
package/tabBar/TabBar.tsx CHANGED
@@ -11,9 +11,11 @@ const TabBar: FC<TabBarProps> = ({
11
11
  onPressTabItem,
12
12
  containerWidth = 0,
13
13
  scrollX,
14
+ direction,
15
+ selectedColor,
16
+ unselectedColor,
14
17
  }) => {
15
18
  const {theme} = useContext(ApplicationContext);
16
-
17
19
  const itemWidth = containerWidth / tabs.length;
18
20
 
19
21
  return (
@@ -35,6 +37,9 @@ const TabBar: FC<TabBarProps> = ({
35
37
  }}
36
38
  active={selectedIndex === index}
37
39
  tab={tab}
40
+ direction={direction}
41
+ selectedColor={selectedColor}
42
+ unselectedColor={unselectedColor}
38
43
  />
39
44
  );
40
45
  })}
@@ -42,9 +47,16 @@ const TabBar: FC<TabBarProps> = ({
42
47
  style={[
43
48
  styles.indicator,
44
49
  {
45
- left: scrollX * itemWidth + Spacing.XS,
50
+ left: scrollX.interpolate({
51
+ inputRange: [0, tabs.length - 1],
52
+ outputRange: [
53
+ Spacing.XS,
54
+ (tabs.length - 1) * itemWidth + Spacing.XS,
55
+ ],
56
+ extrapolate: 'clamp',
57
+ }),
46
58
  width: itemWidth - Spacing.XS * 2,
47
- backgroundColor: theme.colors.primary,
59
+ backgroundColor: selectedColor,
48
60
  },
49
61
  ]}
50
62
  />
@@ -1,28 +1,66 @@
1
1
  import React, {FC} from 'react';
2
- import {TouchableOpacity} from 'react-native';
2
+ import {TouchableOpacity, View} from 'react-native';
3
3
  import {TabItemProps} from '../types';
4
4
  import styles from '../styles';
5
- import {Image, Spacing, Text} from '@momo-kits/foundation';
5
+ import {Badge, BadgeDot, Icon, Spacing, Text} from '@momo-kits/foundation';
6
6
 
7
- const CardTabItem: FC<TabItemProps> = ({tab, onPressTabItem, width}) => {
8
- const {title, icon} = tab;
7
+ const CardTabItem: FC<TabItemProps> = ({
8
+ tab,
9
+ active,
10
+ onPressTabItem,
11
+ width,
12
+ selectedColor,
13
+ unselectedColor,
14
+ }) => {
15
+ const {
16
+ title,
17
+ icon,
18
+ renderIcon,
19
+ showDot = false,
20
+ dotSize = 'small',
21
+ badgeValue,
22
+ accessibilityLabel,
23
+ } = tab;
24
+ const color = active ? selectedColor : unselectedColor;
9
25
 
10
26
  return (
11
27
  <TouchableOpacity
12
28
  onPress={onPressTabItem}
13
- style={[styles.cardTabItem, {width}]}>
14
- {!!icon && (
15
- <Image
16
- source={{uri: icon}}
29
+ style={[styles.cardTabItem, {width}]}
30
+ accessibilityLabel={accessibilityLabel}>
31
+ {renderIcon &&
32
+ !['string', 'boolean', 'number'].includes(typeof renderIcon) && (
33
+ <View
34
+ style={[styles.icon, styles.iconHolder, {marginRight: Spacing.XS}]}>
35
+ {renderIcon}
36
+ </View>
37
+ )}
38
+ {!renderIcon && !!icon && (
39
+ <Icon
40
+ color={color}
17
41
  style={[styles.icon, {marginRight: Spacing.XS}]}
42
+ source={icon}
18
43
  />
19
44
  )}
20
45
  <Text
21
46
  numberOfLines={1}
22
- style={styles.textCenter}
47
+ style={[styles.textCenter, {flexShrink: 1}]}
23
48
  typography={'body_default_regular'}>
24
49
  {title}
25
50
  </Text>
51
+ {showDot && (
52
+ <BadgeDot
53
+ size={dotSize}
54
+ style={{
55
+ marginLeft: Spacing.XS,
56
+ }}
57
+ />
58
+ )}
59
+ {!showDot && badgeValue && (
60
+ <View>
61
+ <Badge label={badgeValue} style={{marginLeft: Spacing.XS}} />
62
+ </View>
63
+ )}
26
64
  </TouchableOpacity>
27
65
  );
28
66
  };
@@ -1,58 +1,143 @@
1
- import React, {FC, useContext} from 'react';
2
- import {ImageStyle} from 'react-native-fast-image';
3
- import {TouchableOpacity, View, ViewStyle} from 'react-native';
1
+ import React, {FC} from 'react';
2
+ import {TouchableOpacity, View} from 'react-native';
4
3
  import {TabItemProps} from '../types';
5
4
  import {
6
- ApplicationContext,
5
+ Badge,
7
6
  BadgeDot,
8
- Image,
7
+ Icon,
8
+ scaleSize,
9
9
  Spacing,
10
10
  Text,
11
11
  Typography,
12
12
  } from '@momo-kits/foundation';
13
13
  import styles from '../styles';
14
14
 
15
- const TabItem: FC<TabItemProps> = ({tab, active, onPressTabItem, width}) => {
16
- const {theme} = useContext(ApplicationContext);
15
+ const TabItem: FC<TabItemProps> = ({
16
+ tab,
17
+ active,
18
+ onPressTabItem,
19
+ width,
20
+ direction,
21
+ selectedColor,
22
+ unselectedColor,
23
+ }) => {
17
24
  const {
18
25
  title,
19
26
  icon,
20
- direction = 'row',
21
27
  showDot = false,
22
28
  dotSize = 'small',
29
+ badgeValue,
30
+ renderIcon,
31
+ accessibilityLabel,
23
32
  } = tab;
24
33
  const typography: Typography = active
25
34
  ? 'header_s_semibold'
26
35
  : 'body_default_regular';
27
- const color = active ? theme.colors.primary : theme.colors.text.default;
36
+ const color = active ? selectedColor : unselectedColor;
28
37
  const dotStyle = dotSize === 'large' ? styles.dot : styles.dotSmall;
29
- const iconStyle: ViewStyle =
30
- direction === 'row'
31
- ? {marginRight: Spacing.XS}
32
- : {marginBottom: Spacing.XS};
33
38
 
34
- return (
35
- <TouchableOpacity
36
- onPress={onPressTabItem}
37
- style={[styles.tabItem, {width, flexDirection: direction}]}>
38
- {!!icon && (
39
- <View>
40
- {showDot && <BadgeDot style={dotStyle} size={dotSize} />}
41
- <Image
42
- style={[styles.icon, iconStyle as ImageStyle]}
43
- source={{uri: icon}}
39
+ const renderRowItem = () => {
40
+ return (
41
+ <TouchableOpacity
42
+ accessibilityLabel={accessibilityLabel}
43
+ style={[
44
+ styles.tabItem,
45
+ {
46
+ width,
47
+ height: scaleSize(48),
48
+ flexDirection: 'row',
49
+ overflow: 'hidden',
50
+ paddingVertical: Spacing.M,
51
+ paddingHorizontal: Spacing.M,
52
+ },
53
+ ]}
54
+ onPress={onPressTabItem}>
55
+ {renderIcon && typeof renderIcon === 'function' && (
56
+ <View
57
+ style={[styles.icon, styles.iconHolder, {marginRight: Spacing.S}]}>
58
+ {renderIcon(active)}
59
+ </View>
60
+ )}
61
+ {!renderIcon && !!icon && (
62
+ <Icon
63
+ style={[styles.icon, {marginRight: Spacing.S}]}
64
+ source={icon}
65
+ color={color}
44
66
  />
67
+ )}
68
+ <Text
69
+ numberOfLines={1}
70
+ typography={typography}
71
+ color={color}
72
+ style={{flexShrink: 1}}>
73
+ {title}
74
+ </Text>
75
+ {showDot && (
76
+ <BadgeDot size={dotSize} style={{marginLeft: Spacing.XS}} />
77
+ )}
78
+ {!showDot && badgeValue && (
79
+ <View>
80
+ <Badge label={badgeValue} style={{marginLeft: Spacing.XS}} />
81
+ </View>
82
+ )}
83
+ </TouchableOpacity>
84
+ );
85
+ };
86
+
87
+ const renderColumnItem = () => {
88
+ return (
89
+ <TouchableOpacity
90
+ style={[
91
+ styles.tabItem,
92
+ {
93
+ width,
94
+ height: scaleSize(68),
95
+ flexDirection: 'column',
96
+ overflow: 'hidden',
97
+ paddingHorizontal: Spacing.M,
98
+ paddingVertical: Spacing.M,
99
+ },
100
+ ]}
101
+ onPress={onPressTabItem}
102
+ accessibilityLabel={accessibilityLabel}>
103
+ <View>
104
+ {renderIcon && typeof renderIcon === 'function' && (
105
+ <View
106
+ style={[
107
+ styles.icon,
108
+ styles.iconHolder,
109
+ {marginBottom: Spacing.XS},
110
+ ]}>
111
+ {renderIcon(active)}
112
+ </View>
113
+ )}
114
+ {!renderIcon && !!icon && (
115
+ <Icon
116
+ style={[
117
+ styles.icon,
118
+ {
119
+ marginBottom: Spacing.XS,
120
+ },
121
+ ]}
122
+ source={icon}
123
+ color={color}
124
+ />
125
+ )}
126
+ {(renderIcon || !!icon) && showDot && (
127
+ <BadgeDot style={dotStyle} size={dotSize} />
128
+ )}
129
+ {(renderIcon || !!icon) && !showDot && badgeValue && (
130
+ <Badge label={badgeValue} style={styles.badge} />
131
+ )}
45
132
  </View>
46
- )}
47
- <Text
48
- style={styles.textCenter}
49
- numberOfLines={1}
50
- color={color}
51
- typography={typography}>
52
- {title}
53
- </Text>
54
- </TouchableOpacity>
55
- );
133
+ <Text numberOfLines={1} typography={typography} color={color}>
134
+ {title}
135
+ </Text>
136
+ </TouchableOpacity>
137
+ );
138
+ };
139
+
140
+ return direction === 'row' ? renderRowItem() : renderColumnItem();
56
141
  };
57
142
 
58
143
  export default TabItem;
package/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import {ReactElement} from 'react';
2
2
  import {PagerViewProps} from 'react-native-pager-view';
3
+ import {Animated} from 'react-native';
3
4
 
4
5
  export type Tab = {
5
6
  /**
@@ -12,10 +13,7 @@ export type Tab = {
12
13
  */
13
14
  icon?: string;
14
15
 
15
- /**
16
- * Optional. Specifies the layout direction for the tab's content, either in a row or column format.
17
- */
18
- direction?: 'row' | 'column';
16
+ renderIcon?: (active: boolean) => ReactElement;
19
17
 
20
18
  /**
21
19
  * The main component or content to be displayed when this tab is active.
@@ -31,6 +29,10 @@ export type Tab = {
31
29
  * Optional. Specifies the size of the dot indicator, either 'small' or 'large'.
32
30
  */
33
31
  dotSize?: 'small' | 'large';
32
+
33
+ badgeValue?: string | number;
34
+
35
+ accessibilityLabel?: string;
34
36
  };
35
37
 
36
38
  export type TabItemProps = {
@@ -53,6 +55,15 @@ export type TabItemProps = {
53
55
  * Optional. Specifies the width of the tab item. Useful for customizing layout and appearance.
54
56
  */
55
57
  width?: number;
58
+
59
+ /**
60
+ * Optional. Specifies the layout direction for the tab's content, either in a row or column format.
61
+ */
62
+ direction?: 'row' | 'column';
63
+
64
+ selectedColor?: string;
65
+
66
+ unselectedColor?: string;
56
67
  };
57
68
 
58
69
  export type TabViewProps = {
@@ -85,6 +96,15 @@ export type TabViewProps = {
85
96
  * Optional. Additional properties to pass to the underlying pager view component.
86
97
  */
87
98
  pagerProps?: PagerViewProps;
99
+
100
+ /**
101
+ * Optional. Specifies the layout direction for the tab's content, either in a row or column format.
102
+ */
103
+ direction?: 'row' | 'column';
104
+
105
+ selectedColor?: string;
106
+
107
+ unselectedColor?: string;
88
108
  };
89
109
 
90
110
  /**
@@ -114,5 +134,18 @@ export type TabBarProps = {
114
134
  /**
115
135
  * Represents the horizontal scroll position in a scrollable tab bar.
116
136
  */
117
- scrollX: number;
137
+ scrollX: Animated.Value;
138
+
139
+ /**
140
+ * Optional. Specifies the layout direction for the tab's content, either in a row or column format.
141
+ */
142
+ direction?: 'row' | 'column';
143
+
144
+ selectedColor?: string;
145
+
146
+ unselectedColor?: string;
147
+ };
148
+
149
+ export type TabViewRef = {
150
+ goToPage: (page: number) => void;
118
151
  };