-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#658 Allow Create functionality [WIP] #660
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import React from 'react'; | ||
import Select from 'react-select'; | ||
|
||
const FLAVOURS = [ | ||
{ label: 'Chocolate', value: 'chocolate' }, | ||
{ label: 'Vanilla', value: 'vanilla' }, | ||
{ label: 'Strawberry', value: 'strawberry' }, | ||
{ label: 'Caramel', value: 'caramel' }, | ||
{ label: 'Cookies and Cream', value: 'cookiescream' }, | ||
{ label: 'Peppermint', value: 'peppermint' }, | ||
]; | ||
|
||
var AllowCreate = React.createClass({ | ||
displayName: 'AllowCreate', | ||
|
||
propTypes: { | ||
allowCreate: React.PropTypes.bool, | ||
label: React.PropTypes.string, | ||
}, | ||
|
||
getInitialState () { | ||
return { | ||
disabled: false, | ||
crazy: false, | ||
options: FLAVOURS, | ||
value: [], | ||
}; | ||
}, | ||
|
||
onLabelClick (data, event) { | ||
console.log(data, event); | ||
}, | ||
|
||
handleSelectChange (value){ | ||
this.setState({ value }); | ||
}, | ||
|
||
renderHint () { | ||
return ( | ||
<div className="hint">Create options in tag mode</div> | ||
); | ||
}, | ||
|
||
render () { | ||
return ( | ||
<div className="section"> | ||
<h3 className="section-heading">{this.props.label}</h3> | ||
<Select | ||
allowCreate={this.props.allowCreate} | ||
value={this.state.value} | ||
multi={true} | ||
placeholder="Select your favourite(s)" | ||
options={this.state.options} | ||
onChange={this.handleSelectChange} /> | ||
{this.renderHint()} | ||
</div> | ||
); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ES6 extra comma |
||
}); | ||
|
||
module.exports = AllowCreate; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New line at the end of the file please :) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ const Option = React.createClass({ | |
onFocus: React.PropTypes.func, // method to handle mouseEnter on option element | ||
onUnfocus: React.PropTypes.func, // method to handle mouseLeave on option element | ||
option: React.PropTypes.object.isRequired, // object that is base for that option | ||
addLabelText: React.PropTypes.string, // text to display with value while creating new option | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor fix, can you align the comment with the lines above. |
||
}, | ||
blockEvent (event) { | ||
event.preventDefault(); | ||
|
@@ -39,7 +40,6 @@ const Option = React.createClass({ | |
render () { | ||
var { option } = this.props; | ||
var className = classNames(this.props.className, option.className); | ||
|
||
return option.disabled ? ( | ||
<div className={className} | ||
onMouseDown={this.blockEvent} | ||
|
@@ -53,7 +53,7 @@ const Option = React.createClass({ | |
onMouseEnter={this.handleMouseEnter} | ||
onMouseMove={this.handleMouseMove} | ||
title={option.title}> | ||
{this.props.children} | ||
{ option.create ? this.props.addLabelText.replace('{label}', option.label) : this.props.children } | ||
</div> | ||
); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -582,9 +582,19 @@ const Select = React.createClass({ | |
}, | ||
|
||
renderMenu (options, valueArray, focusedOption) { | ||
if (options && options.length) { | ||
if (options && options.length || this.props.allowCreate) { | ||
let Option = this.props.optionComponent; | ||
let renderLabel = this.props.optionRenderer || this.getOptionLabel; | ||
let inputValue = this.state.inputValue.trim(); | ||
if (this.props.allowCreate && inputValue) { | ||
options = options.slice(); | ||
let newOption = this.props.newOptionCreator ? this.props.newOptionCreator(inputValue) : { | ||
value: inputValue, | ||
label: inputValue, | ||
create: true | ||
}; | ||
options.unshift(newOption); | ||
} | ||
return options.map((option, i) => { | ||
let isSelected = valueArray && valueArray.indexOf(option) > -1; | ||
let isFocused = option === focusedOption; | ||
|
@@ -606,12 +616,15 @@ const Select = React.createClass({ | |
option={option} | ||
isSelected={isSelected} | ||
ref={optionRef} | ||
addLabelText={this.props.addLabelText} | ||
> | ||
{renderLabel(option)} | ||
</Option> | ||
); | ||
}); | ||
} else { | ||
} else if (this.props.allowCreate){ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What needs to go in here? |
||
} else{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One more space |
||
return ( | ||
<div className="Select-noresults"> | ||
{this.props.noResultsText} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1047,7 +1047,7 @@ describe('Select', () => { | |
describe('with allowCreate=true', () => { | ||
|
||
// TODO: allowCreate hasn't been implemented yet in 1.x | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove comment |
||
return; | ||
// return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess you can just remove the line completely, and the TODO comment as well :) when finished |
||
|
||
beforeEach(() => { | ||
|
||
|
@@ -1060,20 +1060,22 @@ describe('Select', () => { | |
{ value: 'three', label: 'Three' }, | ||
{ value: 'zzzzz', label: 'test value' } | ||
]; | ||
|
||
setValueProp('xyz'); | ||
|
||
// Render an instance of the component | ||
wrapper = createControlWithWrapper({ | ||
value: 'one', | ||
options: options, | ||
allowCreate: true, | ||
searchable: true, | ||
addLabelText: 'Add {label} to values?' | ||
}, { | ||
wireUpOnChangeToValue: true | ||
}); | ||
}); | ||
|
||
it('has an "Add xyz" option when entering xyz', () => { | ||
typeSearchText('xyz'); | ||
|
||
expect(ReactDOM.findDOMNode(instance), 'queried for', '.Select-menu .Select-option', | ||
'to have items satisfying', 'to have text', 'Add xyz to values?'); | ||
}); | ||
|
@@ -1108,28 +1110,12 @@ describe('Select', () => { | |
|
||
it('displays an add option when a value with spaces is entered', () => { | ||
|
||
typeSearchText('got'); | ||
typeSearchText(' got '); | ||
|
||
expect(ReactDOM.findDOMNode(instance).querySelectorAll('.Select-menu .Select-option')[0], | ||
'to have text', 'Add got to values?'); | ||
}); | ||
|
||
it('displays an add option when a value with spaces is entered', () => { | ||
|
||
typeSearchText('got'); | ||
|
||
expect(ReactDOM.findDOMNode(instance).querySelectorAll('.Select-menu .Select-option')[0], | ||
'to have text', 'Add got to values?'); | ||
}); | ||
|
||
it('displays an add option when a label with spaces is entered', () => { | ||
|
||
typeSearchText('test'); | ||
|
||
expect(ReactDOM.findDOMNode(instance).querySelectorAll('.Select-menu .Select-option')[0], | ||
'to have text', 'Add test to values?'); | ||
}); | ||
|
||
it('does not display the option label when an existing value is entered', () => { | ||
|
||
typeSearchText('zzzzz'); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally preferred that boolean props that are true don't have an explicit declaration. remove the
={true}
e.g. https://github.com/JedWatson/react-select/blob/master/examples/src/components/NumericSelect.js#L66