react-native-tab-view 3.3.0 → 3.3.2

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 (56) hide show
  1. package/{LICENSE.md → LICENSE} +0 -0
  2. package/README.md +5 -36
  3. package/lib/commonjs/PagerViewAdapter.js.map +1 -1
  4. package/lib/commonjs/PanResponderAdapter.js +1 -1
  5. package/lib/commonjs/PanResponderAdapter.js.map +1 -1
  6. package/lib/commonjs/SceneMap.js.map +1 -1
  7. package/lib/commonjs/SceneView.js.map +1 -1
  8. package/lib/commonjs/TabBar.js +42 -9
  9. package/lib/commonjs/TabBar.js.map +1 -1
  10. package/lib/commonjs/TabBarIndicator.js +4 -4
  11. package/lib/commonjs/TabBarIndicator.js.map +1 -1
  12. package/lib/commonjs/TabBarItem.js.map +1 -1
  13. package/lib/commonjs/TabView.js +2 -2
  14. package/lib/commonjs/TabView.js.map +1 -1
  15. package/lib/commonjs/index.js +3 -3
  16. package/lib/commonjs/index.js.map +1 -1
  17. package/lib/module/PagerViewAdapter.js.map +1 -1
  18. package/lib/module/PanResponderAdapter.js +2 -2
  19. package/lib/module/PanResponderAdapter.js.map +1 -1
  20. package/lib/module/SceneMap.js.map +1 -1
  21. package/lib/module/SceneView.js +1 -1
  22. package/lib/module/SceneView.js.map +1 -1
  23. package/lib/module/TabBar.js +41 -10
  24. package/lib/module/TabBar.js.map +1 -1
  25. package/lib/module/TabBarIndicator.js +5 -5
  26. package/lib/module/TabBarIndicator.js.map +1 -1
  27. package/lib/module/TabBarItem.js.map +1 -1
  28. package/lib/module/TabView.js +2 -2
  29. package/lib/module/TabView.js.map +1 -1
  30. package/lib/module/index.js +2 -2
  31. package/lib/module/index.js.map +1 -1
  32. package/lib/typescript/{Pager.android.d.ts → src/Pager.android.d.ts} +0 -0
  33. package/lib/typescript/{Pager.d.ts → src/Pager.d.ts} +0 -0
  34. package/lib/typescript/{Pager.ios.d.ts → src/Pager.ios.d.ts} +0 -0
  35. package/lib/typescript/{PagerViewAdapter.d.ts → src/PagerViewAdapter.d.ts} +1 -1
  36. package/lib/typescript/{PanResponderAdapter.d.ts → src/PanResponderAdapter.d.ts} +1 -1
  37. package/lib/typescript/{PlatformPressable.d.ts → src/PlatformPressable.d.ts} +0 -0
  38. package/lib/typescript/{SceneMap.d.ts → src/SceneMap.d.ts} +0 -0
  39. package/lib/typescript/{SceneView.d.ts → src/SceneView.d.ts} +1 -1
  40. package/lib/typescript/{TabBar.d.ts → src/TabBar.d.ts} +5 -4
  41. package/lib/typescript/{TabBarIndicator.d.ts → src/TabBarIndicator.d.ts} +1 -1
  42. package/lib/typescript/{TabBarItem.d.ts → src/TabBarItem.d.ts} +2 -2
  43. package/lib/typescript/{TabView.d.ts → src/TabView.d.ts} +1 -1
  44. package/lib/typescript/{index.d.ts → src/index.d.ts} +7 -7
  45. package/lib/typescript/{types.d.ts → src/types.d.ts} +0 -0
  46. package/lib/typescript/{useAnimatedValue.d.ts → src/useAnimatedValue.d.ts} +0 -0
  47. package/package.json +27 -60
  48. package/src/PagerViewAdapter.tsx +5 -4
  49. package/src/PanResponderAdapter.tsx +10 -9
  50. package/src/SceneMap.tsx +1 -0
  51. package/src/SceneView.tsx +3 -2
  52. package/src/TabBar.tsx +59 -14
  53. package/src/TabBarIndicator.tsx +11 -8
  54. package/src/TabBarItem.tsx +5 -4
  55. package/src/TabView.tsx +6 -5
  56. package/src/index.tsx +7 -12
