Skip to content

Commit

Permalink
fix: remove interpolation from web platoform as animations are disabled
Browse files Browse the repository at this point in the history
  • Loading branch information
kubabutkiewicz committed Oct 17, 2024
1 parent 7814eed commit fba2945
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 35 deletions.
41 changes: 6 additions & 35 deletions src/components/TabSelector/TabSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type {MaterialTopTabBarProps} from '@react-navigation/material-top-tabs/lib/typescript/src/types';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import type {Animated} from 'react-native';
import React, {useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import FocusTrapContainerElement from '@components/FocusTrap/FocusTrapContainerElement';
import * as Expensicons from '@components/Icon/Expensicons';
Expand All @@ -10,6 +9,8 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
import type IconAsset from '@src/types/utils/IconAsset';
import getBackgroundColor from './getBackground';
import getOpacity from './getOpacity';
import TabSelectorItem from './TabSelectorItem';

type TabSelectorProps = MaterialTopTabBarProps & {
Expand Down Expand Up @@ -50,43 +51,13 @@ function getIconAndTitle(route: string, translate: LocaleContextProps['translate
}
}

function getOpacity(position: Animated.AnimatedInterpolation<number>, routesLength: number, tabIndex: number, active: boolean, affectedTabs: number[]) {
const activeValue = active ? 1 : 0;
const inactiveValue = active ? 0 : 1;

if (routesLength > 1) {
const inputRange = Array.from({length: routesLength}, (v, i) => i);

return position.interpolate({
inputRange,
outputRange: inputRange.map((i) => (affectedTabs.includes(tabIndex) && i === tabIndex ? activeValue : inactiveValue)),
});
}
return activeValue;
}

function TabSelector({state, navigation, onTabPress = () => {}, position, onFocusTrapContainerElementChanged}: TabSelectorProps) {
const {translate} = useLocalize();
const theme = useTheme();
const styles = useThemeStyles();
const defaultAffectedAnimatedTabs = useMemo(() => Array.from({length: state.routes.length}, (v, i) => i), [state.routes.length]);
const [affectedAnimatedTabs, setAffectedAnimatedTabs] = useState(defaultAffectedAnimatedTabs);

const getBackgroundColor = useCallback(
(routesLength: number, tabIndex: number, affectedTabs: number[]) => {
if (routesLength > 1) {
const inputRange = Array.from({length: routesLength}, (v, i) => i);

return position.interpolate({
inputRange,
outputRange: inputRange.map((i) => (affectedTabs.includes(tabIndex) && i === tabIndex ? theme.border : theme.appBG)),
}) as unknown as Animated.AnimatedInterpolation<string>;
}
return theme.border;
},
[theme, position],
);

useEffect(() => {
// It is required to wait transition end to reset affectedAnimatedTabs because tabs style is still animating during transition.
setTimeout(() => {
Expand All @@ -98,10 +69,10 @@ function TabSelector({state, navigation, onTabPress = () => {}, position, onFocu
<FocusTrapContainerElement onContainerElementChanged={onFocusTrapContainerElementChanged}>
<View style={styles.tabSelector}>
{state.routes.map((route, index) => {
const activeOpacity = getOpacity(position, state.routes.length, index, true, affectedAnimatedTabs);
const inactiveOpacity = getOpacity(position, state.routes.length, index, false, affectedAnimatedTabs);
const backgroundColor = getBackgroundColor(state.routes.length, index, affectedAnimatedTabs);
const isActive = index === state.index;
const activeOpacity = getOpacity({routesLength: state.routes.length, tabIndex: index, active: true, affectedTabs: affectedAnimatedTabs, position, isActive});
const inactiveOpacity = getOpacity({routesLength: state.routes.length, tabIndex: index, active: false, affectedTabs: affectedAnimatedTabs, position, isActive});
const backgroundColor = getBackgroundColor({routesLength: state.routes.length, tabIndex: index, affectedTabs: affectedAnimatedTabs, theme, position, isActive});
const {icon, title} = getIconAndTitle(route.name, translate);

const onPress = () => {
Expand Down
17 changes: 17 additions & 0 deletions src/components/TabSelector/getBackground/index.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type {Animated} from 'react-native';
import type GetBackgroudColor from './types';

const getBackgroundColor: GetBackgroudColor = ({routesLength, tabIndex, affectedTabs, theme, position}) => {
if (routesLength > 1) {
const inputRange = Array.from({length: routesLength}, (v, i) => i);
return position?.interpolate({
inputRange,
outputRange: inputRange.map((i) => {
return affectedTabs.includes(tabIndex) && i === tabIndex ? theme.border : theme.appBG;
}),
}) as unknown as Animated.AnimatedInterpolation<string>;
}
return theme.border;
};

export default getBackgroundColor;
9 changes: 9 additions & 0 deletions src/components/TabSelector/getBackground/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type GetBackgroudColor from './types';

const getBackgroundColor: GetBackgroudColor = ({routesLength, tabIndex, affectedTabs, theme, isActive}) => {
if (routesLength > 1) {
return affectedTabs.includes(tabIndex) && isActive ? theme.border : theme.appBG;
}
return theme.border;
};
export default getBackgroundColor;
15 changes: 15 additions & 0 deletions src/components/TabSelector/getBackground/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type {Animated} from 'react-native';
import type {ThemeColors} from '@styles/theme/types';

type GetBackgroudColorConfig = {
routesLength: number;
tabIndex: number;
affectedTabs: number[];
theme: ThemeColors;
position?: Animated.AnimatedInterpolation<number>;
isActive?: boolean;
};

type GetBackgroudColor = (args: GetBackgroudColorConfig) => Animated.AnimatedInterpolation<string> | string;

export default GetBackgroudColor;
18 changes: 18 additions & 0 deletions src/components/TabSelector/getOpacity/index.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type GetOpacity from './types';

const getOpacity: GetOpacity = ({routesLength, tabIndex, active, affectedTabs, position, isActive}) => {
const activeValue = active ? 1 : 0;
const inactiveValue = active ? 0 : 1;

if (routesLength > 1) {
const inputRange = Array.from({length: routesLength}, (v, i) => i);

return position?.interpolate({
inputRange,
outputRange: inputRange.map((i) => (affectedTabs.includes(tabIndex) && i === tabIndex && isActive ? activeValue : inactiveValue)),
});
}
return activeValue;
};

export default getOpacity;
13 changes: 13 additions & 0 deletions src/components/TabSelector/getOpacity/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type GetOpacity from './types';

const getOpacity: GetOpacity = ({routesLength, tabIndex, active, affectedTabs, isActive}) => {
const activeValue = active ? 1 : 0;
const inactiveValue = active ? 0 : 1;

if (routesLength > 1) {
return affectedTabs.includes(tabIndex) && isActive ? activeValue : inactiveValue;
}
return activeValue;
};

export default getOpacity;
14 changes: 14 additions & 0 deletions src/components/TabSelector/getOpacity/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type {Animated} from 'react-native';

type GetOpacityConfig = {
routesLength: number;
tabIndex: number;
active: boolean;
affectedTabs: number[];
position?: Animated.AnimatedInterpolation<number>;
isActive?: boolean;
};

type GetOpacity = (args: GetOpacityConfig) => 1 | 0 | Animated.AnimatedInterpolation<number> | undefined;

export default GetOpacity;

0 comments on commit fba2945

Please sign in to comment.