first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,366 @@
"use strict";
import { getDefaultSidebarWidth, getLabel, MissingIcon, useFrameSize } from '@react-navigation/elements';
import { CommonActions, NavigationProvider, useLinkBuilder, useLocale, useTheme } from '@react-navigation/native';
import React from 'react';
import { Animated, Platform, StyleSheet, View } from 'react-native';
import { BottomTabBarHeightCallbackContext } from "../utils/BottomTabBarHeightCallbackContext.js";
import { useIsKeyboardShown } from "../utils/useIsKeyboardShown.js";
import { BottomTabItem } from "./BottomTabItem.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const TABBAR_HEIGHT_UIKIT = 49;
const TABBAR_HEIGHT_UIKIT_COMPACT = 32;
const SPACING_UIKIT = 15;
const SPACING_MATERIAL = 12;
const DEFAULT_MAX_TAB_ITEM_WIDTH = 125;
const useNativeDriver = Platform.OS !== 'web';
const shouldUseHorizontalLabels = ({
state,
descriptors,
dimensions
}) => {
const {
tabBarLabelPosition
} = descriptors[state.routes[state.index].key].options;
if (tabBarLabelPosition) {
switch (tabBarLabelPosition) {
case 'beside-icon':
return true;
case 'below-icon':
return false;
}
}
if (dimensions.width >= 768) {
// Screen size matches a tablet
const maxTabWidth = state.routes.reduce((acc, route) => {
const {
tabBarItemStyle
} = descriptors[route.key].options;
const flattenedStyle = StyleSheet.flatten(tabBarItemStyle);
if (flattenedStyle) {
if (typeof flattenedStyle.width === 'number') {
return acc + flattenedStyle.width;
} else if (typeof flattenedStyle.maxWidth === 'number') {
return acc + flattenedStyle.maxWidth;
}
}
return acc + DEFAULT_MAX_TAB_ITEM_WIDTH;
}, 0);
return maxTabWidth <= dimensions.width;
} else {
return dimensions.width > dimensions.height;
}
};
const isCompact = ({
state,
descriptors,
dimensions
}) => {
const {
tabBarPosition,
tabBarVariant
} = descriptors[state.routes[state.index].key].options;
if (tabBarPosition === 'left' || tabBarPosition === 'right' || tabBarVariant === 'material') {
return false;
}
const isLandscape = dimensions.width > dimensions.height;
const horizontalLabels = shouldUseHorizontalLabels({
state,
descriptors,
dimensions
});
if (Platform.OS === 'ios' && !Platform.isPad && isLandscape && horizontalLabels) {
return true;
}
return false;
};
export const getTabBarHeight = ({
state,
descriptors,
dimensions,
insets,
style
}) => {
const {
tabBarPosition
} = descriptors[state.routes[state.index].key].options;
const flattenedStyle = StyleSheet.flatten(style);
const customHeight = flattenedStyle && 'height' in flattenedStyle ? flattenedStyle.height : undefined;
if (typeof customHeight === 'number') {
return customHeight;
}
const inset = insets[tabBarPosition === 'top' ? 'top' : 'bottom'];
if (isCompact({
state,
descriptors,
dimensions
})) {
return TABBAR_HEIGHT_UIKIT_COMPACT + inset;
}
return TABBAR_HEIGHT_UIKIT + inset;
};
export function BottomTabBar({
state,
navigation,
descriptors,
insets,
style
}) {
const {
colors
} = useTheme();
const {
direction
} = useLocale();
const {
buildHref
} = useLinkBuilder();
const focusedRoute = state.routes[state.index];
const focusedDescriptor = descriptors[focusedRoute.key];
const focusedOptions = focusedDescriptor.options;
const {
tabBarPosition = 'bottom',
tabBarShowLabel,
tabBarLabelPosition,
tabBarHideOnKeyboard = false,
tabBarVisibilityAnimationConfig,
tabBarVariant = 'uikit',
tabBarStyle,
tabBarBackground,
tabBarActiveTintColor,
tabBarInactiveTintColor,
tabBarActiveBackgroundColor,
tabBarInactiveBackgroundColor
} = focusedOptions;
if (tabBarVariant === 'material' && tabBarPosition !== 'left' && tabBarPosition !== 'right') {
throw new Error("The 'material' variant for tab bar is only supported when 'tabBarPosition' is set to 'left' or 'right'.");
}
if (tabBarLabelPosition === 'below-icon' && tabBarVariant === 'uikit' && (tabBarPosition === 'left' || tabBarPosition === 'right')) {
throw new Error("The 'below-icon' label position for tab bar is only supported when 'tabBarPosition' is set to 'top' or 'bottom' when using the 'uikit' variant.");
}
const isKeyboardShown = useIsKeyboardShown();
const onHeightChange = React.useContext(BottomTabBarHeightCallbackContext);
const shouldShowTabBar = !(tabBarHideOnKeyboard && isKeyboardShown);
const visibilityAnimationConfigRef = React.useRef(tabBarVisibilityAnimationConfig);
React.useEffect(() => {
visibilityAnimationConfigRef.current = tabBarVisibilityAnimationConfig;
});
const [isTabBarHidden, setIsTabBarHidden] = React.useState(!shouldShowTabBar);
const [visible] = React.useState(() => new Animated.Value(shouldShowTabBar ? 1 : 0));
React.useEffect(() => {
const visibilityAnimationConfig = visibilityAnimationConfigRef.current;
if (shouldShowTabBar) {
const animation = visibilityAnimationConfig?.show?.animation === 'spring' ? Animated.spring : Animated.timing;
animation(visible, {
toValue: 1,
useNativeDriver,
duration: 250,
...visibilityAnimationConfig?.show?.config
}).start(({
finished
}) => {
if (finished) {
setIsTabBarHidden(false);
}
});
} else {
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
setIsTabBarHidden(true);
const animation = visibilityAnimationConfig?.hide?.animation === 'spring' ? Animated.spring : Animated.timing;
animation(visible, {
toValue: 0,
useNativeDriver,
duration: 200,
...visibilityAnimationConfig?.hide?.config
}).start();
}
return () => visible.stopAnimation();
}, [visible, shouldShowTabBar]);
const [layout, setLayout] = React.useState({
height: 0
});
const handleLayout = e => {
const {
height
} = e.nativeEvent.layout;
onHeightChange?.(height);
setLayout(layout => {
if (height === layout.height) {
return layout;
} else {
return {
height
};
}
});
};
const {
routes
} = state;
const tabBarHeight = useFrameSize(dimensions => getTabBarHeight({
state,
descriptors,
insets,
dimensions,
style: [tabBarStyle, style]
}));
const hasHorizontalLabels = useFrameSize(dimensions => shouldUseHorizontalLabels({
state,
descriptors,
dimensions
}));
const compact = useFrameSize(dimensions => isCompact({
state,
descriptors,
dimensions
}));
const sidebar = tabBarPosition === 'left' || tabBarPosition === 'right';
const spacing = tabBarVariant === 'material' ? SPACING_MATERIAL : SPACING_UIKIT;
const minSidebarWidth = useFrameSize(size => sidebar && hasHorizontalLabels ? getDefaultSidebarWidth(size) : 0);
const tabBarBackgroundElement = tabBarBackground?.();
return /*#__PURE__*/_jsxs(Animated.View, {
style: [tabBarPosition === 'left' ? styles.start : tabBarPosition === 'right' ? styles.end : styles.bottom, (Platform.OS === 'web' ? tabBarPosition === 'right' : direction === 'rtl' && tabBarPosition === 'left' || direction !== 'rtl' && tabBarPosition === 'right') ? {
borderLeftWidth: StyleSheet.hairlineWidth
} : (Platform.OS === 'web' ? tabBarPosition === 'left' : direction === 'rtl' && tabBarPosition === 'right' || direction !== 'rtl' && tabBarPosition === 'left') ? {
borderRightWidth: StyleSheet.hairlineWidth
} : tabBarPosition === 'top' ? {
borderBottomWidth: StyleSheet.hairlineWidth
} : {
borderTopWidth: StyleSheet.hairlineWidth
}, {
backgroundColor: tabBarBackgroundElement != null ? 'transparent' : colors.card,
borderColor: colors.border
}, sidebar ? {
paddingTop: (hasHorizontalLabels ? spacing : spacing / 2) + insets.top,
paddingBottom: (hasHorizontalLabels ? spacing : spacing / 2) + insets.bottom,
paddingStart: spacing + (tabBarPosition === 'left' ? insets.left : 0),
paddingEnd: spacing + (tabBarPosition === 'right' ? insets.right : 0),
minWidth: minSidebarWidth
} : [{
transform: [{
translateY: visible.interpolate({
inputRange: [0, 1],
outputRange: [layout.height + insets[tabBarPosition === 'top' ? 'top' : 'bottom'] + StyleSheet.hairlineWidth, 0]
})
}],
// Absolutely position the tab bar so that the content is below it
// This is needed to avoid gap at bottom when the tab bar is hidden
position: isTabBarHidden ? 'absolute' : undefined
}, {
height: tabBarHeight,
paddingBottom: tabBarPosition === 'bottom' ? insets.bottom : 0,
paddingTop: tabBarPosition === 'top' ? insets.top : 0,
paddingHorizontal: Math.max(insets.left, insets.right)
}], tabBarStyle],
pointerEvents: isTabBarHidden ? 'none' : 'auto',
onLayout: sidebar ? undefined : handleLayout,
children: [/*#__PURE__*/_jsx(View, {
pointerEvents: "none",
style: StyleSheet.absoluteFill,
children: tabBarBackgroundElement
}), /*#__PURE__*/_jsx(View, {
role: "tablist",
style: sidebar ? styles.sideContent : styles.bottomContent,
children: routes.map((route, index) => {
const focused = index === state.index;
const {
options
} = descriptors[route.key];
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true
});
if (!focused && !event.defaultPrevented) {
navigation.dispatch({
...CommonActions.navigate(route),
target: state.key
});
}
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key
});
};
const label = typeof options.tabBarLabel === 'function' ? options.tabBarLabel : getLabel({
label: options.tabBarLabel,
title: options.title
}, route.name);
const accessibilityLabel = options.tabBarAccessibilityLabel !== undefined ? options.tabBarAccessibilityLabel : typeof label === 'string' && Platform.OS === 'ios' ? `${label}, tab, ${index + 1} of ${routes.length}` : undefined;
return /*#__PURE__*/_jsx(NavigationProvider, {
route: route,
navigation: descriptors[route.key].navigation,
children: /*#__PURE__*/_jsx(BottomTabItem, {
href: buildHref(route.name, route.params),
route: route,
descriptor: descriptors[route.key],
focused: focused,
horizontal: hasHorizontalLabels,
compact: compact,
sidebar: sidebar,
variant: tabBarVariant,
onPress: onPress,
onLongPress: onLongPress,
accessibilityLabel: accessibilityLabel,
testID: options.tabBarButtonTestID,
allowFontScaling: options.tabBarAllowFontScaling,
activeTintColor: tabBarActiveTintColor,
inactiveTintColor: tabBarInactiveTintColor,
activeBackgroundColor: tabBarActiveBackgroundColor,
inactiveBackgroundColor: tabBarInactiveBackgroundColor,
button: options.tabBarButton,
icon: options.tabBarIcon ?? (({
color,
size
}) => /*#__PURE__*/_jsx(MissingIcon, {
color: color,
size: size
})),
badge: options.tabBarBadge,
badgeStyle: options.tabBarBadgeStyle,
label: label,
showLabel: tabBarShowLabel,
labelStyle: options.tabBarLabelStyle,
iconStyle: options.tabBarIconStyle,
style: [sidebar ? {
marginVertical: hasHorizontalLabels ? tabBarVariant === 'material' ? 0 : 1 : spacing / 2
} : styles.bottomItem, options.tabBarItemStyle]
})
}, route.key);
})
})]
});
}
const styles = StyleSheet.create({
start: {
top: 0,
bottom: 0,
start: 0
},
end: {
top: 0,
bottom: 0,
end: 0
},
bottom: {
start: 0,
end: 0,
bottom: 0,
elevation: 8
},
bottomContent: {
flex: 1,
flexDirection: 'row'
},
sideContent: {
flex: 1,
flexDirection: 'column'
},
bottomItem: {
flex: 1
}
});
//# sourceMappingURL=BottomTabBar.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,219 @@
"use strict";
import { getLabel, Label, PlatformPressable } from '@react-navigation/elements';
import { useTheme } from '@react-navigation/native';
import Color from 'color';
import React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import { TabBarIcon } from "./TabBarIcon.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const renderButtonDefault = props => /*#__PURE__*/_jsx(PlatformPressable, {
...props
});
const SUPPORTS_LARGE_CONTENT_VIEWER = Platform.OS === 'ios' && parseInt(Platform.Version, 10) >= 13;
export function BottomTabItem({
route,
href,
focused,
descriptor,
label,
icon,
badge,
badgeStyle,
button = renderButtonDefault,
accessibilityLabel,
testID,
onPress,
onLongPress,
horizontal,
compact,
sidebar,
variant,
activeTintColor: customActiveTintColor,
inactiveTintColor: customInactiveTintColor,
activeBackgroundColor: customActiveBackgroundColor,
inactiveBackgroundColor = 'transparent',
showLabel = true,
// On iOS 13+, we use `largeContentTitle` for accessibility
// So we don't need the font to scale up
// https://developer.apple.com/documentation/uikit/uiview/3183939-largecontenttitle
allowFontScaling = SUPPORTS_LARGE_CONTENT_VIEWER ? false : undefined,
labelStyle,
iconStyle,
style
}) {
const {
colors,
fonts
} = useTheme();
const activeTintColor = customActiveTintColor ?? (variant === 'uikit' && sidebar && horizontal ? Color(colors.primary).isDark() ? 'white' : Color(colors.primary).darken(0.71).string() : colors.primary);
const inactiveTintColor = customInactiveTintColor === undefined ? variant === 'material' ? Color(colors.text).alpha(0.68).rgb().string() : Color(colors.text).mix(Color(colors.card), 0.5).hex() : customInactiveTintColor;
const activeBackgroundColor = customActiveBackgroundColor ?? (variant === 'material' ? Color(activeTintColor).alpha(0.12).rgb().string() : sidebar && horizontal ? colors.primary : 'transparent');
const {
options
} = descriptor;
const labelString = getLabel({
label: typeof options.tabBarLabel === 'string' ? options.tabBarLabel : undefined,
title: options.title
}, route.name);
let labelInactiveTintColor = inactiveTintColor;
let iconInactiveTintColor = inactiveTintColor;
if (variant === 'uikit' && sidebar && horizontal && customInactiveTintColor === undefined) {
iconInactiveTintColor = colors.primary;
labelInactiveTintColor = colors.text;
}
const renderLabel = ({
focused
}) => {
if (showLabel === false) {
return null;
}
const color = focused ? activeTintColor : labelInactiveTintColor;
if (typeof label !== 'string') {
return label({
focused,
color,
position: horizontal ? 'beside-icon' : 'below-icon',
children: labelString
});
}
return /*#__PURE__*/_jsx(Label, {
style: [horizontal ? [styles.labelBeside, variant === 'material' ? styles.labelSidebarMaterial : sidebar ? styles.labelSidebarUiKit : compact ? styles.labelBesideUikitCompact : styles.labelBesideUikit, icon == null && {
marginStart: 0
}] : styles.labelBeneath, compact || variant === 'uikit' && sidebar && horizontal ? fonts.regular : fonts.medium, labelStyle],
allowFontScaling: allowFontScaling,
tintColor: color,
children: label
});
};
const renderIcon = ({
focused
}) => {
if (icon === undefined) {
return null;
}
const activeOpacity = focused ? 1 : 0;
const inactiveOpacity = focused ? 0 : 1;
return /*#__PURE__*/_jsx(TabBarIcon, {
route: route,
variant: variant,
size: compact ? 'compact' : 'regular',
badge: badge,
badgeStyle: badgeStyle,
activeOpacity: activeOpacity,
allowFontScaling: allowFontScaling,
inactiveOpacity: inactiveOpacity,
activeTintColor: activeTintColor,
inactiveTintColor: iconInactiveTintColor,
renderIcon: icon,
style: iconStyle
});
};
const scene = {
route,
focused
};
const backgroundColor = focused ? activeBackgroundColor : inactiveBackgroundColor;
const {
flex
} = StyleSheet.flatten(style || {});
const borderRadius = variant === 'material' ? horizontal ? 56 : 16 : sidebar && horizontal ? 10 : 0;
return /*#__PURE__*/_jsx(View, {
style: [
// Clip ripple effect on Android
{
borderRadius,
overflow: variant === 'material' ? 'hidden' : 'visible'
}, style],
children: button({
href,
onPress,
onLongPress,
testID,
'aria-label': accessibilityLabel,
'accessibilityLargeContentTitle': labelString,
'accessibilityShowsLargeContentViewer': true,
// FIXME: role: 'tab' doesn't seem to work as expected on iOS
'role': Platform.select({
ios: 'button',
default: 'tab'
}),
'aria-selected': focused,
'android_ripple': {
borderless: true
},
'hoverEffect': variant === 'material' || sidebar && horizontal ? {
color: colors.text
} : undefined,
'pressOpacity': 1,
'style': [styles.tab, {
flex,
backgroundColor,
borderRadius
}, sidebar ? variant === 'material' ? horizontal ? styles.tabBarSidebarMaterial : styles.tabVerticalMaterial : horizontal ? styles.tabBarSidebarUiKit : styles.tabVerticalUiKit : variant === 'material' ? styles.tabVerticalMaterial : horizontal ? styles.tabHorizontalUiKit : styles.tabVerticalUiKit],
'children': /*#__PURE__*/_jsxs(React.Fragment, {
children: [renderIcon(scene), renderLabel(scene)]
})
})
});
}
const styles = StyleSheet.create({
tab: {
alignItems: 'center',
// Roundness for iPad hover effect
borderRadius: 10,
borderCurve: 'continuous'
},
tabVerticalUiKit: {
justifyContent: 'flex-start',
flexDirection: 'column',
padding: 5
},
tabVerticalMaterial: {
padding: 10
},
tabHorizontalUiKit: {
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
padding: 5
},
tabBarSidebarUiKit: {
justifyContent: 'flex-start',
alignItems: 'center',
flexDirection: 'row',
paddingVertical: 7,
paddingHorizontal: 5
},
tabBarSidebarMaterial: {
justifyContent: 'flex-start',
alignItems: 'center',
flexDirection: 'row',
paddingVertical: 15,
paddingStart: 16,
paddingEnd: 24
},
labelSidebarMaterial: {
marginStart: 12
},
labelSidebarUiKit: {
fontSize: 17,
marginStart: 10
},
labelBeneath: {
fontSize: 10
},
labelBeside: {
marginEnd: 12,
lineHeight: 24
},
labelBesideUikit: {
fontSize: 13,
marginStart: 5
},
labelBesideUikitCompact: {
fontSize: 12,
marginStart: 5
}
});
//# sourceMappingURL=BottomTabItem.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,255 @@
"use strict";
import { getHeaderTitle, Header, SafeAreaProviderCompat, Screen } from '@react-navigation/elements';
import { StackActions } from '@react-navigation/native';
import * as React from 'react';
import { Animated, Platform, StyleSheet } from 'react-native';
import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
import { FadeTransition, ShiftTransition } from "../TransitionConfigs/TransitionPresets.js";
import { BottomTabBarHeightCallbackContext } from "../utils/BottomTabBarHeightCallbackContext.js";
import { BottomTabBarHeightContext } from "../utils/BottomTabBarHeightContext.js";
import { useAnimatedHashMap } from "../utils/useAnimatedHashMap.js";
import { BottomTabBar, getTabBarHeight } from "./BottomTabBar.js";
import { MaybeScreen, MaybeScreenContainer } from "./ScreenFallback.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const EPSILON = 1e-5;
const STATE_INACTIVE = 0;
const STATE_TRANSITIONING_OR_BELOW_TOP = 1;
const STATE_ON_TOP = 2;
const NAMED_TRANSITIONS_PRESETS = {
fade: FadeTransition,
shift: ShiftTransition,
none: {
sceneStyleInterpolator: undefined,
transitionSpec: {
animation: 'timing',
config: {
duration: 0
}
}
}
};
const useNativeDriver = Platform.OS !== 'web';
const hasAnimation = options => {
const {
animation,
transitionSpec
} = options;
if (animation) {
return animation !== 'none';
}
return Boolean(transitionSpec);
};
const renderTabBarDefault = props => /*#__PURE__*/_jsx(BottomTabBar, {
...props
});
export function BottomTabView(props) {
const {
tabBar = renderTabBarDefault,
state,
navigation,
descriptors,
safeAreaInsets,
detachInactiveScreens = Platform.OS === 'web' || Platform.OS === 'android' || Platform.OS === 'ios'
} = props;
const focusedRouteKey = state.routes[state.index].key;
/**
* List of loaded tabs, tabs will be loaded when navigated to.
*/
const [loaded, setLoaded] = React.useState([focusedRouteKey]);
if (!loaded.includes(focusedRouteKey)) {
// Set the current tab to be loaded if it was not loaded before
setLoaded([...loaded, focusedRouteKey]);
}
const previousRouteKeyRef = React.useRef(focusedRouteKey);
const tabAnims = useAnimatedHashMap(state);
React.useEffect(() => {
const previousRouteKey = previousRouteKeyRef.current;
let popToTopAction;
if (previousRouteKey !== focusedRouteKey && descriptors[previousRouteKey]?.options.popToTopOnBlur) {
const prevRoute = state.routes.find(route => route.key === previousRouteKey);
if (prevRoute?.state?.type === 'stack' && prevRoute.state.key) {
popToTopAction = {
...StackActions.popToTop(),
target: prevRoute.state.key
};
}
}
const animateToIndex = () => {
if (previousRouteKey !== focusedRouteKey) {
navigation.emit({
type: 'transitionStart',
target: focusedRouteKey
});
}
Animated.parallel(state.routes.map((route, index) => {
const {
options
} = descriptors[route.key];
const {
animation = 'none',
transitionSpec = NAMED_TRANSITIONS_PRESETS[animation].transitionSpec
} = options;
let spec = transitionSpec;
if (route.key !== previousRouteKey && route.key !== focusedRouteKey) {
// Don't animate if the screen is not previous one or new one
// This will avoid flicker for screens not involved in the transition
spec = NAMED_TRANSITIONS_PRESETS.none.transitionSpec;
}
spec = spec ?? NAMED_TRANSITIONS_PRESETS.none.transitionSpec;
const toValue = index === state.index ? 0 : index >= state.index ? 1 : -1;
return Animated[spec.animation](tabAnims[route.key], {
...spec.config,
toValue,
useNativeDriver
});
}).filter(Boolean)).start(({
finished
}) => {
if (finished && popToTopAction) {
navigation.dispatch(popToTopAction);
}
if (previousRouteKey !== focusedRouteKey) {
navigation.emit({
type: 'transitionEnd',
target: focusedRouteKey
});
}
});
};
animateToIndex();
previousRouteKeyRef.current = focusedRouteKey;
}, [descriptors, focusedRouteKey, navigation, state.index, state.routes, tabAnims]);
const dimensions = SafeAreaProviderCompat.initialMetrics.frame;
const [tabBarHeight, setTabBarHeight] = React.useState(() => getTabBarHeight({
state,
descriptors,
dimensions,
insets: {
...SafeAreaProviderCompat.initialMetrics.insets,
...props.safeAreaInsets
},
style: descriptors[state.routes[state.index].key].options.tabBarStyle
}));
const renderTabBar = () => {
return /*#__PURE__*/_jsx(SafeAreaInsetsContext.Consumer, {
children: insets => tabBar({
state: state,
descriptors: descriptors,
navigation: navigation,
insets: {
top: safeAreaInsets?.top ?? insets?.top ?? 0,
right: safeAreaInsets?.right ?? insets?.right ?? 0,
bottom: safeAreaInsets?.bottom ?? insets?.bottom ?? 0,
left: safeAreaInsets?.left ?? insets?.left ?? 0
}
})
});
};
const {
routes
} = state;
// If there is no animation, we only have 2 states: visible and invisible
const hasTwoStates = !routes.some(route => hasAnimation(descriptors[route.key].options));
const {
tabBarPosition = 'bottom'
} = descriptors[focusedRouteKey].options;
const tabBarElement = /*#__PURE__*/_jsx(BottomTabBarHeightCallbackContext.Provider, {
value: setTabBarHeight,
children: renderTabBar()
}, "tabbar");
return /*#__PURE__*/_jsxs(SafeAreaProviderCompat, {
style: {
flexDirection: tabBarPosition === 'left' || tabBarPosition === 'right' ? 'row' : 'column'
},
children: [tabBarPosition === 'top' || tabBarPosition === 'left' ? tabBarElement : null, /*#__PURE__*/_jsx(MaybeScreenContainer, {
enabled: detachInactiveScreens,
hasTwoStates: hasTwoStates,
style: styles.screens,
children: routes.map((route, index) => {
const descriptor = descriptors[route.key];
const {
lazy = true,
animation = 'none',
sceneStyleInterpolator = NAMED_TRANSITIONS_PRESETS[animation].sceneStyleInterpolator
} = descriptor.options;
const isFocused = state.index === index;
const isPreloaded = state.preloadedRouteKeys.includes(route.key);
if (lazy && !loaded.includes(route.key) && !isFocused && !isPreloaded) {
// Don't render a lazy screen if we've never navigated to it or it wasn't preloaded
return null;
}
const {
freezeOnBlur,
header = ({
layout,
options
}) => /*#__PURE__*/_jsx(Header, {
...options,
layout: layout,
title: getHeaderTitle(options, route.name)
}),
headerShown,
headerStatusBarHeight,
headerTransparent,
sceneStyle: customSceneStyle
} = descriptor.options;
const {
sceneStyle
} = sceneStyleInterpolator?.({
current: {
progress: tabAnims[route.key]
}
}) ?? {};
const animationEnabled = hasAnimation(descriptor.options);
const activityState = isFocused ? STATE_ON_TOP // the screen is on top after the transition
: animationEnabled // is animation is not enabled, immediately move to inactive state
? tabAnims[route.key].interpolate({
inputRange: [0, 1 - EPSILON, 1],
outputRange: [STATE_TRANSITIONING_OR_BELOW_TOP,
// screen visible during transition
STATE_TRANSITIONING_OR_BELOW_TOP, STATE_INACTIVE // the screen is detached after transition
],
extrapolate: 'extend'
}) : STATE_INACTIVE;
return /*#__PURE__*/_jsx(MaybeScreen, {
style: [StyleSheet.absoluteFill, {
zIndex: isFocused ? 0 : -1
}],
active: activityState,
enabled: detachInactiveScreens,
freezeOnBlur: freezeOnBlur,
shouldFreeze: activityState === STATE_INACTIVE && !isPreloaded,
children: /*#__PURE__*/_jsx(BottomTabBarHeightContext.Provider, {
value: tabBarPosition === 'bottom' ? tabBarHeight : 0,
children: /*#__PURE__*/_jsx(Screen, {
focused: isFocused,
route: descriptor.route,
navigation: descriptor.navigation,
headerShown: headerShown,
headerStatusBarHeight: headerStatusBarHeight,
headerTransparent: headerTransparent,
header: header({
layout: dimensions,
route: descriptor.route,
navigation: descriptor.navigation,
options: descriptor.options
}),
style: [customSceneStyle, animationEnabled && sceneStyle],
children: descriptor.render()
})
})
}, route.key);
})
}, "screens"), tabBarPosition === 'bottom' || tabBarPosition === 'right' ? tabBarElement : null]
});
}
const styles = StyleSheet.create({
screens: {
flex: 1,
overflow: 'hidden'
}
});
//# sourceMappingURL=BottomTabView.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,42 @@
"use strict";
import * as React from 'react';
import { View } from 'react-native';
import { jsx as _jsx } from "react/jsx-runtime";
let Screens;
try {
Screens = require('react-native-screens');
} catch (e) {
// Ignore
}
export const MaybeScreenContainer = ({
enabled,
...rest
}) => {
if (Screens?.screensEnabled?.()) {
return /*#__PURE__*/_jsx(Screens.ScreenContainer, {
enabled: enabled,
...rest
});
}
return /*#__PURE__*/_jsx(View, {
...rest
});
};
export function MaybeScreen({
enabled,
active,
...rest
}) {
if (Screens?.screensEnabled?.()) {
return /*#__PURE__*/_jsx(Screens.Screen, {
enabled: enabled,
activityState: active,
...rest
});
}
return /*#__PURE__*/_jsx(View, {
...rest
});
}
//# sourceMappingURL=ScreenFallback.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","View","jsx","_jsx","Screens","require","e","MaybeScreenContainer","enabled","rest","screensEnabled","ScreenContainer","MaybeScreen","active","Screen","activityState"],"sourceRoot":"../../../src","sources":["views/ScreenFallback.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAGEC,IAAI,QAGC,cAAc;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAWtB,IAAIC,OAA0D;AAE9D,IAAI;EACFA,OAAO,GAAGC,OAAO,CAAC,sBAAsB,CAAC;AAC3C,CAAC,CAAC,OAAOC,CAAC,EAAE;EACV;AAAA;AAGF,OAAO,MAAMC,oBAAoB,GAAGA,CAAC;EACnCC,OAAO;EACP,GAAGC;AAKL,CAAC,KAAK;EACJ,IAAIL,OAAO,EAAEM,cAAc,GAAG,CAAC,EAAE;IAC/B,oBAAOP,IAAA,CAACC,OAAO,CAACO,eAAe;MAACH,OAAO,EAAEA,OAAQ;MAAA,GAAKC;IAAI,CAAG,CAAC;EAChE;EAEA,oBAAON,IAAA,CAACF,IAAI;IAAA,GAAKQ;EAAI,CAAG,CAAC;AAC3B,CAAC;AAED,OAAO,SAASG,WAAWA,CAAC;EAAEJ,OAAO;EAAEK,MAAM;EAAE,GAAGJ;AAAwB,CAAC,EAAE;EAC3E,IAAIL,OAAO,EAAEM,cAAc,GAAG,CAAC,EAAE;IAC/B,oBACEP,IAAA,CAACC,OAAO,CAACU,MAAM;MAACN,OAAO,EAAEA,OAAQ;MAACO,aAAa,EAAEF,MAAO;MAAA,GAAKJ;IAAI,CAAG,CAAC;EAEzE;EAEA,oBAAON,IAAA,CAACF,IAAI;IAAA,GAAKQ;EAAI,CAAG,CAAC;AAC3B","ignoreList":[]}