package/package.json CHANGED
@@ -1,27 +1,7 @@
1
1
  {
2
2
  "name": "react-native-tab-view",
3
- "version": "3.3.0",
4
3
  "description": "Tab view component for React Native",
5
- "main": "lib/commonjs/index.js",
6
- "react-native": "src/index.tsx",
7
- "module": "lib/module/index.js",
8
- "types": "lib/typescript/index.d.ts",
9
- "files": [
10
- "src",
11
- "lib"
12
- ],
13
- "scripts": {
14
- "test": "jest",
15
- "typescript": "tsc --noEmit",
16
- "lint": "eslint --ext .js,.ts,.tsx .",
17
- "release": "release-it",
18
- "example": "yarn --cwd example",
19
- "bootstrap": "yarn example && yarn",
20
- "prepare": "bob build"
21
- },
22
- "publishConfig": {
23
- "registry": "https://registry.npmjs.org/"
24
- },
4
+ "version": "3.3.2",
25
5
  "keywords": [
26
6
  "react-native-component",
27
7
  "react-component",
@@ -33,57 +13,46 @@
33
13
  "scrollable",
34
14
  "coverflow"
35
15
  ],
16
+ "license": "MIT",
36
17
  "repository": {
37
18
  "type": "git",
38
- "url": "git+https://github.com/satya164/react-native-tab-view.git"
19
+ "url": "https://github.com/react-navigation/react-navigation.git",
20
+ "directory": "packages/react-native-tab-view"
39
21
  },
40
- "author": "Satyajit Sahoo <satyajit.happy@gmail.com> (https://github.com/satya164/)",
41
- "license": "MIT",
42
22
  "bugs": {
43
- "url": "https://github.com/satya164/react-native-tab-view/issues"
23
+ "url": "https://github.com/react-navigation/react-navigation/issues"
24
+ },
25
+ "homepage": "https://github.com/react-navigation/react-navigation/tree/main/packages/react-native-tab-view#readme",
26
+ "main": "lib/commonjs/index.js",
27
+ "react-native": "src/index.tsx",
28
+ "source": "src/index.tsx",
29
+ "module": "lib/module/index.js",
30
+ "types": "lib/typescript/src/index.d.ts",
31
+ "files": [
32
+ "src",
33
+ "lib",
34
+ "!**/__tests__"
35
+ ],
36
+ "sideEffects": false,
37
+ "scripts": {
38
+ "prepack": "bob build",
39
+ "clean": "del lib"
40
+ },
41
+ "dependencies": {
42
+ "use-latest-callback": "^0.1.5"
44
43
  },
45
- "homepage": "https://github.com/satya164/react-native-tab-view#readme",
46
44
  "devDependencies": {
47
- "@commitlint/config-conventional": "^17.1.0",
48
- "@expo/vector-icons": "^13.0.0",
49
- "@release-it/conventional-changelog": "^5.1.0",
50
- "@types/react": "^18.0.14",
51
- "@types/react-native": "0.69.5",
52
- "babel-jest": "^29.0.1",
53
- "babel-loader": "^8.2.5",
54
- "babel-preset-react-native": "^4.0.0",
55
- "commitlint": "^17.1.2",
56
- "eslint": "^8.23.0",
57
- "eslint-config-satya164": "^3.1.11",
58
- "eslint-plugin-react-native-globals": "^0.1.2",
59
- "husky": "^4.2.5",
60
- "jest": "^29.0.1",
61
- "prettier": "^2.7.1",
62
45
  "react": "18.0.0",
63
46
  "react-native": "0.69.5",
64
- "react-native-builder-bob": "^0.18.3",
47
+ "react-native-builder-bob": "^0.18.1",
65
48
  "react-native-pager-view": "5.4.24",
66
- "release-it": "^15.4.0",
67
- "typescript": "^4.8.2"
49
+ "typescript": "^4.7.4"
68
50
  },
69
51
  "peerDependencies": {
70
52
  "react": "*",
71
53
  "react-native": "*",
72
54
  "react-native-pager-view": "*"
73
55
  },
74
- "husky": {
75
- "hooks": {
76
- "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
77
- "pre-commit": "yarn lint && yarn typescript"
78
- }
79
- },
80
- "jest": {
81
- "preset": "react-native",
82
- "modulePathIgnorePatterns": [
83
- "<rootDir>/example/node_modules",
84
- "<rootDir>/lib/"
85
- ]
86
- },
87
56
  "react-native-builder-bob": {
88
57
  "source": "src",
89
58
  "output": "lib",
@@ -98,7 +67,5 @@
98
67
  ]
99
68
  ]
