react-native-tab-view 3.1.1 → 3.2.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 (65) hide show
  1. package/README.md +13 -1
  2. package/lib/commonjs/Pager.android.js.map +1 -1
  3. package/lib/commonjs/Pager.ios.js.map +1 -1
  4. package/lib/commonjs/Pager.js.map +1 -1
  5. package/lib/commonjs/PagerViewAdapter.js +40 -22
  6. package/lib/commonjs/PagerViewAdapter.js.map +1 -1
  7. package/lib/commonjs/PanResponderAdapter.js +41 -29
  8. package/lib/commonjs/PanResponderAdapter.js.map +1 -1
  9. package/lib/commonjs/PlatformPressable.js +19 -15
  10. package/lib/commonjs/PlatformPressable.js.map +1 -1
  11. package/lib/commonjs/SceneMap.js +14 -11
  12. package/lib/commonjs/SceneMap.js.map +1 -1
  13. package/lib/commonjs/SceneView.js +2 -2
  14. package/lib/commonjs/SceneView.js.map +1 -1
  15. package/lib/commonjs/TabBar.js +124 -81
  16. package/lib/commonjs/TabBar.js.map +1 -1
  17. package/lib/commonjs/TabBarIndicator.js +7 -6
  18. package/lib/commonjs/TabBarIndicator.js.map +1 -1
  19. package/lib/commonjs/TabBarItem.js +7 -6
  20. package/lib/commonjs/TabBarItem.js.map +1 -1
  21. package/lib/commonjs/TabView.js +42 -33
  22. package/lib/commonjs/TabView.js.map +1 -1
  23. package/lib/commonjs/index.js +6 -6
  24. package/lib/commonjs/index.js.map +1 -1
  25. package/lib/commonjs/types.js +4 -0
  26. package/lib/commonjs/types.js.map +1 -1
  27. package/lib/commonjs/useAnimatedValue.js.map +1 -1
  28. package/lib/module/Pager.android.js.map +1 -1
  29. package/lib/module/Pager.ios.js.map +1 -1
  30. package/lib/module/Pager.js.map +1 -1
  31. package/lib/module/PagerViewAdapter.js +40 -22
  32. package/lib/module/PagerViewAdapter.js.map +1 -1
  33. package/lib/module/PanResponderAdapter.js +41 -28
  34. package/lib/module/PanResponderAdapter.js.map +1 -1
  35. package/lib/module/PlatformPressable.js +19 -15
  36. package/lib/module/PlatformPressable.js.map +1 -1
  37. package/lib/module/SceneMap.js +14 -11
  38. package/lib/module/SceneMap.js.map +1 -1
  39. package/lib/module/SceneView.js +2 -2
  40. package/lib/module/SceneView.js.map +1 -1
  41. package/lib/module/TabBar.js +125 -81
  42. package/lib/module/TabBar.js.map +1 -1
  43. package/lib/module/TabBarIndicator.js +7 -6
  44. package/lib/module/TabBarIndicator.js.map +1 -1
  45. package/lib/module/TabBarItem.js +7 -6
  46. package/lib/module/TabBarItem.js.map +1 -1
  47. package/lib/module/TabView.js +41 -32
  48. package/lib/module/TabView.js.map +1 -1
  49. package/lib/module/index.js.map +1 -1
  50. package/lib/module/types.js +1 -1
  51. package/lib/module/types.js.map +1 -1
  52. package/lib/module/useAnimatedValue.js.map +1 -1
  53. package/lib/typescript/PagerViewAdapter.d.ts +1 -1
  54. package/lib/typescript/PanResponderAdapter.d.ts +1 -1
  55. package/lib/typescript/TabBar.d.ts +3 -1
  56. package/lib/typescript/TabBarIndicator.d.ts +1 -0
  57. package/lib/typescript/TabView.d.ts +2 -1
  58. package/lib/typescript/types.d.ts +1 -0
  59. package/package.json +19 -18
  60. package/src/PagerViewAdapter.tsx +23 -9
  61. package/src/PanResponderAdapter.tsx +23 -17
  62. package/src/TabBar.tsx +75 -31
  63. package/src/TabBarIndicator.tsx +14 -5
  64. package/src/TabView.tsx +5 -0
  65. package/src/types.tsx +1 -0
package/src/TabBar.tsx CHANGED
@@ -3,13 +3,14 @@ import {
3
3
  Animated,
4
4
  StyleSheet,
5
5
  View,
6
- ScrollView,
7
6
  StyleProp,
8
7
  ViewStyle,
9
8
  TextStyle,
10
9
  LayoutChangeEvent,
11
10
  I18nManager,
12
11
  Platform,
12
+ FlatList,
13
+ ListRenderItemInfo,
13
14
  } from 'react-native';
