Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add an optional second color param and added reverse focus for bubbleTabBar #135

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions .release-it.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"releaseNotes": "auto-changelog --stdout --commit-limit false --ignore-commit-pattern \"^chore: release v\" --unreleased --template ./release-template.hbs"
},
"npm": {
"publish": false
"publish": true
},
"plugins": {
"@release-it/conventional-changelog": {
Expand All @@ -20,4 +20,4 @@
"hooks": {
"after:bump": "auto-changelog -p --ignore-commit-pattern \"^chore: release v\""
}
}
}
194 changes: 111 additions & 83 deletions CHANGELOG.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gorhom/animated-tabbar",
"version": "2.1.2",
"version": "2.5.1",
"description": "A 60FPS animated tab bar with a variety of cool animation presets.",
"main": "lib/commonjs/index.js",
"module": "lib/module/index.js",
Expand Down Expand Up @@ -38,7 +38,7 @@
},
"dependencies": {
"lodash.isequal": "^4.5.0",
"react-native-redash": "14.2.4"
"react-native-redash": "16.2.3"
},
"devDependencies": {
"@commitlint/cli": "^9.1.1",
Expand All @@ -65,12 +65,12 @@
"typescript": "4.0.3"
},
"peerDependencies": {
"@react-navigation/native": ">=5.0.0",
"@react-native-community/masked-view": ">=0.1.10",
"@react-navigation/native": ">=5.0.0",
"react": "*",
"react-native": "*",
"react-native-gesture-handler": ">=1.6.1",
"react-native-reanimated": ">=1.8.0",
"react-native-reanimated": ">=2.0.0",
"react-native-safe-area-context": ">=0.7.3",
"react-native-svg": ">=12.0.2"
},
Expand Down
2 changes: 1 addition & 1 deletion src/AnimatedTabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Animated, {
call,
onChange,
} from 'react-native-reanimated';
import { useValue } from 'react-native-redash';
import { useValue } from 'react-native-redash/lib/module/v1';

interface Route {
name: string;
Expand Down
2 changes: 1 addition & 1 deletion src/AnimatedTabBarView.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useMemo, useEffect, useRef } from 'react';
import Animated from 'react-native-reanimated';
import { useValue } from 'react-native-redash';
import { useValue } from 'react-native-redash/lib/module/v1';
import Presets, { PresetEnum } from './presets';
import type { AnimatedTabBarViewProps } from './types';

Expand Down
2 changes: 1 addition & 1 deletion src/components/rawButton/RawButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
TapGestureHandler,
LongPressGestureHandler,
} from 'react-native-gesture-handler';
import { useValue, useGestureHandler } from 'react-native-redash';
import { useValue, useGestureHandler } from 'react-native-redash/lib/module/v1';
import { useStableCallback } from '../../hooks';

const { useCode, cond, onChange, eq } = Animated;
Expand Down
78 changes: 78 additions & 0 deletions src/hooks/useReverseTabBarItemFocusTransition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import Animated from 'react-native-reanimated';
import type { TabBarConfigurableProps } from '../types';

const {
block,
cond,
onChange,
Value,
Clock,
set,
eq,
neq,
not,
or,
timing,
and,
startClock,
clockRunning,
stopClock,
} = Animated;

interface useReverseTabBarItemFocusTransitionProps
extends Required<Pick<TabBarConfigurableProps, 'duration' | 'easing'>> {
index: number;
selectedIndex: Animated.Value<number>;
}

export const useReverseTabBarItemFocusTransition = ({
index,
selectedIndex,
duration,
easing,
}: useReverseTabBarItemFocusTransitionProps) => {
//#region variables
const clock = new Clock();
const state = {
finished: new Value(1),
frameTime: new Value(1),
position: new Value(1),
time: new Value(1),
};
const config = {
toValue: new Value(1),
easing,
duration,
};
//#endregion

//#region conditions
const shouldAnimateIn = and(eq(selectedIndex, index), neq(state.position, 0));
const shouldAnimateOut = and(
neq(selectedIndex, index),
neq(state.position, 1)
);
const shouldAnimate = or(shouldAnimateIn, shouldAnimateOut);
//#endregion
const finishTiming = [
stopClock(clock),
set(state.finished, 1),
set(state.frameTime, 1),
set(state.time, 1),
];
return block([
onChange(selectedIndex, finishTiming),
cond(shouldAnimate, [
cond(and(not(clockRunning(clock)), not(state.finished)), [
set(state.frameTime, 1),
set(state.time, 1),
set(state.finished, 1),
set(config.toValue, shouldAnimateIn),
startClock(clock),
]),
timing(clock, state, config),
cond(state.finished, finishTiming),
]),
state.position,
]);
};
2 changes: 1 addition & 1 deletion src/hooks/useTabBarVisibility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Animated, {
startClock,
timing,
} from 'react-native-reanimated';
import { useClock, useValue } from 'react-native-redash';
import { useClock, useValue } from 'react-native-redash/lib/module/v1';
import { Easing } from '../utilities';

