-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update: Checkbox and CheckboxGroup components
- Loading branch information
Showing
10 changed files
with
493 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import _ from 'lodash'; | ||
import React from 'react'; | ||
import Example from '../components/Example'; | ||
import { CheckboxGroup, Checkbox } from '../../src'; | ||
|
||
const onChangeGroup = (value, event, name) => { | ||
_.noop(); | ||
}; | ||
|
||
const onChangeIndividual = (value, event, name) => { | ||
_.noop(); | ||
}; | ||
|
||
class CheckboxGroupExample extends React.PureComponent { | ||
render() { | ||
return ( | ||
<CheckboxGroup name="movies" value={['terminator', 'predator']} onChange={onChangeGroup}> | ||
<Checkbox label="The Terminator" value="terminator" onChange={onChangeIndividual} /> | ||
<Checkbox label="Predator" value="predator" /> | ||
<Checkbox label="The Sound of Music" value="soundofmusic" /> | ||
</CheckboxGroup> | ||
); | ||
} | ||
} | ||
|
||
const exampleProps = { | ||
componentName: 'CheckboxGroup', | ||
notes: 'Contains individual checkboxes. The state of child checkboxes is held in an array.', | ||
exampleCodeSnippet: `<CheckboxGroup name="movies" value={['terminator', 'predator']} onChange={onChangeGroup}> | ||
<Checkbox label="The Terminator" value="terminator" onChange={onChangeIndividual} /> | ||
<Checkbox label="Predator" value="predator" /> | ||
<Checkbox label="The Sound of Music" value="soundofmusic" /> | ||
</CheckboxGroup>`, | ||
propTypeSectionArray: [ | ||
{ | ||
label: '', | ||
propTypes: [ | ||
{ | ||
propType: 'name', | ||
type: 'string', | ||
}, | ||
{ | ||
propType: 'value', | ||
type: 'arrayOf(string: value, ...)', | ||
note: "The strings must be the values of the group's child Checkboxes", | ||
}, | ||
{ | ||
propType: 'children', | ||
type: '<Checkbox /> elements', | ||
}, | ||
{ | ||
propType: 'onChange', | ||
type: 'Function', | ||
}, | ||
], | ||
}, | ||
], | ||
}; | ||
|
||
export default () => ( | ||
<Example {...exampleProps}> | ||
<CheckboxGroupExample /> | ||
</Example> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { expandDts } from 'lib/utils'; | ||
|
||
import './styles.scss'; | ||
|
||
class Checkbox extends React.Component { | ||
static getDerivedStateFromProps(newProps, prevState) { | ||
let isChecked = prevState.checked; | ||
let isDisabled = prevState.disabled; | ||
if (newProps.checked) isChecked = newProps.checked; | ||
if (newProps.disabled) isDisabled = newProps.disabled; | ||
return { | ||
checked: isChecked, | ||
disabled: isDisabled, | ||
}; | ||
} | ||
|
||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
checked: props.checked, | ||
disabled: props.disabled, | ||
}; | ||
this.onChangeDefault = this.onChangeDefault.bind(this); | ||
if (this.props.onChange) { | ||
this.onChange = this.props.onChange.bind(this); | ||
} | ||
} | ||
|
||
onChangeDefault(event) { | ||
const isChecked = Boolean(event.target.checked); | ||
const isDisabled = Boolean(event.target.disabled); | ||
this.setState(() => ({ | ||
checked: isChecked, | ||
disabled: isDisabled, | ||
})); | ||
if (this.onChange) { | ||
this.onChange(event, this.props.name); | ||
} | ||
} | ||
|
||
render() { | ||
const { name, value, label, dts } = this.props; | ||
const optional = { | ||
id: this.props.id ? this.props.id : null, | ||
className: this.props.className ? this.props.className : null, | ||
}; | ||
if (this.props['data-name']) { | ||
optional['data-name'] = this.props['data-name']; | ||
} | ||
return ( | ||
<label className="checkbox-single"> | ||
<input | ||
type="checkbox" | ||
name={name} | ||
value={value} | ||
onChange={this.onChangeDefault} | ||
disabled={this.state.disabled} | ||
checked={this.state.checked} | ||
{...expandDts(dts)} | ||
{...optional} | ||
/> | ||
{label ? <span>{label}</span> : null} | ||
</label> | ||
); | ||
} | ||
} | ||
|
||
Checkbox.propTypes = { | ||
id: PropTypes.string, | ||
className: PropTypes.string, | ||
'data-name': PropTypes.string, | ||
name: PropTypes.string, | ||
label: PropTypes.node, | ||
value: PropTypes.string, | ||
dts: PropTypes.string, | ||
disabled: PropTypes.bool, | ||
checked: PropTypes.bool, | ||
onChange: PropTypes.func, | ||
}; | ||
|
||
Checkbox.defaultProps = { | ||
dts: '', | ||
disabled: false, | ||
checked: false, | ||
}; | ||
|
||
export default Checkbox; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import React from 'react'; | ||
import { shallow, mount } from 'enzyme'; | ||
import sinon from 'sinon'; | ||
import Checkbox from '.'; | ||
|
||
describe('Checkbox', () => { | ||
it('should render with props', () => { | ||
const component = shallow( | ||
<Checkbox label="The Terminator" name="movies" value="terminator" dts="checkbox-terminator" /> | ||
); | ||
const checkboxElement = component.find('input[type="checkbox"]'); | ||
const labelElement = component.find('label'); | ||
expect(labelElement.text()).to.equal('The Terminator'); | ||
expect(checkboxElement).to.have.length(1); | ||
expect(checkboxElement.prop('name')).to.equal('movies'); | ||
expect(checkboxElement.prop('value')).to.equal('terminator'); | ||
expect(checkboxElement.prop('checked')).to.equal(false); | ||
expect(checkboxElement.prop('data-test-selector')).to.equal('checkbox-terminator'); | ||
}); | ||
|
||
it('should render with just label', () => { | ||
const component = shallow(<Checkbox label="Label goes here" />); | ||
const checkboxElement = component.find('input[type="checkbox"]'); | ||
expect(checkboxElement).to.have.length(1); | ||
const labelElement = component.find('label'); | ||
expect(labelElement.text()).to.equal('Label goes here'); | ||
}); | ||
|
||
it('should render with just onChange', () => { | ||
const onChangeHandler = sinon.spy(); | ||
const component = shallow(<Checkbox onChange={onChangeHandler} />); | ||
const checkboxElement = component.find('input[type="checkbox"]'); | ||
const event = { target: { checked: true, disabled: false } }; | ||
checkboxElement.simulate('change', event); | ||
expect(onChangeHandler.callCount).to.equal(1); | ||
expect(component.state()).to.eql({ checked: true, disabled: false }); | ||
}); | ||
|
||
it('should render with id, className, and data-name', () => { | ||
const onChangeHandler = sinon.spy(); | ||
const component = shallow( | ||
<Checkbox onChange={onChangeHandler} id="checkboxId" className="checkboxClass" data-name="checkboxName" /> | ||
); | ||
const checkboxElement = component.find('input[type="checkbox"]'); | ||
const event = { target: { checked: true, disabled: false } }; | ||
checkboxElement.simulate('change', event); | ||
expect(onChangeHandler.callCount).to.equal(1); | ||
expect(component.state()).to.eql({ checked: true, disabled: false }); | ||
}); | ||
|
||
it('should handle change event', () => { | ||
const onChangeHandler = sinon.spy(); | ||
const component = shallow( | ||
<Checkbox | ||
label="The Terminator" | ||
name="movies" | ||
value="terminator" | ||
onChange={onChangeHandler} | ||
dts="checkbox-terminator" | ||
/> | ||
); | ||
const checkboxElement = component.find('input[type="checkbox"]'); | ||
const event = { target: { checked: true, disabled: true } }; | ||
checkboxElement.simulate('change', event); | ||
expect(onChangeHandler.callCount).to.equal(1); | ||
expect(component.state()).to.eql({ checked: true, disabled: true }); | ||
}); | ||
|
||
it('should render without a label', () => { | ||
const component = shallow(<Checkbox name="movies" value="terminator" />); | ||
const labelElement = component.find('label'); | ||
expect(labelElement.text()).to.equal(''); | ||
}); | ||
|
||
it('should render with checked and disabled states', () => { | ||
const component = shallow( | ||
<Checkbox | ||
name="movies" | ||
value="terminator" | ||
checked={true} // eslint-disable-line | ||
disabled={true} // eslint-disable-line | ||
/> | ||
); | ||
expect(component.state()).to.eql({ checked: true, disabled: true }); | ||
}); | ||
|
||
it('should handle change events without a custom onChange handler', () => { | ||
const component = shallow(<Checkbox name="movies" value="terminator" />); | ||
const checkboxElement = component.find('input[type="checkbox"]'); | ||
const event = { target: { checked: true, disabled: false } }; | ||
checkboxElement.simulate('change', event); | ||
expect(component.state()).to.eql({ checked: true, disabled: false }); | ||
}); | ||
|
||
it('should handle props changes', () => { | ||
const component = mount(<Checkbox name="movies" value="terminator" />); | ||
component.setProps({ checked: true, disabled: true }); | ||
expect(component.state()).to.eql({ checked: true, disabled: true }); | ||
}); | ||
|
||
it('should handle props changes when no relevant props are given', () => { | ||
const component = mount(<Checkbox name="movies" value="terminator" />); | ||
component.setProps({ foo: 'bar' }); | ||
expect(component.state()).to.eql({ checked: false, disabled: false }); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
.checkbox-single { | ||
line-height: 16px; | ||
display: block; | ||
|
||
span { | ||
margin: 0 0 0 5px; | ||
} | ||
|
||
input { | ||
margin: 0; | ||
line-height: 16px; | ||
display: inline-block; | ||
} | ||
} |
Oops, something went wrong.