react-native-tab-view 4.0.0-alpha.0 → 4.0.0-alpha.10
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/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 +9 -13
- package/lib/commonjs/PagerViewAdapter.js.map +1 -1
- package/lib/commonjs/PanResponderAdapter.js +4 -4
- package/lib/commonjs/PanResponderAdapter.js.map +1 -1
- package/lib/commonjs/PlatformPressable.js +24 -3
- package/lib/commonjs/PlatformPressable.js.map +1 -1
- package/lib/commonjs/SceneMap.js +2 -2
- package/lib/commonjs/SceneMap.js.map +1 -1
- package/lib/commonjs/SceneView.js +3 -4
- package/lib/commonjs/SceneView.js.map +1 -1
- package/lib/commonjs/TabBar.js +112 -97
- package/lib/commonjs/TabBar.js.map +1 -1
- package/lib/commonjs/TabBarIndicator.js +21 -16
- package/lib/commonjs/TabBarIndicator.js.map +1 -1
- package/lib/commonjs/TabBarItem.js +58 -80
- package/lib/commonjs/TabBarItem.js.map +1 -1
- package/lib/commonjs/TabBarItemLabel.js +4 -4
- package/lib/commonjs/TabBarItemLabel.js.map +1 -1
- package/lib/commonjs/TabView.js +3 -3
- package/lib/commonjs/TabView.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/useAnimatedValue.js +2 -2
- 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 +7 -11
- package/lib/module/PagerViewAdapter.js.map +1 -1
- package/lib/module/PanResponderAdapter.js +2 -2
- package/lib/module/PanResponderAdapter.js.map +1 -1
- package/lib/module/PlatformPressable.js +22 -1
- package/lib/module/PlatformPressable.js.map +1 -1
- package/lib/module/SceneMap.js.map +1 -1
- package/lib/module/SceneView.js +1 -2
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/TabBar.js +110 -95
- package/lib/module/TabBar.js.map +1 -1
- package/lib/module/TabBarIndicator.js +19 -14
- package/lib/module/TabBarIndicator.js.map +1 -1
- package/lib/module/TabBarItem.js +56 -78
- package/lib/module/TabBarItem.js.map +1 -1
- package/lib/module/TabBarItemLabel.js +3 -2
- package/lib/module/TabBarItemLabel.js.map +1 -1
- package/lib/module/TabView.js +1 -1
- package/lib/module/TabView.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useAnimatedValue.js.map +1 -1
- package/lib/typescript/src/PlatformPressable.d.ts +4 -3
- package/lib/typescript/src/PlatformPressable.d.ts.map +1 -1
- package/lib/typescript/src/SceneMap.d.ts +2 -2
- package/lib/typescript/src/SceneMap.d.ts.map +1 -1
- package/lib/typescript/src/SceneView.d.ts +2 -2
- package/lib/typescript/src/SceneView.d.ts.map +1 -1
- package/lib/typescript/src/TabBar.d.ts +7 -18
- package/lib/typescript/src/TabBar.d.ts.map +1 -1
- package/lib/typescript/src/TabBarIndicator.d.ts +3 -3
- package/lib/typescript/src/TabBarIndicator.d.ts.map +1 -1
- package/lib/typescript/src/TabBarItem.d.ts +4 -19
- package/lib/typescript/src/TabBarItem.d.ts.map +1 -1
- package/lib/typescript/src/TabBarItemLabel.d.ts +1 -1
- 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 +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +25 -1
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +11 -11
- package/src/PagerViewAdapter.tsx +2 -2
- package/src/PanResponderAdapter.tsx +4 -4
- package/src/PlatformPressable.tsx +31 -2
- package/src/SceneMap.tsx +1 -3
- package/src/SceneView.tsx +4 -4
- package/src/TabBar.tsx +178 -179
- package/src/TabBarIndicator.tsx +22 -14
- package/src/TabBarItem.tsx +92 -118
- package/src/TabBarItemLabel.tsx +2 -1
- package/src/TabView.tsx +5 -5
- package/src/index.tsx +6 -1
- package/src/types.tsx +25 -1
package/src/TabBar.tsx
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Animated,
|
|
4
|
+
type DimensionValue,
|
|
4
5
|
FlatList,
|
|
5
6
|
I18nManager,
|
|
6
|
-
LayoutChangeEvent,
|
|
7
|
-
ListRenderItemInfo,
|
|
7
|
+
type LayoutChangeEvent,
|
|
8
|
+
type ListRenderItemInfo,
|
|
8
9
|
Platform,
|
|
9
|
-
PressableAndroidRippleConfig,
|
|
10
|
-
StyleProp,
|
|
10
|
+
type PressableAndroidRippleConfig,
|
|
11
|
+
type StyleProp,
|
|
11
12
|
StyleSheet,
|
|
12
|
-
TextStyle,
|
|
13
|
+
type TextStyle,
|
|
13
14
|
View,
|
|
14
|
-
ViewStyle,
|
|
15
|
-
ViewToken,
|
|
15
|
+
type ViewStyle,
|
|
16
|
+
type ViewToken,
|
|
16
17
|
} from 'react-native';
|
|
17
18
|
import useLatestCallback from 'use-latest-callback';
|
|
18
19
|
|
|
19
|
-
import {
|
|
20
|
-
|
|
20
|
+
import {
|
|
21
|
+
type Props as IndicatorProps,
|
|
22
|
+
TabBarIndicator,
|
|
23
|
+
} from './TabBarIndicator';
|
|
24
|
+
import { type Props as TabBarItemProps, TabBarItem } from './TabBarItem';
|
|
21
25
|
import type {
|
|
22
26
|
Event,
|
|
23
27
|
Layout,
|
|
@@ -26,6 +30,7 @@ import type {
|
|
|
26
30
|
Route,
|
|
27
31
|
Scene,
|
|
28
32
|
SceneRendererProps,
|
|
33
|
+
TabDescriptor,
|
|
29
34
|
} from './types';
|
|
30
35
|
import { useAnimatedValue } from './useAnimatedValue';
|
|
31
36
|
|
|
@@ -37,23 +42,8 @@ export type Props<T extends Route> = SceneRendererProps & {
|
|
|
37
42
|
inactiveColor?: string;
|
|
38
43
|
pressColor?: string;
|
|
39
44
|
pressOpacity?: number;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
getAccessibilityLabel?: (scene: Scene<T>) => string | undefined;
|
|
43
|
-
getTestID?: (scene: Scene<T>) => string | undefined;
|
|
44
|
-
renderLabel?: (
|
|
45
|
-
scene: Scene<T> & {
|
|
46
|
-
focused: boolean;
|
|
47
|
-
color: string;
|
|
48
|
-
}
|
|
49
|
-
) => React.ReactNode;
|
|
50
|
-
renderIcon?: (
|
|
51
|
-
scene: Scene<T> & {
|
|
52
|
-
focused: boolean;
|
|
53
|
-
color: string;
|
|
54
|
-
}
|
|
55
|
-
) => React.ReactNode;
|
|
56
|
-
renderBadge?: (scene: Scene<T>) => React.ReactNode;
|
|
45
|
+
options?: Record<string, TabDescriptor<T>>;
|
|
46
|
+
commonOptions?: TabDescriptor<T>;
|
|
57
47
|
renderIndicator?: (props: IndicatorProps<T>) => React.ReactNode;
|
|
58
48
|
renderTabBarItem?: (
|
|
59
49
|
props: TabBarItemProps<T> & { key: string }
|
|
@@ -72,9 +62,6 @@ export type Props<T extends Route> = SceneRendererProps & {
|
|
|
72
62
|
android_ripple?: PressableAndroidRippleConfig;
|
|
73
63
|
};
|
|
74
64
|
|
|
75
|
-
type FlattenedTabWidth = string | number | undefined;
|
|
76
|
-
type FlattenedTabPadding = string | number | undefined;
|
|
77
|
-
|
|
78
65
|
const Separator = ({ width }: { width: number }) => {
|
|
79
66
|
return <View style={{ width }} />;
|
|
80
67
|
};
|
|
@@ -85,24 +72,30 @@ const getFlattenedTabWidth = (style: StyleProp<ViewStyle>) => {
|
|
|
85
72
|
return tabStyle?.width;
|
|
86
73
|
};
|
|
87
74
|
|
|
88
|
-
const
|
|
75
|
+
const getFlattenedPaddingStart = (style: StyleProp<ViewStyle>) => {
|
|
89
76
|
const flattenStyle = StyleSheet.flatten(style);
|
|
90
77
|
|
|
91
78
|
return flattenStyle
|
|
92
|
-
? flattenStyle.paddingLeft ||
|
|
79
|
+
? flattenStyle.paddingLeft ||
|
|
80
|
+
flattenStyle.paddingStart ||
|
|
81
|
+
flattenStyle.paddingHorizontal ||
|
|
82
|
+
0
|
|
93
83
|
: 0;
|
|
94
84
|
};
|
|
95
85
|
|
|
96
|
-
const
|
|
86
|
+
const getFlattenedPaddingEnd = (style: StyleProp<ViewStyle>) => {
|
|
97
87
|
const flattenStyle = StyleSheet.flatten(style);
|
|
98
88
|
|
|
99
89
|
return flattenStyle
|
|
100
|
-
? flattenStyle.paddingRight ||
|
|
90
|
+
? flattenStyle.paddingRight ||
|
|
91
|
+
flattenStyle.paddingEnd ||
|
|
92
|
+
flattenStyle.paddingHorizontal ||
|
|
93
|
+
0
|
|
101
94
|
: 0;
|
|
102
95
|
};
|
|
103
96
|
|
|
104
97
|
const convertPaddingPercentToSize = (
|
|
105
|
-
value:
|
|
98
|
+
value: DimensionValue | undefined,
|
|
106
99
|
layout: Layout
|
|
107
100
|
): number => {
|
|
108
101
|
switch (typeof value) {
|
|
@@ -125,9 +118,9 @@ const getComputedTabWidth = (
|
|
|
125
118
|
routes: Route[],
|
|
126
119
|
scrollEnabled: boolean | undefined,
|
|
127
120
|
tabWidths: { [key: string]: number },
|
|
128
|
-
flattenedWidth:
|
|
129
|
-
|
|
130
|
-
|
|
121
|
+
flattenedWidth: DimensionValue | undefined,
|
|
122
|
+
flattenedPaddingStart: DimensionValue | undefined,
|
|
123
|
+
flattenedPaddingEnd: DimensionValue | undefined,
|
|
131
124
|
gap?: number
|
|
132
125
|
) => {
|
|
133
126
|
if (flattenedWidth === 'auto') {
|
|
@@ -152,8 +145,8 @@ const getComputedTabWidth = (
|
|
|
152
145
|
|
|
153
146
|
const gapTotalWidth = (gap ?? 0) * (routes.length - 1);
|
|
154
147
|
const paddingTotalWidth =
|
|
155
|
-
convertPaddingPercentToSize(
|
|
156
|
-
convertPaddingPercentToSize(
|
|
148
|
+
convertPaddingPercentToSize(flattenedPaddingStart, layout) +
|
|
149
|
+
convertPaddingPercentToSize(flattenedPaddingEnd, layout);
|
|
157
150
|
|
|
158
151
|
return (layout.width - gapTotalWidth - paddingTotalWidth) / routes.length;
|
|
159
152
|
};
|
|
@@ -179,21 +172,21 @@ const getTabBarWidth = <T extends Route>({
|
|
|
179
172
|
gap,
|
|
180
173
|
scrollEnabled,
|
|
181
174
|
flattenedTabWidth,
|
|
182
|
-
|
|
183
|
-
|
|
175
|
+
flattenedPaddingStart,
|
|
176
|
+
flattenedPaddingEnd,
|
|
184
177
|
tabWidths,
|
|
185
178
|
}: Pick<Props<T>, 'navigationState' | 'gap' | 'layout' | 'scrollEnabled'> & {
|
|
186
179
|
tabWidths: Record<string, number>;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
flattenedTabWidth:
|
|
180
|
+
flattenedPaddingStart: DimensionValue | undefined;
|
|
181
|
+
flattenedPaddingEnd: DimensionValue | undefined;
|
|
182
|
+
flattenedTabWidth: DimensionValue | undefined;
|
|
190
183
|
}) => {
|
|
191
184
|
const { routes } = navigationState;
|
|
192
185
|
|
|
193
186
|
const paddingsWidth = Math.max(
|
|
194
187
|
0,
|
|
195
|
-
convertPaddingPercentToSize(
|
|
196
|
-
convertPaddingPercentToSize(
|
|
188
|
+
convertPaddingPercentToSize(flattenedPaddingStart, layout) +
|
|
189
|
+
convertPaddingPercentToSize(flattenedPaddingEnd, layout)
|
|
197
190
|
);
|
|
198
191
|
|
|
199
192
|
return routes.reduce<number>(
|
|
@@ -207,8 +200,8 @@ const getTabBarWidth = <T extends Route>({
|
|
|
207
200
|
scrollEnabled,
|
|
208
201
|
tabWidths,
|
|
209
202
|
flattenedTabWidth,
|
|
210
|
-
|
|
211
|
-
|
|
203
|
+
flattenedPaddingStart,
|
|
204
|
+
flattenedPaddingEnd,
|
|
212
205
|
gap
|
|
213
206
|
),
|
|
214
207
|
paddingsWidth
|
|
@@ -223,15 +216,15 @@ const normalizeScrollValue = <T extends Route>({
|
|
|
223
216
|
tabWidths,
|
|
224
217
|
value,
|
|
225
218
|
flattenedTabWidth,
|
|
226
|
-
|
|
227
|
-
|
|
219
|
+
flattenedPaddingStart,
|
|
220
|
+
flattenedPaddingEnd,
|
|
228
221
|
direction,
|
|
229
222
|
}: Pick<Props<T>, 'layout' | 'navigationState' | 'gap' | 'scrollEnabled'> & {
|
|
230
223
|
tabWidths: Record<string, number>;
|
|
231
224
|
value: number;
|
|
232
|
-
flattenedTabWidth:
|
|
233
|
-
|
|
234
|
-
|
|
225
|
+
flattenedTabWidth: DimensionValue | undefined;
|
|
226
|
+
flattenedPaddingStart: DimensionValue | undefined;
|
|
227
|
+
flattenedPaddingEnd: DimensionValue | undefined;
|
|
235
228
|
direction: LocaleDirection;
|
|
236
229
|
}) => {
|
|
237
230
|
const tabBarWidth = getTabBarWidth({
|
|
@@ -241,8 +234,8 @@ const normalizeScrollValue = <T extends Route>({
|
|
|
241
234
|
gap,
|
|
242
235
|
scrollEnabled,
|
|
243
236
|
flattenedTabWidth,
|
|
244
|
-
|
|
245
|
-
|
|
237
|
+
flattenedPaddingStart,
|
|
238
|
+
flattenedPaddingEnd,
|
|
246
239
|
});
|
|
247
240
|
const maxDistance = getMaxScrollDistance(tabBarWidth, layout.width);
|
|
248
241
|
const scrollValue = Math.max(Math.min(value, maxDistance), 0);
|
|
@@ -263,20 +256,20 @@ const getScrollAmount = <T extends Route>({
|
|
|
263
256
|
scrollEnabled,
|
|
264
257
|
flattenedTabWidth,
|
|
265
258
|
tabWidths,
|
|
266
|
-
|
|
267
|
-
|
|
259
|
+
flattenedPaddingStart,
|
|
260
|
+
flattenedPaddingEnd,
|
|
268
261
|
direction,
|
|
269
262
|
}: Pick<Props<T>, 'layout' | 'navigationState' | 'scrollEnabled' | 'gap'> & {
|
|
270
263
|
tabWidths: Record<string, number>;
|
|
271
|
-
flattenedTabWidth:
|
|
272
|
-
|
|
273
|
-
|
|
264
|
+
flattenedTabWidth: DimensionValue | undefined;
|
|
265
|
+
flattenedPaddingStart: DimensionValue | undefined;
|
|
266
|
+
flattenedPaddingEnd: DimensionValue | undefined;
|
|
274
267
|
direction: LocaleDirection;
|
|
275
268
|
}) => {
|
|
276
269
|
const paddingInitial =
|
|
277
270
|
direction === 'rtl'
|
|
278
|
-
? convertPaddingPercentToSize(
|
|
279
|
-
: convertPaddingPercentToSize(
|
|
271
|
+
? convertPaddingPercentToSize(flattenedPaddingEnd, layout)
|
|
272
|
+
: convertPaddingPercentToSize(flattenedPaddingStart, layout);
|
|
280
273
|
|
|
281
274
|
const centerDistance = Array.from({
|
|
282
275
|
length: navigationState.index + 1,
|
|
@@ -288,8 +281,8 @@ const getScrollAmount = <T extends Route>({
|
|
|
288
281
|
scrollEnabled,
|
|
289
282
|
tabWidths,
|
|
290
283
|
flattenedTabWidth,
|
|
291
|
-
|
|
292
|
-
|
|
284
|
+
flattenedPaddingStart,
|
|
285
|
+
flattenedPaddingEnd,
|
|
293
286
|
gap
|
|
294
287
|
);
|
|
295
288
|
|
|
@@ -312,12 +305,11 @@ const getScrollAmount = <T extends Route>({
|
|
|
312
305
|
gap,
|
|
313
306
|
scrollEnabled,
|
|
314
307
|
flattenedTabWidth,
|
|
315
|
-
|
|
316
|
-
|
|
308
|
+
flattenedPaddingStart,
|
|
309
|
+
flattenedPaddingEnd,
|
|
317
310
|
direction,
|
|
318
311
|
});
|
|
319
312
|
};
|
|
320
|
-
|
|
321
313
|
const getLabelTextDefault = ({ route }: Scene<Route>) => route.title;
|
|
322
314
|
|
|
323
315
|
const getAccessibleDefault = ({ route }: Scene<Route>) =>
|
|
@@ -327,8 +319,8 @@ const getAccessibilityLabelDefault = ({ route }: Scene<Route>) =>
|
|
|
327
319
|
typeof route.accessibilityLabel === 'string'
|
|
328
320
|
? route.accessibilityLabel
|
|
329
321
|
: typeof route.title === 'string'
|
|
330
|
-
|
|
331
|
-
|
|
322
|
+
? route.title
|
|
323
|
+
: undefined;
|
|
332
324
|
|
|
333
325
|
const renderIndicatorDefault = (props: IndicatorProps<Route>) => (
|
|
334
326
|
<TabBarIndicator {...props} />
|
|
@@ -341,10 +333,6 @@ const getTestIdDefault = ({ route }: Scene<Route>) => route.testID;
|
|
|
341
333
|
const MEASURE_PER_BATCH = 10;
|
|
342
334
|
|
|
343
335
|
export function TabBar<T extends Route>({
|
|
344
|
-
getLabelText = getLabelTextDefault,
|
|
345
|
-
getAccessible = getAccessibleDefault,
|
|
346
|
-
getAccessibilityLabel = getAccessibilityLabelDefault,
|
|
347
|
-
getTestID = getTestIdDefault,
|
|
348
336
|
renderIndicator = renderIndicatorDefault,
|
|
349
337
|
gap = 0,
|
|
350
338
|
scrollEnabled,
|
|
@@ -362,9 +350,6 @@ export function TabBar<T extends Route>({
|
|
|
362
350
|
onTabPress,
|
|
363
351
|
pressColor,
|
|
364
352
|
pressOpacity,
|
|
365
|
-
renderBadge,
|
|
366
|
-
renderIcon,
|
|
367
|
-
renderLabel,
|
|
368
353
|
direction = I18nManager.getConstants().isRTL ? 'rtl' : 'ltr',
|
|
369
354
|
renderTabBarItem,
|
|
370
355
|
style,
|
|
@@ -372,6 +357,8 @@ export function TabBar<T extends Route>({
|
|
|
372
357
|
layout: propLayout,
|
|
373
358
|
testID,
|
|
374
359
|
android_ripple,
|
|
360
|
+
options,
|
|
361
|
+
commonOptions,
|
|
375
362
|
}: Props<T>) {
|
|
376
363
|
const [layout, setLayout] = React.useState<Layout>(
|
|
377
364
|
propLayout ?? { width: 0, height: 0 }
|
|
@@ -384,8 +371,8 @@ export function TabBar<T extends Route>({
|
|
|
384
371
|
const { routes } = navigationState;
|
|
385
372
|
const flattenedTabWidth = getFlattenedTabWidth(tabStyle);
|
|
386
373
|
const isWidthDynamic = flattenedTabWidth === 'auto';
|
|
387
|
-
const
|
|
388
|
-
const
|
|
374
|
+
const flattenedPaddingEnd = getFlattenedPaddingEnd(contentContainerStyle);
|
|
375
|
+
const flattenedPaddingStart = getFlattenedPaddingStart(contentContainerStyle);
|
|
389
376
|
const scrollOffset = getScrollAmount({
|
|
390
377
|
layout,
|
|
391
378
|
navigationState,
|
|
@@ -393,8 +380,8 @@ export function TabBar<T extends Route>({
|
|
|
393
380
|
gap,
|
|
394
381
|
scrollEnabled,
|
|
395
382
|
flattenedTabWidth,
|
|
396
|
-
|
|
397
|
-
|
|
383
|
+
flattenedPaddingStart,
|
|
384
|
+
flattenedPaddingEnd,
|
|
398
385
|
direction,
|
|
399
386
|
});
|
|
400
387
|
|
|
@@ -439,15 +426,15 @@ export function TabBar<T extends Route>({
|
|
|
439
426
|
gap,
|
|
440
427
|
scrollEnabled,
|
|
441
428
|
flattenedTabWidth,
|
|
442
|
-
|
|
443
|
-
|
|
429
|
+
flattenedPaddingStart,
|
|
430
|
+
flattenedPaddingEnd,
|
|
444
431
|
});
|
|
445
432
|
|
|
446
433
|
const separatorsWidth = Math.max(0, routes.length - 1) * gap;
|
|
447
434
|
const paddingsWidth = Math.max(
|
|
448
435
|
0,
|
|
449
|
-
convertPaddingPercentToSize(
|
|
450
|
-
convertPaddingPercentToSize(
|
|
436
|
+
convertPaddingPercentToSize(flattenedPaddingStart, layout) +
|
|
437
|
+
convertPaddingPercentToSize(flattenedPaddingEnd, layout)
|
|
451
438
|
);
|
|
452
439
|
|
|
453
440
|
const translateX = React.useMemo(
|
|
@@ -462,86 +449,103 @@ export function TabBar<T extends Route>({
|
|
|
462
449
|
|
|
463
450
|
const renderItem = React.useCallback(
|
|
464
451
|
({ item: route, index }: ListRenderItemInfo<T>) => {
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
route
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
renderIcon: renderIcon,
|
|
476
|
-
renderLabel: renderLabel,
|
|
477
|
-
activeColor: activeColor,
|
|
478
|
-
inactiveColor: inactiveColor,
|
|
479
|
-
pressColor: pressColor,
|
|
480
|
-
pressOpacity: pressOpacity,
|
|
481
|
-
onLayout: isWidthDynamic
|
|
482
|
-
? (e: LayoutChangeEvent) => {
|
|
483
|
-
measuredTabWidths.current[route.key] = e.nativeEvent.layout.width;
|
|
452
|
+
const {
|
|
453
|
+
testID = getTestIdDefault({ route }),
|
|
454
|
+
labelText = getLabelTextDefault({ route }),
|
|
455
|
+
accessible = getAccessibleDefault({ route }),
|
|
456
|
+
accessibilityLabel = getAccessibilityLabelDefault({ route }),
|
|
457
|
+
...rest
|
|
458
|
+
} = {
|
|
459
|
+
...commonOptions,
|
|
460
|
+
...options?.[route.key],
|
|
461
|
+
};
|
|
484
462
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
} else if (
|
|
499
|
-
routes.every(
|
|
463
|
+
const onLayout = isWidthDynamic
|
|
464
|
+
? (e: LayoutChangeEvent) => {
|
|
465
|
+
measuredTabWidths.current[route.key] = e.nativeEvent.layout.width;
|
|
466
|
+
|
|
467
|
+
// When we have measured widths for all of the tabs, we should updates the state
|
|
468
|
+
// We avoid doing separate setState for each layout since it triggers multiple renders and slows down app
|
|
469
|
+
// If we have more than 10 routes divide updating tabWidths into multiple batches. Here we update only first batch of 10 items.
|
|
470
|
+
if (
|
|
471
|
+
routes.length > MEASURE_PER_BATCH &&
|
|
472
|
+
index === MEASURE_PER_BATCH &&
|
|
473
|
+
routes
|
|
474
|
+
.slice(0, MEASURE_PER_BATCH)
|
|
475
|
+
.every(
|
|
500
476
|
(r) => typeof measuredTabWidths.current[r.key] === 'number'
|
|
501
477
|
)
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
478
|
+
) {
|
|
479
|
+
setTabWidths({ ...measuredTabWidths.current });
|
|
480
|
+
} else if (
|
|
481
|
+
routes.every(
|
|
482
|
+
(r) => typeof measuredTabWidths.current[r.key] === 'number'
|
|
483
|
+
)
|
|
484
|
+
) {
|
|
485
|
+
// When we have measured widths for all of the tabs, we should updates the state
|
|
486
|
+
// We avoid doing separate setState for each layout since it triggers multiple renders and slows down app
|
|
487
|
+
setTabWidths({ ...measuredTabWidths.current });
|
|
507
488
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
489
|
+
}
|
|
490
|
+
: undefined;
|
|
491
|
+
|
|
492
|
+
const onPress = () => {
|
|
493
|
+
const event: Scene<T> & Event = {
|
|
494
|
+
route,
|
|
495
|
+
defaultPrevented: false,
|
|
496
|
+
preventDefault: () => {
|
|
497
|
+
event.defaultPrevented = true;
|
|
498
|
+
},
|
|
499
|
+
};
|
|
517
500
|
|
|
518
|
-
|
|
501
|
+
onTabPress?.(event);
|
|
519
502
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
503
|
+
if (event.defaultPrevented) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
523
506
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
507
|
+
jumpTo(route.key);
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
const onLongPress = () => onTabLongPress?.({ route });
|
|
511
|
+
|
|
512
|
+
// Calculate the default width for tab for FlatList to work
|
|
513
|
+
const defaultTabWidth = !isWidthDynamic
|
|
514
|
+
? getComputedTabWidth(
|
|
515
|
+
index,
|
|
516
|
+
layout,
|
|
517
|
+
routes,
|
|
518
|
+
scrollEnabled,
|
|
519
|
+
tabWidths,
|
|
520
|
+
getFlattenedTabWidth(tabStyle),
|
|
521
|
+
getFlattenedPaddingEnd(contentContainerStyle),
|
|
522
|
+
getFlattenedPaddingStart(contentContainerStyle),
|
|
523
|
+
gap
|
|
524
|
+
)
|
|
525
|
+
: undefined;
|
|
526
|
+
|
|
527
|
+
const props = {
|
|
528
|
+
...rest,
|
|
529
|
+
key: route.key,
|
|
530
|
+
position,
|
|
531
|
+
route,
|
|
532
|
+
navigationState,
|
|
533
|
+
testID,
|
|
534
|
+
labelText,
|
|
535
|
+
accessible,
|
|
536
|
+
accessibilityLabel,
|
|
537
|
+
activeColor,
|
|
538
|
+
inactiveColor,
|
|
539
|
+
pressColor,
|
|
540
|
+
pressOpacity,
|
|
541
|
+
onLayout,
|
|
542
|
+
onPress,
|
|
543
|
+
onLongPress,
|
|
544
|
+
labelStyle,
|
|
528
545
|
style: tabStyle,
|
|
529
|
-
|
|
530
|
-
defaultTabWidth: !isWidthDynamic
|
|
531
|
-
? getComputedTabWidth(
|
|
532
|
-
index,
|
|
533
|
-
layout,
|
|
534
|
-
routes,
|
|
535
|
-
scrollEnabled,
|
|
536
|
-
tabWidths,
|
|
537
|
-
getFlattenedTabWidth(tabStyle),
|
|
538
|
-
getFlattenedPaddingRight(contentContainerStyle),
|
|
539
|
-
getFlattenedPaddingLeft(contentContainerStyle),
|
|
540
|
-
gap
|
|
541
|
-
)
|
|
542
|
-
: undefined,
|
|
546
|
+
defaultTabWidth,
|
|
543
547
|
android_ripple,
|
|
544
|
-
};
|
|
548
|
+
} satisfies TabBarItemProps<T> & { key: string };
|
|
545
549
|
|
|
546
550
|
return (
|
|
547
551
|
<>
|
|
@@ -555,33 +559,28 @@ export function TabBar<T extends Route>({
|
|
|
555
559
|
);
|
|
556
560
|
},
|
|
557
561
|
[
|
|
562
|
+
position,
|
|
563
|
+
navigationState,
|
|
564
|
+
commonOptions,
|
|
565
|
+
options,
|
|
558
566
|
activeColor,
|
|
559
|
-
android_ripple,
|
|
560
|
-
gap,
|
|
561
|
-
getAccessibilityLabel,
|
|
562
|
-
getAccessible,
|
|
563
|
-
getLabelText,
|
|
564
|
-
getTestID,
|
|
565
567
|
inactiveColor,
|
|
568
|
+
pressColor,
|
|
569
|
+
pressOpacity,
|
|
566
570
|
isWidthDynamic,
|
|
567
|
-
jumpTo,
|
|
568
571
|
labelStyle,
|
|
572
|
+
tabStyle,
|
|
569
573
|
layout,
|
|
570
|
-
navigationState,
|
|
571
|
-
onTabLongPress,
|
|
572
|
-
onTabPress,
|
|
573
|
-
position,
|
|
574
|
-
pressColor,
|
|
575
|
-
pressOpacity,
|
|
576
|
-
renderBadge,
|
|
577
|
-
renderIcon,
|
|
578
|
-
renderLabel,
|
|
579
|
-
renderTabBarItem,
|
|
580
574
|
routes,
|
|
581
575
|
scrollEnabled,
|
|
582
|
-
tabStyle,
|
|
583
|
-
contentContainerStyle,
|
|
584
576
|
tabWidths,
|
|
577
|
+
contentContainerStyle,
|
|
578
|
+
gap,
|
|
579
|
+
android_ripple,
|
|
580
|
+
renderTabBarItem,
|
|
581
|
+
onTabPress,
|
|
582
|
+
jumpTo,
|
|
583
|
+
onTabLongPress,
|
|
585
584
|
]
|
|
586
585
|
);
|
|
587
586
|
|
|
@@ -655,7 +654,7 @@ export function TabBar<T extends Route>({
|
|
|
655
654
|
),
|
|
656
655
|
style: [
|
|
657
656
|
indicatorStyle,
|
|
658
|
-
{
|
|
657
|
+
{ start: flattenedPaddingStart, end: flattenedPaddingEnd },
|
|
659
658
|
],
|
|
660
659
|
getTabWidth: (i: number) =>
|
|
661
660
|
getComputedTabWidth(
|
|
@@ -665,8 +664,8 @@ export function TabBar<T extends Route>({
|
|
|
665
664
|
scrollEnabled,
|
|
666
665
|
tabWidths,
|
|
667
666
|
flattenedTabWidth,
|
|
668
|
-
|
|
669
|
-
|
|
667
|
+
flattenedPaddingEnd,
|
|
668
|
+
flattenedPaddingStart,
|
|
670
669
|
gap
|
|
671
670
|
),
|
|
672
671
|
gap,
|
|
@@ -725,8 +724,8 @@ const styles = StyleSheet.create({
|
|
|
725
724
|
indicatorContainer: {
|
|
726
725
|
position: 'absolute',
|
|
727
726
|
top: 0,
|
|
728
|
-
|
|
729
|
-
|
|
727
|
+
start: 0,
|
|
728
|
+
end: 0,
|
|
730
729
|
bottom: 0,
|
|
731
730
|
},
|
|
732
731
|
});
|
package/src/TabBarIndicator.tsx
CHANGED
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
Animated,
|
|
4
4
|
Easing,
|
|
5
5
|
Platform,
|
|
6
|
-
StyleProp,
|
|
6
|
+
type StyleProp,
|
|
7
7
|
StyleSheet,
|
|
8
|
-
ViewStyle,
|
|
8
|
+
type ViewStyle,
|
|
9
9
|
} from 'react-native';
|
|
10
10
|
|
|
11
11
|
import type {
|
|
@@ -20,7 +20,7 @@ export type GetTabWidth = (index: number) => number;
|
|
|
20
20
|
|
|
21
21
|
export type Props<T extends Route> = SceneRendererProps & {
|
|
22
22
|
navigationState: NavigationState<T>;
|
|
23
|
-
width:
|
|
23
|
+
width: 'auto' | `${number}%` | number;
|
|
24
24
|
getTabWidth: GetTabWidth;
|
|
25
25
|
direction: LocaleDirection;
|
|
26
26
|
style?: StyleProp<ViewStyle>;
|
|
@@ -131,19 +131,27 @@ export function TabBarIndicator<T extends Route>({
|
|
|
131
131
|
);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
const styleList: StyleProp<ViewStyle> = [];
|
|
135
|
+
|
|
136
|
+
// scaleX doesn't work properly on chrome and opera for linux and android
|
|
137
|
+
if (Platform.OS === 'web' && width === 'auto') {
|
|
138
|
+
styleList.push(
|
|
139
|
+
{ width: transform[1].scaleX },
|
|
140
|
+
{ left: transform[0].translateX }
|
|
141
|
+
);
|
|
142
|
+
} else {
|
|
143
|
+
styleList.push(
|
|
144
|
+
{ width: width === 'auto' ? 1 : width },
|
|
145
|
+
{ start: `${(100 / routes.length) * navigationState.index}%` },
|
|
146
|
+
{ transform }
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
134
150
|
return (
|
|
135
151
|
<Animated.View
|
|
136
152
|
style={[
|
|
137
153
|
styles.indicator,
|
|
138
|
-
|
|
139
|
-
// If layout is not available, use `left` property for positioning the indicator
|
|
140
|
-
// This avoids rendering delay until we are able to calculate translateX
|
|
141
|
-
// If platform is macos use `left` property as `transform` is broken at the moment.
|
|
142
|
-
// See: https://github.com/microsoft/react-native-macos/issues/280
|
|
143
|
-
layout.width && Platform.OS !== 'macos'
|
|
144
|
-
? { left: 0 }
|
|
145
|
-
: { left: `${(100 / routes.length) * navigationState.index}%` },
|
|
146
|
-
{ transform },
|
|
154
|
+
styleList,
|
|
147
155
|
width === 'auto' ? { opacity: opacity } : null,
|
|
148
156
|
style,
|
|
149
157
|
]}
|
|
@@ -157,9 +165,9 @@ const styles = StyleSheet.create({
|
|
|
157
165
|
indicator: {
|
|
158
166
|
backgroundColor: '#ffeb3b',
|
|
159
167
|
position: 'absolute',
|
|
160
|
-
|
|
168
|
+
start: 0,
|
|
161
169
|
bottom: 0,
|
|
162
|
-
|
|
170
|
+
end: 0,
|
|
163
171
|
height: 2,
|
|
164
172
|
},
|
|
165
173
|
});
|