react-native-tab-view 3.2.1 → 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 (66) hide show
  1. package/{LICENSE.md → LICENSE} +0 -0
  2. package/README.md +5 -36
  3. package/lib/commonjs/PagerViewAdapter.js +2 -1
  4. package/lib/commonjs/PagerViewAdapter.js.map +1 -1
  5. package/lib/commonjs/PanResponderAdapter.js +2 -1
  6. package/lib/commonjs/PanResponderAdapter.js.map +1 -1
  7. package/lib/commonjs/SceneMap.js +9 -12
  8. package/lib/commonjs/SceneMap.js.map +1 -1
  9. package/lib/commonjs/SceneView.js +54 -101
  10. package/lib/commonjs/SceneView.js.map +1 -1
  11. package/lib/commonjs/TabBar.js +358 -325
  12. package/lib/commonjs/TabBar.js.map +1 -1
  13. package/lib/commonjs/TabBarIndicator.js +81 -99
  14. package/lib/commonjs/TabBarIndicator.js.map +1 -1
  15. package/lib/commonjs/TabBarItem.js +184 -161
  16. package/lib/commonjs/TabBarItem.js.map +1 -1
  17. package/lib/commonjs/TabView.js +2 -2
  18. package/lib/commonjs/TabView.js.map +1 -1
  19. package/lib/commonjs/index.js +3 -3
  20. package/lib/commonjs/index.js.map +1 -1
  21. package/lib/module/PagerViewAdapter.js +2 -1
  22. package/lib/module/PagerViewAdapter.js.map +1 -1
  23. package/lib/module/PanResponderAdapter.js +3 -2
  24. package/lib/module/PanResponderAdapter.js.map +1 -1
  25. package/lib/module/SceneMap.js +9 -14
  26. package/lib/module/SceneMap.js.map +1 -1
  27. package/lib/module/SceneView.js +54 -99
  28. package/lib/module/SceneView.js.map +1 -1
  29. package/lib/module/TabBar.js +355 -324
  30. package/lib/module/TabBar.js.map +1 -1
  31. package/lib/module/TabBarIndicator.js +75 -93
  32. package/lib/module/TabBarIndicator.js.map +1 -1
  33. package/lib/module/TabBarItem.js +178 -154
  34. package/lib/module/TabBarItem.js.map +1 -1
  35. package/lib/module/TabView.js +2 -2
  36. package/lib/module/TabView.js.map +1 -1
  37. package/lib/module/index.js +2 -2
  38. package/lib/module/index.js.map +1 -1
  39. package/lib/typescript/{Pager.android.d.ts → src/Pager.android.d.ts} +0 -0
  40. package/lib/typescript/{Pager.d.ts → src/Pager.d.ts} +0 -0
  41. package/lib/typescript/{Pager.ios.d.ts → src/Pager.ios.d.ts} +0 -0
  42. package/lib/typescript/{PagerViewAdapter.d.ts → src/PagerViewAdapter.d.ts} +1 -1
  43. package/lib/typescript/{PanResponderAdapter.d.ts → src/PanResponderAdapter.d.ts} +1 -1
  44. package/lib/typescript/{PlatformPressable.d.ts → src/PlatformPressable.d.ts} +0 -0
  45. package/lib/typescript/{SceneMap.d.ts → src/SceneMap.d.ts} +5 -3
  46. package/lib/typescript/src/SceneView.d.ts +15 -0
  47. package/lib/typescript/src/TabBar.d.ts +42 -0
  48. package/lib/typescript/src/TabBarIndicator.d.ts +12 -0
  49. package/lib/typescript/{TabBarItem.d.ts → src/TabBarItem.d.ts} +5 -7
  50. package/lib/typescript/{TabView.d.ts → src/TabView.d.ts} +1 -1
  51. package/lib/typescript/{index.d.ts → src/index.d.ts} +7 -7
  52. package/lib/typescript/{types.d.ts → src/types.d.ts} +0 -0
  53. package/lib/typescript/{useAnimatedValue.d.ts → src/useAnimatedValue.d.ts} +0 -0
  54. package/package.json +28 -58
  55. package/src/PagerViewAdapter.tsx +11 -5
  56. package/src/PanResponderAdapter.tsx +16 -12
  57. package/src/SceneMap.tsx +12 -7
  58. package/src/SceneView.tsx +73 -108
  59. package/src/TabBar.tsx +506 -401
  60. package/src/TabBarIndicator.tsx +114 -117
  61. package/src/TabBarItem.tsx +230 -200
  62. package/src/TabView.tsx +6 -5
  63. package/src/index.tsx +7 -12
  64. package/lib/typescript/SceneView.d.ts +0 -32
  65. package/lib/typescript/TabBar.d.ts +0 -72
  66. package/lib/typescript/TabBarIndicator.d.ts +0 -20
