-
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.
New: Radio and RadioGroup components
- Loading branch information
1 parent
6a477f9
commit ef78c7a
Showing
9 changed files
with
486 additions
and
26 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,89 @@ | ||
import React from 'react'; | ||
import Example from '../components/Example'; | ||
import RadioGroup from 'adslot-ui/RadioGroup'; | ||
import Radio from 'adslot-ui/Radio'; | ||
|
||
class RadioGroupExample extends React.PureComponent { | ||
onChangeGroup(event) { | ||
_.noop(); | ||
} | ||
|
||
onChangeIndividual(event) { | ||
_.noop(); | ||
} | ||
|
||
render() { | ||
return ( | ||
<RadioGroup name="hobbies" value="badminton" onChange={this.onChangeGroup} dts="radio-group-dts"> | ||
<Radio value="swimming" label="Swimming" dts="radio-dts" /> | ||
<Radio value="soccer" label="Soccer" onChange={this.onChangeIndividual} /> | ||
<Radio value="badminton" label="Badminton" /> | ||
</RadioGroup> | ||
); | ||
} | ||
} | ||
|
||
const exampleProps = { | ||
componentName: 'RadioGroup', | ||
designNotes: ( | ||
<p> | ||
<span className="text-bold">Radio buttons</span> used for making a single selection from multiple options. Only | ||
one selection can ever be made from the radio button group at a time. | ||
</p> | ||
), | ||
notes: '', | ||
exampleCodeSnippet: `<RadioGroup name="hobbies" value="badminton" onChange={this.onChangeGroup} dts="radio-group-dts"> | ||
<Radio value="swimming" label="Swimming" dts="radio-dts" /> | ||
<Radio value="soccer" label="Soccer" onChange={this.onChangeIndividual} /> | ||
<Radio value="badminton" label="Badminton" /> | ||
</RadioGroup>`, | ||
propTypeSectionArray: [ | ||
{ | ||
propTypes: [ | ||
{ | ||
propType: 'name', | ||
type: 'string', | ||
note: ( | ||
<span> | ||
<strong>Required.</strong> All Radio buttons within this group will have the same name | ||
</span> | ||
), | ||
}, | ||
{ | ||
propType: 'value', | ||
type: 'string', | ||
note: 'value of the selected radio button', | ||
}, | ||
{ | ||
propType: 'onChange', | ||
type: 'func', | ||
note: 'Triggers when selection changes.', | ||
}, | ||
{ | ||
propType: 'children', | ||
type: 'node', | ||
note: `Should be an array of <Radio /> components`, | ||
}, | ||
{ | ||
propType: 'className', | ||
type: 'string', | ||
}, | ||
{ | ||
propType: 'dts', | ||
type: 'string', | ||
note: 'render `data-test-selector` onto the component. It can be useful for testing.', | ||
}, | ||
{ | ||
propType: 'id', | ||
type: 'string', | ||
}, | ||
], | ||
}, | ||
], | ||
}; | ||
|
||
export default () => ( | ||
<Example {...exampleProps}> | ||
<RadioGroupExample /> | ||
</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,68 @@ | ||
import _ from 'lodash'; | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { expandDts } from 'lib/utils'; | ||
|
||
class RadioButton extends React.Component { | ||
static getDerivedStateFromProps(newProps, prevState) { | ||
return newProps.checked === prevState.checked ? null : { checked: newProps.checked }; | ||
} | ||
|
||
constructor(props) { | ||
super(props); | ||
this.state = { checked: props.checked }; | ||
|
||
this.onChangeDefault = this.onChangeDefault.bind(this); | ||
} | ||
|
||
onChangeDefault(event) { | ||
this.setState({ checked: Boolean(event.target.checked) }); | ||
if (this.props.onChange) { | ||
this.props.onChange(event); | ||
} | ||
} | ||
|
||
render() { | ||
const { name, className, label, dts, disabled, id, value } = this.props; | ||
|
||
const radioInputProps = { | ||
type: 'radio', | ||
name, | ||
checked: this.state.checked, | ||
disabled, | ||
onChange: this.onChangeDefault, | ||
value, | ||
}; | ||
|
||
const optionalProps = _.pickBy({ | ||
id, | ||
className, | ||
}); | ||
|
||
return ( | ||
<div className="radio-component" {...expandDts(dts)}> | ||
<input {...radioInputProps} {...optionalProps} /> | ||
{label ? <span>{label}</span> : null} | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
RadioButton.propTypes = { | ||
id: PropTypes.string, | ||
className: PropTypes.string, | ||
name: PropTypes.string, | ||
label: PropTypes.node, | ||
dts: PropTypes.string, | ||
disabled: PropTypes.bool, | ||
checked: PropTypes.bool, | ||
onChange: PropTypes.func, | ||
value: PropTypes.string, | ||
}; | ||
|
||
RadioButton.defaultProps = { | ||
disabled: false, | ||
checked: false, | ||
}; | ||
|
||
export default RadioButton; |
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,81 @@ | ||
import _ from 'lodash'; | ||
import React from 'react'; | ||
import { shallow } from 'enzyme'; | ||
import sinon from 'sinon'; | ||
import Radio from '.'; | ||
|
||
describe('<Radio />', () => { | ||
let props; | ||
|
||
beforeEach(() => { | ||
props = { | ||
name: 'radio-name', | ||
value: 'radio-value', | ||
label: 'Radio 1', | ||
dts: 'radio-dts', | ||
id: 'radio-id', | ||
className: 'radio-class', | ||
disabled: false, | ||
checked: false, | ||
onChange: sinon.spy(), | ||
}; | ||
}); | ||
|
||
it('should render with props', () => { | ||
const component = shallow(<Radio {...props} />); | ||
expect(component.find('input[type="radio"]')).to.have.length(1); | ||
expect(component.text()).to.equal('Radio 1'); | ||
expect(component.find('[name="radio-name"]')).to.have.length(1); | ||
expect(component.find('[value="radio-value"]')).to.have.length(1); | ||
expect(component.find('[data-test-selector="radio-dts"]')).to.have.length(1); | ||
}); | ||
|
||
it('should not render label if props.label is undefined', () => { | ||
delete props.label; | ||
const component = shallow(<Radio {...props} />); | ||
expect(component.text()).to.equal(''); | ||
}); | ||
|
||
it('should trigger state change and `props.onChange` when change event is triggered', () => { | ||
const component = shallow(<Radio {...props} />); | ||
const event = { target: { checked: true } }; | ||
|
||
expect(component.state('checked')).to.equal(false); | ||
|
||
component.find('input').simulate('change', event); | ||
expect(component.state('checked')).to.equal(true); | ||
expect(props.onChange.calledOnce).to.equal(true); | ||
}); | ||
|
||
it('should still trigger state change when `props.onChange` is not present', () => { | ||
delete props.onChange; | ||
const component = shallow(<Radio {...props} />); | ||
const event = { target: { checked: true } }; | ||
|
||
expect(component.state('checked')).to.equal(false); | ||
|
||
component.find('input').simulate('change', event); | ||
expect(component.state('checked')).to.equal(true); | ||
}); | ||
|
||
it('should override state value when `prop.value` changes', () => { | ||
const component = shallow(<Radio {...props} />); | ||
expect(component.state('checked')).to.equal(false); | ||
|
||
props.checked = true; | ||
component.setProps(props); | ||
expect(component.state('checked')).to.equal(true); | ||
}); | ||
|
||
it('should NOT override state value when other props change', () => { | ||
const component = shallow(<Radio {...props} />); | ||
expect(component.state('checked')).to.equal(false); | ||
|
||
_.assign(props, { | ||
name: 'some-other-name', | ||
label: 'New Label', | ||
}); | ||
component.setProps(props); | ||
expect(component.state('checked')).to.equal(false); | ||
}); | ||
}); |
Oops, something went wrong.