react-native-tab-view 4.2.2 → 5.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +99 -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 +8 -8
- 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 +173 -100
- package/src/index.tsx +10 -0
- package/src/types.tsx +75 -17
- package/src/useMeasureLayout.tsx +34 -0
package/src/TabView.tsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import {
|
|
3
3
|
I18nManager,
|
|
4
|
-
type LayoutChangeEvent,
|
|
5
4
|
Platform,
|
|
6
5
|
type StyleProp,
|
|
7
6
|
StyleSheet,
|
|
@@ -13,35 +12,131 @@ import { Pager } from './Pager';
|
|
|
13
12
|
import { SceneView } from './SceneView';
|
|
14
13
|
import { TabBar } from './TabBar';
|
|
15
14
|
import type {
|
|
16
|
-
|
|
15
|
+
AdapterCommonProps,
|
|
16
|
+
AdapterProps,
|
|
17
|
+
EventEmitterProps,
|
|
17
18
|
LocaleDirection,
|
|
18
19
|
NavigationState,
|
|
19
|
-
PagerProps,
|
|
20
20
|
Route,
|
|
21
21
|
SceneRendererProps,
|
|
22
22
|
TabDescriptor,
|
|
23
23
|
} from './types';
|
|
24
24
|
|
|
25
|
-
export type Props<T extends Route> =
|
|
25
|
+
export type Props<T extends Route> = AdapterCommonProps & {
|
|
26
|
+
/**
|
|
27
|
+
* Callback which is called when the index of the active tab changes.
|
|
28
|
+
* Must update the `navigationState.index` prop to the new index.
|
|
29
|
+
*
|
|
30
|
+
* Example:
|
|
31
|
+
* ```js
|
|
32
|
+
* onIndexChange={(index) => setState({ ...state, index })}
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
26
35
|
onIndexChange: (index: number) => void;
|
|
36
|
+
/**
|
|
37
|
+
* Callback which is called when the tab navigation animation ends.
|
|
38
|
+
* Useful for side effects that should run after the tab change animation.
|
|
39
|
+
*
|
|
40
|
+
* Unlike `onIndexChange`, this is called regardless of whether the index changed or not.
|
|
41
|
+
*/
|
|
27
42
|
onTabSelect?: (props: { index: number }) => void;
|
|
43
|
+
/**
|
|
44
|
+
* State for the tab view containing the current index and routes.
|
|
45
|
+
*
|
|
46
|
+
* Example:
|
|
47
|
+
* ```js
|
|
48
|
+
* {
|
|
49
|
+
* index: 0,
|
|
50
|
+
* routes: [
|
|
51
|
+
* { key: 'first' },
|
|
52
|
+
* { key: 'second' },
|
|
53
|
+
* ],
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
28
57
|
navigationState: NavigationState<T>;
|
|
58
|
+
/**
|
|
59
|
+
* Callback which returns a custom placeholder element.
|
|
60
|
+
* The placeholder is shown when a scene is not yet loaded when `lazy` is enabled.
|
|
61
|
+
*/
|
|
29
62
|
renderLazyPlaceholder?: (props: { route: T }) => React.ReactNode;
|
|
63
|
+
/**
|
|
64
|
+
* Callback which returns a custom tab bar element to display.
|
|
65
|
+
*/
|
|
30
66
|
renderTabBar?: (
|
|
31
|
-
props: SceneRendererProps &
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
67
|
+
props: SceneRendererProps &
|
|
68
|
+
EventEmitterProps & {
|
|
69
|
+
navigationState: NavigationState<T>;
|
|
70
|
+
options: Record<string, TabDescriptor<T>> | undefined;
|
|
71
|
+
}
|
|
35
72
|
) => React.ReactNode;
|
|
73
|
+
/**
|
|
74
|
+
* Callback which returns a custom adapter to use for the tab view.
|
|
75
|
+
* Adapters are responsible for handling gestures and animations between tabs.
|
|
76
|
+
*
|
|
77
|
+
* The following adapters are provided out of the box:
|
|
78
|
+
* - `PagerViewAdapter`: Uses `react-native-pager-view` for native experience.
|
|
79
|
+
* - `PanResponderAdapter`: Uses `PanResponder` for a JS-based implementation.
|
|
80
|
+
* - `ScrollViewAdapter`: Uses `ScrollView` for an implementation based on `ScrollView`.
|
|
81
|
+
*
|
|
82
|
+
* Defaults to `PagerViewAdapter` on Android and iOS, and `PanResponderAdapter` on other platforms.
|
|
83
|
+
*/
|
|
84
|
+
renderAdapter?: (props: AdapterProps) => React.ReactElement;
|
|
85
|
+
/**
|
|
86
|
+
* Position of the tab bar in the tab view.
|
|
87
|
+
* Defaults to `'top'`.
|
|
88
|
+
*/
|
|
36
89
|
tabBarPosition?: 'top' | 'bottom';
|
|
37
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Whether to lazily render the scenes.
|
|
92
|
+
* When enabled, scenes are rendered only when they come into view.
|
|
93
|
+
*
|
|
94
|
+
* Can be a boolean or a function that receives the route and returns a boolean.
|
|
95
|
+
* Defaults to `false`.
|
|
96
|
+
*/
|
|
38
97
|
lazy?: ((props: { route: T }) => boolean) | boolean;
|
|
98
|
+
/**
|
|
99
|
+
* How many screens to preload when `lazy` is enabled.
|
|
100
|
+
*
|
|
101
|
+
* Defaults to `0`.
|
|
102
|
+
*/
|
|
39
103
|
lazyPreloadDistance?: number;
|
|
104
|
+
/**
|
|
105
|
+
* The layout direction of the tab view.
|
|
106
|
+
*
|
|
107
|
+
* Defaults to the app's locale direction (RTL or LTR).
|
|
108
|
+
*/
|
|
40
109
|
direction?: LocaleDirection;
|
|
110
|
+
/**
|
|
111
|
+
* Style to apply to the pager container.
|
|
112
|
+
*/
|
|
41
113
|
pagerStyle?: StyleProp<ViewStyle>;
|
|
114
|
+
/**
|
|
115
|
+
* Style to apply to the tab view container.
|
|
116
|
+
*/
|
|
42
117
|
style?: StyleProp<ViewStyle>;
|
|
118
|
+
/**
|
|
119
|
+
* Callback which returns a React element to render for each route.
|
|
120
|
+
*/
|
|
43
121
|
renderScene: (props: SceneRendererProps & { route: T }) => React.ReactNode;
|
|
122
|
+
/**
|
|
123
|
+
* Options for individual tabs, keyed by route key.
|
|
124
|
+
*
|
|
125
|
+
* Example:
|
|
126
|
+
* ```js
|
|
127
|
+
* {
|
|
128
|
+
* first: { labelText: 'First Tab' },
|
|
129
|
+
* second: { labelText: 'Second Tab' },
|
|
130
|
+
* }
|
|
131
|
+
*
|
|
132
|
+
* These options are merged with `commonOptions`.
|
|
133
|
+
*/
|
|
44
134
|
options?: Record<string, TabDescriptor<T>>;
|
|
135
|
+
/**
|
|
136
|
+
* Options that apply to all tabs.
|
|
137
|
+
*
|
|
138
|
+
* Individual tab options from `options` will override these.
|
|
139
|
+
*/
|
|
45
140
|
commonOptions?: TabDescriptor<T>;
|
|
46
141
|
};
|
|
47
142
|
|
|
@@ -52,7 +147,6 @@ export function TabView<T extends Route>({
|
|
|
52
147
|
onTabSelect,
|
|
53
148
|
navigationState,
|
|
54
149
|
renderScene,
|
|
55
|
-
initialLayout,
|
|
56
150
|
keyboardDismissMode = 'auto',
|
|
57
151
|
lazy = false,
|
|
58
152
|
lazyPreloadDistance = 0,
|
|
@@ -61,13 +155,14 @@ export function TabView<T extends Route>({
|
|
|
61
155
|
renderLazyPlaceholder = renderLazyPlaceholderDefault,
|
|
62
156
|
// eslint-disable-next-line @eslint-react/no-unstable-default-props
|
|
63
157
|
renderTabBar = (props) => <TabBar {...props} />,
|
|
158
|
+
// eslint-disable-next-line @eslint-react/no-unstable-default-props
|
|
159
|
+
renderAdapter = (props) => <Pager {...props} />,
|
|
64
160
|
pagerStyle,
|
|
65
161
|
style,
|
|
66
162
|
direction = I18nManager.getConstants().isRTL ? 'rtl' : 'ltr',
|
|
67
163
|
swipeEnabled = true,
|
|
68
164
|
tabBarPosition = 'top',
|
|
69
165
|
animationEnabled = true,
|
|
70
|
-
overScrollMode,
|
|
71
166
|
options: sceneOptions,
|
|
72
167
|
commonOptions,
|
|
73
168
|
}: Props<T>) {
|
|
@@ -82,30 +177,12 @@ export function TabView<T extends Route>({
|
|
|
82
177
|
);
|
|
83
178
|
}
|
|
84
179
|
|
|
85
|
-
const [layout, setLayout] = React.useState({
|
|
86
|
-
width: 0,
|
|
87
|
-
height: 0,
|
|
88
|
-
...initialLayout,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
180
|
const jumpToIndex = (index: number) => {
|
|
92
181
|
if (index !== navigationState.index) {
|
|
93
182
|
onIndexChange(index);
|
|
94
183
|
}
|
|
95
184
|
};
|
|
96
185
|
|
|
97
|
-
const handleLayout = (e: LayoutChangeEvent) => {
|
|
98
|
-
const { height, width } = e.nativeEvent.layout;
|
|
99
|
-
|
|
100
|
-
setLayout((prevLayout) => {
|
|
101
|
-
if (prevLayout.width === width && prevLayout.height === height) {
|
|
102
|
-
return prevLayout;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return { height, width };
|
|
106
|
-
});
|
|
107
|
-
};
|
|
108
|
-
|
|
109
186
|
const options = Object.fromEntries(
|
|
110
187
|
navigationState.routes.map((route) => [
|
|
111
188
|
route.key,
|
|
@@ -116,82 +193,78 @@ export function TabView<T extends Route>({
|
|
|
116
193
|
])
|
|
117
194
|
);
|
|
118
195
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// This is crucial to optimizing the routes with PureComponent
|
|
138
|
-
const sceneRendererProps = {
|
|
139
|
-
position,
|
|
140
|
-
layout,
|
|
141
|
-
jumpTo,
|
|
142
|
-
};
|
|
196
|
+
const element = renderAdapter({
|
|
197
|
+
navigationState,
|
|
198
|
+
keyboardDismissMode,
|
|
199
|
+
swipeEnabled,
|
|
200
|
+
onSwipeStart,
|
|
201
|
+
onSwipeEnd,
|
|
202
|
+
onIndexChange: jumpToIndex,
|
|
203
|
+
onTabSelect,
|
|
204
|
+
animationEnabled,
|
|
205
|
+
layoutDirection: direction,
|
|
206
|
+
style: pagerStyle,
|
|
207
|
+
children: ({ position, render, subscribe, jumpTo }) => {
|
|
208
|
+
// All the props here must not change between re-renders
|
|
209
|
+
// This is crucial to optimizing the routes with PureComponent
|
|
210
|
+
const sceneRendererProps = {
|
|
211
|
+
position,
|
|
212
|
+
jumpTo,
|
|
213
|
+
};
|
|
143
214
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
215
|
+
return (
|
|
216
|
+
<React.Fragment>
|
|
217
|
+
{tabBarPosition === 'top' &&
|
|
218
|
+
renderTabBar({
|
|
219
|
+
...sceneRendererProps,
|
|
220
|
+
subscribe,
|
|
221
|
+
options,
|
|
222
|
+
navigationState,
|
|
223
|
+
})}
|
|
224
|
+
{render(
|
|
225
|
+
navigationState.routes.map((route, i) => {
|
|
226
|
+
const { sceneStyle } = options?.[route.key] ?? {};
|
|
155
227
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
228
|
+
return (
|
|
229
|
+
<SceneView
|
|
230
|
+
key={route.key}
|
|
231
|
+
{...sceneRendererProps}
|
|
232
|
+
subscribe={subscribe}
|
|
233
|
+
index={i}
|
|
234
|
+
lazy={typeof lazy === 'function' ? lazy({ route }) : lazy}
|
|
235
|
+
lazyPreloadDistance={lazyPreloadDistance}
|
|
236
|
+
navigationState={navigationState}
|
|
237
|
+
style={sceneStyle}
|
|
238
|
+
>
|
|
239
|
+
{({ loading }) =>
|
|
240
|
+
loading
|
|
241
|
+
? renderLazyPlaceholder({ route })
|
|
242
|
+
: renderScene({
|
|
243
|
+
...sceneRendererProps,
|
|
244
|
+
route,
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
</SceneView>
|
|
248
|
+
);
|
|
249
|
+
})
|
|
250
|
+
)}
|
|
251
|
+
{tabBarPosition === 'bottom' &&
|
|
252
|
+
renderTabBar({
|
|
253
|
+
...sceneRendererProps,
|
|
254
|
+
subscribe,
|
|
255
|
+
options,
|
|
256
|
+
navigationState,
|
|
257
|
+
})}
|
|
258
|
+
</React.Fragment>
|
|
259
|
+
);
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
return <View style={[styles.container, style]}>{element}</View>;
|
|
191
264
|
}
|
|
192
265
|
|
|
193
266
|
const styles = StyleSheet.create({
|
|
194
|
-
|
|
267
|
+
container: {
|
|
195
268
|
flex: 1,
|
|
196
269
|
overflow: 'hidden',
|
|
197
270
|
},
|
package/src/index.tsx
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
export {
|
|
2
|
+
PagerViewAdapter,
|
|
3
|
+
type PagerViewAdapterProps,
|
|
4
|
+
} from './PagerViewAdapter';
|
|
5
|
+
export { PanResponderAdapter } from './PanResponderAdapter';
|
|
1
6
|
export { SceneMap } from './SceneMap';
|
|
7
|
+
export {
|
|
8
|
+
ScrollViewAdapter,
|
|
9
|
+
type ScrollViewAdapterProps,
|
|
10
|
+
} from './ScrollViewAdapter';
|
|
2
11
|
export type { Props as TabBarProps } from './TabBar';
|
|
3
12
|
export { TabBar } from './TabBar';
|
|
4
13
|
export type { Props as TabBarIndicatorProps } from './TabBarIndicator';
|
|
@@ -8,6 +17,7 @@ export { TabBarItem } from './TabBarItem';
|
|
|
8
17
|
export type { Props as TabViewProps } from './TabView';
|
|
9
18
|
export { TabView } from './TabView';
|
|
10
19
|
export type {
|
|
20
|
+
AdapterProps,
|
|
11
21
|
NavigationState,
|
|
12
22
|
Route,
|
|
13
23
|
SceneRendererProps,
|
package/src/types.tsx
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type {
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type {
|
|
3
|
+
Animated,
|
|
4
|
+
ColorValue,
|
|
5
|
+
StyleProp,
|
|
6
|
+
TextStyle,
|
|
7
|
+
ViewStyle,
|
|
8
|
+
} from 'react-native';
|
|
3
9
|
|
|
4
10
|
export type TabDescriptor<T extends Route> = {
|
|
5
11
|
accessibilityLabel?: string;
|
|
@@ -12,7 +18,7 @@ export type TabDescriptor<T extends Route> = {
|
|
|
12
18
|
route: T;
|
|
13
19
|
labelText?: string;
|
|
14
20
|
focused: boolean;
|
|
15
|
-
color:
|
|
21
|
+
color: ColorValue;
|
|
16
22
|
allowFontScaling?: boolean;
|
|
17
23
|
style?: StyleProp<TextStyle>;
|
|
18
24
|
}) => React.ReactNode;
|
|
@@ -20,7 +26,7 @@ export type TabDescriptor<T extends Route> = {
|
|
|
20
26
|
icon?: (props: {
|
|
21
27
|
route: T;
|
|
22
28
|
focused: boolean;
|
|
23
|
-
color:
|
|
29
|
+
color: ColorValue;
|
|
24
30
|
size: number;
|
|
25
31
|
}) => React.ReactNode;
|
|
26
32
|
badge?: (props: { route: T }) => React.ReactElement;
|
|
@@ -57,31 +63,83 @@ export type Layout = {
|
|
|
57
63
|
height: number;
|
|
58
64
|
};
|
|
59
65
|
|
|
60
|
-
export type Listener = (
|
|
66
|
+
export type Listener = (event: { type: 'enter'; index: number }) => void;
|
|
61
67
|
|
|
62
68
|
export type SceneRendererProps = {
|
|
63
|
-
layout: Layout;
|
|
64
69
|
position: Animated.AnimatedInterpolation<number>;
|
|
65
70
|
jumpTo: (key: string) => void;
|
|
66
71
|
};
|
|
67
72
|
|
|
68
73
|
export type EventEmitterProps = {
|
|
69
|
-
|
|
74
|
+
subscribe: (listener: Listener) => () => void;
|
|
70
75
|
};
|
|
71
76
|
|
|
72
|
-
export type
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
| 'keyboardDismissMode'
|
|
80
|
-
| 'children'
|
|
81
|
-
> & {
|
|
77
|
+
export type AdapterCommonProps = {
|
|
78
|
+
/**
|
|
79
|
+
* Determines whether the keyboard gets dismissed in response to a drag.
|
|
80
|
+
* - 'auto' (default) - the keyboard is dismissed on drag and tab changes
|
|
81
|
+
* - 'on-drag' - the keyboard is dismissed when a drag begins
|
|
82
|
+
* - 'none' - drags and tab changes do not dismiss the keyboard
|
|
83
|
+
*/
|
|
82
84
|
keyboardDismissMode?: 'none' | 'on-drag' | 'auto';
|
|
85
|
+
/**
|
|
86
|
+
* Whether swiping between tabs is enabled.
|
|
87
|
+
*/
|
|
83
88
|
swipeEnabled?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Whether the tab switch animation is enabled.
|
|
91
|
+
* If set to false, the tab switch will happen immediately without animation.
|
|
92
|
+
*/
|
|
84
93
|
animationEnabled?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Callback that is called when the swipe gesture starts.
|
|
96
|
+
*/
|
|
85
97
|
onSwipeStart?: () => void;
|
|
98
|
+
/**
|
|
99
|
+
* Callback that is called when the swipe gesture ends.
|
|
100
|
+
*/
|
|
86
101
|
onSwipeEnd?: () => void;
|
|
102
|
+
/**
|
|
103
|
+
* Callback that is called when a tab is selected.
|
|
104
|
+
* This is called regardless of whether the index has changed or not.
|
|
105
|
+
*/
|
|
106
|
+
onTabSelect?: (props: { index: number }) => void;
|
|
107
|
+
/**
|
|
108
|
+
* Style for the pager adapter.
|
|
109
|
+
*/
|
|
110
|
+
style?: StyleProp<ViewStyle>;
|
|
87
111
|
};
|
|
112
|
+
|
|
113
|
+
export type AdapterRendererProps = {
|
|
114
|
+
/**
|
|
115
|
+
* Callback to call when the index changes.
|
|
116
|
+
*/
|
|
117
|
+
onIndexChange: (index: number) => void;
|
|
118
|
+
/**
|
|
119
|
+
* The current navigation state of the tab view.
|
|
120
|
+
*/
|
|
121
|
+
navigationState: NavigationState<Route>;
|
|
122
|
+
/**
|
|
123
|
+
* The writing direction of the layout.
|
|
124
|
+
* This can be 'ltr' or 'rtl' based on tab view's `direction` prop.
|
|
125
|
+
*/
|
|
126
|
+
layoutDirection?: LocaleDirection;
|
|
127
|
+
/**
|
|
128
|
+
* Render callback that should render the pages of the tab view.
|
|
129
|
+
*/
|
|
130
|
+
children: (
|
|
131
|
+
props: EventEmitterProps & {
|
|
132
|
+
// Animated value which represents the state of current index
|
|
133
|
+
// It can include fractional digits as it represents the intermediate value
|
|
134
|
+
position: Animated.AnimatedInterpolation<number>;
|
|
135
|
+
// Function to actually render the content of the pager
|
|
136
|
+
// The parent component takes care of rendering
|
|
137
|
+
render: (children: React.ReactElement[]) => React.ReactNode;
|
|
138
|
+
// Callback to call when switching the tab
|
|
139
|
+
// The tab switch animation is performed even if the index in state is unchanged
|
|
140
|
+
jumpTo: (key: string) => void;
|
|
141
|
+
}
|
|
142
|
+
) => React.ReactElement;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export type AdapterProps = AdapterRendererProps & AdapterCommonProps;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type LayoutChangeEvent, type View } from 'react-native';
|
|
3
|
+
import useLatestCallback from 'use-latest-callback';
|
|
4
|
+
|
|
5
|
+
import type { Layout } from './types';
|
|
6
|
+
|
|
7
|
+
export function useMeasureLayout(
|
|
8
|
+
ref: React.RefObject<View | null>,
|
|
9
|
+
onMeasure?: (layout: Layout) => void
|
|
10
|
+
) {
|
|
11
|
+
const [layout, setLayout] = React.useState<Layout>({ width: 0, height: 0 });
|
|
12
|
+
|
|
13
|
+
const onMeasureLatest = useLatestCallback(({ width, height }: Layout) => {
|
|
14
|
+
setLayout((layout) =>
|
|
15
|
+
layout.width === width && layout.height === height
|
|
16
|
+
? layout
|
|
17
|
+
: { width, height }
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
onMeasure?.({ width, height });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
React.useLayoutEffect(() => {
|
|
24
|
+
ref.current?.measure((_x, _y, width, height) => {
|
|
25
|
+
onMeasureLatest({ width, height });
|
|
26
|
+
});
|
|
27
|
+
}, [onMeasureLatest, ref]);
|
|
28
|
+
|
|
29
|
+
const onLayout = useLatestCallback((event: LayoutChangeEvent) => {
|
|
30
|
+
onMeasureLatest(event.nativeEvent.layout);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return [layout, onLayout] as const;
|
|
34
|
+
}
|