react-native-tab-view 4.0.0-alpha.1 → 4.0.0-alpha.10

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 (50) hide show
  1. package/lib/commonjs/PanResponderAdapter.js.map +1 -1
  2. package/lib/commonjs/PlatformPressable.js +22 -1
  3. package/lib/commonjs/PlatformPressable.js.map +1 -1
  4. package/lib/commonjs/SceneView.js.map +1 -1
  5. package/lib/commonjs/TabBar.js +107 -91
  6. package/lib/commonjs/TabBar.js.map +1 -1
  7. package/lib/commonjs/TabBarIndicator.js +19 -14
  8. package/lib/commonjs/TabBarIndicator.js.map +1 -1
  9. package/lib/commonjs/TabBarItem.js +53 -72
  10. package/lib/commonjs/TabBarItem.js.map +1 -1
  11. package/lib/commonjs/TabBarItemLabel.js +3 -2
  12. package/lib/commonjs/TabBarItemLabel.js.map +1 -1
  13. package/lib/commonjs/TabView.js +1 -1
  14. package/lib/module/PanResponderAdapter.js.map +1 -1
  15. package/lib/module/PlatformPressable.js +22 -1
  16. package/lib/module/PlatformPressable.js.map +1 -1
  17. package/lib/module/SceneView.js.map +1 -1
  18. package/lib/module/TabBar.js +107 -91
  19. package/lib/module/TabBar.js.map +1 -1
  20. package/lib/module/TabBarIndicator.js +19 -14
  21. package/lib/module/TabBarIndicator.js.map +1 -1
  22. package/lib/module/TabBarItem.js +53 -72
  23. package/lib/module/TabBarItem.js.map +1 -1
  24. package/lib/module/TabBarItemLabel.js +3 -2
  25. package/lib/module/TabBarItemLabel.js.map +1 -1
  26. package/lib/module/TabView.js +1 -1
  27. package/lib/typescript/src/PlatformPressable.d.ts +3 -2
  28. package/lib/typescript/src/PlatformPressable.d.ts.map +1 -1
  29. package/lib/typescript/src/TabBar.d.ts +4 -15
  30. package/lib/typescript/src/TabBar.d.ts.map +1 -1
  31. package/lib/typescript/src/TabBarIndicator.d.ts.map +1 -1
  32. package/lib/typescript/src/TabBarItem.d.ts +2 -17
  33. package/lib/typescript/src/TabBarItem.d.ts.map +1 -1
  34. package/lib/typescript/src/TabView.d.ts +3 -3
  35. package/lib/typescript/src/TabView.d.ts.map +1 -1
  36. package/lib/typescript/src/index.d.ts +1 -1
  37. package/lib/typescript/src/index.d.ts.map +1 -1
  38. package/lib/typescript/src/types.d.ts +25 -1
  39. package/lib/typescript/src/types.d.ts.map +1 -1
  40. package/package.json +9 -9
  41. package/src/PanResponderAdapter.tsx +2 -2
  42. package/src/PlatformPressable.tsx +31 -2
  43. package/src/SceneView.tsx +2 -2
  44. package/src/TabBar.tsx +160 -162
  45. package/src/TabBarIndicator.tsx +19 -11
  46. package/src/TabBarItem.tsx +86 -110
  47. package/src/TabBarItemLabel.tsx +2 -1
  48. package/src/TabView.tsx +2 -2
  49. package/src/index.tsx +6 -1
  50. package/src/types.tsx +25 -1
@@ -13,9 +13,9 @@ import useLatestCallback from 'use-latest-callback';
13
13
 
14
14
  import { PlatformPressable } from './PlatformPressable';
15
15
  import { TabBarItemLabel } from './TabBarItemLabel';
16
- import type { NavigationState, Route, Scene } from './types';
16
+ import type { NavigationState, Route, TabDescriptor } from './types';
17
17
 
