UNPKG

tuya-panel-kit

Version:

a functional component library for developing tuya device panels!

276 lines (263 loc) 7.4 kB
import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { ViewPropTypes } from 'react-native'; import TYFlatList from '../TYLists/list'; import TYText from '../TYText'; import Footer from './footer'; import { StyledContainer, StyledHeader, StyledTitle, StyledSubTitle, StyledCheckboxList, } from './styled'; import withMotion from './withMotion'; import { ThemeUtils } from '../../utils'; const { getTheme, ThemeConsumer } = ThemeUtils; const ITEM_HEIGHT = 48; class CheckBoxDialog extends Component { static propTypes = { /** * CheckBox 类型: 单选 or 多选 */ type: PropTypes.oneOf(['radio', 'switch']), /** * 选中的值 * 单选为 string 或者 number, 多选类型为 array */ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array]).isRequired, /** * 最大列表项 */ maxItemNum: PropTypes.number, /** * Checkbox 数据源,其中 value 必填, 除 value 外可为 `CheckboxItem` props */ dataSource: PropTypes.arrayOf( PropTypes.shape({ ...TYFlatList.CheckboxItem.propTypes, value: PropTypes.string.isRequired, }) ).isRequired, /** * Checkbox 变更回调事件 */ onChange: PropTypes.func, /** * 容器样式 */ style: ViewPropTypes.style, /** * 头部样式 */ headerStyle: ViewPropTypes.style, /** * 标题超过多少行显示省略号 */ titleNumberOfLines: PropTypes.number, /** * 标题 */ title: PropTypes.string.isRequired, /** * 标题样式 */ titleStyle: TYText.propTypes.style, /** * 副标题 */ subTitle: PropTypes.string, /** * 副标题样式 */ subTitleStyle: TYText.propTypes.style, /** * 内容 */ contentStyle: ViewPropTypes.style, /** * footer容器样式 */ footerWrapperStyle: ViewPropTypes.style, /** * 取消文案 */ cancelText: PropTypes.string.isRequired, /** * 取消文案样式 */ cancelTextStyle: TYText.propTypes.style, /** * 取消按钮测试标示 */ cancelAccessibilityLabel: PropTypes.string, /** * 确认文案 */ confirmText: PropTypes.string.isRequired, /** * 确认文案样式 */ confirmTextStyle: TYText.propTypes.style, /** * 确认按钮测试标示 */ confirmAccessibilityLabel: PropTypes.string, /** * 取消回调函数 */ onCancel: PropTypes.func, /** * 确认回调函数 */ onConfirm: PropTypes.func, }; static defaultProps = { type: 'radio', maxItemNum: 5, style: null, headerStyle: null, titleNumberOfLines: 2, titleStyle: null, subTitle: '', subTitleStyle: null, contentStyle: null, footerWrapperStyle: null, cancelTextStyle: null, cancelAccessibilityLabel: 'Dialog.Cancel', confirmTextStyle: null, confirmAccessibilityLabel: 'Dialog.Confirm', onChange: null, onCancel: null, onConfirm: null, }; constructor(props) { super(props); this.state = { value: props.value, }; if (props.type === 'switch' && !Array.isArray(props.value)) { console.warn('CheckBoxDialog: 复选框的 value 必须为 数组'); } } componentWillReceiveProps(nextProps) { if (this.state.value !== nextProps.value && this.props.value !== nextProps.value) { this.setState({ value: nextProps.value }); } } isChecked(value) { const { type } = this.props; if (type === 'radio') { return this.state.value === value; } else if (type === 'switch') { return this.state.value.some(v => v === value); } return false; } _handleCheckBoxChange = (checked, value) => { const { type, onChange } = this.props; if (type === 'radio') { this.setState(() => { const newValue = checked ? value : undefined; onChange && onChange(newValue); return { value: newValue }; }); } else if (type === 'switch') { this.setState(prevState => { let newValue = Array.isArray(prevState.value) ? prevState.value : []; if (checked) newValue = [...newValue, value]; else newValue = newValue.filter(v => v !== value); onChange && onChange(newValue); return { value: newValue }; }); } }; _handleConfirm = () => { const { onConfirm } = this.props; onConfirm && onConfirm(this.state.value); }; renderCheckBoxItem = ({ item }) => { const { styles = {}, value, title, ...checkboxProps } = item; const isChecked = this.isChecked(value); return ( <ThemeConsumer> {globalTheme => { const checkItemProps = { theme: { dialog: { ...globalTheme.dialog } } }; const itemBackGround = getTheme(checkItemProps, 'dialog.bg'); const itemFontColor = getTheme(checkItemProps, 'dialog.titleFontColor'); const itemFontSize = getTheme(checkItemProps, 'dialog.titleFontSize'); return ( <TYFlatList.CheckboxItem styles={{ ...styles, container: [ { height: ITEM_HEIGHT, backgroundColor: itemBackGround }, styles.container, ], title: [{ fontSize: itemFontSize, color: itemFontColor }, styles.title], }} color={isChecked ? '#44DB5E' : '#e5e5e5'} {...checkboxProps} title={title || value} checked={isChecked} onChange={checked => this._handleCheckBoxChange(checked, value)} /> ); }} </ThemeConsumer> ); }; render() { const { maxItemNum, style, headerStyle, titleNumberOfLines, title, titleStyle, subTitle, subTitleStyle, contentStyle, dataSource, confirmText, confirmTextStyle, confirmAccessibilityLabel, footerWrapperStyle, cancelText, cancelTextStyle, cancelAccessibilityLabel, onCancel, ...TYFlatListProps } = this.props; return ( <StyledContainer style={style}> <StyledHeader style={headerStyle}> <StyledTitle style={titleStyle} numberOfLines={titleNumberOfLines}> {title} </StyledTitle> {!!subTitle && <StyledSubTitle style={subTitleStyle}>{subTitle}</StyledSubTitle>} </StyledHeader> <StyledCheckboxList style={[contentStyle, { maxHeight: ITEM_HEIGHT * maxItemNum }]} scrollEnabled={dataSource.length > maxItemNum} keyExtractor={item => item.value} data={dataSource} renderItem={this.renderCheckBoxItem} {...TYFlatListProps} /> <Footer style={footerWrapperStyle} cancelTextStyle={cancelTextStyle} confirmTextStyle={confirmTextStyle} cancelText={cancelText} confirmText={confirmText} cancelAccessibilityLabel={cancelAccessibilityLabel} confirmAccessibilityLabel={confirmAccessibilityLabel} onCancel={onCancel} onConfirm={this._handleConfirm} /> </StyledContainer> ); } } export default withMotion(CheckBoxDialog);