src/BoxGroup.js
/**
* @file melon/BoxGroup
* @author cxtom<[email protected]>
* @author leon<[email protected]>
*/
import React, {PropTypes, Children} from 'react';
import Option from './boxgroup/Option';
import {create} from 'melon-core/classname/cxBuilder';
import InputComponent from 'melon-core/InputComponent';
import Validity from 'melon-core/Validity';
const cx = create('BoxGroup');
export default class BoxGroup extends InputComponent {
constructor(props, context) {
super(props, context);
const value = this.state.value;
this.state = {
...this.state,
value: Array.isArray(value) ? value : [value]
};
this.onChange = this.onChange.bind(this);
this.renderOption = this.renderOption.bind(this);
}
onChange(e) {
const optionValue = e.target.value;
const value = this.getValue();
const boxModel = this.props.boxModel;
let nextValue;
// 计算 radio 的值
if (boxModel === 'radio') {
nextValue = [optionValue];
}
// 计算 checkbox 的值
else {
const index = value.indexOf(optionValue);
nextValue = index > -1
? [...value.slice(0, index), ...value.slice(index + 1)]
: [...value, optionValue];
}
super.onChange({
type: 'change',
target: this,
value: nextValue
});
}
getValue() {
const currentValue = this.state.value;
return Children
.toArray(this.props.children)
.reduce(function (result, option) {
if (option && option.props) {
const {disabled, value} = option.props;
if (!disabled && currentValue.indexOf(value) > -1) {
result.push(value);
}
}
return result;
}, []);
}
/**
* 渲染选项
*
* @param {?ReactElement} option 选项
* @return {Array.ReactElement}
*/
renderOption(option) {
const {type, props} = option;
// 如果 child 不是一个 <Option> 那么直接返回它
if (type !== 'option') {
return option;
}
const boxModel = this.props.boxModel;
const {value, children, label} = props;
return (
<Option
key={value}
boxModel={boxModel}
label={label || children}
value={value}
checked={this.state.value.indexOf(value) > -1}
disabled={this.props.disabled || props.disabled}
readOnly={this.props.readOnly}
onChange={this.onChange} />
);
}
render() {
return (
<div className={cx(this.props).addStates(this.getStyleStates()).build()}>
{Children.map(this.props.children, this.renderOption)}
<Validity validity={this.state.validity} />
</div>
);
}
}
BoxGroup.displayName = 'BoxGroup';
BoxGroup.propTypes = {
...InputComponent.propTypes,
boxModel: PropTypes.oneOf(['radio', 'checkbox']).isRequired,
value: PropTypes.arrayOf(PropTypes.string),
children: PropTypes.node.isRequired
};
BoxGroup.defaultProps = {
...InputComponent.defaultProps,
boxModel: 'checkbox',
defaultValue: []
};
BoxGroup.childContextTypes = InputComponent.childContextTypes;
BoxGroup.contextTypes = InputComponent.contextTypes;
export function createOptions(datasource) {
return datasource.map(function (option, index) {
const {name, value, disabled} = option;
return (
<option
key={value}
disabled={!!disabled}
label={name}
value={value} />
);
});
}
BoxGroup.createOptions = createOptions;