tuya-panel-kit
Version:
a functional component library for developing tuya device panels!
168 lines (153 loc) • 5.09 kB
JavaScript
/* eslint-disable prettier/prettier */
import React from 'react';
import { View, ViewPropTypes, Animated, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
import { RatioUtils } from '../../../utils';
import RadioButton from './radioButton';
const { convertY } = RatioUtils;
const styles = StyleSheet.create({
activeViewStyle: {
backgroundColor: '#fff',
position: 'absolute',
},
containerStyle: {
height: convertY(30),
borderRadius: convertY(15),
// borderWidth: StyleSheet.hairlineWidth,
borderColor: '#fff',
justifyContent: 'center',
backgroundColor: '#E3E9EE',
},
wrapperStyle: {
flexDirection: 'row',
},
});
class Group extends React.PureComponent {
static propTypes = {
tabs: PropTypes.array.isRequired,
style: ViewPropTypes.style,
wrapperStyle: ViewPropTypes.style,
activeColor: PropTypes.string,
// eslint-disable-next-line react/require-default-props
activeIndex: PropTypes.number,
defaultActiveIndex: PropTypes.number,
gutter: PropTypes.number,
onChange: PropTypes.func,
type: PropTypes.oneOfType([PropTypes.oneOf(['radio', 'radioCircle']), PropTypes.string]),
};
static defaultProps = {
style: {},
wrapperStyle: {},
activeColor: '',
defaultActiveIndex: 0,
gutter: 2,
onChange: () => {},
type: 'radio',
};
constructor(props) {
super(props);
const activeIndex =
props.activeIndex !== undefined ? props.activeIndex : props.defaultActiveIndex;
this.state = {
activeLeft: new Animated.Value(0),
activeIndex,
activeViewHidden: true,
wrapperWidth: 0,
};
this.containerSize = null;
this.wrapperSize = null;
}
componentWillReceiveProps(nextProps) {
if ('activeIndex' in nextProps) {
this.moveActiveView(nextProps.activeIndex);
}
}
getItem = () => {
const { tabs, type, tabTextStyle, tabActiveTextStyle } = this.props;
const buttonStyle = [{ width: this.state.wrapperWidth / tabs.length }];
const defaultTextStyle = [{ opacity: this.state.activeViewHidden ? 0 : 1 }];
const circleStyle = tabTextStyle && tabTextStyle.color && { backgroundColor: tabTextStyle.color }
return tabs.map((item, index) => {
const { style, textStyle, ...other } = item;
return (
<RadioButton
activeTextStyle={tabActiveTextStyle}
circleStyle={circleStyle}
{...other}
// eslint-disable-next-line react/no-array-index-key
key={`tab_${index}`}
type={type}
style={[buttonStyle, style]}
textStyle={[defaultTextStyle, tabTextStyle, textStyle]}
onItemPress={() => this.changeTab(index, item, item.onItemPress)}
isActive={this.state.activeIndex === index}
/>
);
});
};
moveActiveView = index => {
const { gutter } = this.props;
const currentLeft = index * this.state.everyWidth + gutter;
Animated.spring(this.state.activeLeft, {
toValue: currentLeft,
}).start();
this.setState({
activeIndex: index,
});
};
changeTab = (index, item, func) => {
if (func) func(index);
if (index === this.state.activeIndex) return;
const { onChange } = this.props;
onChange && onChange(index, item);
if ('activeIndex' in this.props) return;
this.moveActiveView(index);
};
containerLayout = e => {
this.containerSize = e.nativeEvent.layout;
this.completeCalcWidth();
};
wrapperLayout = e => {
this.wrapperSize = e.nativeEvent.layout;
this.completeCalcWidth();
};
completeCalcWidth = () => {
if (!this.wrapperSize || !this.containerSize) return;
const { tabs, gutter } = this.props;
const everyWidth = this.wrapperSize.width / tabs.length;
this.state.activeLeft.setValue(gutter + everyWidth * this.state.activeIndex);
this.setState({
containerHeight: this.containerSize.height,
wrapperWidth: this.wrapperSize.width,
activeViewHidden: false,
everyWidth,
});
};
render() {
const { style, wrapperStyle, activeColor, tabs, gutter } = this.props;
const containerPadding =
StyleSheet.flatten([styles.containerStyle, style]).borderRadius + gutter;
const containerStyle = [styles.containerStyle, style, { paddingHorizontal: gutter }];
const customWrapperStyle = [styles.wrapperStyle, wrapperStyle];
const activeLeft = { left: this.state.activeLeft };
const activeViewStyle = [
styles.activeViewStyle,
{
width: this.state.wrapperWidth / tabs.length,
height: this.state.containerHeight - gutter * 2,
},
activeColor && { backgroundColor: activeColor },
{ borderRadius: containerPadding },
activeLeft,
];
return (
<View onLayout={this.containerLayout} style={containerStyle}>
{!this.state.activeViewHidden && <Animated.View style={activeViewStyle} />}
<View onLayout={this.wrapperLayout} style={customWrapperStyle}>
{this.getItem()}
</View>
</View>
);
}
}
export default Group;