diff --git a/example/src/screens/BubbleStyled.tsx b/example/src/screens/BubbleStyled.tsx index 39d22f7..7e1f197 100644 --- a/example/src/screens/BubbleStyled.tsx +++ b/example/src/screens/BubbleStyled.tsx @@ -1,4 +1,5 @@ import React, { useMemo } from 'react'; +import { StyleProp, ViewStyle } from 'react-native'; import { useSafeArea } from 'react-native-safe-area-context'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import AnimatedTabBar, { @@ -83,33 +84,38 @@ const BubbleStyledScreen = () => { return 20 + bottom + 12 * 2 + 12 * 2 + 12; }, [bottom]); + const tabBarStyle = useMemo>( + () => ({ + position: 'absolute', + left: 0, + right: 0, + bottom: 0, + borderRadius: 16, + marginLeft: 32, + marginRight: 32, + marginBottom: bottom, + backgroundColor: '#000', + shadowColor: '#000', + shadowOffset: { + width: 0, + height: 12, + }, + shadowOpacity: 0.58, + shadowRadius: 16.0, + + elevation: 24, + }), + [bottom] + ); + const tabBarOptions = useMemo( () => ({ safeAreaInsets: { bottom: 0, }, - style: { - position: 'absolute', - left: 0, - right: 0, - bottom: 0, - borderRadius: 16, - marginLeft: 32, - marginRight: 32, - marginBottom: bottom, - backgroundColor: '#000', - shadowColor: '#000', - shadowOffset: { - width: 0, - height: 12, - }, - shadowOpacity: 0.58, - shadowRadius: 16.0, - - elevation: 24, - }, + style: tabBarStyle, }), - [bottom] + [tabBarStyle] ); // render diff --git a/example/src/screens/FlashyStyled.tsx b/example/src/screens/FlashyStyled.tsx index af18eaa..a93a5bf 100644 --- a/example/src/screens/FlashyStyled.tsx +++ b/example/src/screens/FlashyStyled.tsx @@ -1,4 +1,5 @@ import React, { useMemo } from 'react'; +import { StyleProp, ViewStyle } from 'react-native'; import { useSafeArea } from 'react-native-safe-area-context'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import AnimatedTabBar, { @@ -79,34 +80,41 @@ const FlashyStyledScreen = () => { return 20 + bottom + 12 * 2 + 12 * 2 + 12; }, [bottom]); + const tabBarStyle = useMemo>( + () => ({ + position: 'absolute', + left: 0, + right: 0, + bottom: 0, + borderRadius: 16, + marginLeft: 32, + marginRight: 32, + marginBottom: bottom, + backgroundColor: '#000', + shadowColor: '#000', + shadowOffset: { + width: 0, + height: 12, + }, + shadowOpacity: 0.58, + shadowRadius: 16.0, + + elevation: 24, + }), + [bottom] + ); + const tabBarOptions = useMemo( () => ({ safeAreaInsets: { bottom: 0, }, - style: { - position: 'absolute', - left: 0, - right: 0, - bottom: 0, - borderRadius: 16, - marginLeft: 32, - marginRight: 32, - marginBottom: bottom, - backgroundColor: '#000', - shadowColor: '#000', - shadowOffset: { - width: 0, - height: 12, - }, - shadowOpacity: 0.58, - shadowRadius: 16.0, - - elevation: 24, - }, + style: tabBarStyle, }), - [bottom] + [tabBarStyle] ); + + // render return ( ) => { - //#region Styles + //#region variables + const animatedFocusValues = useMemo( + () => + tabs.map((_, index) => + withTransition({ + index, + selectedIndex, + duration, + easing, + }) + ), + // eslint-disable-next-line react-hooks/exhaustive-deps + [tabs, duration, easing] + ); + //#endregion + + //#region styles const containerStyle = useMemo>( () => [ styles.container, @@ -44,6 +61,8 @@ const BubbleTabBarComponent = ({ [containerStyleOverride, isRTL] ); //#endregion + + // render return ( {tabs.map(({ key, title, ...configs }, index) => { @@ -58,10 +77,8 @@ const BubbleTabBarComponent = ({ > { - // props - const { - index, - selectedIndex, - label, - icon, - background, - labelStyle: labelStyleOverride, - duration, - easing, - itemInnerSpace, - itemOuterSpace, - iconSize, - isRTL, - } = props; - +const BubbleTabBarItemComponent = ({ + animatedFocus, + label, + icon, + background, + labelStyle: labelStyleOverride, + itemInnerSpace, + itemOuterSpace, + iconSize, + isRTL, +}: BubbleTabBarItemProps) => { //#region extract props const { itemInnerVerticalSpace, @@ -73,16 +66,8 @@ const BubbleTabBarItemComponent = (props: BubbleTabBarItemProps) => { }, [itemInnerSpace, itemOuterSpace]); //#endregion - // animations - const animatedFocus = withTransition({ - index, - selectedIndex, - duration, - easing, - }); - - //#region styles - const labelWidth = useValue(0); + //#region variables + const labelWidth = useValue(0); /** * @DEV * min width is calculated by adding outer & inner spaces @@ -98,7 +83,9 @@ const BubbleTabBarItemComponent = (props: BubbleTabBarItemProps) => { * max width is calculated by adding inner space with label width */ const maxWidth = add(labelWidth, itemInnerHorizontalSpace, minWidth); + //#endregion + //#region styles const animatedIconColor = interpolateColor(animatedFocus, { inputRange: [0, 1], outputRange: [icon.inactiveColor, icon.activeColor], @@ -153,10 +140,10 @@ const BubbleTabBarItemComponent = (props: BubbleTabBarItemProps) => { // callbacks const handleTextLayout = ({ nativeEvent: { - // @ts-ignore layout: { width }, }, - }) => requestAnimationFrame(() => labelWidth.setValue(width)); + }: LayoutChangeEvent) => + requestAnimationFrame(() => labelWidth.setValue(width)); // render const renderIcon = () => { @@ -190,9 +177,6 @@ const BubbleTabBarItemComponent = (props: BubbleTabBarItemProps) => { ); }; -const BubbleTabBarItem = memo( - BubbleTabBarItemComponent, - (prevProps, nextProps) => isEqual(prevProps, nextProps) -); +const BubbleTabBarItem = memo(BubbleTabBarItemComponent, isEqual); export default BubbleTabBarItem; diff --git a/src/presets/flashy/FlashyTabBar.tsx b/src/presets/flashy/FlashyTabBar.tsx index c58cb3f..4c561a1 100644 --- a/src/presets/flashy/FlashyTabBar.tsx +++ b/src/presets/flashy/FlashyTabBar.tsx @@ -13,6 +13,7 @@ import { DEFAULT_ITEM_LAYOUT_DIRECTION, DEFAULT_ITEM_CONTAINER_WIDTH, } from './constants'; +import { withTransition } from '../../withTransition'; import { noop } from '../../utilities'; import { TabBarViewProps } from '../../types'; import { FlashyTabConfig } from './types'; @@ -32,7 +33,23 @@ const FlashyTabBarComponent = ({ onLongPress = noop, animatedOnChange, }: TabBarViewProps) => { - //#region Styles + //#region variables + const animatedFocusValues = useMemo( + () => + tabs.map((_, index) => + withTransition({ + index, + selectedIndex, + duration, + easing, + }) + ), + // eslint-disable-next-line react-hooks/exhaustive-deps + [tabs, duration, easing] + ); + //#endregion + + //#region styles const containerStyle = useMemo>( () => [ styles.container, @@ -65,10 +82,8 @@ const FlashyTabBarComponent = ({ > { - // props - const { - index, - selectedIndex, - label, - icon, - labelStyle: labelStyleOverride, - duration, - easing, - itemInnerSpace, - itemOuterSpace, - iconSize, - indicator, - isRTL, - } = props; - +const FlashyTabBarItemComponent = ({ + animatedFocus, + label, + icon, + labelStyle: labelStyleOverride, + itemInnerSpace, + itemOuterSpace, + iconSize, + indicator, + isRTL, +}: FlashyTabBarItemProps) => { //#region extract props const { itemInnerVerticalSpace, @@ -106,16 +99,8 @@ const FlashyTabBarItemComponent = (props: FlashyTabBarItemProps) => { }, [_indicatorVisible, _indicatorColor, _indicatorSize, labelStyleOverride]); //#endregion - // animations - const animatedFocus = withTransition({ - index, - selectedIndex, - duration, - easing, - }); - - //#region styles - const [labelWidth, labelHeight] = useValues([0, 0]); + //#region variables + const [labelWidth, labelHeight] = useValues([0, 0]); const containerHeight = useMemo(() => iconSize + itemInnerVerticalSpace * 2, [ iconSize, itemInnerVerticalSpace, @@ -124,6 +109,9 @@ const FlashyTabBarItemComponent = (props: FlashyTabBarItemProps) => { add(labelWidth, itemInnerHorizontalSpace * 2), iconSize + itemInnerHorizontalSpace * 2 ); + //#endregion + + //#region styles const outerContainerStyle = [ styles.outerContainer, { @@ -243,10 +231,9 @@ const FlashyTabBarItemComponent = (props: FlashyTabBarItemProps) => { // callbacks const handleLabelLayout = ({ nativeEvent: { - // @ts-ignore layout: { height, width }, }, - }) => + }: LayoutChangeEvent) => requestAnimationFrame(() => { labelWidth.setValue(width); labelHeight.setValue(height); diff --git a/src/types.ts b/src/types.ts index ccdfa29..9a995b3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -78,11 +78,13 @@ export interface TabBarViewProps extends TabBarConfigurableProps { } export interface TabBarItemProps - extends Required> { + extends Required< + Omit + > { /** - * Selected animated index. + * Animated focus value. */ - selectedIndex: Animated.Value; + animatedFocus: Animated.Node; /** * Tab index. */ @@ -94,7 +96,10 @@ export interface TabBarItemProps } export interface AnimatedTabBarViewProps - extends Omit, 'selectedIndex' | 'tabs'> { + extends Omit< + TabBarViewProps<{}>, + 'selectedIndex' | 'tabs' | 'animatedOnChange' + > { /** * Initial index. */