-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Extract components #352
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
Merged
Merged
Extract components #352
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
ee8d1e9
extract option component and allow to pass as prop
fa35c42
allow to use passed in props value component or default
b7e751a
add SingleValue component to handle single selection mode
8f5fa75
add desc to propTypes and fix naming convention
a572edb
add props for external optionCreator
4faecf2
fix tests
a1a8648
fix linter warnings
198f684
fix to use value instead of option prop
ee3b4bd
add example with user avatars in menu and value
6a69e5e
Fix undefined val variable
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,33 @@ | ||
| var React = require('react'); | ||
|
|
||
| var Gravatar = require('react-gravatar'); | ||
|
|
||
| var Option = React.createClass({ | ||
| propTypes: { | ||
| addLabelText: React.PropTypes.string, | ||
| className: React.PropTypes.string, | ||
| mouseDown: React.PropTypes.func, | ||
| mouseEnter: React.PropTypes.func, | ||
| mouseLeave: React.PropTypes.func, | ||
| option: React.PropTypes.object.isRequired, | ||
| renderFunc: React.PropTypes.func | ||
| }, | ||
|
|
||
| render: function() { | ||
| var obj = this.props.option; | ||
| var size = 15; | ||
|
|
||
| return ( | ||
| <div className={this.props.className} | ||
| onMouseEnter={this.props.mouseEnter} | ||
| onMouseLeave={this.props.mouseLeave} | ||
| onMouseDown={this.props.mouseDown} | ||
| onClick={this.props.mouseDown}> | ||
| <Gravatar email={obj.email} size={size}/> | ||
| {obj.value} | ||
| </div> | ||
| ); | ||
| } | ||
| }); | ||
|
|
||
| module.exports = Option; |
This file contains hidden or 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,30 @@ | ||
| var React = require('react'); | ||
| var Gravatar = require('react-gravatar'); | ||
|
|
||
| var SingleValue = React.createClass({ | ||
| propTypes: { | ||
| placeholder: React.PropTypes.string, | ||
| value: React.PropTypes.object | ||
| }, | ||
|
|
||
| render: function() { | ||
| var obj = this.props.value; | ||
| var size = 15; | ||
|
|
||
| return ( | ||
| <div className="Select-placeholder"> | ||
| {obj ? ( | ||
| <div> | ||
| <Gravatar email={obj.email} size={size}/> | ||
| {obj.value} | ||
| </div> | ||
| ) : ( | ||
| this.props.placeholder | ||
| ) | ||
| } | ||
| </div> | ||
| ); | ||
| } | ||
| }); | ||
|
|
||
| module.exports = SingleValue; |
This file contains hidden or 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 hidden or 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,5 @@ | ||
| exports.users = [ | ||
| { value: 'John Smith', label: 'John Smith', email: 'john@smith.com' }, | ||
| { value: 'Merry Jane', label: 'Merry Jane', email: 'merry@jane.com' }, | ||
| { value: 'Stan Hoper', label: 'Stan Hoper', email: 'stan@hoper.com' } | ||
| ]; |
This file contains hidden or 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 hidden or 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,32 @@ | ||
| var React = require('react'); | ||
|
|
||
| var Option = React.createClass({ | ||
| propTypes: { | ||
| addLabelText: React.PropTypes.string, // string rendered in case of allowCreate option passed to ReactSelect | ||
| className: React.PropTypes.string, // className (based on mouse position) | ||
| mouseDown: React.PropTypes.func, // method to handle click on option element | ||
| mouseEnter: React.PropTypes.func, // method to handle mouseEnter on option element | ||
| mouseLeave: React.PropTypes.func, // method to handle mouseLeave on option element | ||
| option: React.PropTypes.object.isRequired, // object that is base for that option | ||
| renderFunc: React.PropTypes.func // method passed to ReactSelect component to render label text | ||
| }, | ||
|
|
||
| render: function() { | ||
| var obj = this.props.option; | ||
| var renderedLabel = this.props.renderFunc(obj); | ||
|
|
||
| return obj.disabled ? ( | ||
| <div className={this.props.className}>{renderedLabel}</div> | ||
| ) : ( | ||
| <div className={this.props.className} | ||
| onMouseEnter={this.props.mouseEnter} | ||
| onMouseLeave={this.props.mouseLeave} | ||
| onMouseDown={this.props.mouseDown} | ||
| onClick={this.props.mouseDown}> | ||
| { obj.create ? this.props.addLabelText.replace('{label}', obj.label) : renderedLabel } | ||
| </div> | ||
| ); | ||
| } | ||
| }); | ||
|
|
||
| module.exports = Option; |
This file contains hidden or 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 |
|---|---|---|
|
|
@@ -6,6 +6,8 @@ var React = require('react'); | |
| var Input = require('react-input-autosize'); | ||
| var classes = require('classnames'); | ||
| var Value = require('./Value'); | ||
| var SingleValue = require('./SingleValue'); | ||
| var Option = require('./Option'); | ||
|
|
||
| var requestId = 0; | ||
|
|
||
|
|
@@ -44,7 +46,11 @@ var Select = React.createClass({ | |
| searchable: React.PropTypes.bool, // whether to enable searching feature or not | ||
| searchPromptText: React.PropTypes.string, // label to prompt for search input | ||
| value: React.PropTypes.any, // initial field value | ||
| valueRenderer: React.PropTypes.func // valueRenderer: function(option) {} | ||
| valueRenderer: React.PropTypes.func, // valueRenderer: function(option) {} | ||
| optionComponent: React.PropTypes.func, // option component to render in dropdown | ||
| valueComponent: React.PropTypes.func, // value component to render in multiple mode | ||
| singleValueComponent: React.PropTypes.func,// single value component when multiple is set to false | ||
| newOptionCreator: React.PropTypes.func // factory to create new options when allowCreate set | ||
| }, | ||
|
|
||
| getDefaultProps: function() { | ||
|
|
@@ -72,7 +78,11 @@ var Select = React.createClass({ | |
| placeholder: 'Select...', | ||
| searchable: true, | ||
| searchPromptText: 'Type to search', | ||
| value: undefined | ||
| value: undefined, | ||
| optionComponent: Option, | ||
| valueComponent: Value, | ||
| singleValueComponent: SingleValue, | ||
| newOptionCreator: undefined | ||
| }; | ||
| }, | ||
|
|
||
|
|
@@ -659,11 +669,12 @@ var Select = React.createClass({ | |
| if (this.props.allowCreate && this.state.inputValue.trim()) { | ||
| var inputValue = this.state.inputValue; | ||
| options = options.slice(); | ||
| options.unshift({ | ||
| var newOption = this.props.newOptionCreator ? this.props.newOptionCreator(inputValue) : { | ||
| value: inputValue, | ||
| label: inputValue, | ||
| create: true | ||
| }); | ||
| }; | ||
| options.unshift(newOption); | ||
| } | ||
|
|
||
| var ops = Object.keys(options).map(function(key) { | ||
|
|
@@ -683,13 +694,21 @@ var Select = React.createClass({ | |
| var mouseEnter = this.focusOption.bind(this, op); | ||
| var mouseLeave = this.unfocusOption.bind(this, op); | ||
| var mouseDown = this.selectValue.bind(this, op); | ||
| var renderedLabel = renderLabel(op); | ||
|
|
||
| return op.disabled ? ( | ||
| <div ref={ref} key={'option-' + op.value} className={optionClass}>{renderedLabel}</div> | ||
| ) : ( | ||
| <div ref={ref} key={'option-' + op.value} className={optionClass} onMouseEnter={mouseEnter} onMouseLeave={mouseLeave} onMouseDown={mouseDown} onClick={mouseDown}>{ op.create ? this.props.addLabelText.replace('{label}', op.label) : renderedLabel}</div> | ||
| ); | ||
| var optionResult = React.createElement(this.props.optionComponent, { | ||
| key: 'option-' + op.value, | ||
| className: optionClass, | ||
| renderFunc: renderLabel, | ||
| mouseEnter: mouseEnter, | ||
| mouseLeave: mouseLeave, | ||
| mouseDown: mouseDown, | ||
| click: mouseDown, | ||
| addLabelText: this.props.addLabelText, | ||
| option: op, | ||
| ref: ref | ||
| }); | ||
|
|
||
| return optionResult; | ||
| }, this); | ||
|
|
||
| return ops.length ? ops : ( | ||
|
|
@@ -720,29 +739,39 @@ var Select = React.createClass({ | |
|
|
||
| if (this.props.multi) { | ||
| this.state.values.forEach(function(val) { | ||
| value.push(<Value | ||
| key={val.value} | ||
| option={val} | ||
| renderer={this.props.valueRenderer} | ||
| optionLabelClick={!!this.props.onOptionLabelClick} | ||
| onOptionLabelClick={this.handleOptionLabelClick.bind(this, val)} | ||
| onRemove={this.removeValue.bind(this, val)} | ||
| disabled={this.props.disabled} />); | ||
| var onOptionLabelClick = this.handleOptionLabelClick.bind(this, val); | ||
| var onRemove = this.removeValue.bind(this, val); | ||
|
|
||
| var valueComponent = React.createElement(this.props.valueComponent, { | ||
| key: val.value, | ||
| option: val, | ||
| renderer: this.props.valueRenderer, | ||
| optionLabelClick: !!this.props.onOptionLabelClick, | ||
| onOptionLabelClick: onOptionLabelClick, | ||
| onRemove: onRemove, | ||
| disabled: this.props.disabled | ||
| }); | ||
|
|
||
| value.push(valueComponent); | ||
| }, this); | ||
| } | ||
|
|
||
| if(!this.state.inputValue && (!this.props.multi || !value.length)) { | ||
| var val = this.state.values[0] || null; | ||
| if(this.props.valueRenderer && !!this.state.values.length) { | ||
| var val = this.state.values[0] || null; | ||
| value.push(<Value | ||
| key={0} | ||
| option={val} | ||
|
Collaborator
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. val used here, without being defined |
||
| renderer={this.props.valueRenderer} | ||
| disabled={this.props.disabled} />); | ||
| } else { | ||
| value.push(<div className="Select-placeholder" key="placeholder">{this.state.placeholder}</div>); | ||
| var singleValueComponent = React.createElement(this.props.singleValueComponent, { | ||
| key: 'placeholder', | ||
| value: val, | ||
| placeholder: this.state.placeholder | ||
| }); | ||
| value.push(singleValueComponent); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| var loading = this.state.isLoading ? <span className="Select-loading" aria-hidden="true" /> : null; | ||
|
|
||
This file contains hidden or 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,16 @@ | ||
| var React = require('react'); | ||
|
|
||
| var SingleValue = React.createClass({ | ||
| propTypes: { | ||
| placeholder: React.PropTypes.string, // this is default value provided by React-Select based component | ||
| value: React.PropTypes.object // selected option | ||
| }, | ||
|
|
||
| render: function() { | ||
| return ( | ||
| <div className="Select-placeholder">{this.props.placeholder}</div> | ||
| ); | ||
| } | ||
| }); | ||
|
|
||
| module.exports = SingleValue; |
This file contains hidden or 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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
line 767 should be here