100
69
  },
101
- "dependencies": {
102
- "use-latest-callback": "^0.1.5"
103
- }
70
+ "gitHead": "4e29403ec63d9304561e296667f6cf15806c316b"
104
71
  }
@@ -3,14 +3,15 @@ import { Animated, Keyboard, StyleSheet } from 'react-native';
3
3
  import ViewPager, {
4
4
  PageScrollStateChangedNativeEvent,
5
5
  } from 'react-native-pager-view';
6
- import useAnimatedValue from './useAnimatedValue';
6
+
7
7
  import type {
8
- NavigationState,
9
- Route,
10
- Listener,
11
8
  EventEmitterProps,
9
+ Listener,
10
+ NavigationState,
12
11
  PagerProps,
12
+ Route,
13
13
  } from './types';
14
+ import useAnimatedValue from './useAnimatedValue';
14
15
 
15
16
  const AnimatedViewPager = Animated.createAnimatedComponent(ViewPager);
16
17
 
@@ -1,23 +1,24 @@
1
1
  import * as React from 'react';
2
2
  import {
3
3
  Animated,
4
- PanResponder,
5
- Keyboard,
6
- StyleSheet,
7
4
  GestureResponderEvent,
8
- PanResponderGestureState,
9
5
  I18nManager,
6
+ Keyboard,
7
+ PanResponder,
8
+ PanResponderGestureState,
9
+ StyleSheet,
10
10
  View,
11
11
  } from 'react-native';
12
- import useAnimatedValue from './useAnimatedValue';
12
+
13
13
  import type {
14
- NavigationState,
15
- Route,
16
- Layout,
17
14
  EventEmitterProps,
18
- PagerProps,
15
+ Layout,
19
16
  Listener,
17
+ NavigationState,
18
+ PagerProps,
19
+ Route,
20
20
  } from './types';
21
+ import useAnimatedValue from './useAnimatedValue';
21
22
 
