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