react-native-tab-view 4.0.0-alpha.1 → 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/PanResponderAdapter.js.map +1 -1
- package/lib/commonjs/PlatformPressable.js +22 -1
- package/lib/commonjs/PlatformPressable.js.map +1 -1
- package/lib/commonjs/SceneView.js.map +1 -1
- package/lib/commonjs/TabBar.js +107 -91
- package/lib/commonjs/TabBar.js.map +1 -1
- package/lib/commonjs/TabBarIndicator.js +19 -14
- package/lib/commonjs/TabBarIndicator.js.map +1 -1
- package/lib/commonjs/TabBarItem.js +53 -72
- package/lib/commonjs/TabBarItem.js.map +1 -1
- package/lib/commonjs/TabBarItemLabel.js +3 -2
- package/lib/commonjs/TabBarItemLabel.js.map +1 -1
- package/lib/commonjs/TabView.js +1 -1
- 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/SceneView.js.map +1 -1
- package/lib/module/TabBar.js +107 -91
- 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 +53 -72
- 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/typescript/src/PlatformPressable.d.ts +3 -2
- package/lib/typescript/src/PlatformPressable.d.ts.map +1 -1
- package/lib/typescript/src/TabBar.d.ts +4 -15
- package/lib/typescript/src/TabBar.d.ts.map +1 -1
- package/lib/typescript/src/TabBarIndicator.d.ts.map +1 -1
- package/lib/typescript/src/TabBarItem.d.ts +2 -17
- package/lib/typescript/src/TabBarItem.d.ts.map +1 -1
- package/lib/typescript/src/TabView.d.ts +3 -3
- 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 +9 -9
- package/src/PanResponderAdapter.tsx +2 -2
- package/src/PlatformPressable.tsx +31 -2
- package/src/SceneView.tsx +2 -2
- package/src/TabBar.tsx +160 -162
- package/src/TabBarIndicator.tsx +19 -11
- package/src/TabBarItem.tsx +86 -110
- package/src/TabBarItemLabel.tsx +2 -1
- package/src/TabView.tsx +2 -2
- package/src/index.tsx +6 -1
- package/src/types.tsx +25 -1
package/src/TabBarItem.tsx
CHANGED
|
@@ -13,9 +13,9 @@ import useLatestCallback from 'use-latest-callback';
|
|
|
13
13
|
|
|
14
14
|
import { PlatformPressable } from './PlatformPressable';
|
|
15
15
|
import { TabBarItemLabel } from './TabBarItemLabel';
|
|
16
|
-
import type { NavigationState, Route,
|
|
16
|
+
import type { NavigationState, Route, TabDescriptor } from './types';
|
|
17
17
|
|
|
18
|
-
export type Props<T extends Route> = {
|
|
18
|
+
export type Props<T extends Route> = TabDescriptor<T> & {
|
|
19
19
|
position: Animated.AnimatedInterpolation<number>;
|
|
20
20
|
route: T;
|
|
21
21
|
navigationState: NavigationState<T>;
|
|
@@ -23,21 +23,6 @@ export type Props<T extends Route> = {
|
|
|
23
23
|
inactiveColor?: string;
|
|
24
24
|
pressColor?: string;
|
|
25
25
|
pressOpacity?: number;
|
|
26
|
-
getLabelText: (scene: Scene<T>) => string | undefined;
|
|
27
|
-
getAccessible: (scene: Scene<T>) => boolean | undefined;
|
|
28
|
-
getAccessibilityLabel: (scene: Scene<T>) => string | undefined;
|
|
29
|
-
getTestID: (scene: Scene<T>) => string | undefined;
|
|
30
|
-
renderLabel?: (scene: {
|
|
31
|
-
route: T;
|
|
32
|
-
focused: boolean;
|
|
33
|
-
color: string;
|
|
34
|
-
}) => React.ReactNode;
|
|
35
|
-
renderIcon?: (scene: {
|
|
36
|
-
route: T;
|
|
37
|
-
focused: boolean;
|
|
38
|
-
color: string;
|
|
39
|
-
}) => React.ReactNode;
|
|
40
|
-
renderBadge?: (scene: Scene<T>) => React.ReactNode;
|
|
41
26
|
onLayout?: (event: LayoutChangeEvent) => void;
|
|
42
27
|
onPress: () => void;
|
|
43
28
|
onLongPress: () => void;
|
|
@@ -49,6 +34,7 @@ export type Props<T extends Route> = {
|
|
|
49
34
|
|
|
50
35
|
const DEFAULT_ACTIVE_COLOR = 'rgba(255, 255, 255, 1)';
|
|
51
36
|
const DEFAULT_INACTIVE_COLOR = 'rgba(255, 255, 255, 0.7)';
|
|
37
|
+
const ICON_SIZE = 24;
|
|
52
38
|
|
|
53
39
|
const getActiveOpacity = (
|
|
54
40
|
position: Animated.AnimatedInterpolation<number>,
|
|
@@ -91,26 +77,22 @@ type TabBarItemInternalProps<T extends Route> = Omit<
|
|
|
91
77
|
| 'getLabelText'
|
|
92
78
|
| 'getTestID'
|
|
93
79
|
| 'getAccessible'
|
|
80
|
+
| 'options'
|
|
94
81
|
> & {
|
|
95
82
|
isFocused: boolean;
|
|
96
83
|
index: number;
|
|
97
84
|
routesLength: number;
|
|
98
|
-
|
|
99
|
-
label?: string;
|
|
100
|
-
testID?: string;
|
|
101
|
-
accessible?: boolean;
|
|
102
|
-
};
|
|
85
|
+
} & TabDescriptor<T>;
|
|
103
86
|
|
|
104
87
|
const TabBarItemInternal = <T extends Route>({
|
|
105
88
|
accessibilityLabel,
|
|
106
89
|
accessible,
|
|
107
|
-
label:
|
|
90
|
+
label: customlabel,
|
|
108
91
|
testID,
|
|
109
92
|
onLongPress,
|
|
110
93
|
onPress,
|
|
111
94
|
isFocused,
|
|
112
95
|
position,
|
|
113
|
-
route,
|
|
114
96
|
style,
|
|
115
97
|
inactiveColor: inactiveColorCustom,
|
|
116
98
|
activeColor: activeColorCustom,
|
|
@@ -119,12 +101,15 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
119
101
|
index: tabIndex,
|
|
120
102
|
pressColor,
|
|
121
103
|
pressOpacity,
|
|
122
|
-
renderBadge,
|
|
123
|
-
renderIcon,
|
|
124
104
|
defaultTabWidth,
|
|
105
|
+
icon: customIcon,
|
|
106
|
+
badge: customBadge,
|
|
107
|
+
href,
|
|
108
|
+
labelText,
|
|
125
109
|
routesLength,
|
|
126
|
-
renderLabel: renderLabelCustom,
|
|
127
110
|
android_ripple = { borderless: true },
|
|
111
|
+
labelAllowFontScaling,
|
|
112
|
+
route,
|
|
128
113
|
}: TabBarItemInternalProps<T>) => {
|
|
129
114
|
const labelColorFromStyle = StyleSheet.flatten(labelStyle || {}).color;
|
|
130
115
|
|
|
@@ -132,85 +117,88 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
132
117
|
activeColorCustom !== undefined
|
|
133
118
|
? activeColorCustom
|
|
134
119
|
: typeof labelColorFromStyle === 'string'
|
|
135
|
-
|
|
136
|
-
|
|
120
|
+
? labelColorFromStyle
|
|
121
|
+
: DEFAULT_ACTIVE_COLOR;
|
|
137
122
|
const inactiveColor =
|
|
138
123
|
inactiveColorCustom !== undefined
|
|
139
124
|
? inactiveColorCustom
|
|
140
125
|
: typeof labelColorFromStyle === 'string'
|
|
141
|
-
|
|
142
|
-
|
|
126
|
+
? labelColorFromStyle
|
|
127
|
+
: DEFAULT_INACTIVE_COLOR;
|
|
143
128
|
|
|
144
129
|
const activeOpacity = getActiveOpacity(position, routesLength, tabIndex);
|
|
145
130
|
const inactiveOpacity = getInactiveOpacity(position, routesLength, tabIndex);
|
|
146
131
|
|
|
147
|
-
|
|
148
|
-
|
|
132
|
+
const icon = React.useMemo(() => {
|
|
133
|
+
if (!customIcon) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
149
136
|
|
|
150
|
-
|
|
151
|
-
const activeIcon = renderIcon({
|
|
152
|
-
route,
|
|
153
|
-
focused: true,
|
|
154
|
-
color: activeColor,
|
|
155
|
-
});
|
|
156
|
-
const inactiveIcon = renderIcon({
|
|
157
|
-
route,
|
|
137
|
+
const inactiveIcon = customIcon({
|
|
158
138
|
focused: false,
|
|
159
139
|
color: inactiveColor,
|
|
140
|
+
size: ICON_SIZE,
|
|
141
|
+
route,
|
|
160
142
|
});
|
|
161
143
|
|
|
162
|
-
|
|
163
|
-
icon = (
|
|
164
|
-
<View style={styles.icon}>
|
|
165
|
-
<Animated.View style={{ opacity: inactiveOpacity }}>
|
|
166
|
-
{inactiveIcon}
|
|
167
|
-
</Animated.View>
|
|
168
|
-
<Animated.View
|
|
169
|
-
style={[StyleSheet.absoluteFill, { opacity: activeOpacity }]}
|
|
170
|
-
>
|
|
171
|
-
{activeIcon}
|
|
172
|
-
</Animated.View>
|
|
173
|
-
</View>
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const renderLabel = renderLabelCustom
|
|
179
|
-
? renderLabelCustom
|
|
180
|
-
: (labelProps: { color: string }) => (
|
|
181
|
-
<TabBarItemLabel
|
|
182
|
-
{...labelProps}
|
|
183
|
-
icon={icon}
|
|
184
|
-
label={labelText}
|
|
185
|
-
labelStyle={labelStyle}
|
|
186
|
-
/>
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
if (renderLabel) {
|
|
190
|
-
const activeLabel = renderLabel({
|
|
191
|
-
route,
|
|
144
|
+
const activeIcon = customIcon({
|
|
192
145
|
focused: true,
|
|
193
146
|
color: activeColor,
|
|
194
|
-
|
|
195
|
-
const inactiveLabel = renderLabel({
|
|
147
|
+
size: ICON_SIZE,
|
|
196
148
|
route,
|
|
197
|
-
focused: false,
|
|
198
|
-
color: inactiveColor,
|
|
199
149
|
});
|
|
200
150
|
|
|
201
|
-
|
|
202
|
-
<View>
|
|
151
|
+
return (
|
|
152
|
+
<View style={styles.icon}>
|
|
203
153
|
<Animated.View style={{ opacity: inactiveOpacity }}>
|
|
204
|
-
{
|
|
154
|
+
{inactiveIcon}
|
|
205
155
|
</Animated.View>
|
|
206
156
|
<Animated.View
|
|
207
157
|
style={[StyleSheet.absoluteFill, { opacity: activeOpacity }]}
|
|
208
158
|
>
|
|
209
|
-
{
|
|
159
|
+
{activeIcon}
|
|
210
160
|
</Animated.View>
|
|
211
161
|
</View>
|
|
212
162
|
);
|
|
213
|
-
}
|
|
163
|
+
}, [
|
|
164
|
+
activeColor,
|
|
165
|
+
activeOpacity,
|
|
166
|
+
customIcon,
|
|
167
|
+
inactiveColor,
|
|
168
|
+
inactiveOpacity,
|
|
169
|
+
route,
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
const renderLabel = React.useCallback(
|
|
173
|
+
(focused: boolean) =>
|
|
174
|
+
customlabel ? (
|
|
175
|
+
customlabel({
|
|
176
|
+
focused,
|
|
177
|
+
color: focused ? activeColor : inactiveColor,
|
|
178
|
+
style: labelStyle,
|
|
179
|
+
label: labelText,
|
|
180
|
+
allowFontScaling: labelAllowFontScaling,
|
|
181
|
+
route,
|
|
182
|
+
})
|
|
183
|
+
) : (
|
|
184
|
+
<TabBarItemLabel
|
|
185
|
+
color={focused ? activeColor : inactiveColor}
|
|
186
|
+
icon={icon}
|
|
187
|
+
label={labelText}
|
|
188
|
+
labelStyle={labelStyle}
|
|
189
|
+
/>
|
|
190
|
+
),
|
|
191
|
+
[
|
|
192
|
+
customlabel,
|
|
193
|
+
activeColor,
|
|
194
|
+
labelStyle,
|
|
195
|
+
labelText,
|
|
196
|
+
labelAllowFontScaling,
|
|
197
|
+
route,
|
|
198
|
+
inactiveColor,
|
|
199
|
+
icon,
|
|
200
|
+
]
|
|
201
|
+
);
|
|
214
202
|
|
|
215
203
|
const tabStyle = StyleSheet.flatten(style);
|
|
216
204
|
const isWidthSet = tabStyle?.width !== undefined;
|
|
@@ -219,13 +207,9 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
219
207
|
? null
|
|
220
208
|
: { width: defaultTabWidth };
|
|
221
209
|
|
|
222
|
-
const scene = { route };
|
|
223
|
-
|
|
224
210
|
accessibilityLabel =
|
|
225
211
|
typeof accessibilityLabel !== 'undefined' ? accessibilityLabel : labelText;
|
|
226
212
|
|
|
227
|
-
const badge = renderBadge ? renderBadge(scene) : null;
|
|
228
|
-
|
|
229
213
|
return (
|
|
230
214
|
<PlatformPressable
|
|
231
215
|
android_ripple={android_ripple}
|
|
@@ -240,12 +224,24 @@ const TabBarItemInternal = <T extends Route>({
|
|
|
240
224
|
onLayout={onLayout}
|
|
241
225
|
onPress={onPress}
|
|
242
226
|
onLongPress={onLongPress}
|
|
227
|
+
href={href}
|
|
243
228
|
style={[styles.pressable, tabContainerStyle]}
|
|
244
229
|
>
|
|
245
230
|
<View pointerEvents="none" style={[styles.item, tabStyle]}>
|
|
246
231
|
{icon}
|
|
247
|
-
|
|
248
|
-
|
|
232
|
+
<View>
|
|
233
|
+
<Animated.View style={{ opacity: inactiveOpacity }}>
|
|
234
|
+
{renderLabel(false)}
|
|
235
|
+
</Animated.View>
|
|
236
|
+
<Animated.View
|
|
237
|
+
style={[StyleSheet.absoluteFill, { opacity: activeOpacity }]}
|
|
238
|
+
>
|
|
239
|
+
{renderLabel(true)}
|
|
240
|
+
</Animated.View>
|
|
241
|
+
</View>
|
|
242
|
+
{customBadge != null ? (
|
|
243
|
+
<View style={styles.badge}>{customBadge()}</View>
|
|
244
|
+
) : null}
|
|
249
245
|
</View>
|
|
250
246
|
</PlatformPressable>
|
|
251
247
|
);
|
|
@@ -256,31 +252,15 @@ const MemoizedTabBarItemInternal = React.memo(
|
|
|
256
252
|
) as typeof TabBarItemInternal;
|
|
257
253
|
|
|
258
254
|
export function TabBarItem<T extends Route>(props: Props<T>) {
|
|
259
|
-
const {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
onLayout,
|
|
263
|
-
navigationState,
|
|
264
|
-
route,
|
|
265
|
-
getAccessibilityLabel,
|
|
266
|
-
getLabelText,
|
|
267
|
-
getTestID,
|
|
268
|
-
getAccessible,
|
|
269
|
-
...rest
|
|
270
|
-
} = props;
|
|
255
|
+
const { onPress, onLongPress, onLayout, navigationState, route, ...rest } =
|
|
256
|
+
props;
|
|
257
|
+
|
|
271
258
|
const onPressLatest = useLatestCallback(onPress);
|
|
272
259
|
const onLongPressLatest = useLatestCallback(onLongPress);
|
|
273
260
|
const onLayoutLatest = useLatestCallback(onLayout ? onLayout : () => {});
|
|
274
261
|
|
|
275
262
|
const tabIndex = navigationState.routes.indexOf(route);
|
|
276
263
|
|
|
277
|
-
const scene = { route };
|
|
278
|
-
|
|
279
|
-
const accessibilityLabel = getAccessibilityLabel(scene);
|
|
280
|
-
const label = getLabelText(scene);
|
|
281
|
-
const testID = getTestID(scene);
|
|
282
|
-
const accessible = getAccessible(scene);
|
|
283
|
-
|
|
284
264
|
return (
|
|
285
265
|
<MemoizedTabBarItemInternal
|
|
286
266
|
{...rest}
|
|
@@ -291,10 +271,6 @@ export function TabBarItem<T extends Route>(props: Props<T>) {
|
|
|
291
271
|
route={route}
|
|
292
272
|
index={tabIndex}
|
|
293
273
|
routesLength={navigationState.routes.length}
|
|
294
|
-
accessibilityLabel={accessibilityLabel}
|
|
295
|
-
label={label}
|
|
296
|
-
testID={testID}
|
|
297
|
-
accessible={accessible}
|
|
298
274
|
/>
|
|
299
275
|
);
|
|
300
276
|
}
|
|
@@ -313,7 +289,7 @@ const styles = StyleSheet.create({
|
|
|
313
289
|
badge: {
|
|
314
290
|
position: 'absolute',
|
|
315
291
|
top: 0,
|
|
316
|
-
|
|
292
|
+
end: 0,
|
|
317
293
|
},
|
|
318
294
|
pressable: {
|
|
319
295
|
// The label is not pressable on Windows
|
package/src/TabBarItemLabel.tsx
CHANGED
package/src/TabView.tsx
CHANGED
|
@@ -24,7 +24,6 @@ import type {
|
|
|
24
24
|
export type Props<T extends Route> = Omit<PagerProps, 'layoutDirection'> & {
|
|
25
25
|
onIndexChange: (index: number) => void;
|
|
26
26
|
navigationState: NavigationState<T>;
|
|
27
|
-
renderScene: (props: SceneRendererProps & { route: T }) => React.ReactNode;
|
|
28
27
|
renderLazyPlaceholder?: (props: { route: T }) => React.ReactNode;
|
|
29
28
|
renderTabBar?: (
|
|
30
29
|
props: SceneRendererProps & { navigationState: NavigationState<T> }
|
|
@@ -37,6 +36,7 @@ export type Props<T extends Route> = Omit<PagerProps, 'layoutDirection'> & {
|
|
|
37
36
|
direction?: LocaleDirection;
|
|
38
37
|
pagerStyle?: StyleProp<ViewStyle>;
|
|
39
38
|
style?: StyleProp<ViewStyle>;
|
|
39
|
+
renderScene: (props: SceneRendererProps & { route: T }) => React.ReactNode;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
export function TabView<T extends Route>({
|
|
@@ -111,7 +111,7 @@ export function TabView<T extends Route>({
|
|
|
111
111
|
layoutDirection={direction}
|
|
112
112
|
>
|
|
113
113
|
{({ position, render, addEnterListener, jumpTo }) => {
|
|
114
|
-
// All
|
|
114
|
+
// All the props here must not change between re-renders
|
|
115
115
|
// This is crucial to optimizing the routes with PureComponent
|
|
116
116
|
const sceneRendererProps = {
|
|
117
117
|
position,
|
package/src/index.tsx
CHANGED
|
@@ -7,4 +7,9 @@ export type { Props as TabBarItemProps } from './TabBarItem';
|
|
|
7
7
|
export { TabBarItem } from './TabBarItem';
|
|
8
8
|
export type { Props as TabViewProps } from './TabView';
|
|
9
9
|
export { TabView } from './TabView';
|
|
10
|
-
export type {
|
|
10
|
+
export type {
|
|
11
|
+
NavigationState,
|
|
12
|
+
Route,
|
|
13
|
+
SceneRendererProps,
|
|
14
|
+
TabDescriptor,
|
|
15
|
+
} from './types';
|
package/src/types.tsx
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
|
-
import type { Animated } from 'react-native';
|
|
1
|
+
import type { Animated, StyleProp, TextStyle } from 'react-native';
|
|
2
2
|
import type { PagerViewProps } from 'react-native-pager-view';
|
|
3
3
|
|
|
4
|
+
export type TabDescriptor<T extends Route> = {
|
|
5
|
+
accessibilityLabel?: string;
|
|
6
|
+
accessible?: boolean;
|
|
7
|
+
testID?: string;
|
|
8
|
+
labelText?: string;
|
|
9
|
+
labelAllowFontScaling?: boolean;
|
|
10
|
+
href?: string;
|
|
11
|
+
label?: (props: {
|
|
12
|
+
focused: boolean;
|
|
13
|
+
color: string;
|
|
14
|
+
style?: StyleProp<TextStyle>;
|
|
15
|
+
allowFontScaling?: boolean;
|
|
16
|
+
label?: string;
|
|
17
|
+
route: T;
|
|
18
|
+
}) => React.ReactElement;
|
|
19
|
+
icon?: (props: {
|
|
20
|
+
focused: boolean;
|
|
21
|
+
color: string;
|
|
22
|
+
size: number;
|
|
23
|
+
route: T;
|
|
24
|
+
}) => React.ReactElement;
|
|
25
|
+
badge?: () => React.ReactElement;
|
|
26
|
+
};
|
|
27
|
+
|
|
4
28
|
export type LocaleDirection = 'ltr' | 'rtl';
|
|
5
29
|
|
|
6
30
|
export type Route = {
|