@onekeyfe/react-native-bottom-tabs 0.0.0-stage → 6.7.0-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/LICENSE +46 -0
- package/README.md +94 -2
- package/android/build.gradle +119 -0
- package/android/gradle.properties +4 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/onekey/bottomtabs/BottomBarBlurRenderer.kt +92 -0
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsPackage.kt +16 -0
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsView.kt +1558 -0
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsViewManager.kt +220 -0
- package/android/src/main/java/com/onekey/bottomtabs/FloatingTabBarStyle.kt +50 -0
- package/android/src/main/java/com/onekey/bottomtabs/ImageSource.kt +86 -0
- package/android/src/main/java/com/onekey/bottomtabs/TabInfo.kt +13 -0
- package/android/src/main/java/com/onekey/bottomtabs/Utils.kt +31 -0
- package/android/src/main/java/com/onekey/bottomtabs/events/OnNativeLayoutEvent.kt +20 -0
- package/android/src/main/java/com/onekey/bottomtabs/events/OnTabBarMeasuredEvent.kt +19 -0
- package/android/src/main/java/com/onekey/bottomtabs/events/PageSelectedEvent.kt +21 -0
- package/android/src/main/java/com/onekey/bottomtabs/events/TabDoublePressEvent.kt +19 -0
- package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewComponentDescriptor.h +32 -0
- package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewShadowNode.cpp +18 -0
- package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewShadowNode.h +35 -0
- package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewState.cpp +15 -0
- package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewState.h +25 -0
- package/docs/SPEC.md +168 -0
- package/ios/Extensions.swift +46 -0
- package/ios/RCTBottomAccessoryComponentView.h +12 -0
- package/ios/RCTBottomAccessoryComponentView.mm +67 -0
- package/ios/RCTBottomAccessoryContainerView.swift +51 -0
- package/ios/RCTBottomTabsComponentView.h +12 -0
- package/ios/RCTBottomTabsComponentView.mm +338 -0
- package/ios/RCTBottomTabsContainerView.swift +777 -0
- package/ios/RCTBottomTabsLog.h +7 -0
- package/ios/RCTBottomTabsLog.m +32 -0
- package/ios/SVG/CoreSVG.h +13 -0
- package/ios/SVG/CoreSVG.mm +177 -0
- package/ios/SVG/SvgDecoder.h +10 -0
- package/ios/SVG/SvgDecoder.mm +32 -0
- package/ios/TabBarFontSize.swift +55 -0
- package/lib/module/BottomAccessoryView.js +45 -0
- package/lib/module/BottomAccessoryViewNativeComponent.ts +27 -0
- package/lib/module/BottomTabs.js +325 -0
- package/lib/module/BottomTabsNativeComponent.ts +70 -0
- package/lib/module/DelayedFreeze.js +31 -0
- package/lib/module/NativeSVGDecoder.js +5 -0
- package/lib/module/SceneMap.js +28 -0
- package/lib/module/codegen-types.d.js +2 -0
- package/lib/module/index.js +20 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/utils/BottomTabBarHeightContext.js +5 -0
- package/lib/module/utils/useBottomTabBarHeight.js +12 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/BottomAccessoryView.d.ts +8 -0
- package/lib/typescript/src/BottomAccessoryViewNativeComponent.d.ts +16 -0
- package/lib/typescript/src/BottomTabs.d.ts +209 -0
- package/lib/typescript/src/BottomTabsNativeComponent.d.ts +59 -0
- package/lib/typescript/src/DelayedFreeze.d.ts +9 -0
- package/lib/typescript/src/NativeSVGDecoder.d.ts +6 -0
- package/lib/typescript/src/SceneMap.d.ts +10 -0
- package/lib/typescript/src/index.d.ts +16 -0
- package/lib/typescript/src/types.d.ts +29 -0
- package/lib/typescript/src/utils/BottomTabBarHeightContext.d.ts +3 -0
- package/lib/typescript/src/utils/useBottomTabBarHeight.d.ts +2 -0
- package/package.json +117 -4
- package/react-native-bottom-tabs.podspec +36 -0
- package/react-native.config.js +13 -0
- package/src/BottomAccessoryView.tsx +58 -0
- package/src/BottomAccessoryViewNativeComponent.ts +27 -0
- package/src/BottomTabs.tsx +559 -0
- package/src/BottomTabsNativeComponent.ts +70 -0
- package/src/DelayedFreeze.tsx +33 -0
- package/src/NativeSVGDecoder.ts +5 -0
- package/src/SceneMap.tsx +34 -0
- package/src/codegen-types.d.ts +28 -0
- package/src/index.tsx +18 -0
- package/src/types.ts +31 -0
- package/src/utils/BottomTabBarHeightContext.ts +5 -0
- package/src/utils/useBottomTabBarHeight.ts +15 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { useLayoutEffect, useRef } from 'react';
|
|
4
|
+
import { Image, Platform, StyleSheet, View, processColor } from 'react-native';
|
|
5
|
+
import { BottomTabBarHeightContext } from "./utils/BottomTabBarHeightContext.js";
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line @react-native/no-deep-imports
|
|
8
|
+
|
|
9
|
+
import NativeBottomTabs from './BottomTabsNativeComponent';
|
|
10
|
+
import useLatestCallback from 'use-latest-callback';
|
|
11
|
+
import DelayedFreeze from "./DelayedFreeze.js";
|
|
12
|
+
import { BottomAccessoryView } from "./BottomAccessoryView.js";
|
|
13
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
|
+
const isAppleSymbol = icon => icon?.sfSymbol;
|
|
15
|
+
const ANDROID_MAX_TABS = 100;
|
|
16
|
+
const BottomTabs = ({
|
|
17
|
+
navigationState,
|
|
18
|
+
renderScene,
|
|
19
|
+
renderLazyPlaceholder,
|
|
20
|
+
onIndexChange,
|
|
21
|
+
onTabDoublePress,
|
|
22
|
+
rippleColor,
|
|
23
|
+
tabBarActiveTintColor: activeTintColor,
|
|
24
|
+
tabBarInactiveTintColor: inactiveTintColor,
|
|
25
|
+
getBadge = ({
|
|
26
|
+
route
|
|
27
|
+
}) => route.badge,
|
|
28
|
+
getBadgeBackgroundColor = ({
|
|
29
|
+
route
|
|
30
|
+
}) => route.badgeBackgroundColor,
|
|
31
|
+
getBadgeTextColor = ({
|
|
32
|
+
route
|
|
33
|
+
}) => route.badgeTextColor,
|
|
34
|
+
getLazy = ({
|
|
35
|
+
route
|
|
36
|
+
}) => route.lazy,
|
|
37
|
+
getLabelText = ({
|
|
38
|
+
route
|
|
39
|
+
}) => route.title,
|
|
40
|
+
getIcon = ({
|
|
41
|
+
route,
|
|
42
|
+
focused
|
|
43
|
+
}) => route.unfocusedIcon ? focused ? route.focusedIcon : route.unfocusedIcon : route.focusedIcon,
|
|
44
|
+
getHidden = ({
|
|
45
|
+
route
|
|
46
|
+
}) => route.hidden,
|
|
47
|
+
getActiveTintColor = ({
|
|
48
|
+
route
|
|
49
|
+
}) => route.activeTintColor,
|
|
50
|
+
getTestID = ({
|
|
51
|
+
route
|
|
52
|
+
}) => route.testID,
|
|
53
|
+
getRole = ({
|
|
54
|
+
route
|
|
55
|
+
}) => route.role,
|
|
56
|
+
getSceneStyle = ({
|
|
57
|
+
route
|
|
58
|
+
}) => route.style,
|
|
59
|
+
getPreventsDefault = ({
|
|
60
|
+
route
|
|
61
|
+
}) => route.preventsDefault,
|
|
62
|
+
hapticFeedbackEnabled = false,
|
|
63
|
+
labeled = Platform.OS !== 'android' ? true : undefined,
|
|
64
|
+
getFreezeOnBlur = ({
|
|
65
|
+
route
|
|
66
|
+
}) => route.freezeOnBlur,
|
|
67
|
+
tabBar: renderCustomTabBar,
|
|
68
|
+
tabBarStyle,
|
|
69
|
+
tabLabelStyle,
|
|
70
|
+
renderBottomAccessoryView,
|
|
71
|
+
activeIndicatorColor,
|
|
72
|
+
androidBottomBlurEnabled = Platform.OS === 'android' && Number(Platform.Version) >= 36,
|
|
73
|
+
delayedFreeze = false,
|
|
74
|
+
...props
|
|
75
|
+
}) => {
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
const focusedKey = navigationState.routes[navigationState.index].key;
|
|
78
|
+
const customTabBarWrapperRef = useRef(null);
|
|
79
|
+
const nativeBottomTabsRef = useRef(null);
|
|
80
|
+
const [tabBarHeight, setTabBarHeight] = React.useState(0);
|
|
81
|
+
const [measuredDimensions, setMeasuredDimensions] = React.useState({
|
|
82
|
+
width: '100%',
|
|
83
|
+
height: '100%'
|
|
84
|
+
});
|
|
85
|
+
const trimmedRoutes = React.useMemo(() => {
|
|
86
|
+
if (Platform.OS === 'android' && navigationState.routes.length > ANDROID_MAX_TABS) {
|
|
87
|
+
console.warn(`BottomTabs only supports up to ${ANDROID_MAX_TABS} tabs on Android`);
|
|
88
|
+
return navigationState.routes.slice(0, ANDROID_MAX_TABS);
|
|
89
|
+
}
|
|
90
|
+
return navigationState.routes;
|
|
91
|
+
}, [navigationState.routes]);
|
|
92
|
+
const [loaded, setLoaded] = React.useState([focusedKey]);
|
|
93
|
+
if (!loaded.includes(focusedKey)) {
|
|
94
|
+
setLoaded(loaded => [...loaded, focusedKey]);
|
|
95
|
+
}
|
|
96
|
+
const isIOS = Platform.OS === 'ios';
|
|
97
|
+
|
|
98
|
+
// Unfocused (outline) icons — independent of focusedKey so the array stays
|
|
99
|
+
// stable across tab switches and the native side never reloads on switch.
|
|
100
|
+
const unfocusedIcons = React.useMemo(() => trimmedRoutes.map(route => getIcon({
|
|
101
|
+
route,
|
|
102
|
+
focused: false
|
|
103
|
+
})), [getIcon, trimmedRoutes]);
|
|
104
|
+
// Focused (solid) icons — also stable; handed to iOS as selectedImage.
|
|
105
|
+
const focusedIcons = React.useMemo(() => trimmedRoutes.map(route => getIcon({
|
|
106
|
+
route,
|
|
107
|
+
focused: true
|
|
108
|
+
})), [getIcon, trimmedRoutes]);
|
|
109
|
+
// Legacy single array driven by focusedKey. Android still swaps the icon in
|
|
110
|
+
// JS (it has no selectedImage equivalent).
|
|
111
|
+
const focusKeyedIcons = React.useMemo(() => trimmedRoutes.map(route => getIcon({
|
|
112
|
+
route,
|
|
113
|
+
focused: route.key === focusedKey
|
|
114
|
+
})), [focusedKey, getIcon, trimmedRoutes]);
|
|
115
|
+
|
|
116
|
+
// iOS hands both states to UIKit (image + selectedImage) so the focused
|
|
117
|
+
// artwork swaps natively, in sync with the selection animation, instead of
|
|
118
|
+
// waiting for a JS round-trip. Android keeps the focusedKey-driven array.
|
|
119
|
+
const icons = isIOS ? unfocusedIcons : focusKeyedIcons;
|
|
120
|
+
const items = React.useMemo(() => trimmedRoutes.map((route, index) => {
|
|
121
|
+
const icon = icons[index];
|
|
122
|
+
const isSfSymbol = isAppleSymbol(icon);
|
|
123
|
+
if (Platform.OS === 'android' && isSfSymbol) {
|
|
124
|
+
console.warn('SF Symbols are not supported on Android. Use require() or pass uri to load an image instead.');
|
|
125
|
+
}
|
|
126
|
+
const color = processColor(getActiveTintColor({
|
|
127
|
+
route
|
|
128
|
+
}));
|
|
129
|
+
const badgeBgColor = processColor(getBadgeBackgroundColor?.({
|
|
130
|
+
route
|
|
131
|
+
}));
|
|
132
|
+
const badgeTxtColor = processColor(getBadgeTextColor?.({
|
|
133
|
+
route
|
|
134
|
+
}));
|
|
135
|
+
return {
|
|
136
|
+
key: route.key,
|
|
137
|
+
title: getLabelText({
|
|
138
|
+
route
|
|
139
|
+
}) ?? route.key,
|
|
140
|
+
sfSymbol: isSfSymbol ? icon.sfSymbol : undefined,
|
|
141
|
+
badge: getBadge?.({
|
|
142
|
+
route
|
|
143
|
+
}),
|
|
144
|
+
badgeBackgroundColor: typeof badgeBgColor === 'number' ? badgeBgColor : undefined,
|
|
145
|
+
badgeTextColor: typeof badgeTxtColor === 'number' ? badgeTxtColor : undefined,
|
|
146
|
+
activeTintColor: typeof color === 'number' ? color : undefined,
|
|
147
|
+
hidden: getHidden?.({
|
|
148
|
+
route
|
|
149
|
+
}),
|
|
150
|
+
testID: getTestID?.({
|
|
151
|
+
route
|
|
152
|
+
}),
|
|
153
|
+
role: getRole?.({
|
|
154
|
+
route
|
|
155
|
+
}),
|
|
156
|
+
preventsDefault: getPreventsDefault?.({
|
|
157
|
+
route
|
|
158
|
+
})
|
|
159
|
+
};
|
|
160
|
+
}), [trimmedRoutes, icons, getLabelText, getBadge, getBadgeBackgroundColor, getBadgeTextColor, getActiveTintColor, getHidden, getTestID, getRole, getPreventsDefault]);
|
|
161
|
+
const resolvedIconAssets = React.useMemo(() => icons.map(icon => {
|
|
162
|
+
if (icon && !isAppleSymbol(icon)) {
|
|
163
|
+
// @ts-ignore - resolveAssetSource accepts ImageSourcePropType
|
|
164
|
+
const resolved = Image.resolveAssetSource(icon);
|
|
165
|
+
return {
|
|
166
|
+
uri: resolved?.uri ?? '',
|
|
167
|
+
width: resolved?.width ?? 0,
|
|
168
|
+
height: resolved?.height ?? 0,
|
|
169
|
+
scale: resolved?.scale ?? 1
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
uri: '',
|
|
174
|
+
width: 0,
|
|
175
|
+
height: 0,
|
|
176
|
+
scale: 1
|
|
177
|
+
};
|
|
178
|
+
}), [icons]);
|
|
179
|
+
|
|
180
|
+
// Focused (solid) assets passed to iOS as selectedImage. iOS only — Android
|
|
181
|
+
// ignores selectedIcons and keeps swapping via the focusedKey array above.
|
|
182
|
+
const resolvedSelectedIconAssets = React.useMemo(() => focusedIcons.map(icon => {
|
|
183
|
+
if (icon && !isAppleSymbol(icon)) {
|
|
184
|
+
// @ts-ignore - resolveAssetSource accepts ImageSourcePropType
|
|
185
|
+
const resolved = Image.resolveAssetSource(icon);
|
|
186
|
+
return {
|
|
187
|
+
uri: resolved?.uri ?? '',
|
|
188
|
+
width: resolved?.width ?? 0,
|
|
189
|
+
height: resolved?.height ?? 0,
|
|
190
|
+
scale: resolved?.scale ?? 1
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
uri: '',
|
|
195
|
+
width: 0,
|
|
196
|
+
height: 0,
|
|
197
|
+
scale: 1
|
|
198
|
+
};
|
|
199
|
+
}), [focusedIcons]);
|
|
200
|
+
const jumpTo = useLatestCallback(key => {
|
|
201
|
+
const index = trimmedRoutes.findIndex(route => route.key === key);
|
|
202
|
+
if (index === -1) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
return onIndexChange(index);
|
|
206
|
+
});
|
|
207
|
+
const handleTabDoublePress = React.useCallback(event => {
|
|
208
|
+
const {
|
|
209
|
+
key
|
|
210
|
+
} = event.nativeEvent;
|
|
211
|
+
const index = trimmedRoutes.findIndex(route => route.key === key);
|
|
212
|
+
if (index !== -1) {
|
|
213
|
+
onTabDoublePress?.(index);
|
|
214
|
+
}
|
|
215
|
+
}, [trimmedRoutes, onTabDoublePress]);
|
|
216
|
+
const handlePageSelected = React.useCallback(event => {
|
|
217
|
+
const {
|
|
218
|
+
key
|
|
219
|
+
} = event.nativeEvent;
|
|
220
|
+
const accepted = jumpTo(key);
|
|
221
|
+
if (accepted === false) {
|
|
222
|
+
nativeBottomTabsRef.current?.setNativeProps({
|
|
223
|
+
selectedPage: focusedKey
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}, [focusedKey, jumpTo]);
|
|
227
|
+
const handleTabBarMeasured = React.useCallback(event => {
|
|
228
|
+
setTabBarHeight(event.nativeEvent.height);
|
|
229
|
+
}, [setTabBarHeight]);
|
|
230
|
+
const handleNativeLayout = React.useCallback(event => {
|
|
231
|
+
const {
|
|
232
|
+
width,
|
|
233
|
+
height
|
|
234
|
+
} = event.nativeEvent;
|
|
235
|
+
setMeasuredDimensions({
|
|
236
|
+
width,
|
|
237
|
+
height
|
|
238
|
+
});
|
|
239
|
+
}, [setMeasuredDimensions]);
|
|
240
|
+
useLayoutEffect(() => {
|
|
241
|
+
if (renderCustomTabBar && customTabBarWrapperRef.current) {
|
|
242
|
+
customTabBarWrapperRef.current.measure((_x, _y, _width, height) => {
|
|
243
|
+
setTabBarHeight(height);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}, [renderCustomTabBar]);
|
|
247
|
+
return /*#__PURE__*/_jsxs(BottomTabBarHeightContext.Provider, {
|
|
248
|
+
value: tabBarHeight,
|
|
249
|
+
children: [/*#__PURE__*/_jsxs(NativeBottomTabs, {
|
|
250
|
+
ref: nativeBottomTabsRef,
|
|
251
|
+
...props,
|
|
252
|
+
...tabLabelStyle,
|
|
253
|
+
style: styles.fullWidth,
|
|
254
|
+
items: items,
|
|
255
|
+
icons: renderCustomTabBar ? undefined : resolvedIconAssets,
|
|
256
|
+
selectedIcons: isIOS && !renderCustomTabBar ? resolvedSelectedIconAssets : undefined,
|
|
257
|
+
selectedPage: focusedKey,
|
|
258
|
+
tabBarHidden: props.tabBarHidden ?? !!renderCustomTabBar,
|
|
259
|
+
onTabDoublePress: handleTabDoublePress,
|
|
260
|
+
onPageSelected: handlePageSelected,
|
|
261
|
+
onTabBarMeasured: handleTabBarMeasured,
|
|
262
|
+
onNativeLayout: handleNativeLayout,
|
|
263
|
+
hapticFeedbackEnabled: hapticFeedbackEnabled,
|
|
264
|
+
activeTintColor: activeTintColor,
|
|
265
|
+
inactiveTintColor: inactiveTintColor,
|
|
266
|
+
barTintColor: tabBarStyle?.backgroundColor,
|
|
267
|
+
rippleColor: rippleColor,
|
|
268
|
+
activeIndicatorColor: activeIndicatorColor,
|
|
269
|
+
androidBottomBlurEnabled: Platform.OS === 'android' && !renderCustomTabBar && androidBottomBlurEnabled,
|
|
270
|
+
labeled: labeled,
|
|
271
|
+
children: [trimmedRoutes.map(route => {
|
|
272
|
+
if (getLazy({
|
|
273
|
+
route
|
|
274
|
+
}) !== false && !loaded.includes(route.key)) {
|
|
275
|
+
return /*#__PURE__*/_jsx(View, {
|
|
276
|
+
collapsable: false,
|
|
277
|
+
style: styles.fullWidth,
|
|
278
|
+
children: renderLazyPlaceholder?.({
|
|
279
|
+
route
|
|
280
|
+
})
|
|
281
|
+
}, route.key);
|
|
282
|
+
}
|
|
283
|
+
const focused = route.key === focusedKey;
|
|
284
|
+
const freeze = !focused ? getFreezeOnBlur({
|
|
285
|
+
route
|
|
286
|
+
}) : false;
|
|
287
|
+
const customStyle = getSceneStyle({
|
|
288
|
+
route
|
|
289
|
+
});
|
|
290
|
+
return /*#__PURE__*/_jsx(View, {
|
|
291
|
+
style: [styles.screen, renderCustomTabBar ? styles.fullWidth : measuredDimensions, customStyle],
|
|
292
|
+
collapsable: false,
|
|
293
|
+
pointerEvents: focused ? 'auto' : 'none',
|
|
294
|
+
accessibilityElementsHidden: !focused,
|
|
295
|
+
importantForAccessibility: focused ? 'auto' : 'no-hide-descendants',
|
|
296
|
+
children: /*#__PURE__*/_jsx(DelayedFreeze, {
|
|
297
|
+
freeze: !!freeze,
|
|
298
|
+
delayedFreeze: delayedFreeze,
|
|
299
|
+
children: renderScene({
|
|
300
|
+
route,
|
|
301
|
+
jumpTo
|
|
302
|
+
})
|
|
303
|
+
})
|
|
304
|
+
}, route.key);
|
|
305
|
+
}), Platform.OS === 'ios' && parseFloat(Platform.Version) >= 26 && renderBottomAccessoryView && !renderCustomTabBar ? /*#__PURE__*/_jsx(BottomAccessoryView, {
|
|
306
|
+
renderBottomAccessoryView: renderBottomAccessoryView
|
|
307
|
+
}) : null]
|
|
308
|
+
}), renderCustomTabBar ? /*#__PURE__*/_jsx(View, {
|
|
309
|
+
ref: customTabBarWrapperRef,
|
|
310
|
+
children: renderCustomTabBar()
|
|
311
|
+
}) : null]
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
const styles = StyleSheet.create({
|
|
315
|
+
fullWidth: {
|
|
316
|
+
width: '100%',
|
|
317
|
+
height: '100%',
|
|
318
|
+
flex: 1
|
|
319
|
+
},
|
|
320
|
+
screen: {
|
|
321
|
+
position: 'absolute'
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
export default BottomTabs;
|
|
325
|
+
//# sourceMappingURL=BottomTabs.js.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
|
2
|
+
import type { ColorValue, ProcessedColorValue, ViewProps } from 'react-native';
|
|
3
|
+
import type {
|
|
4
|
+
DirectEventHandler,
|
|
5
|
+
Double,
|
|
6
|
+
Int32,
|
|
7
|
+
WithDefault,
|
|
8
|
+
} from 'react-native/Libraries/Types/CodegenTypes';
|
|
9
|
+
//@ts-ignore
|
|
10
|
+
import type { ImageSource } from 'react-native/Libraries/Image/ImageSource';
|
|
11
|
+
|
|
12
|
+
export type OnPageSelectedEventData = Readonly<{
|
|
13
|
+
key: string;
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
export type OnTabBarMeasured = Readonly<{
|
|
17
|
+
height: Int32;
|
|
18
|
+
}>;
|
|
19
|
+
|
|
20
|
+
export type OnNativeLayout = Readonly<{
|
|
21
|
+
width: Double;
|
|
22
|
+
height: Double;
|
|
23
|
+
}>;
|
|
24
|
+
|
|
25
|
+
export type BottomTabsItems = ReadonlyArray<{
|
|
26
|
+
key: string;
|
|
27
|
+
title: string;
|
|
28
|
+
sfSymbol?: string;
|
|
29
|
+
badge?: string;
|
|
30
|
+
badgeBackgroundColor?: ProcessedColorValue | null;
|
|
31
|
+
badgeTextColor?: ProcessedColorValue | null;
|
|
32
|
+
activeTintColor?: ProcessedColorValue | null;
|
|
33
|
+
hidden?: boolean;
|
|
34
|
+
testID?: string;
|
|
35
|
+
role?: string;
|
|
36
|
+
preventsDefault?: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
|
|
39
|
+
export interface BottomTabsNativeProps extends ViewProps {
|
|
40
|
+
items: BottomTabsItems;
|
|
41
|
+
selectedPage: string;
|
|
42
|
+
onPageSelected?: DirectEventHandler<OnPageSelectedEventData>;
|
|
43
|
+
onTabDoublePress?: DirectEventHandler<OnPageSelectedEventData>;
|
|
44
|
+
onTabBarMeasured?: DirectEventHandler<OnTabBarMeasured>;
|
|
45
|
+
onNativeLayout?: DirectEventHandler<OnNativeLayout>;
|
|
46
|
+
icons?: ReadonlyArray<ImageSource>;
|
|
47
|
+
selectedIcons?: ReadonlyArray<ImageSource>;
|
|
48
|
+
tabBarHidden?: boolean;
|
|
49
|
+
labeled?: boolean;
|
|
50
|
+
sidebarAdaptable?: boolean;
|
|
51
|
+
scrollEdgeAppearance?: string;
|
|
52
|
+
barTintColor?: ColorValue;
|
|
53
|
+
translucent?: WithDefault<boolean, true>;
|
|
54
|
+
androidBottomBlurEnabled?: WithDefault<boolean, false>;
|
|
55
|
+
rippleColor?: ColorValue;
|
|
56
|
+
activeTintColor?: ColorValue;
|
|
57
|
+
inactiveTintColor?: ColorValue;
|
|
58
|
+
disablePageAnimations?: boolean;
|
|
59
|
+
activeIndicatorColor?: ColorValue;
|
|
60
|
+
hapticFeedbackEnabled?: boolean;
|
|
61
|
+
minimizeBehavior?: string;
|
|
62
|
+
fontFamily?: string;
|
|
63
|
+
fontWeight?: string;
|
|
64
|
+
fontSize?: Int32;
|
|
65
|
+
ignoreBottomInsets?: boolean;
|
|
66
|
+
androidTabBarStyle?: WithDefault<'default' | 'floating', 'default'>;
|
|
67
|
+
ignoreKeyboardInsets?: WithDefault<boolean, true>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default codegenNativeComponent<BottomTabsNativeProps>('RNBottomTabsView');
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Freeze } from 'react-freeze';
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
const ANIMATION_DELAY = 200;
|
|
7
|
+
function DelayedFreeze({
|
|
8
|
+
freeze,
|
|
9
|
+
delayedFreeze,
|
|
10
|
+
children
|
|
11
|
+
}) {
|
|
12
|
+
const [freezeState, setFreezeState] = React.useState(false);
|
|
13
|
+
React.useEffect(() => {
|
|
14
|
+
if (!delayedFreeze) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const id = setTimeout(() => {
|
|
18
|
+
setFreezeState(freeze);
|
|
19
|
+
}, ANIMATION_DELAY);
|
|
20
|
+
return () => {
|
|
21
|
+
clearTimeout(id);
|
|
22
|
+
};
|
|
23
|
+
}, [freeze, delayedFreeze]);
|
|
24
|
+
const shouldFreeze = delayedFreeze ? freeze ? freezeState : false : freeze;
|
|
25
|
+
return /*#__PURE__*/_jsx(Freeze, {
|
|
26
|
+
freeze: shouldFreeze,
|
|
27
|
+
children: children
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export default DelayedFreeze;
|
|
31
|
+
//# sourceMappingURL=DelayedFreeze.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
const SceneComponent = /*#__PURE__*/React.memo(({
|
|
6
|
+
component,
|
|
7
|
+
...rest
|
|
8
|
+
}) => {
|
|
9
|
+
return /*#__PURE__*/React.createElement(component, rest);
|
|
10
|
+
});
|
|
11
|
+
SceneComponent.displayName = 'SceneComponent';
|
|
12
|
+
export function SceneMap(scenes) {
|
|
13
|
+
return ({
|
|
14
|
+
route,
|
|
15
|
+
jumpTo
|
|
16
|
+
}) => {
|
|
17
|
+
const component = scenes[route.key];
|
|
18
|
+
if (!component) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return /*#__PURE__*/_jsx(SceneComponent, {
|
|
22
|
+
jumpTo: jumpTo,
|
|
23
|
+
component: component,
|
|
24
|
+
route: route
|
|
25
|
+
}, route.key);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=SceneMap.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import BottomTabs from "./BottomTabs.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Views
|
|
7
|
+
*/
|
|
8
|
+
export default BottomTabs;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Utilities
|
|
12
|
+
*/
|
|
13
|
+
export { SceneMap } from "./SceneMap.js";
|
|
14
|
+
export { useBottomTabBarHeight } from "./utils/useBottomTabBarHeight.js";
|
|
15
|
+
export { BottomTabBarHeightContext } from "./utils/BottomTabBarHeightContext.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Types
|
|
19
|
+
*/
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { BottomTabBarHeightContext } from "./BottomTabBarHeightContext.js";
|
|
5
|
+
export function useBottomTabBarHeight() {
|
|
6
|
+
const height = React.useContext(BottomTabBarHeightContext);
|
|
7
|
+
if (height === undefined) {
|
|
8
|
+
throw new Error("Couldn't find the bottom tab bar height. Are you inside a screen in Native Bottom Tab Navigator?");
|
|
9
|
+
}
|
|
10
|
+
return height;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=useBottomTabBarHeight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface RNBottomTabsAccessoryViewProps {
|
|
3
|
+
renderBottomAccessoryView: (props: {
|
|
4
|
+
placement: 'inline' | 'expanded' | 'none';
|
|
5
|
+
}) => React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare const BottomAccessoryView: (props: RNBottomTabsAccessoryViewProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=BottomAccessoryView.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ViewProps } from 'react-native';
|
|
2
|
+
import type { DirectEventHandler, Double } from 'react-native/Libraries/Types/CodegenTypes';
|
|
3
|
+
export type OnNativeLayout = Readonly<{
|
|
4
|
+
width: Double;
|
|
5
|
+
height: Double;
|
|
6
|
+
}>;
|
|
7
|
+
export type OnPlacementChanged = Readonly<{
|
|
8
|
+
placement: string;
|
|
9
|
+
}>;
|
|
10
|
+
export interface BottomAccessoryViewNativeProps extends ViewProps {
|
|
11
|
+
onNativeLayout?: DirectEventHandler<OnNativeLayout>;
|
|
12
|
+
onPlacementChanged?: DirectEventHandler<OnPlacementChanged>;
|
|
13
|
+
}
|
|
14
|
+
declare const _default: import("react-native/types_generated/Libraries/Utilities/codegenNativeComponent").NativeComponentType<BottomAccessoryViewNativeProps>;
|
|
15
|
+
export default _default;
|
|
16
|
+
//# sourceMappingURL=BottomAccessoryViewNativeComponent.d.ts.map
|