@@ -1,9 +1,9 @@
1
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2
-
3
1
  import * as React from 'react';
4
- import { Animated, StyleSheet, View, I18nManager, Platform } from 'react-native';
5
- import TabBarItem from './TabBarItem';
2
+ import { Animated, I18nManager, Platform, StyleSheet, View } from 'react-native';
3
+ import useLatestCallback from 'use-latest-callback';
6
4
  import TabBarIndicator from './TabBarIndicator';
5
+ import TabBarItem from './TabBarItem';
6
+ import useAnimatedValue from './useAnimatedValue';
7
7
 
8
8
  const Separator = _ref => {
9
9
  let {
@@ -16,359 +16,390 @@ const Separator = _ref => {
16
16
  });
17
17
  };
18
18
 
19
- export default class TabBar extends React.Component {
20
- constructor() {
21
- super(...arguments);
22
-
23
- _defineProperty(this, "state", {
24
- layout: {
25
- width: 0,
26
- height: 0
27
- },
28
- tabWidths: {}
29
- });
19
+ const getFlattenedTabWidth = style => {
20
+ const tabStyle = StyleSheet.flatten(style);
21
+ return tabStyle === null || tabStyle === void 0 ? void 0 : tabStyle.width;
22
+ };
30
23
 
31
- _defineProperty(this, "measuredTabWidths", {});
24
+ const getComputedTabWidth = (index, layout, routes, scrollEnabled, tabWidths, flattenedWidth) => {
25
+ if (flattenedWidth === 'auto') {
26
+ return tabWidths[routes[index].key] || 0;
27
+ }
32
28
 
33
- _defineProperty(this, "scrollAmount", new Animated.Value(0));
29
+ switch (typeof flattenedWidth) {
30
+ case 'number':
31
+ return flattenedWidth;
34
32
 
35
- _defineProperty(this, "flatListRef", /*#__PURE__*/React.createRef());
33
+ case 'string':
34
+ if (flattenedWidth.endsWith('%')) {
35
+ const width = parseFloat(flattenedWidth);
36
36
 
37
- _defineProperty(this, "getFlattenedTabWidth", style => {
38
- const tabStyle = StyleSheet.flatten(style);
39
- return tabStyle ? tabStyle.width : undefined;
40
- });
41
-
42
- _defineProperty(this, "getComputedTabWidth", (index, layout, routes, scrollEnabled, tabWidths, flattenedWidth) => {
43
- if (flattenedWidth === 'auto') {
44
- return tabWidths[routes[index].key] || 0;
37
+ if (Number.isFinite(width)) {
38
+ return layout.width * (width / 100);
39
+ }
45
40
  }
46
41
 
47
- switch (typeof flattenedWidth) {
48
- case 'number':
49
- return flattenedWidth;
42
+ }
50
43
 
51
- case 'string':
52
- if (flattenedWidth.endsWith('%')) {
53
- const width = parseFloat(flattenedWidth);
44
+ if (scrollEnabled) {
45
+ return layout.width / 5 * 2;
46
+ }
54
47
 
55
- if (Number.isFinite(width)) {
56
- return layout.width * (width / 100);
57
- }
58
- }
48
+ return layout.width / routes.length;
49
+ };
59
50
 
60
- }
51
+ const getMaxScrollDistance = (tabBarWidth, layoutWidth) => tabBarWidth - layoutWidth;
61
52
 
62
- if (scrollEnabled) {
63
- return layout.width / 5 * 2;
64
- }
53
+ const getTranslateX = (scrollAmount, maxScrollDistance) => Animated.multiply(Platform.OS === 'android' && I18nManager.isRTL ? Animated.add(maxScrollDistance, Animated.multiply(scrollAmount, -1)) : scrollAmount, I18nManager.isRTL ? 1 : -1);
65
54
 
66
- return layout.width / routes.length;
67
- });
55
+ const getTabBarWidth = _ref2 => {
56
+ let {
57
+ navigationState,
58
+ layout,
59
+ gap,
60
+ scrollEnabled,
61
+ flattenedTabWidth,
62
+ tabWidths
63
+ } = _ref2;
64
+ const {
65
+ routes
66
+ } = navigationState;
67
+ return routes.reduce((acc, _, i) => acc + (i > 0 ? gap !== null && gap !== void 0 ? gap : 0 : 0) + getComputedTabWidth(i, layout, routes, scrollEnabled, tabWidths, flattenedTabWidth), 0);
68
+ };
68
69
 
69
- _defineProperty(this, "getMaxScrollDistance", (tabBarWidth, layoutWidth) => tabBarWidth - layoutWidth);
70
-
71
- _defineProperty(this, "getTabBarWidth", (props, state) => {
72
- const {
73
- layout,
74
- tabWidths
75
- } = state;
76
- const {
77
- scrollEnabled,
78
- tabStyle
79
- } = props;
80
- const {
81
- routes
82
- } = props.navigationState;
83
- return routes.reduce((acc, _, i) => acc + (i > 0 ? props.gap ?? 0 : 0) + this.getComputedTabWidth(i, layout, routes, scrollEnabled, tabWidths, this.getFlattenedTabWidth(tabStyle)), 0);
84
- });
70
+ const normalizeScrollValue = _ref3 => {
71
+ let {
72
+ layout,
73
+ navigationState,
74
+ gap,
75
+ scrollEnabled,
76
+ tabWidths,
77
+ value,
78
+ flattenedTabWidth
79
+ } = _ref3;
80
+ const tabBarWidth = getTabBarWidth({
81
+ layout,
82
+ navigationState,
83
+ tabWidths,
84
+ gap,
85
+ scrollEnabled,
86
+ flattenedTabWidth
87
+ });
88
+ const maxDistance = getMaxScrollDistance(tabBarWidth, layout.width);
89
+ const scrollValue = Math.max(Math.min(value, maxDistance), 0);
85
90
 
86
- _defineProperty(this, "normalizeScrollValue", (props, state, value) => {
87
- const {
88
- layout
89
- } = state;
90
- const tabBarWidth = this.getTabBarWidth(props, state);
91
- const maxDistance = this.getMaxScrollDistance(tabBarWidth, layout.width);
92
- const scrollValue = Math.max(Math.min(value, maxDistance), 0);
93
-
94
- if (Platform.OS === 'android' && I18nManager.isRTL) {
95
- // On Android, scroll value is not applied in reverse in RTL
96
- // so we need to manually adjust it to apply correct value
97
- return maxDistance - scrollValue;
98
- }
91
+ if (Platform.OS === 'android' && I18nManager.isRTL) {
92
+ // On Android, scroll value is not applied in reverse in RTL
93
+ // so we need to manually adjust it to apply correct value
94
+ return maxDistance - scrollValue;
95
+ }
99
96
 
100
- return scrollValue;
101
- });
97
+ return scrollValue;
98
+ };
102
99
 
103
- _defineProperty(this, "getScrollAmount", (props, state, index) => {
104
- const {
105
- layout,
106
- tabWidths
107
- } = state;
108
- const {
109
- scrollEnabled,
110
- tabStyle
111
- } = props;
112
- const {
113
- routes
114
- } = props.navigationState;
115
- const centerDistance = Array.from({
116
- length: index + 1
117
- }).reduce((total, _, i) => {
118
- const tabWidth = this.getComputedTabWidth(i, layout, routes, scrollEnabled, tabWidths, this.getFlattenedTabWidth(tabStyle)); // To get the current index centered we adjust scroll amount by width of indexes
119
- // 0 through (i - 1) and add half the width of current index i
120
-
121
- return total + (index === i ? (tabWidth + (props.gap ?? 0)) / 2 : tabWidth + (props.gap ?? 0));
122
- }, 0);
123
- const scrollAmount = centerDistance - layout.width / 2;
124
- return this.normalizeScrollValue(props, state, scrollAmount);
125
- });
100
+ const getScrollAmount = _ref4 => {
101
+ let {
102
+ layout,
103
+ navigationState,
104
+ gap,
105
+ scrollEnabled,
106
+ flattenedTabWidth,
107
+ tabWidths
108
+ } = _ref4;
109
+ const centerDistance = Array.from({
110
+ length: navigationState.index + 1
111
+ }).reduce((total, _, i) => {
112
+ const tabWidth = getComputedTabWidth(i, layout, navigationState.routes, scrollEnabled, tabWidths, flattenedTabWidth); // To get the current index centered we adjust scroll amount by width of indexes
113
+ // 0 through (i - 1) and add half the width of current index i
114
+
115
+ return total + (navigationState.index === i ? (tabWidth + (gap !== null && gap !== void 0 ? gap : 0)) / 2 : tabWidth + (gap !== null && gap !== void 0 ? gap : 0));
116
+ }, 0);
117
+ const scrollAmount = centerDistance - layout.width / 2;
118
+ return normalizeScrollValue({
119
+ layout,
120
+ navigationState,
121
+ tabWidths,
122
+ value: scrollAmount,
123
+ gap,
124
+ scrollEnabled,
125
+ flattenedTabWidth
126
+ });
127
+ };
126
128
 
127
- _defineProperty(this, "resetScroll", index => {
128
- if (this.props.scrollEnabled) {
129
- var _this$flatListRef$cur;
129
+ const getLabelTextDefault = _ref5 => {
130
+ let {
131
+ route
132
+ } = _ref5;
133
+ return route.title;
134
+ };
130
135
 
131
- (_this$flatListRef$cur = this.flatListRef.current) === null || _this$flatListRef$cur === void 0 ? void 0 : _this$flatListRef$cur.scrollToOffset({
132
- offset: this.getScrollAmount(this.props, this.state, index),
133
- animated: true
134
- });
135
- }
136
- });
136
+ const getAccessibleDefault = _ref6 => {
137
+ let {
138
+ route
139
+ } = _ref6;
140
+ return typeof route.accessible !== 'undefined' ? route.accessible : true;
141
+ };
137
142
 
138
- _defineProperty(this, "handleLayout", e => {
139
- const {
140
- height,
141
- width
142
- } = e.nativeEvent.layout;
143
+ const getAccessibilityLabelDefault = _ref7 => {
144
+ let {
145
+ route
146
+ } = _ref7;
147
+ return typeof route.accessibilityLabel === 'string' ? route.accessibilityLabel : typeof route.title === 'string' ? route.title : undefined;
148
+ };
143
149
 
144
- if (this.state.layout.width === width && this.state.layout.height === height) {
145
- return;
146
- }
150
+ const renderIndicatorDefault = props => /*#__PURE__*/React.createElement(TabBarIndicator, props);
147
151
 
148
- this.setState({
149
- layout: {
150
- height,
151
- width
152
- }
153
- });
154
- });
152
+ const getTestIdDefault = _ref8 => {
153
+ let {
154
+ route
155
+ } = _ref8;
156
+ return route.testID;
157
+ }; // How many items measurements should we update per batch.
158
+ // Defaults to 10, since that's whats FlatList is using in initialNumToRender.
155
159
 
156
- _defineProperty(this, "getTranslateX", (scrollAmount, maxScrollDistance) => Animated.multiply(Platform.OS === 'android' && I18nManager.isRTL ? Animated.add(maxScrollDistance, Animated.multiply(scrollAmount, -1)) : scrollAmount, I18nManager.isRTL ? 1 : -1));
157
- }
158
160
 
159
- componentDidUpdate(prevProps, prevState) {
160
- const {
161
- navigationState
162
- } = this.props;
163
- const {
164
- layout,
165
- tabWidths
166
- } = this.state;
167
-
168
- if (prevProps.navigationState.routes.length !== navigationState.routes.length || prevProps.navigationState.index !== navigationState.index || prevState.layout.width !== layout.width || prevState.tabWidths !== tabWidths) {
169
- if (this.getFlattenedTabWidth(this.props.tabStyle) === 'auto' && !(layout.width && navigationState.routes.every(r => typeof tabWidths[r.key] === 'number'))) {
170
- // When tab width is dynamic, only adjust the scroll once we have all tab widths and layout
171
- return;
172
- }
161
+ const MEASURE_PER_BATCH = 10;
162
+ export default function TabBar(_ref9) {
163
+ let {
164
+ getLabelText = getLabelTextDefault,
165
+ getAccessible = getAccessibleDefault,
166
+ getAccessibilityLabel = getAccessibilityLabelDefault,
167
+ getTestID = getTestIdDefault,
168
+ renderIndicator = renderIndicatorDefault,
169
+ gap = 0,
170
+ scrollEnabled,
171
+ jumpTo,
172
+ navigationState,
173
+ position,
174
+ activeColor,
175
+ bounces,
176
+ contentContainerStyle,
177
+ inactiveColor,
178
+ indicatorContainerStyle,
179
+ indicatorStyle,
180
+ labelStyle,
181
+ onTabLongPress,
182
+ onTabPress,
183
+ pressColor,
184
+ pressOpacity,
185
+ renderBadge,
186
+ renderIcon,
187
+ renderLabel,
188
+ renderTabBarItem,
189
+ style,
190
+ tabStyle,
191
+ testID
192
+ } = _ref9;
193
+ const [layout, setLayout] = React.useState({
194
+ width: 0,
195
+ height: 0
196
+ });
197
+ const [tabWidths, setTabWidths] = React.useState({});
198
+ const flatListRef = React.useRef(null);
199
+ const isFirst = React.useRef(true);
200
+ const scrollAmount = useAnimatedValue(0);
201
+ const measuredTabWidths = React.useRef({});
202
+ const {
203
+ routes
204
+ } = navigationState;
205
+ const flattenedTabWidth = getFlattenedTabWidth(tabStyle);
206
+ const isWidthDynamic = flattenedTabWidth === 'auto';
207
+ const scrollOffset = getScrollAmount({
208
+ layout,
209
+ navigationState,
210
+ tabWidths,
211
+ gap,
212
+ scrollEnabled,
213
+ flattenedTabWidth
214
+ });
215
+ const hasMeasuredTabWidths = Boolean(layout.width) && routes.slice(0, navigationState.index).every(r => typeof tabWidths[r.key] === 'number');
216
+ React.useEffect(() => {
217
+ if (isFirst.current) {
218
+ isFirst.current = false;
219
+ return;
220
+ }
173
221
 
174
- this.resetScroll(navigationState.index);
222
+ if (isWidthDynamic && !hasMeasuredTabWidths) {
223
+ return;
175
224
  }
176
- } // to store the layout.width of each tab
177
- // when all onLayout's are fired, this would be set in state
178
225
 
226
+ if (scrollEnabled) {
227
+ var _flatListRef$current;
179
228
 
180
- render() {
181
- const {
182
- position,
183
- navigationState,
184
- jumpTo,
185
- scrollEnabled,
186
- bounces,
187
- getAccessibilityLabel,
188
- getAccessible,
189
- getLabelText,
190
- getTestID,
191
- renderBadge,
192
- renderIcon,
193
- renderLabel,
194
- renderTabBarItem,
195
- activeColor,
196
- inactiveColor,
197
- pressColor,
198
- pressOpacity,
199
- onTabPress,
200
- onTabLongPress,
201
- tabStyle,
202
- labelStyle,
203
- indicatorStyle,
204
- contentContainerStyle,
205
- style,
206
- indicatorContainerStyle,
207
- gap = 0
208
- } = this.props;
209
- const {
210
- layout,
211
- tabWidths
212
- } = this.state;
229
+ (_flatListRef$current = flatListRef.current) === null || _flatListRef$current === void 0 ? void 0 : _flatListRef$current.scrollToOffset({
230
+ offset: scrollOffset,
231
+ animated: true
232
+ });
233
+ }
234
+ }, [hasMeasuredTabWidths, isWidthDynamic, scrollEnabled, scrollOffset]);
235
+
236
+ const handleLayout = e => {
213
237
  const {
214
- routes
215
- } = navigationState;
216
- const isWidthDynamic = this.getFlattenedTabWidth(tabStyle) === 'auto';
217
- const tabBarWidth = this.getTabBarWidth(this.props, this.state);
218
- const separatorsWidth = Math.max(0, routes.length - 1) * gap;
219
- const separatorPercent = separatorsWidth / tabBarWidth * 100;
220
- const tabBarWidthPercent = `${routes.length * 40}%`;
221
- const translateX = this.getTranslateX(this.scrollAmount, this.getMaxScrollDistance(tabBarWidth, layout.width));
222
- return /*#__PURE__*/React.createElement(Animated.View, {
223
- onLayout: this.handleLayout,
224
- style: [styles.tabBar, style]
225
- }, /*#__PURE__*/React.createElement(Animated.View, {
226
- pointerEvents: "none",
227
- style: [styles.indicatorContainer, scrollEnabled ? {
228
- transform: [{
229
- translateX
230
- }]
231
- } : null, tabBarWidth > separatorsWidth ? {
232
- width: tabBarWidth - separatorsWidth
233
- } : scrollEnabled ? {
234
- width: tabBarWidthPercent
235
- } : null, indicatorContainerStyle]
236
- }, this.props.renderIndicator({
237
- position,
238
- layout,
239
- navigationState,
240
- jumpTo,
241
- width: isWidthDynamic ? 'auto' : `${(100 - separatorPercent) / routes.length}%`,
242
- style: indicatorStyle,
243
- getTabWidth: i => this.getComputedTabWidth(i, layout, routes, scrollEnabled, tabWidths, this.getFlattenedTabWidth(tabStyle)),
244
- gap
245
- })), /*#__PURE__*/React.createElement(View, {
246
- style: styles.scroll
247
- }, /*#__PURE__*/React.createElement(Animated.FlatList, {
248
- data: routes,
249
- keyExtractor: item => item.key,
250
- horizontal: true,
251
- accessibilityRole: "tablist",
252
- keyboardShouldPersistTaps: "handled",
253
- scrollEnabled: scrollEnabled,
254
- bounces: bounces,
255
- alwaysBounceHorizontal: false,
256
- scrollsToTop: false,
257
- showsHorizontalScrollIndicator: false,
258
- showsVerticalScrollIndicator: false,
259
- automaticallyAdjustContentInsets: false,
260
- overScrollMode: "never",
261
- contentContainerStyle: [styles.tabContent, scrollEnabled ? {
262
- width: tabBarWidth > separatorsWidth ? tabBarWidth : tabBarWidthPercent
263
- } : styles.container, contentContainerStyle],
264
- scrollEventThrottle: 16,
265
- renderItem: _ref2 => {
266
- let {
267
- item: route,
268
- index
269
- } = _ref2;
270
- const props = {
271
- key: route.key,
272
- position: position,
273
- route: route,
274
- navigationState: navigationState,
275
- getAccessibilityLabel: getAccessibilityLabel,
276
- getAccessible: getAccessible,
277
- getLabelText: getLabelText,
278
- getTestID: getTestID,
279
- renderBadge: renderBadge,
280
- renderIcon: renderIcon,
281
- renderLabel: renderLabel,
282
- activeColor: activeColor,
283
- inactiveColor: inactiveColor,
284
- pressColor: pressColor,
285
- pressOpacity: pressOpacity,
286
- onLayout: isWidthDynamic ? e => {
287
- this.measuredTabWidths[route.key] = e.nativeEvent.layout.width; // When we have measured widths for all of the tabs, we should updates the state
288
- // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app
289
-
290
- if (routes.every(r => typeof this.measuredTabWidths[r.key] === 'number')) {
291
- this.setState({
292
- tabWidths: { ...this.measuredTabWidths
293
- }
294
- });
295
- }
296
- } : undefined,
297
- onPress: () => {
298
- const event = {
299
- route,
300
- defaultPrevented: false,
301
- preventDefault: () => {
302
- event.defaultPrevented = true;
303
- }
304
- };
305
- onTabPress === null || onTabPress === void 0 ? void 0 : onTabPress(event);
306
-
307
- if (event.defaultPrevented) {
308
- return;
309
- }
310
-
311
- this.props.jumpTo(route.key);
312
- },
313
- onLongPress: () => onTabLongPress === null || onTabLongPress === void 0 ? void 0 : onTabLongPress({
314
- route
315
- }),
316
- labelStyle: labelStyle,
317
- style: [tabStyle, // Calculate the deafult width for tab for FlatList to work.
318
- this.getFlattenedTabWidth(tabStyle) === undefined && {
319
- width: this.getComputedTabWidth(index, layout, routes, scrollEnabled, tabWidths, this.getFlattenedTabWidth(tabStyle))
320
- }]
321
- };
322
- return /*#__PURE__*/React.createElement(React.Fragment, {
323
- key: route.key
324
- }, gap > 0 && index > 0 ? /*#__PURE__*/React.createElement(Separator, {
325
- width: gap
326
- }) : null, renderTabBarItem ? renderTabBarItem(props) : /*#__PURE__*/React.createElement(TabBarItem, props));
327
- },
328
- onScroll: Animated.event([{
329
- nativeEvent: {
330
- contentOffset: {
331
- x: this.scrollAmount
238
+ height,
239
+ width
240
+ } = e.nativeEvent.layout;
241
+ setLayout(layout => layout.width === width && layout.height === height ? layout : {
242
+ width,
243
+ height
244
+ });
245
+ };
246
+
247
+ const tabBarWidth = getTabBarWidth({
248
+ layout,
249
+ navigationState,
250
+ tabWidths,
251
+ gap,
252
+ scrollEnabled,
253
+ flattenedTabWidth
254
+ });
255
+ const separatorsWidth = Math.max(0, routes.length - 1) * gap;
256
+ const separatorPercent = separatorsWidth / tabBarWidth * 100;
257
+ const tabBarWidthPercent = `${routes.length * 40}%`;
258
+ const translateX = React.useMemo(() => getTranslateX(scrollAmount, getMaxScrollDistance(tabBarWidth, layout.width)), [layout.width, scrollAmount, tabBarWidth]);
259
+ const renderItem = React.useCallback(_ref10 => {
260
+ let {
261
+ item: route,
262
+ index
263
+ } = _ref10;
264
+ const props = {
265
+ key: route.key,
266
+ position: position,
267
+ route: route,
268
+ navigationState: navigationState,
269
+ getAccessibilityLabel: getAccessibilityLabel,
270
+ getAccessible: getAccessible,
271
+ getLabelText: getLabelText,
272
+ getTestID: getTestID,
273
+ renderBadge: renderBadge,
274
+ renderIcon: renderIcon,
275
+ renderLabel: renderLabel,
276
+ activeColor: activeColor,
277
+ inactiveColor: inactiveColor,
278
+ pressColor: pressColor,
279
+ pressOpacity: pressOpacity,
280
+ onLayout: isWidthDynamic ? e => {
281
+ measuredTabWidths.current[route.key] = e.nativeEvent.layout.width; // When we have measured widths for all of the tabs, we should updates the state
282
+ // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app
283
+ // If we have more than 10 routes divide updating tabWidths into multiple batches. Here we update only first batch of 10 items.
284
+
285
+ if (routes.length > MEASURE_PER_BATCH && index === MEASURE_PER_BATCH && routes.slice(0, MEASURE_PER_BATCH).every(r => typeof measuredTabWidths.current[r.key] === 'number')) {
286
+ setTabWidths({ ...measuredTabWidths.current
287
+ });
288
+ } else if (routes.every(r => typeof measuredTabWidths.current[r.key] === 'number')) {
289
+ // When we have measured widths for all of the tabs, we should updates the state
290
+ // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app
291
+ setTabWidths({ ...measuredTabWidths.current
292
+ });
293
+ }
294
+ } : undefined,
295
+ onPress: () => {
296
+ const event = {
297
+ route,
298
+ defaultPrevented: false,
299
+ preventDefault: () => {
300
+ event.defaultPrevented = true;
332
301
  }
302
+ };
303
+ onTabPress === null || onTabPress === void 0 ? void 0 : onTabPress(event);
304
+
305
+ if (event.defaultPrevented) {
306
+ return;
333
307
  }
334
- }], {
335
- useNativeDriver: true
308
+
309
+ jumpTo(route.key);
310
+ },
311
+ onLongPress: () => onTabLongPress === null || onTabLongPress === void 0 ? void 0 : onTabLongPress({
312
+ route
336
313
  }),
337
- ref: this.flatListRef
338
- })));
339
- }
314
+ labelStyle: labelStyle,
315
+ style: tabStyle,
316
+ // Calculate the deafult width for tab for FlatList to work
317
+ defaultTabWidth: !isWidthDynamic ? getComputedTabWidth(index, layout, routes, scrollEnabled, tabWidths, getFlattenedTabWidth(tabStyle)) : undefined
318
+ };
319
+ return /*#__PURE__*/React.createElement(React.Fragment, null, gap > 0 && index > 0 ? /*#__PURE__*/React.createElement(Separator, {
320
+ width: gap
321
+ }) : null, renderTabBarItem ? renderTabBarItem(props) : /*#__PURE__*/React.createElement(TabBarItem, props));
322
+ }, [activeColor, gap, getAccessibilityLabel, getAccessible, getLabelText, getTestID, inactiveColor, isWidthDynamic, jumpTo, labelStyle, layout, navigationState, onTabLongPress, onTabPress, position, pressColor, pressOpacity, renderBadge, renderIcon, renderLabel, renderTabBarItem, routes, scrollEnabled, tabStyle, tabWidths]);
323
+ const keyExtractor = React.useCallback(item => item.key, []);
324
+ const contentContainerStyleMemoized = React.useMemo(() => [styles.tabContent, scrollEnabled ? {
325
+ width: tabBarWidth > separatorsWidth ? tabBarWidth : tabBarWidthPercent
326
+ } : styles.container, contentContainerStyle], [contentContainerStyle, scrollEnabled, separatorsWidth, tabBarWidth, tabBarWidthPercent]);
327
+ const handleScroll = React.useMemo(() => Animated.event([{
328
+ nativeEvent: {
329
+ contentOffset: {
330
+ x: scrollAmount
331
+ }
332
+ }
333
+ }], {
334
+ useNativeDriver: true
335
+ }), [scrollAmount]);
336
+ const handleViewableItemsChanged = useLatestCallback(_ref11 => {
337
+ let {
338
+ changed
339
+ } = _ref11;
340
340
 
341
- }
341
+ if (routes.length <= MEASURE_PER_BATCH) {
342
+ return;
343
+ } // Get next vievable item
342
344
 
343
- _defineProperty(TabBar, "defaultProps", {
344
- getLabelText: _ref3 => {
345
- let {
346
- route
347
- } = _ref3;
348
- return route.title;
349
- },
350
- getAccessible: _ref4 => {
351
- let {
352
- route
353
- } = _ref4;
354
- return typeof route.accessible !== 'undefined' ? route.accessible : true;
355
- },
356
- getAccessibilityLabel: _ref5 => {
357
- let {
358
- route
359
- } = _ref5;
360
- return typeof route.accessibilityLabel === 'string' ? route.accessibilityLabel : typeof route.title === 'string' ? route.title : undefined;
361
- },
362
- getTestID: _ref6 => {
363
- let {
364
- route
365
- } = _ref6;
366
- return route.testID;
367
- },
368
- renderIndicator: props => /*#__PURE__*/React.createElement(TabBarIndicator, props),
369
- gap: 0
370
- });
371
345
 
346
+ const item = changed[changed.length - 1];
347
+ const index = (item === null || item === void 0 ? void 0 : item.index) || 0;
348
+
349
+ if (item.isViewable && (index % 10 === 0 || index === navigationState.index || index === routes.length - 1)) {
350
+ setTabWidths({ ...measuredTabWidths.current
351
+ });
352
+ }
353
+ });
354
+ return /*#__PURE__*/React.createElement(Animated.View, {
355
+ onLayout: handleLayout,
356
+ style: [styles.tabBar, style]
357
+ }, /*#__PURE__*/React.createElement(Animated.View, {
358
+ pointerEvents: "none",
359
+ style: [styles.indicatorContainer, scrollEnabled ? {
360
+ transform: [{
361
+ translateX
362
+ }]
363
+ } : null, tabBarWidth > separatorsWidth ? {
364
+ width: tabBarWidth - separatorsWidth
365
+ } : scrollEnabled ? {
366
+ width: tabBarWidthPercent
367
+ } : null, indicatorContainerStyle]
368
+ }, renderIndicator({
369
+ position,
370
+ layout,
371
+ navigationState,
372
+ jumpTo,
373
+ width: isWidthDynamic ? 'auto' : `${(100 - separatorPercent) / routes.length}%`,
374
+ style: indicatorStyle,
375
+ getTabWidth: i => getComputedTabWidth(i, layout, routes, scrollEnabled, tabWidths, flattenedTabWidth),
376
+ gap
377
+ })), /*#__PURE__*/React.createElement(View, {
378
+ style: styles.scroll
379
+ }, /*#__PURE__*/React.createElement(Animated.FlatList, {
380
+ data: routes,
381
+ keyExtractor: keyExtractor,
382
+ horizontal: true,
383
+ accessibilityRole: "tablist",
384
+ keyboardShouldPersistTaps: "handled",
385
+ scrollEnabled: scrollEnabled,
386
+ bounces: bounces,
387
+ initialNumToRender: MEASURE_PER_BATCH,
388
+ onViewableItemsChanged: handleViewableItemsChanged,
389
+ alwaysBounceHorizontal: false,
390
+ scrollsToTop: false,
391
+ showsHorizontalScrollIndicator: false,
392
+ showsVerticalScrollIndicator: false,
393
+ automaticallyAdjustContentInsets: false,
394
+ overScrollMode: "never",
395
+ contentContainerStyle: contentContainerStyleMemoized,
396
+ scrollEventThrottle: 16,
397
+ renderItem: renderItem,
398
+ onScroll: handleScroll,
399
+ ref: flatListRef,
400
+ testID: testID
401
+ })));
402
+ }
372
403
  const styles = StyleSheet.create({
373
404
  container: {
374
405
  flex: 1