UNPKG

react-native-ui-lib

Version:

<p align="center"> <img src="https://user-images.githubusercontent.com/1780255/105469025-56759000-5ca0-11eb-993d-3568c1fd54f4.png" height="250px" style="display:block"/> </p> <p align="center">UI Toolset & Components Library for React Native</p> <p a

253 lines (220 loc) • 6.43 kB
import _pt from "prop-types"; import _ from 'lodash'; import React, { PureComponent } from 'react'; import { StyleSheet, Animated, Easing } from 'react-native'; import { Colors, Typography, Spacings } from "../../style"; import { Constants, asBaseComponent } from "../../commons/new"; import View from "../view"; import TouchableOpacity from "../touchableOpacity"; import Text from "../text"; import Image from "../image"; import Badge from "../badge"; const INDICATOR_HEIGHT = 2; const INDICATOR_BG_COLOR = Colors.primary; const HORIZONTAL_PADDING = Constants.isTablet ? Spacings.s7 : Spacings.s5; /** * @description: TabBar.Item, inner component of TabBar for configuring the tabs * @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/TabBarScreen.tsx * @extends: TouchableOpacity * @extendsLink: https://reactnative.dev/docs/touchableopacity */ class TabBarItem extends PureComponent { static propTypes = { /** * icon of the tab */ icon: _pt.number, /** * icon tint color */ iconColor: _pt.string, /** * icon selected tint color */ iconSelectedColor: _pt.string, /** * label of the tab */ label: _pt.string, /** * Pass to render a leading element */ leadingAccessory: _pt.element, /** * Pass to render a trailing element */ trailingAccessory: _pt.element, /** * maximum number of lines the label can break */ maxLines: _pt.number, /** * whether the tab is selected or not */ selected: _pt.bool, /** * whether the tab will have a divider on its right */ showDivider: _pt.bool, /** * A fixed width for the item */ width: _pt.number, /** * tabBar's background color */ backgroundColor: _pt.string, /** * ignore of the tab */ ignore: _pt.bool, /** * callback for when pressing a tab */ onPress: _pt.func, /** * whether to change the text to uppercase */ uppercase: _pt.bool, /** * Apply background color on press for TouchableOpacity */ activeBackgroundColor: _pt.string, accessibilityLabel: _pt.string, testID: _pt.string }; static displayName = 'TabBar.Item'; static defaultProps = { maxLines: 1 }; constructor(props) { super(props); this.state = { indicatorOpacity: props.selected ? new Animated.Value(1) : new Animated.Value(0), selected: props.selected }; } componentDidUpdate(prevProps) { if (prevProps.selected !== this.props.selected) { this.animate(this.props.selected); } } animate(newValue) { Animated.timing(this.state.indicatorOpacity, { toValue: newValue ? 1 : 0, easing: Easing.ease, duration: 150, useNativeDriver: true }).start(this.onAnimateCompleted); } onAnimateCompleted = () => { this.setState({ selected: this.props.selected }); }; getFlattenStyle(style) { return StyleSheet.flatten(style); } getStylePropValue(flattenStyle, propName) { let prop; if (flattenStyle) { const propObject = _.pick(flattenStyle, [propName]); prop = propObject[propName]; } return prop; } getColorFromStyle(style) { const flattenStyle = this.getFlattenStyle(style); return this.getStylePropValue(flattenStyle, 'color'); } getLayout() { return this.layout; } onLayout = event => { this.layout = event.nativeEvent.layout; }; render() { const { indicatorOpacity, selected } = this.state; const { children, indicatorStyle, icon, iconColor, iconSelectedColor, label, labelStyle, badgeProps, leadingAccessory, trailingAccessory, uppercase, maxLines, selectedLabelStyle, showDivider, width, onPress, activeBackgroundColor, backgroundColor, testID, accessibilityLabel, style } = this.props; const iconTint = iconColor || this.getColorFromStyle(labelStyle) || this.getColorFromStyle(styles.label); const iconSelectedTint = iconSelectedColor || this.getColorFromStyle(selectedLabelStyle) || this.getColorFromStyle(styles.selectedLabel); const badgeSize = _.get(badgeProps, 'size', 16); return <TouchableOpacity activeOpacity={1} onPress={onPress} style={[width ? { width } : { flex: 1 }, style]} testID={testID} backgroundColor={backgroundColor} activeBackgroundColor={activeBackgroundColor} onLayout={this.onLayout} accessibilityState={selected ? { selected: true } : undefined} accessibilityRole={'tab'} accessibilityLabel={accessibilityLabel}> <View row flex center style={[showDivider && styles.divider, styles.contentContainer]}> {leadingAccessory} {icon && <Image style={!_.isEmpty(label) && styles.icon} source={icon} tintColor={selected ? iconSelectedTint : iconTint} />} {!_.isEmpty(label) && <Text numberOfLines={maxLines} uppercase={uppercase} style={[labelStyle || styles.label, selected && (selectedLabelStyle || styles.selectedLabel)]}> {label} </Text>} {children} {!_.isNil(badgeProps) && <Badge backgroundColor={Colors.red30} {...badgeProps} size={badgeSize} containerStyle={[styles.badge, badgeProps.containerStyle]} />} {trailingAccessory} </View> <Animated.View style={[{ opacity: indicatorOpacity }, styles.indicator, indicatorStyle]} /> </TouchableOpacity>; } } export default asBaseComponent(TabBarItem); const styles = StyleSheet.create({ contentContainer: { paddingHorizontal: HORIZONTAL_PADDING }, label: { color: Colors.primary, ...Typography.text80 }, selectedLabel: { color: Colors.primary, ...Typography.text80, fontWeight: 'bold' }, divider: { borderRightWidth: 1, borderRightColor: Colors.grey70, marginVertical: 14 // NOTE: will not cut long text at the top and bottom in iOS if TabBar not high enough }, indicator: { backgroundColor: INDICATOR_BG_COLOR, height: INDICATOR_HEIGHT, marginHorizontal: HORIZONTAL_PADDING }, badge: { marginLeft: Spacings.s1 }, icon: { marginRight: 6 } });