Skip to content

Commit e613079

Browse files
committed
Add src/CheckBox.js
Add src/CheckboxGroup.js Add src/RCheckbox.js Add src/style/checkbox.scss
1 parent 414c1f4 commit e613079

File tree

4 files changed

+476
-0
lines changed

4 files changed

+476
-0
lines changed

src/CheckBox.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import classNames from 'classnames';
4+
import shallowEqual from 'shallowequal';
5+
import RCheckbox from './RCheckbox';
6+
7+
export default class Checkbox extends Component {
8+
static propTypes = {
9+
className: PropTypes.string,
10+
style: PropTypes.object,
11+
prefixCls: PropTypes.string
12+
};
13+
14+
static defaultProps = {
15+
prefixCls: 'nex-checkbox',
16+
className: '',
17+
style: {}
18+
};
19+
20+
static contextTypes = {
21+
checkboxGroup: PropTypes.any,
22+
};
23+
24+
shouldComponentUpdate(nextProps, nextState, nextContext) {
25+
return !shallowEqual(this.props, nextProps) ||
26+
!shallowEqual(this.state, nextState) ||
27+
!shallowEqual(this.context.checkboxGroup, nextContext.checkboxGroup);
28+
}
29+
30+
render() {
31+
const { props, context } = this;
32+
const {
33+
prefixCls,
34+
className,
35+
children,
36+
style,
37+
onMouseEnter,
38+
onMouseLeave,
39+
...others
40+
} = this.props;
41+
42+
const { checkboxGroup } = context;
43+
if (checkboxGroup) {
44+
others.onChange = () => checkboxGroup.toggleOption({ label: children, value: props.value });
45+
others.checked = checkboxGroup.value.indexOf(props.value) !== -1;
46+
others.disabled = 'disabled' in props ? props.disabled : checkboxGroup.disabled;
47+
}
48+
49+
const classString = classNames({
50+
[`${prefixCls}-wrapper`]: true,
51+
[className]: !!className
52+
});
53+
54+
return (
55+
<label
56+
className={classString}
57+
style={style}
58+
onMouseEnter={onMouseEnter}
59+
onMouseLeave={onMouseLeave}
60+
>
61+
<RCheckbox
62+
{...others}
63+
prefixCls={prefixCls}
64+
/>
65+
{children !== undefined ? <span className={`${prefixCls}-label`}>{children}</span> : null}
66+
</label>
67+
);
68+
}
69+
}

src/CheckboxGroup.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import classNames from 'classnames';
4+
import shallowEqual from 'shallowequal';
5+
import Checkbox from './Checkbox';
6+
7+
export default class CheckboxGroup extends React.Component {
8+
static defaultProps = {
9+
options: [],
10+
prefixCls: 'nex-checkbox-group',
11+
};
12+
13+
static propTypes = {
14+
defaultValue: PropTypes.array,
15+
value: PropTypes.array,
16+
options: PropTypes.array.isRequired,
17+
onChange: PropTypes.func,
18+
};
19+
20+
static childContextTypes = {
21+
checkboxGroup: PropTypes.any,
22+
};
23+
24+
constructor(props) {
25+
super(props);
26+
this.state = {
27+
value: props.value || props.defaultValue || [],
28+
};
29+
}
30+
31+
getChildContext() {
32+
return {
33+
checkboxGroup: {
34+
toggleOption: this.toggleOption,
35+
value: this.state.value,
36+
disabled: this.props.disabled,
37+
},
38+
};
39+
}
40+
41+
componentWillReceiveProps(nextProps) {
42+
if ('value' in nextProps) {
43+
this.setState({
44+
value: nextProps.value || [],
45+
});
46+
}
47+
}
48+
shouldComponentUpdate(nextProps, nextState) {
49+
return !shallowEqual(this.props, nextProps) ||
50+
!shallowEqual(this.state, nextState);
51+
}
52+
getOptions() {
53+
const { options } = this.props;
54+
return options.map(option => {
55+
if (typeof option === 'string') {
56+
return {
57+
label: option,
58+
value: option,
59+
};
60+
}
61+
return option;
62+
});
63+
}
64+
toggleOption = (option) => {
65+
const optionIndex = this.state.value.indexOf(option.value);
66+
const value = [...this.state.value];
67+
if (optionIndex === - 1) {
68+
value.push(option.value);
69+
} else {
70+
value.splice(optionIndex, 1);
71+
}
72+
if (!('value' in this.props)) {
73+
this.setState({ value });
74+
}
75+
const onChange = this.props.onChange;
76+
if (onChange) {
77+
onChange(value);
78+
}
79+
}
80+
render() {
81+
const { props, state } = this;
82+
const { prefixCls, className, options } = props;
83+
let children = props.children;
84+
if (options && options.length > 0) {
85+
children = this.getOptions().map(option => (
86+
<Checkbox
87+
key={option.value}
88+
disabled={'disabled' in option ? option.disabled : props.disabled}
89+
value={option.value}
90+
checked={state.value.indexOf(option.value) !== -1}
91+
onChange={() => this.toggleOption(option)}
92+
className={`${prefixCls}-item`}
93+
>
94+
{option.label}
95+
</Checkbox>
96+
));
97+
}
98+
99+
const classString = classNames(prefixCls, className);
100+
return (
101+
<div className={classString}>
102+
{children}
103+
</div>
104+
);
105+
}
106+
}

