Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions examples/src/CustomOption.js
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;
30 changes: 30 additions & 0 deletions examples/src/CustomSingleValue.js
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;
27 changes: 27 additions & 0 deletions examples/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

var React = require('react');
var Select = require('react-select');
var GravatarOption = require('./CustomOption');
var GravatarValue = require('./CustomSingleValue');

var STATES = require('./data/states');
var USERS = require('./data/users');
var id = 0;

function logChange(value) {
Expand All @@ -20,6 +23,29 @@ var CountrySelect = React.createClass({
}
});

var UsersField = React.createClass({
getDefaultProps: function () {
return {
searchable: true,
label: 'Users: (with custom option and value component)'
};
},
render: function() {

return (
<div>
<label>{this.props.label}</label>
<Select
onOptionLabelClick={this.onLabelClick}
placeholder="Select user"
optionComponent={GravatarOption}
singleValueComponent={GravatarValue}
options={USERS.users}/>
</div>
);
}
});

var StatesField = React.createClass({
getDefaultProps: function () {
return {
Expand Down Expand Up @@ -285,6 +311,7 @@ React.render(
<div>
<StatesField />
<StatesField label="States (non-searchable):" searchable={false} />
<UsersField />
<MultiSelectField label="Multiselect:"/>
<SelectedValuesField label="Clickable labels (labels as links):" />
<SelectedValuesFieldCreate label="Option Creation (tags mode):" />
Expand Down
5 changes: 5 additions & 0 deletions examples/src/data/users.js
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' }
];
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"mocha": "^2.2.5",
"mocha-jsdom": "^1.0.0",
"react": ">=0.13.3",
"react-gravatar": "2.0.0",
"react-component-gulp-tasks": "^0.7.0",
"sinon": "^1.15.4",
"sinon-chai": "^2.8.0",
Expand Down
32 changes: 32 additions & 0 deletions src/Option.js
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;
71 changes: 50 additions & 21 deletions src/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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
};
},

Expand Down Expand Up @@ -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) {
Expand All @@ -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 : (
Expand Down Expand Up @@ -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) {
Copy link
Collaborator

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

var val = this.state.values[0] || null;
value.push(<Value
key={0}
option={val}
Copy link
Collaborator

Choose a reason for hiding this comment

The 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;
Expand Down
16 changes: 16 additions & 0 deletions src/SingleValue.js
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;
12 changes: 6 additions & 6 deletions src/Value.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ var Value = React.createClass({
displayName: 'Value',

propTypes: {
disabled: React.PropTypes.bool,
onOptionLabelClick: React.PropTypes.func,
onRemove: React.PropTypes.func,
option: React.PropTypes.object.isRequired,
optionLabelClick: React.PropTypes.bool,
renderer: React.PropTypes.func
disabled: React.PropTypes.bool, // disabled prop passed to ReactSelect
onOptionLabelClick: React.PropTypes.func, // method to handle click on value label
onRemove: React.PropTypes.func, // method to handle remove of that value
option: React.PropTypes.object.isRequired, // option passed to component
optionLabelClick: React.PropTypes.bool, // indicates if onOptionLabelClick should be handled
renderer: React.PropTypes.func // method to render option label passed to ReactSelect
},

blockEvent: function(event) {
Expand Down