UNPKG

@freakycoder/animated-tabbar

Version:

A 60FPS animated tab bar with a variety of cool animation presets.

128 lines 4.87 kB
import React, { useMemo, memo } from 'react'; import { View, Text } from 'react-native'; import Animated, { useSharedValue, useAnimatedStyle, interpolate, Extrapolate } from 'react-native-reanimated'; import MaskedView from '@react-native-community/masked-view'; import { Svg, Circle } from 'react-native-svg'; import isEqual from 'lodash.isequal'; import { DEFAULT_INDICATOR_VISIBILITY, DEFAULT_INDICATOR_SIZE, DEFAULT_INDICATOR_COLOR } from '../constants'; import { styles } from './styles'; const AnimatedSvg = Animated.createAnimatedComponent(Svg); const AnimatedCircle = Animated.createAnimatedComponent(Circle); const FlashyTabBarItemComponent = ({ animatedFocus, label, icon, labelStyle: labelStyleOverride, spacing, iconSize, indicator, isRTL }) => { const { innerVerticalSpace, innerHorizontalSpace, outerVerticalSpace, outerHorizontalSpace } = spacing; const { size: _indicatorSize, color: _indicatorColor, visible: _indicatorVisible } = indicator || { size: undefined, color: undefined, visible: undefined }; const { indicatorVisibility, indicatorColor, indicatorSize } = useMemo(() => { var _ref; return { indicatorVisibility: _indicatorVisible !== null && _indicatorVisible !== void 0 ? _indicatorVisible : DEFAULT_INDICATOR_VISIBILITY, indicatorColor: (_ref = _indicatorColor !== null && _indicatorColor !== void 0 ? _indicatorColor : labelStyleOverride === null || labelStyleOverride === void 0 ? void 0 : labelStyleOverride.color) !== null && _ref !== void 0 ? _ref : DEFAULT_INDICATOR_COLOR, indicatorSize: _indicatorSize !== null && _indicatorSize !== void 0 ? _indicatorSize : DEFAULT_INDICATOR_SIZE }; }, [_indicatorVisible, _indicatorColor, _indicatorSize, labelStyleOverride]); const labelWidth = useSharedValue(0); const labelHeight = useSharedValue(0); const containerHeight = useMemo(() => iconSize + innerVerticalSpace * 2, [iconSize, innerVerticalSpace]); const containerWidth = useSharedValue(iconSize + innerHorizontalSpace * 2); const labelContainerStyle = useAnimatedStyle(() => ({ transform: [{ translateY: interpolate(animatedFocus.value, [0, 1], [labelHeight.value * 0.5, labelHeight.value * -0.5], Extrapolate.CLAMP) }] })); const iconContainerStyle = useAnimatedStyle(() => ({ transform: [{ translateY: interpolate(animatedFocus.value, [0, 1], [iconSize * -0.5, iconSize * -1.5], Extrapolate.CLAMP) }] })); const handleLabelLayout = ({ nativeEvent: { layout: { height, width } } }) => { labelWidth.value = width; labelHeight.value = height; containerWidth.value = Math.max(width + innerHorizontalSpace * 2, containerWidth.value); }; const renderIcon = () => { const IconComponent = icon.component; return typeof IconComponent === 'function' ? /*#__PURE__*/React.createElement(IconComponent, { animatedFocus: animatedFocus.value, color: icon.color, size: iconSize }) : /*#__PURE__*/React.createElement(IconComponent, { animatedFocus: animatedFocus.value, color: icon.color, size: iconSize }); }; return /*#__PURE__*/React.createElement(Animated.View, { style: [styles.outerContainer, { paddingHorizontal: outerHorizontalSpace, paddingVertical: outerVerticalSpace }] }, /*#__PURE__*/React.createElement(Animated.View, { style: [styles.container, { width: containerWidth.value, height: containerHeight }] }, /*#__PURE__*/React.createElement(MaskedView, { style: styles.root, maskElement: /*#__PURE__*/React.createElement(Animated.View, { style: iconContainerStyle }) }, /*#__PURE__*/React.createElement(Animated.View, { pointerEvents: "none", style: iconContainerStyle }, /*#__PURE__*/React.createElement(View, { style: styles.icon }, renderIcon()))), /*#__PURE__*/React.createElement(MaskedView, { style: styles.root, maskElement: /*#__PURE__*/React.createElement(Animated.View, { style: labelContainerStyle }) }, /*#__PURE__*/React.createElement(Animated.View, { style: labelContainerStyle }, /*#__PURE__*/React.createElement(Text, { numberOfLines: 1, style: [styles.label, labelStyleOverride], onLayout: handleLabelLayout }, label))), indicatorVisibility && /*#__PURE__*/React.createElement(AnimatedSvg, { style: [styles.root, { left: containerWidth.value / 2 - indicatorSize / 2, top: containerHeight - indicatorSize }] }, /*#__PURE__*/React.createElement(AnimatedCircle, { r: interpolate(animatedFocus.value, [0.5, 1], [0, indicatorSize / 2], Extrapolate.CLAMP), fill: indicatorColor })))); }; export default /*#__PURE__*/memo(FlashyTabBarItemComponent, isEqual); //# sourceMappingURL=FlashyTabBarItem.js.map