22
23
  type Props<T extends Route> = PagerProps & {
23
24
  layout: Layout;
package/src/SceneMap.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as React from 'react';
2
+
2
3
  import type { SceneRendererProps } from './types';
3
4
 
4
5
  type SceneProps = {
package/src/SceneView.tsx CHANGED
@@ -1,10 +1,11 @@
1
1
  import * as React from 'react';
2
- import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
2
+ import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
3
+
3
4
  import type {
4
- SceneRendererProps,
5
5
  EventEmitterProps,
6
6
  NavigationState,
7
7
  Route,
8
+ SceneRendererProps,
8
9
  } from './types';
9
10
 
10
11
  type Props<T extends Route> = SceneRendererProps &
package/src/TabBar.tsx CHANGED
@@ -1,26 +1,29 @@
1
1
  import * as React from 'react';
2
2
  import {
3
3
  Animated,
4
+ FlatList,
5
+ I18nManager,
6
+ LayoutChangeEvent,
7
+ ListRenderItemInfo,
8
+ Platform,
9
+ StyleProp,
4
10
  StyleSheet,
11
+ TextStyle,
5
12
  View,
6
- StyleProp,
7
13
  ViewStyle,
8
- TextStyle,
9
- LayoutChangeEvent,
10
- I18nManager,
11
- Platform,
12
- FlatList,
13
- ListRenderItemInfo,
14
+ ViewToken,
14
15
  } from 'react-native';
15
- import TabBarItem, { Props as TabBarItemProps } from './TabBarItem';
16
+ import useLatestCallback from 'use-latest-callback';
17
+
16
18
  import TabBarIndicator, { Props as IndicatorProps } from './TabBarIndicator';
19
+ import TabBarItem, { Props as TabBarItemProps } from './TabBarItem';
17
20
  import type {
21
+ Event,
22
+ Layout,
23
+ NavigationState,
18
24
  Route,
19
25
  Scene,
20
26
  SceneRendererProps,
21
- NavigationState,
22
- Layout,
23
- Event,
24
27
  } from './types';
25
28
  import useAnimatedValue from './useAnimatedValue';
26
29
 
@@ -62,6 +65,7 @@ export type Props<T extends Route> = SceneRendererProps & {
62
65
  contentContainerStyle?: StyleProp<ViewStyle>;
63
66
  style?: StyleProp<ViewStyle>;
64
67
  gap?: number;
68
+ testID?: string;
65
69
  };
66
70
 
67
71
  type FlattenedTabWidth = string | number | undefined;
@@ -246,6 +250,10 @@ const renderIndicatorDefault = (props: IndicatorProps<Route>) => (
246
250
 
247
251
  const getTestIdDefault = ({ route }: Scene<Route>) => route.testID;
248
252
 
253
+ // How many items measurements should we update per batch.
254
+ // Defaults to 10, since that's whats FlatList is using in initialNumToRender.
255
+ const MEASURE_PER_BATCH = 10;
256
+
249
257
  export default function TabBar<T extends Route>({
250
258
  getLabelText = getLabelTextDefault,
251
259
  getAccessible = getAccessibleDefault,
@@ -274,10 +282,11 @@ export default function TabBar<T extends Route>({
274
282
  renderTabBarItem,
275
283
  style,
276
284
  tabStyle,
285
+ testID,
277
286
  }: Props<T>) {
278
287
  const [layout, setLayout] = React.useState<Layout>({ width: 0, height: 0 });
279
288
  const [tabWidths, setTabWidths] = React.useState<Record<string, number>>({});
280
- const flatListRef = React.useRef<FlatList>(null);
289
+ const flatListRef = React.useRef<FlatList | null>(null);
281
290
  const isFirst = React.useRef(true);
282
291
  const scrollAmount = useAnimatedValue(0);
283
292
  const measuredTabWidths = React.useRef<Record<string, number>>({});
@@ -296,7 +305,9 @@ export default function TabBar<T extends Route>({
296
305
 
297
306
  const hasMeasuredTabWidths =
298
307
  Boolean(layout.width) &&
299
- routes.every((r) => typeof tabWidths[r.key] === 'number');
308
+ routes
309
+ .slice(0, navigationState.index)
310
+ .every((r) => typeof tabWidths[r.key] === 'number');
300
311
 
301
312
  React.useEffect(() => {
302
313
  if (isFirst.current) {
@@ -305,7 +316,6 @@ export default function TabBar<T extends Route>({
305
316
  }
306
317
 
307
318
  if (isWidthDynamic && !hasMeasuredTabWidths) {
308
- // When tab width is dynamic, only adjust the scroll once we have all tab widths and layout
309
319
  return;
310
320
  }
311
321
 
@@ -373,11 +383,24 @@ export default function TabBar<T extends Route>({
373
383
 
374
384
  // When we have measured widths for all of the tabs, we should updates the state
375
385
  // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app
386
+ // If we have more than 10 routes divide updating tabWidths into multiple batches. Here we update only first batch of 10 items.
376
387
  if (
388
+ routes.length > MEASURE_PER_BATCH &&
389
+ index === MEASURE_PER_BATCH &&
390
+ routes
391
+ .slice(0, MEASURE_PER_BATCH)
392
+ .every(
393
+ (r) => typeof measuredTabWidths.current[r.key] === 'number'
394
+ )
395
+ ) {
396
+ setTabWidths({ ...measuredTabWidths.current });
397
+ } else if (
377
398
  routes.every(
378
399
  (r) => typeof measuredTabWidths.current[r.key] === 'number'
379
400
  )
380
401
  ) {
402
+ // When we have measured widths for all of the tabs, we should updates the state
403
+ // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app
381
404
  setTabWidths({ ...measuredTabWidths.current });
382
405
  }
383
406
  }
@@ -492,6 +515,25 @@ export default function TabBar<T extends Route>({
492
515
  [scrollAmount]
493
516
  );
494
517
 
518
+ const handleViewableItemsChanged = useLatestCallback(
519
+ ({ changed }: { changed: ViewToken[] }) => {
520
+ if (routes.length <= MEASURE_PER_BATCH) {
521
+ return;
522
+ }
523
+ // Get next vievable item
524
+ const item = changed[changed.length - 1];
525
+ const index = item?.index || 0;
526
+ if (
527
+ item.isViewable &&
528
+ (index % 10 === 0 ||
529
+ index === navigationState.index ||
530
+ index === routes.length - 1)
531
+ ) {
532
+ setTabWidths({ ...measuredTabWidths.current });
533
+ }
534
+ }
535
+ );
536
+
495
537
  return (
496
538
  <Animated.View onLayout={handleLayout} style={[styles.tabBar, style]}>
497
539
  <Animated.View
@@ -537,6 +579,8 @@ export default function TabBar<T extends Route>({
537
579
  keyboardShouldPersistTaps="handled"
538
580
  scrollEnabled={scrollEnabled}
539
581
  bounces={bounces}
582
+ initialNumToRender={MEASURE_PER_BATCH}
583
+ onViewableItemsChanged={handleViewableItemsChanged}
540
584
  alwaysBounceHorizontal={false}
541
585
  scrollsToTop={false}
542
586
  showsHorizontalScrollIndicator={false}
@@ -548,6 +592,7 @@ export default function TabBar<T extends Route>({
548
592
  renderItem={renderItem}
549
593
  onScroll={handleScroll}
550
594
  ref={flatListRef}
595
+ testID={testID}
551
596
  />
552
597
  </View>
553
598
  </Animated.View>
@@ -2,14 +2,14 @@ import * as React from 'react';
2
2
  import {
3
3
  Animated,
4
4
  Easing,
5
- StyleSheet,
6
5
  I18nManager,
6
+ Platform,
7
7
  StyleProp,
8
+ StyleSheet,
8
9
  ViewStyle,
9
- Platform,
10
10
  } from 'react-native';
11
11
 
12
- import type { Route, SceneRendererProps, NavigationState } from './types';
12
+ import type { NavigationState, Route, SceneRendererProps } from './types';
13
13
  import useAnimatedValue from './useAnimatedValue';
14
14
 
15
15
  export type GetTabWidth = (index: number) => number;
@@ -59,9 +59,12 @@ export default function TabBarIndicator<T extends Route>({
59
59
 
60
60
  const opacity = useAnimatedValue(isWidthDynamic ? 0 : 1);
61
61
 
62
- const hasMeasuredTabWidths =
63
- Boolean(layout.width) &&
64
- navigationState.routes.every((_, i) => getTabWidth(i));
62
+ const indicatorVisible = isWidthDynamic
63
+ ? layout.width &&
64
+ navigationState.routes
65
+ .slice(0, navigationState.index)
66
+ .every((_, r) => getTabWidth(r))
67
+ : true;
65
68
 
66
69
  React.useEffect(() => {
67
70
  const fadeInIndicator = () => {
@@ -69,7 +72,7 @@ export default function TabBarIndicator<T extends Route>({
69
72
  !isIndicatorShown.current &&
70
73
  isWidthDynamic &&
71
74
  // We should fade-in the indicator when we have widths for all the tab items
72
- hasMeasuredTabWidths
75
+ indicatorVisible
73
76
  ) {
74
77
  isIndicatorShown.current = true;
75
78
 
@@ -85,7 +88,7 @@ export default function TabBarIndicator<T extends Route>({
85
88
  fadeInIndicator();
86
89
 
87
90
  return () => opacity.stopAnimation();
88
- }, [hasMeasuredTabWidths, isWidthDynamic, opacity]);
91
+ }, [indicatorVisible, isWidthDynamic, opacity]);
89
92
 
90
93
  const { routes } = navigationState;
91
94
 
@@ -1,16 +1,17 @@
1
1
  import * as React from 'react';
2
2
  import {
3
3
  Animated,
4
- StyleSheet,
5
- View,
6
- StyleProp,
7
4
  LayoutChangeEvent,
5
+ StyleProp,
6
+ StyleSheet,
8
7
  TextStyle,
8
+ View,
9
9
  ViewStyle,
10
10
  } from 'react-native';
11
11
  import useLatestCallback from 'use-latest-callback';
12
+
12
13
  import PlatformPressable from './PlatformPressable';
13
- import type { Scene, Route, NavigationState } from './types';
14
+ import type { NavigationState, Route, Scene } from './types';
14
15
 
15
16
  export type Props<T extends Route> = {
16
17
  position: Animated.AnimatedInterpolation;
package/src/TabView.tsx CHANGED
@@ -1,20 +1,21 @@
1
1
  import * as React from 'react';
2
2
  import {
3
+ LayoutChangeEvent,
4
+ StyleProp,
3
5
  StyleSheet,
4
6
  View,
5
- StyleProp,
6
7
  ViewStyle,
7
- LayoutChangeEvent,
8
8
  } from 'react-native';
9
- import TabBar from './TabBar';
10
- import SceneView from './SceneView';
9
+
11
10
  import Pager from './Pager';
11
+ import SceneView from './SceneView';
12
+ import TabBar from './TabBar';
12
13
  import type {
13
14
  Layout,
14
15
  NavigationState,
16
+ PagerProps,
15
17
  Route,
16
18
  SceneRendererProps,
17
- PagerProps,
18
19
  } from './types';
19
20
 
20
21
  export type Props<T extends Route> = PagerProps & {
package/src/index.tsx CHANGED
@@ -1,15 +1,10 @@
1
- export { default as TabBar } from './TabBar';
1
+ export { default as SceneMap } from './SceneMap';
2
2
  export type { Props as TabBarProps } from './TabBar';
3
-
4
- export { default as TabView } from './TabView';
5
- export type { Props as TabViewProps } from './TabView';
6
-
7
- export { default as TabBarIndicator } from './TabBarIndicator';
3
+ export { default as TabBar } from './TabBar';
8
4
  export type { Props as TabBarIndicatorProps } from './TabBarIndicator';
9
-
10
- export { default as TabBarItem } from './TabBarItem';
5
+ export { default as TabBarIndicator } from './TabBarIndicator';
11
6
  export type { Props as TabBarItemProps } from './TabBarItem';
12
-
13
- export { default as SceneMap } from './SceneMap';
14
-
15
- export type { Route, NavigationState, SceneRendererProps } from './types';
7
+ export { default as TabBarItem } from './TabBarItem';
8
+ export type { Props as TabViewProps } from './TabView';
9
+ export { default as TabView } from './TabView';
10
+ export type { NavigationState, Route, SceneRendererProps } from './types';