export const useTabBarVisibility = (shouldShowTabBar: boolean) => {
Expand Down
18 changes: 17 additions & 1 deletion src/presets/bubble/BubbleTabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { noop } from '../../utilities';
import type { TabBarViewProps } from '../../types';
import type { BubbleTabBarConfig, BubbleTabBarItemConfig } from './types';
import { styles } from './styles';
import { useReverseTabBarItemFocusTransition } from '../../hooks/useReverseTabBarItemFocusTransition';

const BubbleTabBarComponent = ({
selectedIndex,
Expand All @@ -36,7 +37,7 @@ const BubbleTabBarComponent = ({
animatedOnChange,
onLongPress = noop,
}: TabBarViewProps<BubbleTabBarConfig, BubbleTabBarItemConfig>) => {
//#region variables
// #region variables
const animatedFocusValues = useMemo(
() =>
tabs.map((_, index) =>
Expand All @@ -51,6 +52,20 @@ const BubbleTabBarComponent = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
[tabs, duration, easing]
);
const reverseAnimatedFocusValues = useMemo(
() =>
tabs.map((_, index) =>
// eslint-disable-next-line react-hooks/rules-of-hooks
useReverseTabBarItemFocusTransition({
index,
selectedIndex,
duration,
easing,
})
),
// eslint-disable-next-line react-hooks/exhaustive-deps
[tabs, duration, easing]
);
const tabBarItemSpacing = useTabBarItemSpacing(
itemInnerSpace,
itemOuterSpace,
Expand Down Expand Up @@ -88,6 +103,7 @@ const BubbleTabBarComponent = ({
<BubbleTabBarItem
index={index}
animatedFocus={animatedFocusValues[index]}
reverseAnimatedFocus={reverseAnimatedFocusValues[index]}
label={title}
spacing={tabBarItemSpacing}
itemContainerWidth={itemContainerWidth}
Expand Down
25 changes: 23 additions & 2 deletions src/presets/bubble/item/BubbleTabBarItem.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useMemo, memo } from 'react';
import { View, Text, LayoutChangeEvent } from 'react-native';
import Animated from 'react-native-reanimated';
import { interpolateColor, useValue } from 'react-native-redash';
import { interpolateColor, useValue } from 'react-native-redash/lib/module/v1';
// @ts-ignore 😞
import isEqual from 'lodash.isequal';
import { interpolate } from '../../../utilities';
Expand All @@ -16,9 +16,11 @@ const BubbleTabBarItemComponent = ({
icon,
background,
labelStyle: labelStyleOverride,
labelAllowFontScaling,
spacing,
iconSize,
isRTL,
reverseAnimatedFocus,
}: BubbleTabBarItemProps) => {
//#region extract props
const {
Expand Down Expand Up @@ -51,6 +53,16 @@ const BubbleTabBarItemComponent = ({
inputRange: [0, 1],
outputRange: [icon.inactiveColor, icon.activeColor],
});
const animatedIconSecondColor = useMemo(() => {
if (!icon.secondColor) return undefined;
return interpolateColor(animatedFocus, {
inputRange: [0, 1],
outputRange: [
icon.secondColor.inactiveColor,
icon.secondColor.activeColor,
],
});
}, [animatedFocus, icon.secondColor]);
const containerStyle = [
styles.container,
{
Expand Down Expand Up @@ -113,13 +125,17 @@ const BubbleTabBarItemComponent = ({
IconComponent({
animatedFocus,
color: animatedIconColor,
secondColor: animatedIconSecondColor,
size: iconSize,
reverseAnimatedFocus,
})
) : (
<IconComponent
animatedFocus={animatedFocus}
color={animatedIconColor}
secondColor={animatedIconSecondColor}
size={iconSize}
reverseAnimatedFocus={reverseAnimatedFocus}
/>
);
};
Expand All @@ -130,7 +146,12 @@ const BubbleTabBarItemComponent = ({
<View style={iconContainerStyle}>{renderIcon()}</View>
</Animated.View>
<Animated.View style={labelContainerStyle}>
<Text onLayout={handleTextLayout} style={labelStyle} numberOfLines={1}>
<Text
allowFontScaling={labelAllowFontScaling}
onLayout={handleTextLayout}
style={labelStyle}
numberOfLines={1}
>
{label}
</Text>
</Animated.View>
Expand Down
35 changes: 34 additions & 1 deletion src/presets/bubble/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TextStyle } from 'react-native';
import type { TextProps, TextStyle } from 'react-native';
import type Animated from 'react-native-reanimated';
import type { TabBarItemProps } from '../../types';

Expand All @@ -16,6 +16,10 @@ export interface BubbleTabBarItemConfig {
* }
*/
labelStyle: TextStyle;
/**
* Specifies whether fonts should scale to respect Text Size accessibility settings. The default is true.
*/
labelAllowFontScaling: TextProps['allowFontScaling'];
/**
* Tab bar item icon config.
*/
Expand All @@ -39,6 +43,22 @@ export interface BubbleTabBarItemConfig {
* @type {string}
*/
inactiveColor: string;

/**
* Icon second color.
*/
secondColor?: {
/**
* Tab bar item second color active variant.
* @type {string}
*/
activeColor: string;
/**
* Tab bar item second color inactive variant.
* @type {string}
*/
inactiveColor: string;
};
};
background: {
/**
Expand All @@ -62,11 +82,24 @@ export interface BubbleTabBarIconProps {
* @type {Animated.Node<number>}
*/
animatedFocus: Animated.Node<number>;

/**
* Tab bar item animated focus value reverse.
* @type {Animated.Node<number> | undefined}
*/
reverseAnimatedFocus?: Animated.Node<number>;
/**
* Tab bar item animated icon color.
* @type {Animated.Node<string | number>}
*/
color: Animated.Node<string | number>;

/**
* Tab bar item animated second icon color.
* @type {Animated.Node<string | number> | undefined}
*/
secondColor?: Animated.Node<string | number>;

/**
* Tab bar item icon size.
* @type {number}
Expand Down
Loading