* Started with bottom tabs layout * code clean up * Added animation to bottom tab bar * returns null if not focused * code clean up * Updating layout * Updated modal screen * Updated animation * Updated animation * Fix SafeArea on Home * A few clean ups * code clean up * Fix issue with navigation on Android * Use React Navigation in combination of RNN & create bottom tab bar * Set tab bar line separator height to 0.5 * Fix snapshot tests * Add home tab mention badge * Apply new themes * Home Tab badge * Remove unused constants Co-authored-by: Avinash Lingaloo <> Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
117 lines
2.8 KiB
TypeScript
117 lines
2.8 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import * as React from 'react';
|
|
import {Animated, StyleProp, StyleSheet, TextStyle} from 'react-native';
|
|
|
|
import {useTheme} from '@context/theme';
|
|
|
|
type Props = {
|
|
|
|
/**
|
|
* Whether the badge is visible
|
|
*/
|
|
visible: boolean;
|
|
|
|
/**
|
|
* Content of the `Badge`.
|
|
*/
|
|
children?: string | number;
|
|
|
|
/**
|
|
* Size of the `Badge`.
|
|
*/
|
|
size?: number;
|
|
|
|
/**
|
|
* Style object for the tab bar container.
|
|
*/
|
|
style?: Animated.WithAnimatedValue<StyleProp<TextStyle>>;
|
|
};
|
|
|
|
export default function Badge({
|
|
visible = true,
|
|
size = 18,
|
|
children,
|
|
style,
|
|
...rest
|
|
}: Props) {
|
|
const [opacity] = React.useState(() => new Animated.Value(visible ? 1 : 0));
|
|
const [rendered, setRendered] = React.useState(Boolean(visible));
|
|
|
|
const theme = useTheme();
|
|
|
|
React.useEffect(() => {
|
|
if (!rendered) {
|
|
return;
|
|
}
|
|
|
|
Animated.timing(opacity, {
|
|
toValue: visible ? 1 : 0,
|
|
duration: 150,
|
|
useNativeDriver: true,
|
|
}).start(({finished}) => {
|
|
if (finished && !visible) {
|
|
setRendered(false);
|
|
}
|
|
});
|
|
}, [opacity, rendered, visible]);
|
|
|
|
if (visible && !rendered) {
|
|
setRendered(true);
|
|
}
|
|
|
|
if (!visible && !rendered) {
|
|
return null;
|
|
}
|
|
|
|
// @ts-expect-error: backgroundColor definitely exists
|
|
const {backgroundColor = theme.buttonBg, ...restStyle} =
|
|
StyleSheet.flatten(style) || {};
|
|
const textColor = theme.buttonColor;
|
|
const borderRadius = size / 2;
|
|
const fontSize = Math.floor((size * 3) / 4);
|
|
|
|
return (
|
|
<Animated.Text
|
|
numberOfLines={1}
|
|
style={[
|
|
{
|
|
opacity,
|
|
transform: [
|
|
{
|
|
scale: opacity.interpolate({
|
|
inputRange: [0, 1],
|
|
outputRange: [0.5, 1],
|
|
}),
|
|
},
|
|
],
|
|
backgroundColor,
|
|
color: textColor,
|
|
fontSize,
|
|
lineHeight: size - 1,
|
|
height: size,
|
|
minWidth: size,
|
|
borderRadius,
|
|
},
|
|
styles.container,
|
|
restStyle,
|
|
]}
|
|
{...rest}
|
|
>
|
|
{children}
|
|
</Animated.Text>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
position: 'absolute',
|
|
top: -1,
|
|
left: 15,
|
|
alignSelf: 'flex-end',
|
|
textAlign: 'center',
|
|
paddingHorizontal: 4,
|
|
overflow: 'hidden',
|
|
},
|
|
});
|