src/RCheckbox.js

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import React, { PureComponent } from 'react';
2+
import PropTypes from 'prop-types';
3+
import classNames from 'classnames';
4+
5+
export default class Checkbox extends PureComponent {
6+
static propTypes = {
7+
prefixCls: PropTypes.string,
8+
className: PropTypes.string,
9+
style: PropTypes.object,
10+
name: PropTypes.string,
11+
type: PropTypes.string,
12+
defaultChecked: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
13+
checked: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
14+
disabled: PropTypes.bool,
15+
onFocus: PropTypes.func,
16+
onBlur: PropTypes.func,
17+
onChange: PropTypes.func,
18+
onClick: PropTypes.func,
19+
tabIndex: PropTypes.string,
20+
readOnly: PropTypes.bool,
21+
};
22+
static defaultProps = {
23+
prefixCls: 'nex-checkbox',
24+
className: '',
25+
style: {},
26+
type: 'checkbox',
27+
defaultChecked: false,
28+
onFocus() {},
29+
onBlur() {},
30+
onChange() {},
31+
};
32+
constructor(props) {
33+
super(props);
34+
35+
const checked = 'checked' in props ? props.checked : props.defaultChecked;
36+
37+
this.state = {
38+
checked,
39+
};
40+
}
41+
42+
componentWillReceiveProps(nextProps) {
43+
if ('checked' in nextProps) {
44+
this.setState({
45+
checked: nextProps.checked,
46+
});
47+
}
48+
}
49+
50+
handleChange = (e) => {
51+
const { props } = this;
52+
if (props.disabled) {
53+
return;
54+
}
55+
if (!('checked' in props)) {
56+
this.setState({
57+
checked: e.target.checked,
58+
});
59+
}
60+
props.onChange({
61+
target: {
62+
...props,
63+
checked: e.target.checked,
64+
},
65+
stopPropagation() {
66+
e.stopPropagation();
67+
},
68+
preventDefault() {
69+
e.preventDefault();
70+
},
71+
});
72+
};
73+
74+
render() {
75+
const {
76+
prefixCls,
77+
className,
78+
style,
79+
name,
80+
type,
81+
disabled,
82+
readOnly,
83+
tabIndex,
84+
onClick,
85+
onFocus,
86+
onBlur,
87+
indeterminate,
88+
...others,
89+
} = this.props;
90+
91+
const globalProps = Object.keys(others).reduce((prev, key) => {
92+
if (key.substr(0, 5) === 'aria-' || key.substr(0, 5) === 'data-' || key === 'role') {
93+
prev[key] = others[key];
94+
}
95+
return prev;
96+
}, {});
97+
98+
const { checked } = this.state;
99+
const classString = classNames(prefixCls, className, {
100+
[`${prefixCls}-checked`]: checked,
101+
[`${prefixCls}-indeterminate`]: indeterminate,
102+
[`${prefixCls}-disabled`]: disabled,
103+
});
104+
105+
return (
106+
<span className={classString} style={style}>
107+
<input
108+
name={name}
109+
type={type}
110+
readOnly={readOnly}
111+
disabled={disabled}
112+
tabIndex={tabIndex}
113+
className={`${prefixCls}-input`}
114+
checked={!!checked}
115+
onClick={onClick}
116+
onFocus={onFocus}
117+
onBlur={onBlur}
118+
onChange={this.handleChange}
119+
{...globalProps}
120+
/>
121+
<span className={`${prefixCls}-inner`} />
122+
</span>
123+
);
124+
}
125+
}

0 commit comments

Comments
 (0)