18
- export type Props<T extends Route> = {
18
+ export type Props<T extends Route> = TabDescriptor<T> & {
19
19
  position: Animated.AnimatedInterpolation<number>;
20
20
  route: T;
21
21
  navigationState: NavigationState<T>;
@@ -23,21 +23,6 @@ export type Props<T extends Route> = {
23
23
  inactiveColor?: string;
24
24
  pressColor?: string;
25
25
  pressOpacity?: number;
26
- getLabelText: (scene: Scene<T>) => string | undefined;
27
- getAccessible: (scene: Scene<T>) => boolean | undefined;
28
- getAccessibilityLabel: (scene: Scene<T>) => string | undefined;
29
- getTestID: (scene: Scene<T>) => string | undefined;
30
- renderLabel?: (scene: {
31
- route: T;
32
- focused: boolean;
33
- color: string;
34
- }) => React.ReactNode;
35
- renderIcon?: (scene: {
36
- route: T;
37
- focused: boolean;
38
- color: string;
39
- }) => React.ReactNode;
40
- renderBadge?: (scene: Scene<T>) => React.ReactNode;
41
26
  onLayout?: (event: LayoutChangeEvent) => void;
42
27
  onPress: () => void;
43
28
  onLongPress: () => void;
@@ -49,6 +34,7 @@ export type Props<T extends Route> = {
49
34
 
50
35
  const DEFAULT_ACTIVE_COLOR = 'rgba(255, 255, 255, 1)';
51
36
  const DEFAULT_INACTIVE_COLOR = 'rgba(255, 255, 255, 0.7)';
37
+ const ICON_SIZE = 24;
52
38
 
53
39
  const getActiveOpacity = (
54
40
  position: Animated.AnimatedInterpolation<number>,
@@ -91,26 +77,22 @@ type TabBarItemInternalProps<T extends Route> = Omit<
91
77
  | 'getLabelText'
92
78
  | 'getTestID'
93
79
  | 'getAccessible'
80
+ | 'options'
94
81
  > & {
95
82
  isFocused: boolean;
96
83
  index: number;
97
84
  routesLength: number;
98
- accessibilityLabel?: string;
99
- label?: string;
100
- testID?: string;
101
- accessible?: boolean;
102
- };
85
+ } & TabDescriptor<T>;
103
86
 
104
87
  const TabBarItemInternal = <T extends Route>({
105
88
  accessibilityLabel,
106
89
  accessible,
107
- label: labelText,
90
+ label: customlabel,
108
91
  testID,
109
92
  onLongPress,
110
93
  onPress,
111
94
  isFocused,
112
95
  position,
113
- route,
114
96
  style,
115
97
  inactiveColor: inactiveColorCustom,
116
98
  activeColor: activeColorCustom,
@@ -119,12 +101,15 @@ const TabBarItemInternal = <T extends Route>({
119
101
  index: tabIndex,
120
102
  pressColor,
121
103
  pressOpacity,
122
- renderBadge,
123
- renderIcon,
124
104
  defaultTabWidth,
105
+ icon: customIcon,
106
+ badge: customBadge,
107
+ href,
108
+ labelText,
125
109
  routesLength,
126
- renderLabel: renderLabelCustom,
127
110
  android_ripple = { borderless: true },
111
+ labelAllowFontScaling,
112
+ route,
128
113
  }: TabBarItemInternalProps<T>) => {
129
114
  const labelColorFromStyle = StyleSheet.flatten(labelStyle || {}).color;
130
115
 
@@ -132,85 +117,88 @@ const TabBarItemInternal = <T extends Route>({
132
117
  activeColorCustom !== undefined
133
118
  ? activeColorCustom
134
119
  : typeof labelColorFromStyle === 'string'
135
- ? labelColorFromStyle
136
- : DEFAULT_ACTIVE_COLOR;
120
+ ? labelColorFromStyle
121
+ : DEFAULT_ACTIVE_COLOR;
137
122
  const inactiveColor =
138
123
  inactiveColorCustom !== undefined
139
124
  ? inactiveColorCustom
140
125
  : typeof labelColorFromStyle === 'string'
141
- ? labelColorFromStyle
142
- : DEFAULT_INACTIVE_COLOR;
126
+ ? labelColorFromStyle
127
+ : DEFAULT_INACTIVE_COLOR;
143
128
 
144
129
  const activeOpacity = getActiveOpacity(position, routesLength, tabIndex);
145
130
  const inactiveOpacity = getInactiveOpacity(position, routesLength, tabIndex);
146
131
 
147
- let icon: React.ReactNode | null = null;
148
- let label: React.ReactNode | null = null;
132
+ const icon = React.useMemo(() => {
133
+ if (!customIcon) {
134
+ return null;
135
+ }
149
136
 
150
- if (renderIcon) {
151
- const activeIcon = renderIcon({
152
- route,
153
- focused: true,
154
- color: activeColor,
155
- });
156
- const inactiveIcon = renderIcon({
157
- route,
137
+ const inactiveIcon = customIcon({
158
138
  focused: false,
159
139
  color: inactiveColor,
140
+ size: ICON_SIZE,
141
+ route,
160
142
  });
161
143
 
162
- if (inactiveIcon != null && activeIcon != null) {
163
- icon = (
164
- <View style={styles.icon}>
165
- <Animated.View style={{ opacity: inactiveOpacity }}>
166
- {inactiveIcon}
167
- </Animated.View>
168
- <Animated.View
169
- style={[StyleSheet.absoluteFill, { opacity: activeOpacity }]}
170
- >
171
- {activeIcon}
172
- </Animated.View>
173
- </View>
174
- );
175
- }
176
- }
177
-
178
- const renderLabel = renderLabelCustom
179
- ? renderLabelCustom
180
- : (labelProps: { color: string }) => (
181
- <TabBarItemLabel
182
- {...labelProps}
183
- icon={icon}
184
- label={labelText}
185
- labelStyle={labelStyle}
186
- />
187
- );
188
-
189
- if (renderLabel) {
190
- const activeLabel = renderLabel({
191
- route,
144
+ const activeIcon = customIcon({
192
145
  focused: true,
193
146
  color: activeColor,
194
- });
195
- const inactiveLabel = renderLabel({
147
+ size: ICON_SIZE,
196
148
  route,
197
- focused: false,
198
- color: inactiveColor,
199
149
  });
200
150
 
201
- label = (
202
- <View>
151
+ return (
152
+ <View style={styles.icon}>
203
153
  <Animated.View style={{ opacity: inactiveOpacity }}>
204
- {inactiveLabel}
154
+ {inactiveIcon}
205
155
  </Animated.View>
206
156
  <Animated.View
207
157
  style={[StyleSheet.absoluteFill, { opacity: activeOpacity }]}
208
158
  >
209
- {activeLabel}
159
+ {activeIcon}
210
160
  </Animated.View>
211
161
  </View>
212
162
  );
213
- }
163
+ }, [
164
+ activeColor,
165
+ activeOpacity,
166
+ customIcon,
167
+ inactiveColor,
168
+ inactiveOpacity,
169
+ route,
170
+ ]);
171
+
172
+ const renderLabel = React.useCallback(
173
+ (focused: boolean) =>
174
+ customlabel ? (
175
+ customlabel({
176
+ focused,
177
+ color: focused ? activeColor : inactiveColor,
178
+ style: labelStyle,
179
+ label: labelText,
180
+ allowFontScaling: labelAllowFontScaling,
181
+ route,
182
+ })
183
+ ) : (
184
+ <TabBarItemLabel
185
+ color={focused ? activeColor : inactiveColor}
186
+ icon={icon}
187
+ label={labelText}
188
+ labelStyle={labelStyle}
189
+ />
190
+ ),
191
+ [
192
+ customlabel,
193
+ activeColor,
194
+ labelStyle,
195
+ labelText,
196
+ labelAllowFontScaling,
197
+ route,
198
+ inactiveColor,
199
+ icon,
200
+ ]
201
+ );
214
202
 
215
203
  const tabStyle = StyleSheet.flatten(style);
216
204
  const isWidthSet = tabStyle?.width !== undefined;
@@ -219,13 +207,9 @@ const TabBarItemInternal = <T extends Route>({
219
207
  ? null
220
208
  : { width: defaultTabWidth };
221
209
 
222
- const scene = { route };
223
-
224
210
  accessibilityLabel =
225
211
  typeof accessibilityLabel !== 'undefined' ? accessibilityLabel : labelText;
226
212
 
227
- const badge = renderBadge ? renderBadge(scene) : null;
228
-
229
213
  return (
230
214
  <PlatformPressable
231
215
  android_ripple={android_ripple}
@@ -240,12 +224,24 @@ const TabBarItemInternal = <T extends Route>({
240
224
  onLayout={onLayout}
241
225
  onPress={onPress}
242
226
  onLongPress={onLongPress}
227
+ href={href}
243
228
  style={[styles.pressable, tabContainerStyle]}
244
229
  >
245
230
  <View pointerEvents="none" style={[styles.item, tabStyle]}>
246
231
  {icon}
247
- {label}
248
- {badge != null ? <View style={styles.badge}>{badge}</View> : null}
232
+ <View>
233
+ <Animated.View style={{ opacity: inactiveOpacity }}>
234
+ {renderLabel(false)}
235
+ </Animated.View>
236
+ <Animated.View
237
+ style={[StyleSheet.absoluteFill, { opacity: activeOpacity }]}
238
+ >
239
+ {renderLabel(true)}
240
+ </Animated.View>
241
+ </View>
242
+ {customBadge != null ? (
243
+ <View style={styles.badge}>{customBadge()}</View>
244
+ ) : null}
249
245
  </View>
250
246
  </PlatformPressable>
251
247
  );
@@ -256,31 +252,15 @@ const MemoizedTabBarItemInternal = React.memo(
256
252
  ) as typeof TabBarItemInternal;
257
253
 
258
254
  export function TabBarItem<T extends Route>(props: Props<T>) {
259
- const {
260
- onPress,
261
- onLongPress,
262
- onLayout,
263
- navigationState,
264
- route,
265
- getAccessibilityLabel,
266
- getLabelText,
267
- getTestID,
268
- getAccessible,
269
- ...rest
270
- } = props;
255
+ const { onPress, onLongPress, onLayout, navigationState, route, ...rest } =
256
+ props;
257
+
271
258
  const onPressLatest = useLatestCallback(onPress);
272
259
  const onLongPressLatest = useLatestCallback(onLongPress);
273
260
  const onLayoutLatest = useLatestCallback(onLayout ? onLayout : () => {});
274
261
 
275
262
  const tabIndex = navigationState.routes.indexOf(route);
276
263
 
277
- const scene = { route };
278
-
279
- const accessibilityLabel = getAccessibilityLabel(scene);
280
- const label = getLabelText(scene);
281
- const testID = getTestID(scene);
282
- const accessible = getAccessible(scene);
283
-
284
264
  return (
285
265
  <MemoizedTabBarItemInternal
286
266
  {...rest}
@@ -291,10 +271,6 @@ export function TabBarItem<T extends Route>(props: Props<T>) {
291
271
  route={route}
292
272
  index={tabIndex}
293
273
  routesLength={navigationState.routes.length}
294
- accessibilityLabel={accessibilityLabel}
295
- label={label}
296
- testID={testID}
297
- accessible={accessible}
298
274
  />
299
275
  );
300
276
  }
@@ -313,7 +289,7 @@ const styles = StyleSheet.create({
313
289
  badge: {
314
290
  position: 'absolute',
315
291
  top: 0,
316
- right: 0,
292
+ end: 0,
317
293
  },
318
294
  pressable: {
319
295
  // The label is not pressable on Windows
@@ -33,7 +33,8 @@ export const TabBarItemLabel = React.memo(
33
33
  const styles = StyleSheet.create({
34
34
  label: {
35
35
  margin: 4,
36
+ fontSize: 14,
37
+ fontWeight: '500',
36
38
  backgroundColor: 'transparent',
37
- textTransform: 'uppercase',
38
39
  },
39
40
  });
package/src/TabView.tsx CHANGED
@@ -24,7 +24,6 @@ import type {
24
24
  export type Props<T extends Route> = Omit<PagerProps, 'layoutDirection'> & {
25
25
  onIndexChange: (index: number) => void;
26
26
  navigationState: NavigationState<T>;
27
- renderScene: (props: SceneRendererProps & { route: T }) => React.ReactNode;
28
27
  renderLazyPlaceholder?: (props: { route: T }) => React.ReactNode;
29
28
  renderTabBar?: (
30
29
  props: SceneRendererProps & { navigationState: NavigationState<T> }
@@ -37,6 +36,7 @@ export type Props<T extends Route> = Omit<PagerProps, 'layoutDirection'> & {
37
36
  direction?: LocaleDirection;
38
37
  pagerStyle?: StyleProp<ViewStyle>;
39
38
  style?: StyleProp<ViewStyle>;
39
+ renderScene: (props: SceneRendererProps & { route: T }) => React.ReactNode;
40
40
  };
41
41
 
42
42
  export function TabView<T extends Route>({
@@ -111,7 +111,7 @@ export function TabView<T extends Route>({
111
111
  layoutDirection={direction}
112
112
  >
113
113
  {({ position, render, addEnterListener, jumpTo }) => {
114
- // All of the props here must not change between re-renders
114
+ // All the props here must not change between re-renders
115
115
  // This is crucial to optimizing the routes with PureComponent
116
116
  const sceneRendererProps = {
117
117
  position,
package/src/index.tsx CHANGED
@@ -7,4 +7,9 @@ export type { Props as TabBarItemProps } from './TabBarItem';
7
7
  export { TabBarItem } from './TabBarItem';
8
8
  export type { Props as TabViewProps } from './TabView';
9
9
  export { TabView } from './TabView';
10
- export type { NavigationState, Route, SceneRendererProps } from './types';
10
+ export type {
11
+ NavigationState,
12
+ Route,
13
+ SceneRendererProps,
14
+ TabDescriptor,
15
+ } from './types';
package/src/types.tsx CHANGED
@@ -1,6 +1,30 @@
1
- import type { Animated } from 'react-native';
1
+ import type { Animated, StyleProp, TextStyle } from 'react-native';
2
2
  import type { PagerViewProps } from 'react-native-pager-view';
3
3
 
4
+ export type TabDescriptor<T extends Route> = {
5
+ accessibilityLabel?: string;
6
+ accessible?: boolean;
7
+ testID?: string;
8
+ labelText?: string;
9
+ labelAllowFontScaling?: boolean;
10
+ href?: string;
11
+ label?: (props: {
12
+ focused: boolean;
13
+ color: string;
14
+ style?: StyleProp<TextStyle>;
15
+ allowFontScaling?: boolean;
16
+ label?: string;
17
+ route: T;
18
+ }) => React.ReactElement;
19
+ icon?: (props: {
20
+ focused: boolean;
21
+ color: string;
22
+ size: number;
23
+ route: T;
24
+ }) => React.ReactElement;
25
+ badge?: () => React.ReactElement;
26
+ };
27
+
4
28
  export type LocaleDirection = 'ltr' | 'rtl';
5
29
 
6
30
  export type Route = {