14
15
  import TabBarItem, { Props as TabBarItemProps } from './TabBarItem';
15
16
  import TabBarIndicator, { Props as IndicatorProps } from './TabBarIndicator';
@@ -59,6 +60,7 @@ export type Props<T extends Route> = SceneRendererProps & {
59
60
  labelStyle?: StyleProp<TextStyle>;
60
61
  contentContainerStyle?: StyleProp<ViewStyle>;
61
62
  style?: StyleProp<ViewStyle>;
63
+ gap?: number;
62
64
  };
63
65
 
64
66
  type State = {
@@ -66,6 +68,10 @@ type State = {
66
68
  tabWidths: { [key: string]: number };
67
69
  };
68
70
 
71
+ const Separator = ({ width }: { width: number }) => {
72
+ return <View style={{ width }} />;
73
+ };
74
+
69
75
  export default class TabBar<T extends Route> extends React.Component<
70
76
  Props<T>,
71
77
  State
@@ -84,6 +90,7 @@ export default class TabBar<T extends Route> extends React.Component<
84
90
  renderIndicator: (props: IndicatorProps<Route>) => (
85
91
  <TabBarIndicator {...props} />
86
92
  ),
93
+ gap: 0,
87
94
  };
88
95
 
89
96
  state: State = {
@@ -125,7 +132,7 @@ export default class TabBar<T extends Route> extends React.Component<
125
132
 
126
133
  private scrollAmount = new Animated.Value(0);
127
134
 
128
- private scrollViewRef = React.createRef<ScrollView>();
135
+ private flatListRef = React.createRef<FlatList>();
129
136
 
130
137
  private getFlattenedTabWidth = (style: StyleProp<ViewStyle>) => {
131
138
  const tabStyle = StyleSheet.flatten(style);
@@ -160,7 +167,6 @@ export default class TabBar<T extends Route> extends React.Component<
160
167
  if (scrollEnabled) {
161
168
  return (layout.width / 5) * 2;
162
169
  }
163
-
164
170
  return layout.width / routes.length;
165
171
  };
166
172
 
@@ -175,6 +181,7 @@ export default class TabBar<T extends Route> extends React.Component<
175
181
  return routes.reduce<number>(
176
182
  (acc, _, i) =>
177
183
  acc +
184
+ (i > 0 ? props.gap ?? 0 : 0) +
178
185
  this.getComputedTabWidth(
179
186
  i,
180
187
  layout,
@@ -224,7 +231,12 @@ export default class TabBar<T extends Route> extends React.Component<
224
231
 
225
232
  // To get the current index centered we adjust scroll amount by width of indexes
226
233
  // 0 through (i - 1) and add half the width of current index i
227
- return total + (index === i ? tabWidth / 2 : tabWidth);
234
+ return (
235
+ total +
236
+ (index === i
237
+ ? (tabWidth + (props.gap ?? 0)) / 2
238
+ : tabWidth + (props.gap ?? 0))
239
+ );
228
240
  },
229
241
  0
230
242
  );
@@ -236,8 +248,8 @@ export default class TabBar<T extends Route> extends React.Component<
236
248
 
237
249
  private resetScroll = (index: number) => {
238
250
  if (this.props.scrollEnabled) {
239
- this.scrollViewRef.current?.scrollTo({
240
- x: this.getScrollAmount(this.props, this.state, index),
251
+ this.flatListRef.current?.scrollToOffset({
252
+ offset: this.getScrollAmount(this.props, this.state, index),
241
253
  animated: true,
242
254
  });
243
255
  }
@@ -299,12 +311,16 @@ export default class TabBar<T extends Route> extends React.Component<
299
311
  contentContainerStyle,
300
312
  style,
301
313
  indicatorContainerStyle,
314
+ gap = 0,
302
315
  } = this.props;
303
316
  const { layout, tabWidths } = this.state;
304
317
  const { routes } = navigationState;
305
318
 
306
319
  const isWidthDynamic = this.getFlattenedTabWidth(tabStyle) === 'auto';
307
320
  const tabBarWidth = this.getTabBarWidth(this.props, this.state);
321
+ const separatorsWidth = Math.max(0, routes.length - 1) * gap;
322
+ const separatorPercent = (separatorsWidth / tabBarWidth) * 100;
323
+
308
324
  const tabBarWidthPercent = `${routes.length * 40}%`;
309
325
  const translateX = this.getTranslateX(
310
326
  this.scrollAmount,
@@ -321,8 +337,8 @@ export default class TabBar<T extends Route> extends React.Component<
321
337
  style={[
322
338
  styles.indicatorContainer,
323
339
  scrollEnabled ? { transform: [{ translateX }] as any } : null,
324
- tabBarWidth
325
- ? { width: tabBarWidth }
340
+ tabBarWidth > separatorsWidth
341
+ ? { width: tabBarWidth - separatorsWidth }
326
342
  : scrollEnabled
327
343
  ? { width: tabBarWidthPercent }
328
344
  : null,
@@ -334,7 +350,9 @@ export default class TabBar<T extends Route> extends React.Component<
334
350
  layout,
335
351
  navigationState,
336
352
  jumpTo,
337
- width: isWidthDynamic ? 'auto' : `${100 / routes.length}%`,
353
+ width: isWidthDynamic
354
+ ? 'auto'
355
+ : `${(100 - separatorPercent) / routes.length}%`,
338
356
  style: indicatorStyle,
339
357
  getTabWidth: (i: number) =>
340
358
  this.getComputedTabWidth(
@@ -345,10 +363,13 @@ export default class TabBar<T extends Route> extends React.Component<
345
363
  tabWidths,
346
364
  this.getFlattenedTabWidth(tabStyle)
347
365
  ),
366
+ gap,
348
367
  })}
349
368
  </Animated.View>
350
369
  <View style={styles.scroll}>
351
- <Animated.ScrollView
370
+ <Animated.FlatList
371
+ data={routes as Animated.WithAnimatedValue<T>[]}
372
+ keyExtractor={(item) => item.key}
352
373
  horizontal
353
374
  accessibilityRole="tablist"
354
375
  keyboardShouldPersistTaps="handled"
@@ -357,29 +378,23 @@ export default class TabBar<T extends Route> extends React.Component<
357
378
  alwaysBounceHorizontal={false}
358
379
  scrollsToTop={false}
359
380
  showsHorizontalScrollIndicator={false}
381
+ showsVerticalScrollIndicator={false}
360
382
  automaticallyAdjustContentInsets={false}
361
383
  overScrollMode="never"
362
384
  contentContainerStyle={[
363
385
  styles.tabContent,
364
386
  scrollEnabled
365
- ? { width: tabBarWidth || tabBarWidthPercent }
387
+ ? {
388
+ width:
389
+ tabBarWidth > separatorsWidth
390
+ ? tabBarWidth
391
+ : tabBarWidthPercent,
392
+ }
366
393
  : styles.container,
367
394
  contentContainerStyle,
368
395
  ]}
369
396
  scrollEventThrottle={16}
370
- onScroll={Animated.event(
371
- [
372
- {
373
- nativeEvent: {
374
- contentOffset: { x: this.scrollAmount },
375
- },
376
- },
377
- ],
378
- { useNativeDriver: true }
379
- )}
380
- ref={this.scrollViewRef}
381
- >
382
- {routes.map((route: T) => {
397
+ renderItem={({ item: route, index }: ListRenderItemInfo<T>) => {
383
398
  const props: TabBarItemProps<T> & { key: string } = {
384
399
  key: route.key,
385
400
  position: position,
@@ -434,16 +449,45 @@ export default class TabBar<T extends Route> extends React.Component<
434
449
  },
435
450
  onLongPress: () => onTabLongPress?.({ route }),
436
451
  labelStyle: labelStyle,
437
- style: tabStyle,
452
+ style: [
453
+ tabStyle,
454
+ // Calculate the deafult width for tab for FlatList to work.
455
+ this.getFlattenedTabWidth(tabStyle) === undefined && {
456
+ width: this.getComputedTabWidth(
457
+ index,
458
+ layout,
459
+ routes,
460
+ scrollEnabled,
461
+ tabWidths,
462
+ this.getFlattenedTabWidth(tabStyle)
463
+ ),
464
+ },
465
+ ],
438
466
  };
439
467
 
440
- return renderTabBarItem ? (
441
- renderTabBarItem(props)
442
- ) : (
443
- <TabBarItem {...props} />
468
+ return (
469
+ <React.Fragment key={route.key}>
470
+ {gap > 0 && index > 0 ? <Separator width={gap} /> : null}
471
+ {renderTabBarItem ? (
472
+ renderTabBarItem(props)
473
+ ) : (
474
+ <TabBarItem {...props} />
475
+ )}
476
+ </React.Fragment>
444
477
  );
445
- })}
446
- </Animated.ScrollView>
478
+ }}
479
+ onScroll={Animated.event(
480
+ [
481
+ {
482
+ nativeEvent: {
483
+ contentOffset: { x: this.scrollAmount },
484
+ },
485
+ },
486
+ ],
487
+ { useNativeDriver: true }
488
+ )}
489
+ ref={this.flatListRef}
490
+ />
447
491
  </View>
448
492
  </Animated.View>
449
493
  );
@@ -18,6 +18,7 @@ export type Props<T extends Route> = SceneRendererProps & {
18
18
  width: string | number;
19
19
  style?: StyleProp<ViewStyle>;
20
20
  getTabWidth: GetTabWidth;
21
+ gap?: number;
21
22
  };
22
23
 
23
24
  export default class TabBarIndicator<T extends Route> extends React.Component<
@@ -59,14 +60,15 @@ export default class TabBarIndicator<T extends Route> extends React.Component<
59
60
  private getTranslateX = (
60
61
  position: Animated.AnimatedInterpolation,
61
62
  routes: Route[],
62
- getTabWidth: GetTabWidth
63
+ getTabWidth: GetTabWidth,
64
+ gap?: number
63
65
  ) => {
64
66
  const inputRange = routes.map((_, i) => i);
65
67
 
66
68
  // every index contains widths at all previous indices
67
69
  const outputRange = routes.reduce<number[]>((acc, _, i) => {
68
70
  if (i === 0) return [0];
69
- return [...acc, acc[i - 1] + getTabWidth(i - 1)];
71
+ return [...acc, acc[i - 1] + getTabWidth(i - 1) + (gap ?? 0)];
70
72
  }, []);
71
73
 
72
74
  const translateX = position.interpolate({
@@ -79,8 +81,15 @@ export default class TabBarIndicator<T extends Route> extends React.Component<
79
81
  };
80
82
 
81
83
  render() {
82
- const { position, navigationState, getTabWidth, width, style, layout } =
83
- this.props;
84
+ const {
85
+ position,
86
+ navigationState,
87
+ getTabWidth,
88
+ width,
89
+ style,
90
+ layout,
91
+ gap,
92
+ } = this.props;
84
93
  const { routes } = navigationState;
85
94
 
86
95
  const transform = [];
@@ -88,7 +97,7 @@ export default class TabBarIndicator<T extends Route> extends React.Component<
88
97
  if (layout.width) {
89
98
  const translateX =
90
99
  routes.length > 1
91
- ? this.getTranslateX(position, routes, getTabWidth)
100
+ ? this.getTranslateX(position, routes, getTabWidth, gap)
92
101
  : 0;
93
102
 
94
103
  transform.push({ translateX });
package/src/TabView.tsx CHANGED
@@ -30,6 +30,7 @@ export type Props<T extends Route> = PagerProps & {
30
30
  lazy?: ((props: { route: T }) => boolean) | boolean;
31
31
  lazyPreloadDistance?: number;
32
32
  sceneContainerStyle?: StyleProp<ViewStyle>;
33
+ pagerStyle?: StyleProp<ViewStyle>;
33
34
  style?: StyleProp<ViewStyle>;
34
35
  };
35
36
 
@@ -46,9 +47,11 @@ export default function TabView<T extends Route>({
46
47
  renderLazyPlaceholder = () => null,
47
48
  renderTabBar = (props) => <TabBar {...props} />,
48
49
  sceneContainerStyle,
50
+ pagerStyle,
49
51
  style,
50
52
  swipeEnabled = true,
51
53
  tabBarPosition = 'top',
54
+ animationEnabled = true,
52
55
  }: Props<T>) {
53
56
  const [layout, setLayout] = React.useState({
54
57
  width: 0,
@@ -84,6 +87,8 @@ export default function TabView<T extends Route>({
84
87
  onSwipeStart={onSwipeStart}
85
88
  onSwipeEnd={onSwipeEnd}
86
89
  onIndexChange={jumpToIndex}
90
+ animationEnabled={animationEnabled}
91
+ style={pagerStyle}
87
92
  >
88
93
  {({ position, render, addEnterListener, jumpTo }) => {
89
94
  // All of the props here must not change between re-renders
package/src/types.tsx CHANGED
@@ -53,6 +53,7 @@ export type PagerProps = Omit<
53
53
  > & {
54
54
  keyboardDismissMode?: 'none' | 'on-drag' | 'auto';
55
55
  swipeEnabled?: boolean;
56
+ animationEnabled?: boolean;
56
57
  onSwipeStart?: () => void;
57
58
  onSwipeEnd?: () => void;
58
59
  };