View File

@@ -0,0 +1,97 @@
"use strict";
import { Badge } from '@react-navigation/elements';
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
* Icon sizes taken from Apple HIG
* https://developer.apple.com/design/human-interface-guidelines/tab-bars
*/
const ICON_SIZE_WIDE = 31;
const ICON_SIZE_WIDE_COMPACT = 23;
const ICON_SIZE_TALL = 28;
const ICON_SIZE_TALL_COMPACT = 20;
const ICON_SIZE_ROUND = 25;
const ICON_SIZE_ROUND_COMPACT = 18;
const ICON_SIZE_MATERIAL = 24;
export function TabBarIcon({
route: _,
variant,
size,
badge,
badgeStyle,
activeOpacity,
inactiveOpacity,
activeTintColor,
inactiveTintColor,
renderIcon,
allowFontScaling,
style
}) {
const iconSize = variant === 'material' ? ICON_SIZE_MATERIAL : size === 'compact' ? ICON_SIZE_ROUND_COMPACT : ICON_SIZE_ROUND;
// We render the icon twice at the same position on top of each other:
// active and inactive one, so we can fade between them.
return /*#__PURE__*/_jsxs(View, {
style: [variant === 'material' ? styles.wrapperMaterial : size === 'compact' ? styles.wrapperUikitCompact : styles.wrapperUikit, style],
children: [/*#__PURE__*/_jsx(View, {
style: [styles.icon, {
opacity: activeOpacity,
// Workaround for react-native >= 0.54 layout bug
minWidth: iconSize
}],
children: renderIcon({
focused: true,
size: iconSize,
color: activeTintColor
})
}), /*#__PURE__*/_jsx(View, {
style: [styles.icon, {
opacity: inactiveOpacity
}],
children: renderIcon({
focused: false,
size: iconSize,
color: inactiveTintColor
})
}), /*#__PURE__*/_jsx(Badge, {
visible: badge != null,
size: iconSize * 0.75,
allowFontScaling: allowFontScaling,
style: [styles.badge, badgeStyle],
children: badge
})]
});
}
const styles = StyleSheet.create({
icon: {
// We render the icon twice at the same position on top of each other:
// active and inactive one, so we can fade between them:
// Cover the whole iconContainer:
position: 'absolute',
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
width: '100%'
},
wrapperUikit: {
width: ICON_SIZE_WIDE,
height: ICON_SIZE_TALL
},
wrapperUikitCompact: {
width: ICON_SIZE_WIDE_COMPACT,
height: ICON_SIZE_TALL_COMPACT
},
wrapperMaterial: {
width: ICON_SIZE_MATERIAL,
height: ICON_SIZE_MATERIAL
},
badge: {
position: 'absolute',
end: -3,
top: -3
}
});
//# sourceMappingURL=TabBarIcon.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["Badge","React","StyleSheet","View","jsx","_jsx","jsxs","_jsxs","ICON_SIZE_WIDE","ICON_SIZE_WIDE_COMPACT","ICON_SIZE_TALL","ICON_SIZE_TALL_COMPACT","ICON_SIZE_ROUND","ICON_SIZE_ROUND_COMPACT","ICON_SIZE_MATERIAL","TabBarIcon","route","_","variant","size","badge","badgeStyle","activeOpacity","inactiveOpacity","activeTintColor","inactiveTintColor","renderIcon","allowFontScaling","style","iconSize","styles","wrapperMaterial","wrapperUikitCompact","wrapperUikit","children","icon","opacity","minWidth","focused","color","visible","create","position","alignSelf","alignItems","justifyContent","height","width","end","top"],"sourceRoot":"../../../src","sources":["views/TabBarIcon.tsx"],"mappings":"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","ignoreList":[]}