@freakycoder/animated-tabbar
Version:
A 60FPS animated tab bar with a variety of cool animation presets.
126 lines (119 loc) • 4.19 kB
JavaScript
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import React, { useMemo, useCallback, useRef } from 'react';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { AnimatedTabBarView } from './AnimatedTabBarView';
import { useTabBarVisibility, useStableCallback } from './hooks';
import Animated, { useSharedValue, useAnimatedStyle, interpolate as reanimatedInterpolate } from 'react-native-reanimated';
export function AnimatedTabBar(props) {
var _overrideSafeAreaInse;
// props
const {
tabs,
state,
navigation,
descriptors,
onTabPress,
onTabLongPress,
style: overrideStyle,
safeAreaInsets: overrideSafeAreaInsets,
...rest
} = props;
//#region variables
const tabBarContainerRef = useRef(null);
const isReactNavigation5 = useMemo(() => Boolean(state), [state]);
const tabBarHeight = useSharedValue(0);
const {
index: navigationIndex,
routes
} = useMemo(() => {
if (isReactNavigation5) {
return state;
} else {
return {
index: navigation.state.index,
routes: navigation.state.routes
};
}
}, [state, navigation, isReactNavigation5]);
const shouldShowTabBar = useMemo(() => {
if (!isReactNavigation5) {
return true;
}
const route = routes[navigationIndex];
const {
options
} = descriptors[route.key];
return typeof options.tabBarVisible === 'boolean' ? options.tabBarVisible : true;
}, [isReactNavigation5, routes, descriptors, navigationIndex]);
const shouldShowTabBarAnimated = useTabBarVisibility(shouldShowTabBar);
const safeAreaInsets = useSafeAreaInsets();
const safeBottomArea = (_overrideSafeAreaInse = overrideSafeAreaInsets === null || overrideSafeAreaInsets === void 0 ? void 0 : overrideSafeAreaInsets.bottom) !== null && _overrideSafeAreaInse !== void 0 ? _overrideSafeAreaInse : safeAreaInsets.bottom;
//#endregion
//#region styles
const animatedContainerStyle = useAnimatedStyle(() => {
return {
bottom: 0,
left: 0,
right: 0,
transform: [{
translateY: reanimatedInterpolate(shouldShowTabBarAnimated.value, [0, 1], [tabBarHeight.value, 0])
}],
position: shouldShowTabBar ? 'relative' : 'absolute'
};
}, [shouldShowTabBar]);
const style = useMemo(() => ({
...overrideStyle,
paddingBottom: safeBottomArea
}), [overrideStyle, safeBottomArea]);
//#endregion
//#region callbacks
const handleIndexChange = useStableCallback(index => {
const {
key,
name
} = routes[index];
const event = navigation.emit({
type: 'tabPress',
target: key,
canPreventDefault: true
});
if (!event.defaultPrevented) {
navigation.navigate(name);
}
});
const handleLongPress = useStableCallback(index => {
const {
key
} = routes[index];
navigation.emit({
type: 'tabLongPress',
target: key
});
});
const handleLayout = useCallback(event => {
tabBarHeight.value = event.nativeEvent.layout.height;
}, []);
//#endregion
// render
return /*#__PURE__*/React.createElement(Animated.View, {
ref: tabBarContainerRef,
style: animatedContainerStyle,
onLayout: handleLayout
}, /*#__PURE__*/React.createElement(AnimatedTabBarView, _extends({
index: navigationIndex,
onIndexChange: handleIndexChange,
onLongPress: handleLongPress,
tabs: routes.reduce((result, route) => {
var _descriptors$route$ke;
const routeConfig = tabs[route.name] || tabs[route.key];
const title = ((_descriptors$route$ke = descriptors[route.key]) === null || _descriptors$route$ke === void 0 ? void 0 : _descriptors$route$ke.title) || route.name;
result[route.key] = {
title,
...routeConfig
};
return result;
}, {}),
style: style
}, rest)));
}
//# sourceMappingURL=AnimatedTabBar.js.map