Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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