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.
- package/README.md +13 -1
- package/lib/commonjs/Pager.android.js.map +1 -1
- package/lib/commonjs/Pager.ios.js.map +1 -1
- package/lib/commonjs/Pager.js.map +1 -1
- package/lib/commonjs/PagerViewAdapter.js +40 -22
- package/lib/commonjs/PagerViewAdapter.js.map +1 -1
- package/lib/commonjs/PanResponderAdapter.js +41 -29
- package/lib/commonjs/PanResponderAdapter.js.map +1 -1
- package/lib/commonjs/PlatformPressable.js +19 -15
- package/lib/commonjs/PlatformPressable.js.map +1 -1
- package/lib/commonjs/SceneMap.js +14 -11
- package/lib/commonjs/SceneMap.js.map +1 -1
- package/lib/commonjs/SceneView.js +2 -2
- package/lib/commonjs/SceneView.js.map +1 -1
- package/lib/commonjs/TabBar.js +124 -81
- package/lib/commonjs/TabBar.js.map +1 -1
- package/lib/commonjs/TabBarIndicator.js +7 -6
- package/lib/commonjs/TabBarIndicator.js.map +1 -1
- package/lib/commonjs/TabBarItem.js +7 -6
- package/lib/commonjs/TabBarItem.js.map +1 -1
- package/lib/commonjs/TabView.js +42 -33
- package/lib/commonjs/TabView.js.map +1 -1
- package/lib/commonjs/index.js +6 -6
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types.js +4 -0
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/useAnimatedValue.js.map +1 -1
- package/lib/module/Pager.android.js.map +1 -1
- package/lib/module/Pager.ios.js.map +1 -1
- package/lib/module/Pager.js.map +1 -1
- package/lib/module/PagerViewAdapter.js +40 -22
- package/lib/module/PagerViewAdapter.js.map +1 -1
- package/lib/module/PanResponderAdapter.js +41 -28
- package/lib/module/PanResponderAdapter.js.map +1 -1
- package/lib/module/PlatformPressable.js +19 -15
- package/lib/module/PlatformPressable.js.map +1 -1
- package/lib/module/SceneMap.js +14 -11
- package/lib/module/SceneMap.js.map +1 -1
- package/lib/module/SceneView.js +2 -2
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/TabBar.js +125 -81
- package/lib/module/TabBar.js.map +1 -1
- package/lib/module/TabBarIndicator.js +7 -6
- package/lib/module/TabBarIndicator.js.map +1 -1
- package/lib/module/TabBarItem.js +7 -6
- package/lib/module/TabBarItem.js.map +1 -1
- package/lib/module/TabView.js +41 -32
- package/lib/module/TabView.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useAnimatedValue.js.map +1 -1
- package/lib/typescript/PagerViewAdapter.d.ts +1 -1
- package/lib/typescript/PanResponderAdapter.d.ts +1 -1
- package/lib/typescript/TabBar.d.ts +3 -1
- package/lib/typescript/TabBarIndicator.d.ts +1 -0
- package/lib/typescript/TabView.d.ts +2 -1
- package/lib/typescript/types.d.ts +1 -0
- package/package.json +19 -18
- package/src/PagerViewAdapter.tsx +23 -9
- package/src/PanResponderAdapter.tsx +23 -17
- package/src/TabBar.tsx +75 -31
- package/src/TabBarIndicator.tsx +14 -5
- package/src/TabView.tsx +5 -0
- 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
|
|
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
|
|
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.
|
|
240
|
-
|
|
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
|
|
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.
|
|
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
|
-
? {
|
|
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
|
-
|
|
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:
|
|
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
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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
|
-
|
|
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
|
);
|
package/src/TabBarIndicator.tsx
CHANGED
|
@@ -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 {
|
|
83
|
-
|
|
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
|