react-native-tab-view 4.2.1 → 5.0.0-alpha.0
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/lib/module/Pager.android.js +1 -1
- package/lib/module/Pager.android.js.map +1 -1
- package/lib/module/Pager.ios.js +1 -1
- package/lib/module/Pager.ios.js.map +1 -1
- package/lib/module/PagerViewAdapter.js +3 -127
- package/lib/module/PagerViewAdapter.js.map +1 -1
- package/lib/module/PagerViewAdapter.native.js +130 -0
- package/lib/module/PagerViewAdapter.native.js.map +1 -0
- package/lib/module/PanResponderAdapter.js +43 -31
- package/lib/module/PanResponderAdapter.js.map +1 -1
- package/lib/module/PlatformPressable.js.map +1 -1
- package/lib/module/SceneView.js +22 -31
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/ScrollViewAdapter.js +210 -0
- package/lib/module/ScrollViewAdapter.js.map +1 -0
- package/lib/module/TabBar.js +98 -61
- package/lib/module/TabBar.js.map +1 -1
- package/lib/module/TabBarIndicator.js +6 -9
- package/lib/module/TabBarIndicator.js.map +1 -1
- package/lib/module/TabBarItem.js +4 -4
- package/lib/module/TabBarItem.js.map +1 -1
- package/lib/module/TabView.js +65 -84
- package/lib/module/TabView.js.map +1 -1
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/useMeasureLayout.js +36 -0
- package/lib/module/useMeasureLayout.js.map +1 -0
- package/lib/typescript/src/PagerViewAdapter.d.ts +3 -17
- package/lib/typescript/src/PagerViewAdapter.d.ts.map +1 -1
- package/lib/typescript/src/PagerViewAdapter.native.d.ts +6 -0
- package/lib/typescript/src/PagerViewAdapter.native.d.ts.map +1 -0
- package/lib/typescript/src/PanResponderAdapter.d.ts +3 -17
- package/lib/typescript/src/PanResponderAdapter.d.ts.map +1 -1
- package/lib/typescript/src/PlatformPressable.d.ts +2 -2
- package/lib/typescript/src/PlatformPressable.d.ts.map +1 -1
- package/lib/typescript/src/SceneView.d.ts +1 -1
- package/lib/typescript/src/SceneView.d.ts.map +1 -1
- package/lib/typescript/src/ScrollViewAdapter.d.ts +12 -0
- package/lib/typescript/src/ScrollViewAdapter.d.ts.map +1 -0
- package/lib/typescript/src/TabBar.d.ts +7 -7
- package/lib/typescript/src/TabBar.d.ts.map +1 -1
- package/lib/typescript/src/TabBarIndicator.d.ts +1 -1
- package/lib/typescript/src/TabBarIndicator.d.ts.map +1 -1
- package/lib/typescript/src/TabBarItem.d.ts +4 -4
- package/lib/typescript/src/TabBarItem.d.ts.map +1 -1
- package/lib/typescript/src/TabBarItemLabel.d.ts +2 -2
- package/lib/typescript/src/TabBarItemLabel.d.ts.map +1 -1
- package/lib/typescript/src/TabView.d.ts +5 -5
- package/lib/typescript/src/TabView.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +4 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +64 -8
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useMeasureLayout.d.ts +5 -0
- package/lib/typescript/src/useMeasureLayout.d.ts.map +1 -0
- package/package.json +11 -11
- package/src/PagerViewAdapter.native.tsx +174 -0
- package/src/PagerViewAdapter.tsx +8 -181
- package/src/PanResponderAdapter.tsx +64 -77
- package/src/PlatformPressable.tsx +2 -1
- package/src/SceneView.tsx +23 -45
- package/src/ScrollViewAdapter.tsx +268 -0
- package/src/TabBar.tsx +134 -133
- package/src/TabBarIndicator.tsx +7 -11
- package/src/TabBarItem.tsx +8 -6
- package/src/TabBarItemLabel.tsx +2 -2
- package/src/TabView.tsx +79 -100
- package/src/index.tsx +10 -0
- package/src/types.tsx +75 -17
- package/src/useMeasureLayout.tsx +34 -0
package/src/TabBar.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Animated,
|
|
4
|
+
type ColorValue,
|
|
4
5
|
type DimensionValue,
|
|
5
6
|
FlatList,
|
|
6
7
|
I18nManager,
|
|
@@ -23,7 +24,7 @@ import {
|
|
|
23
24
|
import { type Props as TabBarItemProps, TabBarItem } from './TabBarItem';
|
|
24
25
|
import type {
|
|
25
26
|
Event,
|
|
26
|
-
|
|
27
|
+
EventEmitterProps,
|
|
27
28
|
LocaleDirection,
|
|
28
29
|
NavigationState,
|
|
29
30
|
Route,
|
|
@@ -32,31 +33,43 @@ import type {
|
|
|
32
33
|
TabDescriptor,
|
|
33
34
|
} from './types';
|
|
34
35
|
import { useAnimatedValue } from './useAnimatedValue';
|
|
36
|
+
import { useMeasureLayout } from './useMeasureLayout';
|
|
37
|
+
|
|
38
|
+
export type Props<T extends Route> = SceneRendererProps &
|
|
39
|
+
EventEmitterProps & {
|
|
40
|
+
navigationState: NavigationState<T>;
|
|
41
|
+
scrollEnabled?: boolean;
|
|
42
|
+
bounces?: boolean;
|
|
43
|
+
activeColor?: ColorValue;
|
|
44
|
+
inactiveColor?: ColorValue;
|
|
45
|
+
pressColor?: ColorValue;
|
|
46
|
+
pressOpacity?: number;
|
|
47
|
+
options?: Record<string, TabDescriptor<T>>;
|
|
48
|
+
renderIndicator?: (props: IndicatorProps<T>) => React.ReactNode;
|
|
49
|
+
renderTabBarItem?: (
|
|
50
|
+
props: TabBarItemProps<T> & { key: string }
|
|
51
|
+
) => React.ReactElement;
|
|
52
|
+
onTabPress?: (scene: Scene<T> & Event) => void;
|
|
53
|
+
onTabLongPress?: (scene: Scene<T>) => void;
|
|
54
|
+
tabStyle?: StyleProp<ViewStyle>;
|
|
55
|
+
indicatorStyle?: StyleProp<ViewStyle>;
|
|
56
|
+
indicatorContainerStyle?: StyleProp<ViewStyle>;
|
|
57
|
+
contentContainerStyle?: StyleProp<ViewStyle>;
|
|
58
|
+
style?: StyleProp<ViewStyle>;
|
|
59
|
+
direction?: LocaleDirection;
|
|
60
|
+
gap?: number;
|
|
61
|
+
testID?: string;
|
|
62
|
+
android_ripple?: PressableAndroidRippleConfig;
|
|
63
|
+
};
|
|
35
64
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
options?: Record<string, TabDescriptor<T>>;
|
|
45
|
-
renderIndicator?: (props: IndicatorProps<T>) => React.ReactNode;
|
|
46
|
-
renderTabBarItem?: (
|
|
47
|
-
props: TabBarItemProps<T> & { key: string }
|
|
48
|
-
) => React.ReactElement;
|
|
49
|
-
onTabPress?: (scene: Scene<T> & Event) => void;
|
|
50
|
-
onTabLongPress?: (scene: Scene<T>) => void;
|
|
51
|
-
tabStyle?: StyleProp<ViewStyle>;
|
|
52
|
-
indicatorStyle?: StyleProp<ViewStyle>;
|
|
53
|
-
indicatorContainerStyle?: StyleProp<ViewStyle>;
|
|
54
|
-
contentContainerStyle?: StyleProp<ViewStyle>;
|
|
55
|
-
style?: StyleProp<ViewStyle>;
|
|
56
|
-
direction?: LocaleDirection;
|
|
57
|
-
gap?: number;
|
|
58
|
-
testID?: string;
|
|
59
|
-
android_ripple?: PressableAndroidRippleConfig;
|
|
65
|
+
type CalculationOptions = {
|
|
66
|
+
layoutWidth: number;
|
|
67
|
+
gap: number | undefined;
|
|
68
|
+
scrollEnabled: boolean | undefined;
|
|
69
|
+
tabWidths: Record<string, number>;
|
|
70
|
+
flattenedPaddingStart: DimensionValue | undefined;
|
|
71
|
+
flattenedPaddingEnd: DimensionValue | undefined;
|
|
72
|
+
flattenedTabWidth: DimensionValue | undefined;
|
|
60
73
|
};
|
|
61
74
|
|
|
62
75
|
const useNativeDriver = Platform.OS !== 'web';
|
|
@@ -95,7 +108,7 @@ const getFlattenedPaddingEnd = (style: StyleProp<ViewStyle>) => {
|
|
|
95
108
|
|
|
96
109
|
const convertPaddingPercentToSize = (
|
|
97
110
|
value: DimensionValue | undefined,
|
|
98
|
-
|
|
111
|
+
layoutWidth: number
|
|
99
112
|
): number => {
|
|
100
113
|
switch (typeof value) {
|
|
101
114
|
case 'number':
|
|
@@ -104,50 +117,53 @@ const convertPaddingPercentToSize = (
|
|
|
104
117
|
if (value.endsWith('%')) {
|
|
105
118
|
const width = parseFloat(value);
|
|
106
119
|
if (Number.isFinite(width)) {
|
|
107
|
-
return
|
|
120
|
+
return layoutWidth * (width / 100);
|
|
108
121
|
}
|
|
109
122
|
}
|
|
110
123
|
}
|
|
111
124
|
return 0;
|
|
112
125
|
};
|
|
113
126
|
|
|
114
|
-
const getComputedTabWidth = (
|
|
115
|
-
index
|
|
116
|
-
|
|
117
|
-
routes
|
|
118
|
-
scrollEnabled
|
|
119
|
-
tabWidths
|
|
120
|
-
|
|
121
|
-
flattenedPaddingStart
|
|
122
|
-
flattenedPaddingEnd
|
|
123
|
-
gap
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
const getComputedTabWidth = ({
|
|
128
|
+
index,
|
|
129
|
+
layoutWidth,
|
|
130
|
+
routes,
|
|
131
|
+
scrollEnabled,
|
|
132
|
+
tabWidths,
|
|
133
|
+
flattenedTabWidth,
|
|
134
|
+
flattenedPaddingStart,
|
|
135
|
+
flattenedPaddingEnd,
|
|
136
|
+
gap,
|
|
137
|
+
}: CalculationOptions & {
|
|
138
|
+
index: number;
|
|
139
|
+
routes: Route[];
|
|
140
|
+
}) => {
|
|
141
|
+
if (flattenedTabWidth === 'auto') {
|
|
126
142
|
return tabWidths[routes[index].key] || 0;
|
|
127
143
|
}
|
|
128
144
|
|
|
129
|
-
switch (typeof
|
|
145
|
+
switch (typeof flattenedTabWidth) {
|
|
130
146
|
case 'number':
|
|
131
|
-
return
|
|
147
|
+
return flattenedTabWidth;
|
|
132
148
|
case 'string':
|
|
133
|
-
if (
|
|
134
|
-
const width = parseFloat(
|
|
149
|
+
if (flattenedTabWidth.endsWith('%')) {
|
|
150
|
+
const width = parseFloat(flattenedTabWidth);
|
|
135
151
|
if (Number.isFinite(width)) {
|
|
136
|
-
return
|
|
152
|
+
return layoutWidth * (width / 100);
|
|
137
153
|
}
|
|
138
154
|
}
|
|
139
155
|
}
|
|
140
156
|
|
|
141
157
|
if (scrollEnabled) {
|
|
142
|
-
return (
|
|
158
|
+
return (layoutWidth / 5) * 2;
|
|
143
159
|
}
|
|
144
160
|
|
|
145
161
|
const gapTotalWidth = (gap ?? 0) * (routes.length - 1);
|
|
146
162
|
const paddingTotalWidth =
|
|
147
|
-
convertPaddingPercentToSize(flattenedPaddingStart,
|
|
148
|
-
convertPaddingPercentToSize(flattenedPaddingEnd,
|
|
163
|
+
convertPaddingPercentToSize(flattenedPaddingStart, layoutWidth) +
|
|
164
|
+
convertPaddingPercentToSize(flattenedPaddingEnd, layoutWidth);
|
|
149
165
|
|
|
150
|
-
return (
|
|
166
|
+
return (layoutWidth - gapTotalWidth - paddingTotalWidth) / routes.length;
|
|
151
167
|
};
|
|
152
168
|
|
|
153
169
|
const getMaxScrollDistance = (tabBarWidth: number, layoutWidth: number) =>
|
|
@@ -166,50 +182,45 @@ const getTranslateX = (
|
|
|
166
182
|
);
|
|
167
183
|
|
|
168
184
|
const getTabBarWidth = <T extends Route>({
|
|
169
|
-
|
|
170
|
-
|
|
185
|
+
routes,
|
|
186
|
+
layoutWidth,
|
|
171
187
|
gap,
|
|
172
188
|
scrollEnabled,
|
|
173
189
|
flattenedTabWidth,
|
|
174
190
|
flattenedPaddingStart,
|
|
175
191
|
flattenedPaddingEnd,
|
|
176
192
|
tabWidths,
|
|
177
|
-
}:
|
|
178
|
-
|
|
179
|
-
flattenedPaddingStart: DimensionValue | undefined;
|
|
180
|
-
flattenedPaddingEnd: DimensionValue | undefined;
|
|
181
|
-
flattenedTabWidth: DimensionValue | undefined;
|
|
193
|
+
}: CalculationOptions & {
|
|
194
|
+
routes: T[];
|
|
182
195
|
}) => {
|
|
183
|
-
const { routes } = navigationState;
|
|
184
|
-
|
|
185
196
|
const paddingsWidth = Math.max(
|
|
186
197
|
0,
|
|
187
|
-
convertPaddingPercentToSize(flattenedPaddingStart,
|
|
188
|
-
convertPaddingPercentToSize(flattenedPaddingEnd,
|
|
198
|
+
convertPaddingPercentToSize(flattenedPaddingStart, layoutWidth) +
|
|
199
|
+
convertPaddingPercentToSize(flattenedPaddingEnd, layoutWidth)
|
|
189
200
|
);
|
|
190
201
|
|
|
191
202
|
return routes.reduce<number>(
|
|
192
203
|
(acc, _, i) =>
|
|
193
204
|
acc +
|
|
194
205
|
(i > 0 ? (gap ?? 0) : 0) +
|
|
195
|
-
getComputedTabWidth(
|
|
196
|
-
i,
|
|
197
|
-
|
|
206
|
+
getComputedTabWidth({
|
|
207
|
+
index: i,
|
|
208
|
+
layoutWidth,
|
|
198
209
|
routes,
|
|
199
210
|
scrollEnabled,
|
|
200
211
|
tabWidths,
|
|
201
212
|
flattenedTabWidth,
|
|
202
213
|
flattenedPaddingStart,
|
|
203
214
|
flattenedPaddingEnd,
|
|
204
|
-
gap
|
|
205
|
-
),
|
|
215
|
+
gap,
|
|
216
|
+
}),
|
|
206
217
|
paddingsWidth
|
|
207
218
|
);
|
|
208
219
|
};
|
|
209
220
|
|
|
210
221
|
const normalizeScrollValue = <T extends Route>({
|
|
211
|
-
|
|
212
|
-
|
|
222
|
+
layoutWidth,
|
|
223
|
+
routes,
|
|
213
224
|
gap,
|
|
214
225
|
scrollEnabled,
|
|
215
226
|
tabWidths,
|
|
@@ -218,17 +229,14 @@ const normalizeScrollValue = <T extends Route>({
|
|
|
218
229
|
flattenedPaddingStart,
|
|
219
230
|
flattenedPaddingEnd,
|
|
220
231
|
direction,
|
|
221
|
-
}:
|
|
222
|
-
|
|
232
|
+
}: CalculationOptions & {
|
|
233
|
+
routes: T[];
|
|
223
234
|
value: number;
|
|
224
|
-
flattenedTabWidth: DimensionValue | undefined;
|
|
225
|
-
flattenedPaddingStart: DimensionValue | undefined;
|
|
226
|
-
flattenedPaddingEnd: DimensionValue | undefined;
|
|
227
235
|
direction: LocaleDirection;
|
|
228
236
|
}) => {
|
|
229
237
|
const tabBarWidth = getTabBarWidth({
|
|
230
|
-
|
|
231
|
-
|
|
238
|
+
layoutWidth,
|
|
239
|
+
routes,
|
|
232
240
|
tabWidths,
|
|
233
241
|
gap,
|
|
234
242
|
scrollEnabled,
|
|
@@ -236,7 +244,7 @@ const normalizeScrollValue = <T extends Route>({
|
|
|
236
244
|
flattenedPaddingStart,
|
|
237
245
|
flattenedPaddingEnd,
|
|
238
246
|
});
|
|
239
|
-
const maxDistance = getMaxScrollDistance(tabBarWidth,
|
|
247
|
+
const maxDistance = getMaxScrollDistance(tabBarWidth, layoutWidth);
|
|
240
248
|
const scrollValue = Math.max(Math.min(value, maxDistance), 0);
|
|
241
249
|
|
|
242
250
|
if (Platform.OS === 'android' && direction === 'rtl') {
|
|
@@ -249,8 +257,9 @@ const normalizeScrollValue = <T extends Route>({
|
|
|
249
257
|
};
|
|
250
258
|
|
|
251
259
|
const getScrollAmount = <T extends Route>({
|
|
252
|
-
|
|
253
|
-
|
|
260
|
+
index,
|
|
261
|
+
routes,
|
|
262
|
+
layoutWidth,
|
|
254
263
|
gap,
|
|
255
264
|
scrollEnabled,
|
|
256
265
|
flattenedTabWidth,
|
|
@@ -258,47 +267,43 @@ const getScrollAmount = <T extends Route>({
|
|
|
258
267
|
flattenedPaddingStart,
|
|
259
268
|
flattenedPaddingEnd,
|
|
260
269
|
direction,
|
|
261
|
-
}:
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
flattenedPaddingStart: DimensionValue | undefined;
|
|
265
|
-
flattenedPaddingEnd: DimensionValue | undefined;
|
|
270
|
+
}: CalculationOptions & {
|
|
271
|
+
index: number;
|
|
272
|
+
routes: T[];
|
|
266
273
|
direction: LocaleDirection;
|
|
267
274
|
}) => {
|
|
268
275
|
const paddingInitial =
|
|
269
276
|
direction === 'rtl'
|
|
270
|
-
? convertPaddingPercentToSize(flattenedPaddingEnd,
|
|
271
|
-
: convertPaddingPercentToSize(flattenedPaddingStart,
|
|
277
|
+
? convertPaddingPercentToSize(flattenedPaddingEnd, layoutWidth)
|
|
278
|
+
: convertPaddingPercentToSize(flattenedPaddingStart, layoutWidth);
|
|
272
279
|
|
|
273
280
|
const centerDistance = Array.from({
|
|
274
|
-
length:
|
|
281
|
+
length: index + 1,
|
|
275
282
|
}).reduce<number>((total, _, i) => {
|
|
276
|
-
const tabWidth = getComputedTabWidth(
|
|
277
|
-
i,
|
|
278
|
-
|
|
279
|
-
|
|
283
|
+
const tabWidth = getComputedTabWidth({
|
|
284
|
+
index: i,
|
|
285
|
+
layoutWidth,
|
|
286
|
+
routes,
|
|
280
287
|
scrollEnabled,
|
|
281
288
|
tabWidths,
|
|
282
289
|
flattenedTabWidth,
|
|
283
290
|
flattenedPaddingStart,
|
|
284
291
|
flattenedPaddingEnd,
|
|
285
|
-
gap
|
|
286
|
-
);
|
|
292
|
+
gap,
|
|
293
|
+
});
|
|
287
294
|
|
|
288
295
|
// To get the current index centered we adjust scroll amount by width of indexes
|
|
289
296
|
// 0 through (i - 1) and add half the width of current index i
|
|
290
297
|
return (
|
|
291
|
-
total +
|
|
292
|
-
(i > 0 ? (gap ?? 0) : 0) +
|
|
293
|
-
(navigationState.index === i ? tabWidth / 2 : tabWidth)
|
|
298
|
+
total + (i > 0 ? (gap ?? 0) : 0) + (index === i ? tabWidth / 2 : tabWidth)
|
|
294
299
|
);
|
|
295
300
|
}, paddingInitial);
|
|
296
301
|
|
|
297
|
-
const scrollAmount = centerDistance -
|
|
302
|
+
const scrollAmount = centerDistance - layoutWidth / 2;
|
|
298
303
|
|
|
299
304
|
return normalizeScrollValue({
|
|
300
|
-
|
|
301
|
-
|
|
305
|
+
layoutWidth,
|
|
306
|
+
routes,
|
|
302
307
|
tabWidths,
|
|
303
308
|
value: scrollAmount,
|
|
304
309
|
gap,
|
|
@@ -352,14 +357,13 @@ export function TabBar<T extends Route>({
|
|
|
352
357
|
renderTabBarItem,
|
|
353
358
|
style,
|
|
354
359
|
tabStyle,
|
|
355
|
-
layout: propLayout,
|
|
356
360
|
testID,
|
|
357
361
|
android_ripple,
|
|
358
362
|
options,
|
|
359
363
|
}: Props<T>) {
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
364
|
+
const containerRef = React.useRef<View>(null);
|
|
365
|
+
const [layout, onLayout] = useMeasureLayout(containerRef);
|
|
366
|
+
|
|
363
367
|
const [tabWidths, setTabWidths] = React.useState<Record<string, number>>({});
|
|
364
368
|
const flatListRef = React.useRef<FlatList | null>(null);
|
|
365
369
|
const isFirst = React.useRef(true);
|
|
@@ -370,9 +374,11 @@ export function TabBar<T extends Route>({
|
|
|
370
374
|
const isWidthDynamic = flattenedTabWidth === 'auto';
|
|
371
375
|
const flattenedPaddingEnd = getFlattenedPaddingEnd(contentContainerStyle);
|
|
372
376
|
const flattenedPaddingStart = getFlattenedPaddingStart(contentContainerStyle);
|
|
377
|
+
|
|
373
378
|
const scrollOffset = getScrollAmount({
|
|
374
|
-
layout,
|
|
375
|
-
|
|
379
|
+
layoutWidth: layout.width,
|
|
380
|
+
routes,
|
|
381
|
+
index: navigationState.index,
|
|
376
382
|
tabWidths,
|
|
377
383
|
gap,
|
|
378
384
|
scrollEnabled,
|
|
@@ -383,7 +389,7 @@ export function TabBar<T extends Route>({
|
|
|
383
389
|
});
|
|
384
390
|
|
|
385
391
|
const hasMeasuredTabWidths =
|
|
386
|
-
Boolean(layout
|
|
392
|
+
Boolean(layout?.width) &&
|
|
387
393
|
routes
|
|
388
394
|
.slice(0, navigationState.index)
|
|
389
395
|
.every((r) => typeof tabWidths[r.key] === 'number');
|
|
@@ -406,19 +412,9 @@ export function TabBar<T extends Route>({
|
|
|
406
412
|
}
|
|
407
413
|
}, [hasMeasuredTabWidths, isWidthDynamic, scrollEnabled, scrollOffset]);
|
|
408
414
|
|
|
409
|
-
const handleLayout = (e: LayoutChangeEvent) => {
|
|
410
|
-
const { height, width } = e.nativeEvent.layout;
|
|
411
|
-
|
|
412
|
-
setLayout((layout) =>
|
|
413
|
-
layout.width === width && layout.height === height
|
|
414
|
-
? layout
|
|
415
|
-
: { width, height }
|
|
416
|
-
);
|
|
417
|
-
};
|
|
418
|
-
|
|
419
415
|
const tabBarWidth = getTabBarWidth({
|
|
420
|
-
layout,
|
|
421
|
-
|
|
416
|
+
layoutWidth: layout.width,
|
|
417
|
+
routes,
|
|
422
418
|
tabWidths,
|
|
423
419
|
gap,
|
|
424
420
|
scrollEnabled,
|
|
@@ -430,8 +426,8 @@ export function TabBar<T extends Route>({
|
|
|
430
426
|
const separatorsWidth = Math.max(0, routes.length - 1) * gap;
|
|
431
427
|
const paddingsWidth = Math.max(
|
|
432
428
|
0,
|
|
433
|
-
convertPaddingPercentToSize(flattenedPaddingStart, layout) +
|
|
434
|
-
convertPaddingPercentToSize(flattenedPaddingEnd, layout)
|
|
429
|
+
convertPaddingPercentToSize(flattenedPaddingStart, layout.width) +
|
|
430
|
+
convertPaddingPercentToSize(flattenedPaddingEnd, layout.width)
|
|
435
431
|
);
|
|
436
432
|
|
|
437
433
|
const translateX = React.useMemo(
|
|
@@ -505,17 +501,19 @@ export function TabBar<T extends Route>({
|
|
|
505
501
|
|
|
506
502
|
// Calculate the default width for tab for FlatList to work
|
|
507
503
|
const defaultTabWidth = !isWidthDynamic
|
|
508
|
-
? getComputedTabWidth(
|
|
504
|
+
? getComputedTabWidth({
|
|
509
505
|
index,
|
|
510
|
-
layout,
|
|
506
|
+
layoutWidth: layout.width,
|
|
511
507
|
routes,
|
|
512
508
|
scrollEnabled,
|
|
513
509
|
tabWidths,
|
|
514
|
-
getFlattenedTabWidth(tabStyle),
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
510
|
+
flattenedTabWidth: getFlattenedTabWidth(tabStyle),
|
|
511
|
+
flattenedPaddingStart: getFlattenedPaddingStart(
|
|
512
|
+
contentContainerStyle
|
|
513
|
+
),
|
|
514
|
+
flattenedPaddingEnd: getFlattenedPaddingEnd(contentContainerStyle),
|
|
515
|
+
gap,
|
|
516
|
+
})
|
|
519
517
|
: undefined;
|
|
520
518
|
|
|
521
519
|
const props = {
|
|
@@ -620,9 +618,12 @@ export function TabBar<T extends Route>({
|
|
|
620
618
|
);
|
|
621
619
|
|
|
622
620
|
return (
|
|
623
|
-
<Animated.View
|
|
621
|
+
<Animated.View
|
|
622
|
+
ref={containerRef}
|
|
623
|
+
onLayout={onLayout}
|
|
624
|
+
style={[styles.tabBar, style]}
|
|
625
|
+
>
|
|
624
626
|
<Animated.View
|
|
625
|
-
pointerEvents="none"
|
|
626
627
|
style={[
|
|
627
628
|
styles.indicatorContainer,
|
|
628
629
|
scrollEnabled ? { transform: [{ translateX }] as any } : null,
|
|
@@ -632,7 +633,6 @@ export function TabBar<T extends Route>({
|
|
|
632
633
|
>
|
|
633
634
|
{renderIndicator({
|
|
634
635
|
position,
|
|
635
|
-
layout,
|
|
636
636
|
navigationState,
|
|
637
637
|
jumpTo,
|
|
638
638
|
direction,
|
|
@@ -647,17 +647,17 @@ export function TabBar<T extends Route>({
|
|
|
647
647
|
{ start: flattenedPaddingStart, end: flattenedPaddingEnd },
|
|
648
648
|
],
|
|
649
649
|
getTabWidth: (i: number) =>
|
|
650
|
-
getComputedTabWidth(
|
|
651
|
-
i,
|
|
652
|
-
layout,
|
|
650
|
+
getComputedTabWidth({
|
|
651
|
+
index: i,
|
|
652
|
+
layoutWidth: layout.width,
|
|
653
653
|
routes,
|
|
654
654
|
scrollEnabled,
|
|
655
655
|
tabWidths,
|
|
656
656
|
flattenedTabWidth,
|
|
657
657
|
flattenedPaddingEnd,
|
|
658
658
|
flattenedPaddingStart,
|
|
659
|
-
gap
|
|
660
|
-
),
|
|
659
|
+
gap,
|
|
660
|
+
}),
|
|
661
661
|
gap,
|
|
662
662
|
})}
|
|
663
663
|
</Animated.View>
|
|
@@ -696,7 +696,7 @@ const styles = StyleSheet.create({
|
|
|
696
696
|
},
|
|
697
697
|
tabBar: {
|
|
698
698
|
zIndex: 1,
|
|
699
|
-
backgroundColor: '#
|
|
699
|
+
backgroundColor: '#fff',
|
|
700
700
|
elevation: 4,
|
|
701
701
|
...Platform.select({
|
|
702
702
|
default: {
|
|
@@ -724,5 +724,6 @@ const styles = StyleSheet.create({
|
|
|
724
724
|
start: 0,
|
|
725
725
|
end: 0,
|
|
726
726
|
bottom: 0,
|
|
727
|
+
pointerEvents: 'none',
|
|
727
728
|
},
|
|
728
729
|
});
|
package/src/TabBarIndicator.tsx
CHANGED
|
@@ -71,7 +71,6 @@ const getTranslateX = (
|
|
|
71
71
|
|
|
72
72
|
export function TabBarIndicator<T extends Route>({
|
|
73
73
|
getTabWidth,
|
|
74
|
-
layout,
|
|
75
74
|
navigationState,
|
|
76
75
|
position,
|
|
77
76
|
width,
|
|
@@ -86,8 +85,7 @@ export function TabBarIndicator<T extends Route>({
|
|
|
86
85
|
const opacity = useAnimatedValue(isWidthDynamic ? 0 : 1);
|
|
87
86
|
|
|
88
87
|
const indicatorVisible = isWidthDynamic
|
|
89
|
-
?
|
|
90
|
-
navigationState.routes
|
|
88
|
+
? navigationState.routes
|
|
91
89
|
.slice(0, navigationState.index)
|
|
92
90
|
.every((_, r) => getTabWidth(r))
|
|
93
91
|
: true;
|
|
@@ -120,14 +118,12 @@ export function TabBarIndicator<T extends Route>({
|
|
|
120
118
|
|
|
121
119
|
const transform = [];
|
|
122
120
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
routes
|
|
126
|
-
|
|
127
|
-
: 0;
|
|
121
|
+
const translateX =
|
|
122
|
+
routes.length > 1
|
|
123
|
+
? getTranslateX(position, routes, getTabWidth, direction, gap, width)
|
|
124
|
+
: 0;
|
|
128
125
|
|
|
129
|
-
|
|
130
|
-
}
|
|
126
|
+
transform.push({ translateX });
|
|
131
127
|
|
|
132
128
|
if (width === 'auto') {
|
|
133
129
|
const inputRange = routes.map((_, i) => i);
|
|
@@ -180,7 +176,7 @@ export function TabBarIndicator<T extends Route>({
|
|
|
180
176
|
|
|
181
177
|
const styles = StyleSheet.create({
|
|
182
178
|
indicator: {
|
|
183
|
-
backgroundColor: '
|
|
179
|
+
backgroundColor: 'rgb(0, 122, 255)',
|
|
184
180
|
position: 'absolute',
|
|
185
181
|
start: 0,
|
|
186
182
|
bottom: 0,
|
package/src/TabBarItem.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Animated,
|
|
4
|
+
type ColorValue,
|
|
4
5
|
type LayoutChangeEvent,
|
|
5
6
|
Platform,
|
|
6
7
|
type PressableAndroidRippleConfig,
|
|
@@ -19,9 +20,9 @@ export type Props<T extends Route> = TabDescriptor<T> & {
|
|
|
19
20
|
position: Animated.AnimatedInterpolation<number>;
|
|
20
21
|
route: T;
|
|
21
22
|
navigationState: NavigationState<T>;
|
|
22
|
-
activeColor?:
|
|
23
|
-
inactiveColor?:
|
|
24
|
-
pressColor?:
|
|
23
|
+
activeColor?: ColorValue;
|
|
24
|
+
inactiveColor?: ColorValue;
|
|
25
|
+
pressColor?: ColorValue;
|
|
25
26
|
pressOpacity?: number;
|
|
26
27
|
onLayout?: (event: LayoutChangeEvent) => void;
|
|
27
28
|
onPress: () => void;
|
|
@@ -31,8 +32,8 @@ export type Props<T extends Route> = TabDescriptor<T> & {
|
|
|
31
32
|
android_ripple?: PressableAndroidRippleConfig;
|
|
32
33
|
};
|
|
33
34
|
|
|
34
|
-
const DEFAULT_ACTIVE_COLOR = 'rgba(
|
|
35
|
-
const DEFAULT_INACTIVE_COLOR = 'rgba(
|
|
35
|
+
const DEFAULT_ACTIVE_COLOR = 'rgba(0, 0, 0, 1)';
|
|
36
|
+
const DEFAULT_INACTIVE_COLOR = 'rgba(0, 0, 0, 0.5)';
|
|
36
37
|
const ICON_SIZE = 24;
|
|
37
38
|
|
|
38
39
|
const getActiveOpacity = (
|
|
@@ -228,7 +229,7 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
228
229
|
href={href}
|
|
229
230
|
style={[styles.pressable, tabContainerStyle]}
|
|
230
231
|
>
|
|
231
|
-
<View
|
|
232
|
+
<View style={[styles.item, tabStyle]}>
|
|
232
233
|
{icon}
|
|
233
234
|
<View>
|
|
234
235
|
<Animated.View style={{ opacity: inactiveOpacity }}>
|
|
@@ -286,6 +287,7 @@ const styles = StyleSheet.create({
|
|
|
286
287
|
justifyContent: 'center',
|
|
287
288
|
padding: 10,
|
|
288
289
|
minHeight: 48,
|
|
290
|
+
pointerEvents: 'none',
|
|
289
291
|
},
|
|
290
292
|
badge: {
|
|
291
293
|
position: 'absolute',
|
package/src/TabBarItemLabel.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
import type { ColorValue, StyleProp, ViewStyle } from 'react-native';
|
|
3
3
|
import { Animated, StyleSheet } from 'react-native';
|
|
4
4
|
|
|
5
5
|
interface TabBarItemLabelProps {
|
|
6
|
-
color:
|
|
6
|
+
color: ColorValue;
|
|
7
7
|
label?: string;
|
|
8
8
|
style: StyleProp<ViewStyle>;
|
|
9
9
|
icon: React.ReactNode;
|