@onekeyfe/react-native-bottom-tabs 6.7.0-19 → 6.7.0-21
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/android/src/main/java/com/onekey/bottomtabs/BottomBarBlurRenderer.kt +50 -30
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsDrawerManager.kt +55 -0
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsDrawerView.kt +496 -0
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsPackage.kt +1 -1
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsView.kt +24 -4
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsViewManager.kt +3 -0
- package/docs/SPEC.md +184 -20
- package/ios/RCTBottomTabsComponentView.mm +37 -0
- package/ios/RCTBottomTabsContainerView.swift +192 -7
- package/ios/RCTBottomTabsDrawerComponentView.h +8 -0
- package/ios/RCTBottomTabsDrawerComponentView.mm +79 -0
- package/ios/RCTBottomTabsDrawerContainerView.swift +327 -0
- package/lib/module/BottomTabs.js +144 -87
- package/lib/module/BottomTabsDrawerNativeComponent.ts +19 -0
- package/lib/module/BottomTabsDrawerNativeComponent.web.js +13 -0
- package/lib/module/BottomTabsNativeComponent.ts +13 -0
- package/lib/typescript/src/BottomTabs.d.ts +36 -10
- package/lib/typescript/src/BottomTabsDrawerNativeComponent.d.ts +15 -0
- package/lib/typescript/src/BottomTabsDrawerNativeComponent.web.d.ts +4 -0
- package/lib/typescript/src/BottomTabsNativeComponent.d.ts +8 -0
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/types.d.ts +1 -0
- package/package.json +3 -2
- package/react-native.config.js +4 -1
- package/src/BottomTabs.tsx +235 -115
- package/src/BottomTabsDrawerNativeComponent.ts +19 -0
- package/src/BottomTabsDrawerNativeComponent.web.tsx +9 -0
- package/src/BottomTabsNativeComponent.ts +13 -0
- package/src/index.tsx +1 -1
- package/src/types.ts +3 -0
package/lib/module/BottomTabs.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import React, { useLayoutEffect, useRef } from
|
|
4
|
-
import { Image, Platform, StyleSheet, View, processColor } from
|
|
3
|
+
import React, { useLayoutEffect, useRef } from "react";
|
|
4
|
+
import { Image, Platform, StyleSheet, View, processColor } from "react-native";
|
|
5
5
|
import { BottomTabBarHeightContext } from "./utils/BottomTabBarHeightContext.js";
|
|
6
6
|
|
|
7
7
|
// eslint-disable-next-line @react-native/no-deep-imports
|
|
8
8
|
|
|
9
|
-
import NativeBottomTabs from
|
|
10
|
-
import useLatestCallback from
|
|
9
|
+
import NativeBottomTabs from "./BottomTabsNativeComponent";
|
|
10
|
+
import useLatestCallback from "use-latest-callback";
|
|
11
11
|
import DelayedFreeze from "./DelayedFreeze.js";
|
|
12
|
+
import NativeBottomTabsDrawer from "./BottomTabsDrawerNativeComponent";
|
|
12
13
|
import { BottomAccessoryView } from "./BottomAccessoryView.js";
|
|
13
14
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
15
|
const isAppleSymbol = icon => icon?.sfSymbol;
|
|
@@ -19,6 +20,10 @@ const BottomTabs = ({
|
|
|
19
20
|
renderLazyPlaceholder,
|
|
20
21
|
onIndexChange,
|
|
21
22
|
onTabDoublePress,
|
|
23
|
+
renderDrawerContent,
|
|
24
|
+
drawerOpen = false,
|
|
25
|
+
drawerSwipeEnabled = false,
|
|
26
|
+
onDrawerOpenChange,
|
|
22
27
|
rippleColor,
|
|
23
28
|
tabBarActiveTintColor: activeTintColor,
|
|
24
29
|
tabBarInactiveTintColor: inactiveTintColor,
|
|
@@ -60,7 +65,7 @@ const BottomTabs = ({
|
|
|
60
65
|
route
|
|
61
66
|
}) => route.preventsDefault,
|
|
62
67
|
hapticFeedbackEnabled = false,
|
|
63
|
-
labeled = Platform.OS !==
|
|
68
|
+
labeled = Platform.OS !== "android" ? true : undefined,
|
|
64
69
|
getFreezeOnBlur = ({
|
|
65
70
|
route
|
|
66
71
|
}) => route.freezeOnBlur,
|
|
@@ -69,21 +74,27 @@ const BottomTabs = ({
|
|
|
69
74
|
tabLabelStyle,
|
|
70
75
|
renderBottomAccessoryView,
|
|
71
76
|
activeIndicatorColor,
|
|
72
|
-
androidBottomBlurEnabled = Platform.OS ===
|
|
77
|
+
androidBottomBlurEnabled = Platform.OS === "android" && Number(Platform.Version) >= 36,
|
|
73
78
|
delayedFreeze = false,
|
|
79
|
+
onTabBarPlacementChange,
|
|
80
|
+
sideAccessoryIcon,
|
|
81
|
+
sideAccessoryLabel,
|
|
82
|
+
onSideAccessoryPress,
|
|
74
83
|
...props
|
|
75
84
|
}) => {
|
|
76
85
|
// @ts-ignore
|
|
77
86
|
const focusedKey = navigationState.routes[navigationState.index].key;
|
|
78
87
|
const customTabBarWrapperRef = useRef(null);
|
|
79
88
|
const nativeBottomTabsRef = useRef(null);
|
|
80
|
-
const [
|
|
89
|
+
const [nativeTabBarHeight, setNativeTabBarHeight] = React.useState(0);
|
|
90
|
+
const [customTabBarHeight, setCustomTabBarHeight] = React.useState(0);
|
|
91
|
+
const tabBarHeight = renderCustomTabBar ? customTabBarHeight : props.tabBarHidden ? 0 : nativeTabBarHeight;
|
|
81
92
|
const [measuredDimensions, setMeasuredDimensions] = React.useState({
|
|
82
|
-
width:
|
|
83
|
-
height:
|
|
93
|
+
width: "100%",
|
|
94
|
+
height: "100%"
|
|
84
95
|
});
|
|
85
96
|
const trimmedRoutes = React.useMemo(() => {
|
|
86
|
-
if (Platform.OS ===
|
|
97
|
+
if (Platform.OS === "android" && navigationState.routes.length > ANDROID_MAX_TABS) {
|
|
87
98
|
console.warn(`BottomTabs only supports up to ${ANDROID_MAX_TABS} tabs on Android`);
|
|
88
99
|
return navigationState.routes.slice(0, ANDROID_MAX_TABS);
|
|
89
100
|
}
|
|
@@ -93,7 +104,7 @@ const BottomTabs = ({
|
|
|
93
104
|
if (!loaded.includes(focusedKey)) {
|
|
94
105
|
setLoaded(loaded => [...loaded, focusedKey]);
|
|
95
106
|
}
|
|
96
|
-
const isIOS = Platform.OS ===
|
|
107
|
+
const isIOS = Platform.OS === "ios";
|
|
97
108
|
|
|
98
109
|
// Unfocused (outline) icons — independent of focusedKey so the array stays
|
|
99
110
|
// stable across tab switches and the native side never reloads on switch.
|
|
@@ -120,8 +131,8 @@ const BottomTabs = ({
|
|
|
120
131
|
const items = React.useMemo(() => trimmedRoutes.map((route, index) => {
|
|
121
132
|
const icon = icons[index];
|
|
122
133
|
const isSfSymbol = isAppleSymbol(icon);
|
|
123
|
-
if (Platform.OS ===
|
|
124
|
-
console.warn(
|
|
134
|
+
if (Platform.OS === "android" && isSfSymbol) {
|
|
135
|
+
console.warn("SF Symbols are not supported on Android. Use require() or pass uri to load an image instead.");
|
|
125
136
|
}
|
|
126
137
|
const color = processColor(getActiveTintColor({
|
|
127
138
|
route
|
|
@@ -141,9 +152,9 @@ const BottomTabs = ({
|
|
|
141
152
|
badge: getBadge?.({
|
|
142
153
|
route
|
|
143
154
|
}),
|
|
144
|
-
badgeBackgroundColor: typeof badgeBgColor ===
|
|
145
|
-
badgeTextColor: typeof badgeTxtColor ===
|
|
146
|
-
activeTintColor: typeof color ===
|
|
155
|
+
badgeBackgroundColor: typeof badgeBgColor === "number" ? badgeBgColor : undefined,
|
|
156
|
+
badgeTextColor: typeof badgeTxtColor === "number" ? badgeTxtColor : undefined,
|
|
157
|
+
activeTintColor: typeof color === "number" ? color : undefined,
|
|
147
158
|
hidden: getHidden?.({
|
|
148
159
|
route
|
|
149
160
|
}),
|
|
@@ -163,14 +174,14 @@ const BottomTabs = ({
|
|
|
163
174
|
// @ts-ignore - resolveAssetSource accepts ImageSourcePropType
|
|
164
175
|
const resolved = Image.resolveAssetSource(icon);
|
|
165
176
|
return {
|
|
166
|
-
uri: resolved?.uri ??
|
|
177
|
+
uri: resolved?.uri ?? "",
|
|
167
178
|
width: resolved?.width ?? 0,
|
|
168
179
|
height: resolved?.height ?? 0,
|
|
169
180
|
scale: resolved?.scale ?? 1
|
|
170
181
|
};
|
|
171
182
|
}
|
|
172
183
|
return {
|
|
173
|
-
uri:
|
|
184
|
+
uri: "",
|
|
174
185
|
width: 0,
|
|
175
186
|
height: 0,
|
|
176
187
|
scale: 1
|
|
@@ -184,14 +195,14 @@ const BottomTabs = ({
|
|
|
184
195
|
// @ts-ignore - resolveAssetSource accepts ImageSourcePropType
|
|
185
196
|
const resolved = Image.resolveAssetSource(icon);
|
|
186
197
|
return {
|
|
187
|
-
uri: resolved?.uri ??
|
|
198
|
+
uri: resolved?.uri ?? "",
|
|
188
199
|
width: resolved?.width ?? 0,
|
|
189
200
|
height: resolved?.height ?? 0,
|
|
190
201
|
scale: resolved?.scale ?? 1
|
|
191
202
|
};
|
|
192
203
|
}
|
|
193
204
|
return {
|
|
194
|
-
uri:
|
|
205
|
+
uri: "",
|
|
195
206
|
width: 0,
|
|
196
207
|
height: 0,
|
|
197
208
|
scale: 1
|
|
@@ -225,8 +236,8 @@ const BottomTabs = ({
|
|
|
225
236
|
}
|
|
226
237
|
}, [focusedKey, jumpTo]);
|
|
227
238
|
const handleTabBarMeasured = React.useCallback(event => {
|
|
228
|
-
|
|
229
|
-
}, [
|
|
239
|
+
setNativeTabBarHeight(event.nativeEvent.height);
|
|
240
|
+
}, [setNativeTabBarHeight]);
|
|
230
241
|
const handleNativeLayout = React.useCallback(event => {
|
|
231
242
|
const {
|
|
232
243
|
width,
|
|
@@ -237,88 +248,134 @@ const BottomTabs = ({
|
|
|
237
248
|
height
|
|
238
249
|
});
|
|
239
250
|
}, [setMeasuredDimensions]);
|
|
251
|
+
const handleTabBarPlacementChange = React.useCallback(event => {
|
|
252
|
+
onTabBarPlacementChange?.(event.nativeEvent.placement);
|
|
253
|
+
}, [onTabBarPlacementChange]);
|
|
254
|
+
const handleSideAccessoryPress = React.useCallback(() => {
|
|
255
|
+
onSideAccessoryPress?.();
|
|
256
|
+
}, [onSideAccessoryPress]);
|
|
257
|
+
const resolvedSideAccessoryIcon = React.useMemo(() => {
|
|
258
|
+
if (!isIOS || !sideAccessoryIcon) {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
// @ts-ignore - resolveAssetSource accepts ImageSourcePropType
|
|
262
|
+
const resolved = Image.resolveAssetSource(sideAccessoryIcon);
|
|
263
|
+
return resolved?.uri ? {
|
|
264
|
+
uri: resolved.uri,
|
|
265
|
+
width: resolved.width ?? 0,
|
|
266
|
+
height: resolved.height ?? 0,
|
|
267
|
+
scale: resolved.scale ?? 1
|
|
268
|
+
} : undefined;
|
|
269
|
+
}, [sideAccessoryIcon]);
|
|
240
270
|
useLayoutEffect(() => {
|
|
241
271
|
if (renderCustomTabBar && customTabBarWrapperRef.current) {
|
|
242
272
|
customTabBarWrapperRef.current.measure((_x, _y, _width, height) => {
|
|
243
|
-
|
|
273
|
+
setCustomTabBarHeight(height);
|
|
244
274
|
});
|
|
245
275
|
}
|
|
246
276
|
}, [renderCustomTabBar]);
|
|
247
|
-
return /*#__PURE__*/
|
|
277
|
+
return /*#__PURE__*/_jsx(BottomTabBarHeightContext.Provider, {
|
|
248
278
|
value: tabBarHeight,
|
|
249
|
-
children:
|
|
250
|
-
ref: nativeBottomTabsRef,
|
|
251
|
-
...props,
|
|
252
|
-
...tabLabelStyle,
|
|
279
|
+
children: /*#__PURE__*/_jsxs(NativeBottomTabsDrawer, {
|
|
253
280
|
style: styles.fullWidth,
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
selectedPage: focusedKey,
|
|
258
|
-
tabBarHidden: props.tabBarHidden ?? !!renderCustomTabBar,
|
|
259
|
-
onTabDoublePress: handleTabDoublePress,
|
|
260
|
-
onPageSelected: handlePageSelected,
|
|
261
|
-
onTabBarMeasured: handleTabBarMeasured,
|
|
262
|
-
onNativeLayout: handleNativeLayout,
|
|
281
|
+
enabled: !!renderDrawerContent,
|
|
282
|
+
open: drawerOpen,
|
|
283
|
+
swipeEnabled: drawerSwipeEnabled,
|
|
263
284
|
hapticFeedbackEnabled: hapticFeedbackEnabled,
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
285
|
+
bottomBarHeight: tabBarHeight ?? 0,
|
|
286
|
+
onDrawerOpenChange: event => onDrawerOpenChange?.(event.nativeEvent.open),
|
|
287
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
288
|
+
collapsable: false,
|
|
289
|
+
style: styles.drawerMenu,
|
|
290
|
+
children: Platform.OS !== "web" ? renderDrawerContent?.() : null
|
|
291
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
292
|
+
collapsable: false,
|
|
293
|
+
style: styles.fullWidth,
|
|
294
|
+
children: [/*#__PURE__*/_jsxs(NativeBottomTabs, {
|
|
295
|
+
ref: nativeBottomTabsRef,
|
|
296
|
+
...props,
|
|
297
|
+
...tabLabelStyle,
|
|
298
|
+
style: styles.fullWidth,
|
|
299
|
+
items: items,
|
|
300
|
+
icons: renderCustomTabBar ? undefined : resolvedIconAssets,
|
|
301
|
+
selectedIcons: isIOS && !renderCustomTabBar ? resolvedSelectedIconAssets : undefined,
|
|
302
|
+
selectedPage: focusedKey,
|
|
303
|
+
tabBarHidden: props.tabBarHidden ?? !!renderCustomTabBar,
|
|
304
|
+
onTabDoublePress: handleTabDoublePress,
|
|
305
|
+
onPageSelected: handlePageSelected,
|
|
306
|
+
onTabBarMeasured: handleTabBarMeasured,
|
|
307
|
+
onNativeLayout: handleNativeLayout,
|
|
308
|
+
onTabBarPlacementChange: handleTabBarPlacementChange,
|
|
309
|
+
sideAccessoryIcon: renderCustomTabBar ? undefined : resolvedSideAccessoryIcon,
|
|
310
|
+
sideAccessoryLabel: sideAccessoryLabel,
|
|
311
|
+
onSideAccessoryPress: handleSideAccessoryPress,
|
|
312
|
+
hapticFeedbackEnabled: hapticFeedbackEnabled,
|
|
313
|
+
activeTintColor: activeTintColor,
|
|
314
|
+
inactiveTintColor: inactiveTintColor,
|
|
315
|
+
barTintColor: tabBarStyle?.backgroundColor,
|
|
316
|
+
rippleColor: rippleColor,
|
|
317
|
+
activeIndicatorColor: activeIndicatorColor,
|
|
318
|
+
androidBottomBlurEnabled: Platform.OS === "android" && !renderCustomTabBar && androidBottomBlurEnabled,
|
|
319
|
+
labeled: labeled,
|
|
320
|
+
children: [trimmedRoutes.map(route => {
|
|
321
|
+
if (getLazy({
|
|
322
|
+
route
|
|
323
|
+
}) !== false && !loaded.includes(route.key)) {
|
|
324
|
+
return /*#__PURE__*/_jsx(View, {
|
|
325
|
+
collapsable: false,
|
|
326
|
+
style: styles.fullWidth,
|
|
327
|
+
children: renderLazyPlaceholder?.({
|
|
328
|
+
route
|
|
329
|
+
})
|
|
330
|
+
}, route.key);
|
|
331
|
+
}
|
|
332
|
+
const focused = route.key === focusedKey;
|
|
333
|
+
const freeze = !focused ? getFreezeOnBlur({
|
|
279
334
|
route
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
})
|
|
308
|
-
})
|
|
309
|
-
ref: customTabBarWrapperRef,
|
|
310
|
-
children: renderCustomTabBar()
|
|
311
|
-
}) : null]
|
|
335
|
+
}) : false;
|
|
336
|
+
const customStyle = getSceneStyle({
|
|
337
|
+
route
|
|
338
|
+
});
|
|
339
|
+
return /*#__PURE__*/_jsx(View, {
|
|
340
|
+
style: [styles.screen, renderCustomTabBar ? styles.fullWidth : measuredDimensions, customStyle],
|
|
341
|
+
collapsable: false,
|
|
342
|
+
pointerEvents: focused ? "auto" : "none",
|
|
343
|
+
accessibilityElementsHidden: !focused,
|
|
344
|
+
importantForAccessibility: focused ? "auto" : "no-hide-descendants",
|
|
345
|
+
children: /*#__PURE__*/_jsx(DelayedFreeze, {
|
|
346
|
+
freeze: !!freeze,
|
|
347
|
+
delayedFreeze: delayedFreeze,
|
|
348
|
+
children: renderScene({
|
|
349
|
+
route,
|
|
350
|
+
jumpTo
|
|
351
|
+
})
|
|
352
|
+
})
|
|
353
|
+
}, route.key);
|
|
354
|
+
}), Platform.OS === "ios" && parseFloat(Platform.Version) >= 26 && renderBottomAccessoryView && !renderCustomTabBar ? /*#__PURE__*/_jsx(BottomAccessoryView, {
|
|
355
|
+
renderBottomAccessoryView: renderBottomAccessoryView
|
|
356
|
+
}) : null]
|
|
357
|
+
}), renderCustomTabBar ? /*#__PURE__*/_jsx(View, {
|
|
358
|
+
ref: customTabBarWrapperRef,
|
|
359
|
+
onLayout: event => setCustomTabBarHeight(event.nativeEvent.layout.height),
|
|
360
|
+
children: renderCustomTabBar()
|
|
361
|
+
}) : null]
|
|
362
|
+
})]
|
|
363
|
+
})
|
|
312
364
|
});
|
|
313
365
|
};
|
|
314
366
|
const styles = StyleSheet.create({
|
|
315
367
|
fullWidth: {
|
|
316
|
-
width:
|
|
317
|
-
height:
|
|
368
|
+
width: "100%",
|
|
369
|
+
height: "100%",
|
|
318
370
|
flex: 1
|
|
319
371
|
},
|
|
372
|
+
drawerMenu: {
|
|
373
|
+
position: "absolute",
|
|
374
|
+
width: "78%",
|
|
375
|
+
height: "100%"
|
|
376
|
+
},
|
|
320
377
|
screen: {
|
|
321
|
-
position:
|
|
378
|
+
position: "absolute"
|
|
322
379
|
}
|
|
323
380
|
});
|
|
324
381
|
export default BottomTabs;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { codegenNativeComponent, type ViewProps } from "react-native";
|
|
2
|
+
import type {
|
|
3
|
+
DirectEventHandler,
|
|
4
|
+
Double,
|
|
5
|
+
WithDefault,
|
|
6
|
+
} from "react-native/Libraries/Types/CodegenTypes";
|
|
7
|
+
|
|
8
|
+
export interface BottomTabsDrawerNativeProps extends ViewProps {
|
|
9
|
+
enabled?: WithDefault<boolean, false>;
|
|
10
|
+
open?: WithDefault<boolean, false>;
|
|
11
|
+
swipeEnabled?: WithDefault<boolean, false>;
|
|
12
|
+
hapticFeedbackEnabled?: WithDefault<boolean, false>;
|
|
13
|
+
bottomBarHeight?: Double;
|
|
14
|
+
onDrawerOpenChange?: DirectEventHandler<Readonly<{ open: boolean }>>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default codegenNativeComponent<BottomTabsDrawerNativeProps>(
|
|
18
|
+
"RNBottomTabsDrawer"
|
|
19
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
// The fixed first slot is the menu; Web only renders the foreground slot.
|
|
6
|
+
export default function BottomTabsDrawerWeb({
|
|
7
|
+
children
|
|
8
|
+
}) {
|
|
9
|
+
return /*#__PURE__*/_jsx(_Fragment, {
|
|
10
|
+
children: React.Children.toArray(children)[1]
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=BottomTabsDrawerNativeComponent.web.js.map
|
|
@@ -22,6 +22,14 @@ export type OnNativeLayout = Readonly<{
|
|
|
22
22
|
height: Double;
|
|
23
23
|
}>;
|
|
24
24
|
|
|
25
|
+
// Where the system draws the tab bar: 'bottom', or 'leading' / 'trailing' for
|
|
26
|
+
// a vertical bar (the iPhone Duo side strip, iOS 27.1+).
|
|
27
|
+
export type OnTabBarPlacementChange = Readonly<{
|
|
28
|
+
placement: string;
|
|
29
|
+
}>;
|
|
30
|
+
|
|
31
|
+
export type OnSideAccessoryPress = Readonly<{}>;
|
|
32
|
+
|
|
25
33
|
export type BottomTabsItems = ReadonlyArray<{
|
|
26
34
|
key: string;
|
|
27
35
|
title: string;
|
|
@@ -65,6 +73,11 @@ export interface BottomTabsNativeProps extends ViewProps {
|
|
|
65
73
|
ignoreBottomInsets?: boolean;
|
|
66
74
|
androidTabBarStyle?: WithDefault<'default' | 'floating', 'default'>;
|
|
67
75
|
ignoreKeyboardInsets?: WithDefault<boolean, true>;
|
|
76
|
+
onTabBarPlacementChange?: DirectEventHandler<OnTabBarPlacementChange>;
|
|
77
|
+
// A round button drawn above a vertical tab bar; iOS only.
|
|
78
|
+
sideAccessoryIcon?: ImageSource;
|
|
79
|
+
sideAccessoryLabel?: string;
|
|
80
|
+
onSideAccessoryPress?: DirectEventHandler<OnSideAccessoryPress>;
|
|
68
81
|
}
|
|
69
82
|
|
|
70
83
|
export default codegenNativeComponent<BottomTabsNativeProps>('RNBottomTabsView');
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { type ColorValue, type StyleProp, type ViewStyle } from
|
|
3
|
-
import type { ImageSource } from
|
|
4
|
-
import type { AppleIcon, BaseRoute, NavigationState, TabRole } from
|
|
5
|
-
import { type RNBottomTabsAccessoryViewProps } from
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type ColorValue, type ImageSourcePropType, type StyleProp, type ViewStyle } from "react-native";
|
|
3
|
+
import type { ImageSource } from "react-native/Libraries/Image/ImageSource";
|
|
4
|
+
import type { AppleIcon, BaseRoute, NavigationState, TabBarPlacement, TabRole } from "./types";
|
|
5
|
+
import { type RNBottomTabsAccessoryViewProps } from "./BottomAccessoryView";
|
|
6
6
|
interface Props<Route extends BaseRoute> {
|
|
7
7
|
labeled?: boolean;
|
|
8
|
+
/** Optional physical-left menu; all motion and input are owned by native. */
|
|
9
|
+
renderDrawerContent?: () => React.ReactNode;
|
|
10
|
+
/** External drawer target. Mirror onDrawerOpenChange for user transitions. */
|
|
11
|
+
drawerOpen?: boolean;
|
|
12
|
+
/** Enables root-screen content swipes after inner horizontal views reach their boundary. */
|
|
13
|
+
drawerSwipeEnabled?: boolean;
|
|
14
|
+
/** Reports a completed user target so the external open state can follow it. */
|
|
15
|
+
onDrawerOpenChange?: (open: boolean) => void;
|
|
8
16
|
/**
|
|
9
17
|
* A tab bar style that adapts to each platform.
|
|
10
18
|
*
|
|
@@ -27,11 +35,11 @@ interface Props<Route extends BaseRoute> {
|
|
|
27
35
|
/**
|
|
28
36
|
* Describes the appearance attributes for the tabBar to use when an observable scroll view is scrolled to the bottom. (iOS only)
|
|
29
37
|
*/
|
|
30
|
-
scrollEdgeAppearance?:
|
|
38
|
+
scrollEdgeAppearance?: "default" | "opaque" | "transparent";
|
|
31
39
|
/**
|
|
32
40
|
* Behavior for minimizing the tab bar. (iOS 26+)
|
|
33
41
|
*/
|
|
34
|
-
minimizeBehavior?:
|
|
42
|
+
minimizeBehavior?: "automatic" | "onScrollDown" | "onScrollUp" | "never";
|
|
35
43
|
/**
|
|
36
44
|
* Active tab color.
|
|
37
45
|
*/
|
|
@@ -178,7 +186,7 @@ interface Props<Route extends BaseRoute> {
|
|
|
178
186
|
* A function that returns a React element to display as bottom accessory view.
|
|
179
187
|
* iOS 26+ only.
|
|
180
188
|
*/
|
|
181
|
-
renderBottomAccessoryView?: RNBottomTabsAccessoryViewProps[
|
|
189
|
+
renderBottomAccessoryView?: RNBottomTabsAccessoryViewProps["renderBottomAccessoryView"];
|
|
182
190
|
/**
|
|
183
191
|
* Whether the tab bar is hidden.
|
|
184
192
|
*/
|
|
@@ -190,7 +198,7 @@ interface Props<Route extends BaseRoute> {
|
|
|
190
198
|
/**
|
|
191
199
|
* Visual style of the Android tab bar. Android only.
|
|
192
200
|
*/
|
|
193
|
-
androidTabBarStyle?:
|
|
201
|
+
androidTabBarStyle?: "default" | "floating";
|
|
194
202
|
/**
|
|
195
203
|
* Whether the tab bar ignores the soft keyboard. Defaults to true, so the
|
|
196
204
|
* keyboard covers the tab bar as on iOS. Set to false to pad the tab bar by
|
|
@@ -203,7 +211,25 @@ interface Props<Route extends BaseRoute> {
|
|
|
203
211
|
* original delayed behavior.
|
|
204
212
|
*/
|
|
205
213
|
delayedFreeze?: boolean;
|
|
214
|
+
/**
|
|
215
|
+
* Called when the system moves the tab bar between the bottom edge and a
|
|
216
|
+
* vertical bar on the leading or trailing edge (iPhone Duo). iOS only.
|
|
217
|
+
*/
|
|
218
|
+
onTabBarPlacementChange?: (placement: TabBarPlacement) => void;
|
|
219
|
+
/**
|
|
220
|
+
* Icon of a round button shown above a vertical tab bar. The button only
|
|
221
|
+
* appears while the tab bar is vertical and visible. iOS only.
|
|
222
|
+
*/
|
|
223
|
+
sideAccessoryIcon?: ImageSourcePropType;
|
|
224
|
+
/**
|
|
225
|
+
* Accessibility label of the side accessory button.
|
|
226
|
+
*/
|
|
227
|
+
sideAccessoryLabel?: string;
|
|
228
|
+
/**
|
|
229
|
+
* Called when the side accessory button is pressed.
|
|
230
|
+
*/
|
|
231
|
+
onSideAccessoryPress?: () => void;
|
|
206
232
|
}
|
|
207
|
-
declare const BottomTabs: <Route extends BaseRoute>({ navigationState, renderScene, renderLazyPlaceholder, onIndexChange, onTabDoublePress, rippleColor, tabBarActiveTintColor: activeTintColor, tabBarInactiveTintColor: inactiveTintColor, getBadge, getBadgeBackgroundColor, getBadgeTextColor, getLazy, getLabelText, getIcon, getHidden, getActiveTintColor, getTestID, getRole, getSceneStyle, getPreventsDefault, hapticFeedbackEnabled, labeled, getFreezeOnBlur, tabBar: renderCustomTabBar, tabBarStyle, tabLabelStyle, renderBottomAccessoryView, activeIndicatorColor, androidBottomBlurEnabled, delayedFreeze, ...props }: Props<Route>) => import("react/jsx-runtime").JSX.Element;
|
|
233
|
+
declare const BottomTabs: <Route extends BaseRoute>({ navigationState, renderScene, renderLazyPlaceholder, onIndexChange, onTabDoublePress, renderDrawerContent, drawerOpen, drawerSwipeEnabled, onDrawerOpenChange, rippleColor, tabBarActiveTintColor: activeTintColor, tabBarInactiveTintColor: inactiveTintColor, getBadge, getBadgeBackgroundColor, getBadgeTextColor, getLazy, getLabelText, getIcon, getHidden, getActiveTintColor, getTestID, getRole, getSceneStyle, getPreventsDefault, hapticFeedbackEnabled, labeled, getFreezeOnBlur, tabBar: renderCustomTabBar, tabBarStyle, tabLabelStyle, renderBottomAccessoryView, activeIndicatorColor, androidBottomBlurEnabled, delayedFreeze, onTabBarPlacementChange, sideAccessoryIcon, sideAccessoryLabel, onSideAccessoryPress, ...props }: Props<Route>) => import("react/jsx-runtime").JSX.Element;
|
|
208
234
|
export default BottomTabs;
|
|
209
235
|
//# sourceMappingURL=BottomTabs.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ViewProps } from "react-native";
|
|
2
|
+
import type { DirectEventHandler, Double, WithDefault } from "react-native/Libraries/Types/CodegenTypes";
|
|
3
|
+
export interface BottomTabsDrawerNativeProps extends ViewProps {
|
|
4
|
+
enabled?: WithDefault<boolean, false>;
|
|
5
|
+
open?: WithDefault<boolean, false>;
|
|
6
|
+
swipeEnabled?: WithDefault<boolean, false>;
|
|
7
|
+
hapticFeedbackEnabled?: WithDefault<boolean, false>;
|
|
8
|
+
bottomBarHeight?: Double;
|
|
9
|
+
onDrawerOpenChange?: DirectEventHandler<Readonly<{
|
|
10
|
+
open: boolean;
|
|
11
|
+
}>>;
|
|
12
|
+
}
|
|
13
|
+
declare const _default: import("react-native/types_generated/Libraries/Utilities/codegenNativeComponent").NativeComponentType<BottomTabsDrawerNativeProps>;
|
|
14
|
+
export default _default;
|
|
15
|
+
//# sourceMappingURL=BottomTabsDrawerNativeComponent.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { BottomTabsDrawerNativeProps } from "./BottomTabsDrawerNativeComponent";
|
|
3
|
+
export default function BottomTabsDrawerWeb({ children, }: React.PropsWithChildren<BottomTabsDrawerNativeProps>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
//# sourceMappingURL=BottomTabsDrawerNativeComponent.web.d.ts.map
|
|
@@ -11,6 +11,10 @@ export type OnNativeLayout = Readonly<{
|
|
|
11
11
|
width: Double;
|
|
12
12
|
height: Double;
|
|
13
13
|
}>;
|
|
14
|
+
export type OnTabBarPlacementChange = Readonly<{
|
|
15
|
+
placement: string;
|
|
16
|
+
}>;
|
|
17
|
+
export type OnSideAccessoryPress = Readonly<{}>;
|
|
14
18
|
export type BottomTabsItems = ReadonlyArray<{
|
|
15
19
|
key: string;
|
|
16
20
|
title: string;
|
|
@@ -53,6 +57,10 @@ export interface BottomTabsNativeProps extends ViewProps {
|
|
|
53
57
|
ignoreBottomInsets?: boolean;
|
|
54
58
|
androidTabBarStyle?: WithDefault<'default' | 'floating', 'default'>;
|
|
55
59
|
ignoreKeyboardInsets?: WithDefault<boolean, true>;
|
|
60
|
+
onTabBarPlacementChange?: DirectEventHandler<OnTabBarPlacementChange>;
|
|
61
|
+
sideAccessoryIcon?: ImageSource;
|
|
62
|
+
sideAccessoryLabel?: string;
|
|
63
|
+
onSideAccessoryPress?: DirectEventHandler<OnSideAccessoryPress>;
|
|
56
64
|
}
|
|
57
65
|
declare const _default: import("react-native").HostComponent<BottomTabsNativeProps>;
|
|
58
66
|
export default _default;
|
|
@@ -12,5 +12,5 @@ export { BottomTabBarHeightContext } from './utils/BottomTabBarHeightContext';
|
|
|
12
12
|
/**
|
|
13
13
|
* Types
|
|
14
14
|
*/
|
|
15
|
-
export type { AppleIcon, TabRole } from './types';
|
|
15
|
+
export type { AppleIcon, TabBarPlacement, TabRole } from './types';
|
|
16
16
|
//# sourceMappingURL=index.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/react-native-bottom-tabs",
|
|
3
|
-
"version": "6.7.0-
|
|
3
|
+
"version": "6.7.0-21",
|
|
4
4
|
"description": "Native bottom tabs (tab bar + scene container) for React Native on iOS and Android",
|
|
5
5
|
"source": "./src/index.tsx",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
@@ -107,7 +107,8 @@
|
|
|
107
107
|
"ios": {
|
|
108
108
|
"componentProvider": {
|
|
109
109
|
"RNBottomTabsView": "RCTBottomTabsComponentView",
|
|
110
|
-
"RNBottomTabsAccessoryView": "RCTBottomAccessoryComponentView"
|
|
110
|
+
"RNBottomTabsAccessoryView": "RCTBottomAccessoryComponentView",
|
|
111
|
+
"RNBottomTabsDrawer": "RCTBottomTabsDrawerComponentView"
|
|
111
112
|
},
|
|
112
113
|
"modulesConformingToProtocol": {
|
|
113
114
|
"RCTImageDataDecoder": [
|
package/react-native.config.js
CHANGED
|
@@ -2,7 +2,10 @@ module.exports = {
|
|
|
2
2
|
dependency: {
|
|
3
3
|
platforms: {
|
|
4
4
|
android: {
|
|
5
|
-
componentDescriptors: [
|
|
5
|
+
componentDescriptors: [
|
|
6
|
+
'RNBottomTabsViewComponentDescriptor',
|
|
7
|
+
'RNBottomTabsDrawerComponentDescriptor',
|
|
8
|
+
],
|
|
6
9
|
cmakeListsPath: undefined,
|
|
7
10
|
packageImportPath:
|
|
8
11
|
'import com.onekey.bottomtabs.BottomTabsPackage;',
|