react-native-tab-view 5.0.0-alpha.1 → 5.0.0-alpha.11
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/DefaultAdapter.android.js +4 -0
- package/lib/module/DefaultAdapter.android.js.map +1 -0
- package/lib/module/DefaultAdapter.ios.js +4 -0
- package/lib/module/DefaultAdapter.ios.js.map +1 -0
- package/lib/module/DefaultAdapter.js +5 -0
- package/lib/module/DefaultAdapter.js.map +1 -0
- package/lib/module/PagerViewAdapter.native.js +29 -13
- package/lib/module/PagerViewAdapter.native.js.map +1 -1
- package/lib/module/PanResponderAdapter.js +3 -0
- package/lib/module/PanResponderAdapter.js.map +1 -1
- package/lib/module/PlatformPressable.js +1 -1
- package/lib/module/PlatformPressable.js.map +1 -1
- package/lib/module/SceneMap.js +12 -6
- package/lib/module/SceneMap.js.map +1 -1
- package/lib/module/SceneView.js +25 -1
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/ScrollViewAdapter.js +49 -18
- package/lib/module/ScrollViewAdapter.js.map +1 -1
- package/lib/module/TabBar.js +279 -169
- package/lib/module/TabBar.js.map +1 -1
- package/lib/module/TabBarIndicator.js +314 -90
- package/lib/module/TabBarIndicator.js.map +1 -1
- package/lib/module/TabBarItem.js +94 -44
- 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 +2 -2
- package/lib/module/TabView.js.map +1 -1
- package/lib/module/constants.js +10 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/useLayoutWidths.js +46 -0
- package/lib/module/useLayoutWidths.js.map +1 -0
- package/lib/typescript/src/DefaultAdapter.android.d.ts +2 -0
- package/lib/typescript/src/DefaultAdapter.android.d.ts.map +1 -0
- package/lib/typescript/src/DefaultAdapter.d.ts +6 -0
- package/lib/typescript/src/DefaultAdapter.d.ts.map +1 -0
- package/lib/typescript/src/DefaultAdapter.ios.d.ts +2 -0
- package/lib/typescript/src/DefaultAdapter.ios.d.ts.map +1 -0
- package/lib/typescript/src/PagerViewAdapter.d.ts +1 -1
- package/lib/typescript/src/PagerViewAdapter.d.ts.map +1 -1
- package/lib/typescript/src/PagerViewAdapter.native.d.ts +2 -2
- package/lib/typescript/src/PagerViewAdapter.native.d.ts.map +1 -1
- package/lib/typescript/src/PanResponderAdapter.d.ts +1 -1
- package/lib/typescript/src/PanResponderAdapter.d.ts.map +1 -1
- package/lib/typescript/src/PlatformPressable.d.ts +5 -5
- 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/ScrollViewAdapter.d.ts +2 -3
- package/lib/typescript/src/ScrollViewAdapter.d.ts.map +1 -1
- package/lib/typescript/src/TabBar.d.ts +26 -25
- package/lib/typescript/src/TabBar.d.ts.map +1 -1
- package/lib/typescript/src/TabBarIndicator.d.ts +5 -7
- package/lib/typescript/src/TabBarIndicator.d.ts.map +1 -1
- package/lib/typescript/src/TabBarItem.d.ts +17 -10
- package/lib/typescript/src/TabBarItem.d.ts.map +1 -1
- package/lib/typescript/src/TabBarItemLabel.d.ts +4 -3
- package/lib/typescript/src/TabBarItemLabel.d.ts.map +1 -1
- package/lib/typescript/src/TabView.d.ts +17 -17
- package/lib/typescript/src/TabView.d.ts.map +1 -1
- package/lib/typescript/src/constants.d.ts +8 -0
- package/lib/typescript/src/constants.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +13 -12
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +31 -31
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useLayoutWidths.d.ts +2 -0
- package/lib/typescript/src/useLayoutWidths.d.ts.map +1 -0
- package/lib/typescript/src/useMeasureLayout.d.ts +1 -1
- package/lib/typescript/src/useMeasureLayout.d.ts.map +1 -1
- package/package.json +14 -13
- package/src/DefaultAdapter.android.tsx +1 -0
- package/src/DefaultAdapter.ios.tsx +1 -0
- package/src/DefaultAdapter.tsx +13 -0
- package/src/PagerViewAdapter.native.tsx +36 -18
- package/src/PanResponderAdapter.tsx +4 -0
- package/src/PlatformPressable.tsx +11 -7
- package/src/SceneMap.tsx +17 -9
- package/src/SceneView.tsx +41 -2
- package/src/ScrollViewAdapter.tsx +88 -22
- package/src/TabBar.tsx +440 -235
- package/src/TabBarIndicator.tsx +389 -124
- package/src/TabBarItem.tsx +107 -46
- package/src/TabBarItemLabel.tsx +5 -4
- package/src/TabView.tsx +24 -20
- package/src/constants.tsx +8 -0
- package/src/index.tsx +5 -1
- package/src/types.tsx +40 -36
- package/src/useLayoutWidths.tsx +51 -0
- package/lib/module/Pager.android.js +0 -4
- package/lib/module/Pager.android.js.map +0 -1
- package/lib/module/Pager.ios.js +0 -4
- package/lib/module/Pager.ios.js.map +0 -1
- package/lib/module/Pager.js +0 -4
- package/lib/module/Pager.js.map +0 -1
- package/lib/typescript/src/Pager.android.d.ts +0 -2
- package/lib/typescript/src/Pager.android.d.ts.map +0 -1
- package/lib/typescript/src/Pager.d.ts +0 -2
- package/lib/typescript/src/Pager.d.ts.map +0 -1
- package/lib/typescript/src/Pager.ios.d.ts +0 -2
- package/lib/typescript/src/Pager.ios.d.ts.map +0 -1
- package/src/Pager.android.tsx +0 -1
- package/src/Pager.ios.tsx +0 -1
- package/src/Pager.tsx +0 -1
package/src/TabBarItem.tsx
CHANGED
|
@@ -12,28 +12,37 @@ import {
|
|
|
12
12
|
} from 'react-native';
|
|
13
13
|
import useLatestCallback from 'use-latest-callback';
|
|
14
14
|
|
|
15
|
+
import {
|
|
16
|
+
TAB_BAR_INACTIVE_COLOR,
|
|
17
|
+
TAB_BAR_PRIMARY_ACTIVE_COLOR,
|
|
18
|
+
TAB_BAR_SECONDARY_ACTIVE_COLOR,
|
|
19
|
+
} from './constants';
|
|
15
20
|
import { PlatformPressable } from './PlatformPressable';
|
|
16
21
|
import { TabBarItemLabel } from './TabBarItemLabel';
|
|
17
22
|
import type { NavigationState, Route, TabDescriptor } from './types';
|
|
18
23
|
|
|
24
|
+
type Layout = {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
19
29
|
export type Props<T extends Route> = TabDescriptor<T> & {
|
|
30
|
+
variant?: 'primary' | 'secondary' | undefined;
|
|
20
31
|
position: Animated.AnimatedInterpolation<number>;
|
|
21
32
|
route: T;
|
|
22
33
|
navigationState: NavigationState<T>;
|
|
23
|
-
activeColor?: ColorValue;
|
|
24
|
-
inactiveColor?: ColorValue;
|
|
25
|
-
pressColor?: ColorValue;
|
|
26
|
-
pressOpacity?: number;
|
|
27
|
-
|
|
34
|
+
activeColor?: ColorValue | undefined;
|
|
35
|
+
inactiveColor?: ColorValue | undefined;
|
|
36
|
+
pressColor?: ColorValue | undefined;
|
|
37
|
+
pressOpacity?: number | undefined;
|
|
38
|
+
onMeasureLayout: (layout: Layout) => void;
|
|
39
|
+
onMeasureLabelLayout: (layout: Layout) => void;
|
|
28
40
|
onPress: () => void;
|
|
29
41
|
onLongPress: () => void;
|
|
30
|
-
defaultTabWidth?: number;
|
|
31
42
|
style: StyleProp<ViewStyle>;
|
|
32
|
-
android_ripple?: PressableAndroidRippleConfig;
|
|
43
|
+
android_ripple?: PressableAndroidRippleConfig | undefined;
|
|
33
44
|
};
|
|
34
45
|
|
|
35
|
-
const DEFAULT_ACTIVE_COLOR = 'rgba(0, 0, 0, 1)';
|
|
36
|
-
const DEFAULT_INACTIVE_COLOR = 'rgba(0, 0, 0, 0.5)';
|
|
37
46
|
const ICON_SIZE = 24;
|
|
38
47
|
|
|
39
48
|
const getActiveOpacity = (
|
|
@@ -78,15 +87,18 @@ type TabBarItemInternalProps<T extends Route> = Omit<
|
|
|
78
87
|
| 'getTestID'
|
|
79
88
|
| 'getAccessible'
|
|
80
89
|
| 'options'
|
|
90
|
+
| 'variant'
|
|
81
91
|
> & {
|
|
82
92
|
isFocused: boolean;
|
|
83
93
|
index: number;
|
|
84
94
|
routesLength: number;
|
|
95
|
+
variant: NonNullable<Props<T>['variant']>;
|
|
85
96
|
} & TabDescriptor<T>;
|
|
86
97
|
|
|
87
|
-
const ANDROID_RIPPLE_DEFAULT = { borderless: true };
|
|
98
|
+
const ANDROID_RIPPLE_DEFAULT = { borderless: false, foreground: true };
|
|
88
99
|
|
|
89
100
|
const TabBarItemInternal = <T extends Route>({
|
|
101
|
+
variant,
|
|
90
102
|
accessibilityLabel,
|
|
91
103
|
accessible,
|
|
92
104
|
label: customlabel,
|
|
@@ -99,11 +111,11 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
99
111
|
inactiveColor: inactiveColorCustom,
|
|
100
112
|
activeColor: activeColorCustom,
|
|
101
113
|
labelStyle,
|
|
102
|
-
|
|
114
|
+
onMeasureLayout,
|
|
115
|
+
onMeasureLabelLayout,
|
|
103
116
|
index: tabIndex,
|
|
104
117
|
pressColor,
|
|
105
118
|
pressOpacity,
|
|
106
|
-
defaultTabWidth,
|
|
107
119
|
icon: customIcon,
|
|
108
120
|
badge: customBadge,
|
|
109
121
|
href,
|
|
@@ -114,19 +126,23 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
114
126
|
route,
|
|
115
127
|
}: TabBarItemInternalProps<T>) => {
|
|
116
128
|
const labelColorFromStyle = StyleSheet.flatten(labelStyle || {}).color;
|
|
129
|
+
const defaultActiveColor =
|
|
130
|
+
variant === 'primary'
|
|
131
|
+
? TAB_BAR_PRIMARY_ACTIVE_COLOR
|
|
132
|
+
: TAB_BAR_SECONDARY_ACTIVE_COLOR;
|
|
117
133
|
|
|
118
134
|
const activeColor =
|
|
119
135
|
activeColorCustom !== undefined
|
|
120
136
|
? activeColorCustom
|
|
121
137
|
: typeof labelColorFromStyle === 'string'
|
|
122
138
|
? labelColorFromStyle
|
|
123
|
-
:
|
|
139
|
+
: defaultActiveColor;
|
|
124
140
|
const inactiveColor =
|
|
125
141
|
inactiveColorCustom !== undefined
|
|
126
142
|
? inactiveColorCustom
|
|
127
143
|
: typeof labelColorFromStyle === 'string'
|
|
128
144
|
? labelColorFromStyle
|
|
129
|
-
:
|
|
145
|
+
: TAB_BAR_INACTIVE_COLOR;
|
|
130
146
|
|
|
131
147
|
const activeOpacity = getActiveOpacity(position, routesLength, tabIndex);
|
|
132
148
|
const inactiveOpacity = getInactiveOpacity(position, routesLength, tabIndex);
|
|
@@ -151,7 +167,7 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
151
167
|
});
|
|
152
168
|
|
|
153
169
|
return (
|
|
154
|
-
<View
|
|
170
|
+
<View>
|
|
155
171
|
<Animated.View style={{ opacity: inactiveOpacity }}>
|
|
156
172
|
{inactiveIcon}
|
|
157
173
|
</Animated.View>
|
|
@@ -188,6 +204,7 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
188
204
|
icon={icon}
|
|
189
205
|
label={labelText}
|
|
190
206
|
style={labelStyle}
|
|
207
|
+
allowFontScaling={labelAllowFontScaling}
|
|
191
208
|
/>
|
|
192
209
|
),
|
|
193
210
|
[
|
|
@@ -202,16 +219,39 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
202
219
|
]
|
|
203
220
|
);
|
|
204
221
|
|
|
205
|
-
const tabStyle = StyleSheet.flatten(style);
|
|
206
|
-
const isWidthSet = tabStyle?.width !== undefined;
|
|
207
|
-
|
|
208
|
-
const tabContainerStyle: ViewStyle | null = isWidthSet
|
|
209
|
-
? null
|
|
210
|
-
: { width: defaultTabWidth };
|
|
211
|
-
|
|
212
222
|
const ariaLabel =
|
|
213
223
|
typeof accessibilityLabel !== 'undefined' ? accessibilityLabel : labelText;
|
|
214
224
|
|
|
225
|
+
const viewRef = React.useRef<View>(null);
|
|
226
|
+
const labelRef = React.useRef<View>(null);
|
|
227
|
+
|
|
228
|
+
React.useLayoutEffect(() => {
|
|
229
|
+
viewRef.current?.measure((_x, _y, width, height) => {
|
|
230
|
+
onMeasureLayout({ width, height });
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
labelRef.current?.measure((_x, _y, width, height) => {
|
|
234
|
+
onMeasureLabelLayout({ width, height });
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Only measure on mount. onLayout handles updates.
|
|
238
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
239
|
+
}, []);
|
|
240
|
+
|
|
241
|
+
const onLayout = (event: LayoutChangeEvent) => {
|
|
242
|
+
const { width, height } = event.nativeEvent.layout;
|
|
243
|
+
|
|
244
|
+
onMeasureLayout({ width, height });
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const onLabelLayout = (event: LayoutChangeEvent) => {
|
|
248
|
+
const { width, height } = event.nativeEvent.layout;
|
|
249
|
+
|
|
250
|
+
onMeasureLabelLayout({ width, height });
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const hasIconAndLabel = Boolean(customIcon && labelText);
|
|
254
|
+
|
|
215
255
|
return (
|
|
216
256
|
<PlatformPressable
|
|
217
257
|
android_ripple={android_ripple}
|
|
@@ -223,23 +263,32 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
223
263
|
pressColor={pressColor}
|
|
224
264
|
pressOpacity={pressOpacity}
|
|
225
265
|
unstable_pressDelay={0}
|
|
226
|
-
onLayout={onLayout}
|
|
227
266
|
onPress={onPress}
|
|
228
267
|
onLongPress={onLongPress}
|
|
229
268
|
href={href}
|
|
230
|
-
style={
|
|
269
|
+
style={styles.pressable}
|
|
231
270
|
>
|
|
232
|
-
<View
|
|
233
|
-
{
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
271
|
+
<View
|
|
272
|
+
ref={viewRef}
|
|
273
|
+
onLayout={onLayout}
|
|
274
|
+
style={[
|
|
275
|
+
styles.item,
|
|
276
|
+
hasIconAndLabel ? styles.itemWithIcon : null,
|
|
277
|
+
style,
|
|
278
|
+
]}
|
|
279
|
+
>
|
|
280
|
+
<View ref={labelRef} onLayout={onLabelLayout} style={styles.content}>
|
|
281
|
+
{icon}
|
|
282
|
+
<View>
|
|
283
|
+
<Animated.View style={{ opacity: inactiveOpacity }}>
|
|
284
|
+
{renderLabel(false)}
|
|
285
|
+
</Animated.View>
|
|
286
|
+
<Animated.View
|
|
287
|
+
style={[StyleSheet.absoluteFill, { opacity: activeOpacity }]}
|
|
288
|
+
>
|
|
289
|
+
{renderLabel(true)}
|
|
290
|
+
</Animated.View>
|
|
291
|
+
</View>
|
|
243
292
|
</View>
|
|
244
293
|
{customBadge != null ? (
|
|
245
294
|
<View style={styles.badge}>{customBadge({ route })}</View>
|
|
@@ -253,21 +302,30 @@ const MemoizedTabBarItemInternal = React.memo(
|
|
|
253
302
|
TabBarItemInternal
|
|
254
303
|
) as typeof TabBarItemInternal;
|
|
255
304
|
|
|
256
|
-
export function TabBarItem<T extends Route>(
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
305
|
+
export function TabBarItem<T extends Route>({
|
|
306
|
+
variant = 'primary',
|
|
307
|
+
onPress,
|
|
308
|
+
onLongPress,
|
|
309
|
+
onMeasureLayout,
|
|
310
|
+
onMeasureLabelLayout,
|
|
311
|
+
navigationState,
|
|
312
|
+
route,
|
|
313
|
+
...rest
|
|
314
|
+
}: Props<T>) {
|
|
260
315
|
const onPressLatest = useLatestCallback(onPress);
|
|
261
316
|
const onLongPressLatest = useLatestCallback(onLongPress);
|
|
262
|
-
const
|
|
317
|
+
const onMeasureLayoutLatest = useLatestCallback(onMeasureLayout);
|
|
318
|
+
const onMeasureLabelLayoutLatest = useLatestCallback(onMeasureLabelLayout);
|
|
263
319
|
|
|
264
320
|
const tabIndex = navigationState.routes.indexOf(route);
|
|
265
321
|
|
|
266
322
|
return (
|
|
267
323
|
<MemoizedTabBarItemInternal
|
|
268
324
|
{...rest}
|
|
325
|
+
variant={variant}
|
|
269
326
|
onPress={onPressLatest}
|
|
270
|
-
|
|
327
|
+
onMeasureLayout={onMeasureLayoutLatest}
|
|
328
|
+
onMeasureLabelLayout={onMeasureLabelLayoutLatest}
|
|
271
329
|
onLongPress={onLongPressLatest}
|
|
272
330
|
isFocused={navigationState.index === tabIndex}
|
|
273
331
|
route={route}
|
|
@@ -278,17 +336,20 @@ export function TabBarItem<T extends Route>(props: Props<T>) {
|
|
|
278
336
|
}
|
|
279
337
|
|
|
280
338
|
const styles = StyleSheet.create({
|
|
281
|
-
icon: {
|
|
282
|
-
margin: 2,
|
|
283
|
-
},
|
|
284
339
|
item: {
|
|
285
|
-
flex: 1,
|
|
286
340
|
alignItems: 'center',
|
|
287
341
|
justifyContent: 'center',
|
|
288
|
-
|
|
342
|
+
paddingHorizontal: 16,
|
|
289
343
|
minHeight: 48,
|
|
290
344
|
pointerEvents: 'none',
|
|
291
345
|
},
|
|
346
|
+
itemWithIcon: {
|
|
347
|
+
minHeight: 62,
|
|
348
|
+
},
|
|
349
|
+
content: {
|
|
350
|
+
alignItems: 'center',
|
|
351
|
+
justifyContent: 'center',
|
|
352
|
+
},
|
|
292
353
|
badge: {
|
|
293
354
|
position: 'absolute',
|
|
294
355
|
top: 0,
|
package/src/TabBarItemLabel.tsx
CHANGED
|
@@ -4,19 +4,21 @@ import { Animated, StyleSheet } from 'react-native';
|
|
|
4
4
|
|
|
5
5
|
interface TabBarItemLabelProps {
|
|
6
6
|
color: ColorValue;
|
|
7
|
-
label
|
|
8
|
-
style: StyleProp<ViewStyle>;
|
|
7
|
+
label: string | undefined;
|
|
9
8
|
icon: React.ReactNode;
|
|
9
|
+
style: StyleProp<ViewStyle>;
|
|
10
|
+
allowFontScaling?: boolean | undefined;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export const TabBarItemLabel = React.memo(
|
|
13
|
-
({ color, label, style, icon }: TabBarItemLabelProps) => {
|
|
14
|
+
({ color, label, style, icon, allowFontScaling }: TabBarItemLabelProps) => {
|
|
14
15
|
if (!label) {
|
|
15
16
|
return null;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
return (
|
|
19
20
|
<Animated.Text
|
|
21
|
+
allowFontScaling={allowFontScaling}
|
|
20
22
|
style={[
|
|
21
23
|
styles.label,
|
|
22
24
|
icon ? { marginTop: 0 } : null,
|
|
@@ -34,7 +36,6 @@ TabBarItemLabel.displayName = 'TabBarItemLabel';
|
|
|
34
36
|
|
|
35
37
|
const styles = StyleSheet.create({
|
|
36
38
|
label: {
|
|
37
|
-
margin: 4,
|
|
38
39
|
fontSize: 14,
|
|
39
40
|
fontWeight: '500',
|
|
40
41
|
backgroundColor: 'transparent',
|
package/src/TabView.tsx
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
type ViewStyle,
|
|
9
9
|
} from 'react-native';
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { DefaultAdapter } from './DefaultAdapter';
|
|
12
12
|
import { SceneView } from './SceneView';
|
|
13
13
|
import { TabBar } from './TabBar';
|
|
14
14
|
import type {
|
|
@@ -39,7 +39,7 @@ export type Props<T extends Route> = AdapterCommonProps & {
|
|
|
39
39
|
*
|
|
40
40
|
* Unlike `onIndexChange`, this is called regardless of whether the index changed or not.
|
|
41
41
|
*/
|
|
42
|
-
onTabSelect?: (props: { index: number }) => void;
|
|
42
|
+
onTabSelect?: ((props: { index: number }) => void) | undefined;
|
|
43
43
|
/**
|
|
44
44
|
* State for the tab view containing the current index and routes.
|
|
45
45
|
*
|
|
@@ -59,17 +59,21 @@ export type Props<T extends Route> = AdapterCommonProps & {
|
|
|
59
59
|
* Callback which returns a custom placeholder element.
|
|
60
60
|
* The placeholder is shown when a scene is not yet loaded when `lazy` is enabled.
|
|
61
61
|
*/
|
|
62
|
-
renderLazyPlaceholder?:
|
|
62
|
+
renderLazyPlaceholder?:
|
|
63
|
+
| ((props: { route: T }) => React.ReactNode)
|
|
64
|
+
| undefined;
|
|
63
65
|
/**
|
|
64
66
|
* Callback which returns a custom tab bar element to display.
|
|
65
67
|
*/
|
|
66
|
-
renderTabBar?:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
renderTabBar?:
|
|
69
|
+
| ((
|
|
70
|
+
props: SceneRendererProps &
|
|
71
|
+
EventEmitterProps & {
|
|
72
|
+
navigationState: NavigationState<T>;
|
|
73
|
+
options: Record<string, TabDescriptor<T>> | undefined;
|
|
74
|
+
}
|
|
75
|
+
) => React.ReactNode)
|
|
76
|
+
| undefined;
|
|
73
77
|
/**
|
|
74
78
|
* Callback which returns a custom adapter to use for the tab view.
|
|
75
79
|
* Adapters are responsible for handling gestures and animations between tabs.
|
|
@@ -81,12 +85,12 @@ export type Props<T extends Route> = AdapterCommonProps & {
|
|
|
81
85
|
*
|
|
82
86
|
* Defaults to `PagerViewAdapter` on Android and iOS, and `PanResponderAdapter` on other platforms.
|
|
83
87
|
*/
|
|
84
|
-
renderAdapter?: (props: AdapterProps) => React.ReactElement;
|
|
88
|
+
renderAdapter?: ((props: AdapterProps) => React.ReactElement) | undefined;
|
|
85
89
|
/**
|
|
86
90
|
* Position of the tab bar in the tab view.
|
|
87
91
|
* Defaults to `'top'`.
|
|
88
92
|
*/
|
|
89
|
-
tabBarPosition?: 'top' | 'bottom';
|
|
93
|
+
tabBarPosition?: 'top' | 'bottom' | undefined;
|
|
90
94
|
/**
|
|
91
95
|
* Whether to lazily render the scenes.
|
|
92
96
|
* When enabled, scenes are rendered only when they come into view.
|
|
@@ -94,27 +98,27 @@ export type Props<T extends Route> = AdapterCommonProps & {
|
|
|
94
98
|
* Can be a boolean or a function that receives the route and returns a boolean.
|
|
95
99
|
* Defaults to `false`.
|
|
96
100
|
*/
|
|
97
|
-
lazy?: ((props: { route: T }) => boolean) | boolean;
|
|
101
|
+
lazy?: ((props: { route: T }) => boolean) | boolean | undefined;
|
|
98
102
|
/**
|
|
99
103
|
* How many screens to preload when `lazy` is enabled.
|
|
100
104
|
*
|
|
101
105
|
* Defaults to `0`.
|
|
102
106
|
*/
|
|
103
|
-
lazyPreloadDistance?: number;
|
|
107
|
+
lazyPreloadDistance?: number | undefined;
|
|
104
108
|
/**
|
|
105
109
|
* The layout direction of the tab view.
|
|
106
110
|
*
|
|
107
111
|
* Defaults to the app's locale direction (RTL or LTR).
|
|
108
112
|
*/
|
|
109
|
-
direction?: LocaleDirection;
|
|
113
|
+
direction?: LocaleDirection | undefined;
|
|
110
114
|
/**
|
|
111
115
|
* Style to apply to the pager container.
|
|
112
116
|
*/
|
|
113
|
-
pagerStyle?: StyleProp<ViewStyle
|
|
117
|
+
pagerStyle?: StyleProp<ViewStyle> | undefined;
|
|
114
118
|
/**
|
|
115
119
|
* Style to apply to the tab view container.
|
|
116
120
|
*/
|
|
117
|
-
style?: StyleProp<ViewStyle
|
|
121
|
+
style?: StyleProp<ViewStyle> | undefined;
|
|
118
122
|
/**
|
|
119
123
|
* Callback which returns a React element to render for each route.
|
|
120
124
|
*/
|
|
@@ -131,13 +135,13 @@ export type Props<T extends Route> = AdapterCommonProps & {
|
|
|
131
135
|
*
|
|
132
136
|
* These options are merged with `commonOptions`.
|
|
133
137
|
*/
|
|
134
|
-
options?: Record<string, TabDescriptor<T
|
|
138
|
+
options?: Record<string, TabDescriptor<T>> | undefined;
|
|
135
139
|
/**
|
|
136
140
|
* Options that apply to all tabs.
|
|
137
141
|
*
|
|
138
142
|
* Individual tab options from `options` will override these.
|
|
139
143
|
*/
|
|
140
|
-
commonOptions?: TabDescriptor<T
|
|
144
|
+
commonOptions?: TabDescriptor<T> | undefined;
|
|
141
145
|
};
|
|
142
146
|
|
|
143
147
|
const renderLazyPlaceholderDefault = () => null;
|
|
@@ -156,7 +160,7 @@ export function TabView<T extends Route>({
|
|
|
156
160
|
// eslint-disable-next-line @eslint-react/no-unstable-default-props
|
|
157
161
|
renderTabBar = (props) => <TabBar {...props} />,
|
|
158
162
|
// eslint-disable-next-line @eslint-react/no-unstable-default-props
|
|
159
|
-
renderAdapter = (props) => <
|
|
163
|
+
renderAdapter = (props) => <DefaultAdapter {...props} />,
|
|
160
164
|
pagerStyle,
|
|
161
165
|
style,
|
|
162
166
|
direction = I18nManager.getConstants().isRTL ? 'rtl' : 'ltr',
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const TAB_BAR_PRIMARY_ACTIVE_COLOR = '#6750a4';
|
|
2
|
+
export const TAB_BAR_SECONDARY_ACTIVE_COLOR = '#1d1b20';
|
|
3
|
+
export const TAB_BAR_INACTIVE_COLOR = '#49454f';
|
|
4
|
+
export const TAB_BAR_BACKGROUND_COLOR = '#fef7ff';
|
|
5
|
+
export const TAB_BAR_BORDER_COLOR = '#cac4d0';
|
|
6
|
+
|
|
7
|
+
export const PRIMARY_INDICATOR_MIN_WIDTH = 24;
|
|
8
|
+
export const TAB_MIN_WIDTH = 90;
|
package/src/index.tsx
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
export { DefaultAdapter, type DefaultAdapterProps } from './DefaultAdapter';
|
|
1
2
|
export {
|
|
2
3
|
PagerViewAdapter,
|
|
3
4
|
type PagerViewAdapterProps,
|
|
4
5
|
} from './PagerViewAdapter';
|
|
5
|
-
export {
|
|
6
|
+
export {
|
|
7
|
+
PanResponderAdapter,
|
|
8
|
+
type PanResponderAdapterProps,
|
|
9
|
+
} from './PanResponderAdapter';
|
|
6
10
|
export { SceneMap } from './SceneMap';
|
|
7
11
|
export {
|
|
8
12
|
ScrollViewAdapter,
|
package/src/types.tsx
CHANGED
|
@@ -8,40 +8,44 @@ import type {
|
|
|
8
8
|
} from 'react-native';
|
|
9
9
|
|
|
10
10
|
export type TabDescriptor<T extends Route> = {
|
|
11
|
-
accessibilityLabel?: string;
|
|
12
|
-
accessible?: boolean;
|
|
13
|
-
testID?: string;
|
|
14
|
-
labelText?: string;
|
|
15
|
-
labelAllowFontScaling?: boolean;
|
|
16
|
-
href?: string;
|
|
17
|
-
label?:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
11
|
+
accessibilityLabel?: string | undefined;
|
|
12
|
+
accessible?: boolean | undefined;
|
|
13
|
+
testID?: string | undefined;
|
|
14
|
+
labelText?: string | undefined;
|
|
15
|
+
labelAllowFontScaling?: boolean | undefined;
|
|
16
|
+
href?: string | undefined;
|
|
17
|
+
label?:
|
|
18
|
+
| ((props: {
|
|
19
|
+
route: T;
|
|
20
|
+
labelText?: string | undefined;
|
|
21
|
+
focused: boolean;
|
|
22
|
+
color: ColorValue;
|
|
23
|
+
allowFontScaling?: boolean | undefined;
|
|
24
|
+
style?: StyleProp<TextStyle> | undefined;
|
|
25
|
+
}) => React.ReactNode)
|
|
26
|
+
| undefined;
|
|
27
|
+
labelStyle?: StyleProp<TextStyle> | undefined;
|
|
28
|
+
icon?:
|
|
29
|
+
| ((props: {
|
|
30
|
+
route: T;
|
|
31
|
+
focused: boolean;
|
|
32
|
+
color: ColorValue;
|
|
33
|
+
size: number;
|
|
34
|
+
}) => React.ReactNode)
|
|
35
|
+
| undefined;
|
|
36
|
+
badge?: ((props: { route: T }) => React.ReactElement) | undefined;
|
|
37
|
+
sceneStyle?: StyleProp<ViewStyle> | undefined;
|
|
34
38
|
};
|
|
35
39
|
|
|
36
40
|
export type LocaleDirection = 'ltr' | 'rtl';
|
|
37
41
|
|
|
38
42
|
export type Route = {
|
|
39
43
|
key: string;
|
|
40
|
-
icon?: string;
|
|
41
|
-
title?: string;
|
|
42
|
-
accessible?: boolean;
|
|
43
|
-
accessibilityLabel?: string;
|
|
44
|
-
testID?: string;
|
|
44
|
+
icon?: string | undefined;
|
|
45
|
+
title?: string | undefined;
|
|
46
|
+
accessible?: boolean | undefined;
|
|
47
|
+
accessibilityLabel?: string | undefined;
|
|
48
|
+
testID?: string | undefined;
|
|
45
49
|
};
|
|
46
50
|
|
|
47
51
|
export type Event = {
|
|
@@ -81,33 +85,33 @@ export type AdapterCommonProps = {
|
|
|
81
85
|
* - 'on-drag' - the keyboard is dismissed when a drag begins
|
|
82
86
|
* - 'none' - drags and tab changes do not dismiss the keyboard
|
|
83
87
|
*/
|
|
84
|
-
keyboardDismissMode?: 'none' | 'on-drag' | 'auto';
|
|
88
|
+
keyboardDismissMode?: 'none' | 'on-drag' | 'auto' | undefined;
|
|
85
89
|
/**
|
|
86
90
|
* Whether swiping between tabs is enabled.
|
|
87
91
|
*/
|
|
88
|
-
swipeEnabled?: boolean;
|
|
92
|
+
swipeEnabled?: boolean | undefined;
|
|
89
93
|
/**
|
|
90
94
|
* Whether the tab switch animation is enabled.
|
|
91
95
|
* If set to false, the tab switch will happen immediately without animation.
|
|
92
96
|
*/
|
|
93
|
-
animationEnabled?: boolean;
|
|
97
|
+
animationEnabled?: boolean | undefined;
|
|
94
98
|
/**
|
|
95
99
|
* Callback that is called when the swipe gesture starts.
|
|
96
100
|
*/
|
|
97
|
-
onSwipeStart?: () => void;
|
|
101
|
+
onSwipeStart?: (() => void) | undefined;
|
|
98
102
|
/**
|
|
99
103
|
* Callback that is called when the swipe gesture ends.
|
|
100
104
|
*/
|
|
101
|
-
onSwipeEnd?: () => void;
|
|
105
|
+
onSwipeEnd?: (() => void) | undefined;
|
|
102
106
|
/**
|
|
103
107
|
* Callback that is called when a tab is selected.
|
|
104
108
|
* This is called regardless of whether the index has changed or not.
|
|
105
109
|
*/
|
|
106
|
-
onTabSelect?: (props: { index: number }) => void;
|
|
110
|
+
onTabSelect?: ((props: { index: number }) => void) | undefined;
|
|
107
111
|
/**
|
|
108
112
|
* Style for the pager adapter.
|
|
109
113
|
*/
|
|
110
|
-
style?: StyleProp<ViewStyle
|
|
114
|
+
style?: StyleProp<ViewStyle> | undefined;
|
|
111
115
|
};
|
|
112
116
|
|
|
113
117
|
export type AdapterRendererProps = {
|
|
@@ -123,7 +127,7 @@ export type AdapterRendererProps = {
|
|
|
123
127
|
* The writing direction of the layout.
|
|
124
128
|
* This can be 'ltr' or 'rtl' based on tab view's `direction` prop.
|
|
125
129
|
*/
|
|
126
|
-
layoutDirection?: LocaleDirection;
|
|
130
|
+
layoutDirection?: LocaleDirection | undefined;
|
|
127
131
|
/**
|
|
128
132
|
* Render callback that should render the pages of the tab view.
|
|
129
133
|
*/
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
// Batches onLayout updates from multiple keyed views into a single state update
|
|
4
|
+
// per frame, so layout passes don't trigger N renders.
|
|
5
|
+
export function useLayoutWidths(priorityKeys: string[]) {
|
|
6
|
+
const [widths, setWidths] = React.useState<Record<string, number>>({});
|
|
7
|
+
|
|
8
|
+
const measured = React.useRef<Record<string, number>>({});
|
|
9
|
+
const handle = React.useRef<ReturnType<typeof requestAnimationFrame>>(null);
|
|
10
|
+
|
|
11
|
+
const priorityKeysRef = React.useRef(priorityKeys);
|
|
12
|
+
|
|
13
|
+
React.useEffect(() => {
|
|
14
|
+
priorityKeysRef.current = priorityKeys;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const hasFinishedLayoutRef = React.useRef(false);
|
|
18
|
+
|
|
19
|
+
React.useLayoutEffect(() => {
|
|
20
|
+
hasFinishedLayoutRef.current = true;
|
|
21
|
+
}, []);
|
|
22
|
+
|
|
23
|
+
const onMeasureWidth = React.useCallback((key: string, width: number) => {
|
|
24
|
+
measured.current[key] = width;
|
|
25
|
+
|
|
26
|
+
if (handle.current != null) {
|
|
27
|
+
cancelAnimationFrame(handle.current);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (
|
|
31
|
+
priorityKeysRef.current.includes(key) &&
|
|
32
|
+
!hasFinishedLayoutRef.current
|
|
33
|
+
) {
|
|
34
|
+
// Synchronously set widths during the initial layout phase
|
|
35
|
+
// So we don't have to wait for the next frame to render the indicator
|
|
36
|
+
setWidths((prev) => ({ ...prev, [key]: width }));
|
|
37
|
+
} else if (hasFinishedLayoutRef.current) {
|
|
38
|
+
handle.current = requestAnimationFrame(() => {
|
|
39
|
+
setWidths({ ...measured.current });
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return () => {
|
|
44
|
+
if (handle.current != null) {
|
|
45
|
+
cancelAnimationFrame(handle.current);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}, []);
|
|
49
|
+
|
|
50
|
+
return [widths, onMeasureWidth] as const;
|
|
51
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["PagerViewAdapter","Pager"],"sourceRoot":"../../src","sources":["Pager.android.tsx"],"mappings":";;AAAA,SAASA,gBAAgB,IAAIC,KAAK,QAAQ,oBAAoB","ignoreList":[]}
|
package/lib/module/Pager.ios.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["PagerViewAdapter","Pager"],"sourceRoot":"../../src","sources":["Pager.ios.tsx"],"mappings":";;AAAA,SAASA,gBAAgB,IAAIC,KAAK,QAAQ,oBAAoB","ignoreList":[]}
|
package/lib/module/Pager.js
DELETED
package/lib/module/Pager.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["PanResponderAdapter","Pager"],"sourceRoot":"../../src","sources":["Pager.tsx"],"mappings":";;AAAA,SAASA,mBAAmB,IAAIC,KAAK,QAAQ,0BAAuB","ignoreList":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Pager.android.d.ts","sourceRoot":"","sources":["../../../src/Pager.android.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,IAAI,KAAK,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Pager.d.ts","sourceRoot":"","sources":["../../../src/Pager.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,IAAI,KAAK,EAAE,MAAM,uBAAuB,CAAC"}
|