diff --git a/README.md b/README.md
index e04ce55c..477a7f68 100644
--- a/README.md
+++ b/README.md
@@ -210,6 +210,13 @@ Default: false
If true, options will still be rendered when there is no value.
+#### props.selectFirst
+
+Type: `boolean`
+Default: false
+
+If true, first option will be selected by default.
+
### Typeahead ([Exposed Component Functions][reactecf])
#### typeahead.focus
diff --git a/dist/react-typeahead.js b/dist/react-typeahead.js
index 22ed056b..e2b885f0 100644
--- a/dist/react-typeahead.js
+++ b/dist/react-typeahead.js
@@ -99,7 +99,7 @@ fuzzy.match = function(pattern, string, opts) {
pattern = opts.caseSensitive && pattern || pattern.toLowerCase();
// For each character in the string, either add it to the result
- // or wrap in template if its the next string in the pattern
+ // or wrap in template if it's the next string in the pattern
for(var idx = 0; idx < len; idx++) {
ch = string[idx];
if(compareString[idx] === pattern[patternIdx]) {
@@ -141,8 +141,8 @@ fuzzy.match = function(pattern, string, opts) {
// // string to put after matching character
// , post: ''
//
-// // Optional function. Input is an element from the passed in
-// // `arr`, output should be the string to test `pattern` against.
+// // Optional function. Input is an entry in the given arr`,
+// // output should be the string to test `pattern` against.
// // In this example, if `arr = [{crying: 'koala'}]` we would return
// // 'koala'.
// , extract: function(arg) { return arg.crying; }
@@ -150,31 +150,31 @@ fuzzy.match = function(pattern, string, opts) {
fuzzy.filter = function(pattern, arr, opts) {
opts = opts || {};
return arr
- .reduce(function(prev, element, idx, arr) {
- var str = element;
- if(opts.extract) {
- str = opts.extract(element);
- }
- var rendered = fuzzy.match(pattern, str, opts);
- if(rendered != null) {
- prev[prev.length] = {
- string: rendered.rendered
- , score: rendered.score
- , index: idx
- , original: element
- };
- }
- return prev;
- }, [])
-
- // Sort by score. Browsers are inconsistent wrt stable/unstable
- // sorting, so force stable by using the index in the case of tie.
- // See http://ofb.net/~sethml/is-sort-stable.html
- .sort(function(a,b) {
- var compare = b.score - a.score;
- if(compare) return compare;
- return a.index - b.index;
- });
+ .reduce(function(prev, element, idx, arr) {
+ var str = element;
+ if(opts.extract) {
+ str = opts.extract(element);
+ }
+ var rendered = fuzzy.match(pattern, str, opts);
+ if(rendered != null) {
+ prev[prev.length] = {
+ string: rendered.rendered
+ , score: rendered.score
+ , index: idx
+ , original: element
+ };
+ }
+ return prev;
+ }, [])
+
+ // Sort by score. Browsers are inconsistent wrt stable/unstable
+ // sorting, so force stable by using the index in the case of tie.
+ // See http://ofb.net/~sethml/is-sort-stable.html
+ .sort(function(a,b) {
+ var compare = b.score - a.score;
+ if(compare) return compare;
+ return a.index - b.index;
+ });
};
@@ -554,6 +554,7 @@ var Typeahead = React.createClass({
formInputOption: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.func]),
defaultClassNames: React.PropTypes.bool,
customListComponent: React.PropTypes.oneOfType([React.PropTypes.element, React.PropTypes.func]),
+ selectFirst: React.PropTypes.bool,
showOptionsWhenEmpty: React.PropTypes.bool
},
@@ -578,6 +579,7 @@ var Typeahead = React.createClass({
filterOption: null,
defaultClassNames: true,
customListComponent: TypeaheadSelector,
+ selectFirst: false,
showOptionsWhenEmpty: false
};
},
@@ -791,9 +793,14 @@ var Typeahead = React.createClass({
},
componentWillReceiveProps: function (nextProps) {
- this.setState({
+ var typeaheadOptionsState = {
visible: this.getOptionsForValue(this.state.entryValue, nextProps.options)
- });
+ };
+ if (this.props.selectFirst && nextProps.options.length) {
+ typeaheadOptionsState.selectionIndex = 0;
+ }
+
+ this.setState(typeaheadOptionsState);
},
render: function () {
diff --git a/src/typeahead/index.js b/src/typeahead/index.js
index a02eaf91..534cee38 100644
--- a/src/typeahead/index.js
+++ b/src/typeahead/index.js
@@ -48,6 +48,7 @@ var Typeahead = React.createClass({
React.PropTypes.element,
React.PropTypes.func
]),
+ selectFirst: React.PropTypes.bool,
showOptionsWhenEmpty: React.PropTypes.bool
},
@@ -72,6 +73,7 @@ var Typeahead = React.createClass({
filterOption: null,
defaultClassNames: true,
customListComponent: TypeaheadSelector,
+ selectFirst: false,
showOptionsWhenEmpty: false
};
},
@@ -288,9 +290,14 @@ var Typeahead = React.createClass({
},
componentWillReceiveProps: function(nextProps) {
- this.setState({
+ var typeaheadOptionsState = {
visible: this.getOptionsForValue(this.state.entryValue, nextProps.options)
- });
+ }
+ if (this.props.selectFirst && nextProps.options.length) {
+ typeaheadOptionsState.selectionIndex = 0;
+ }
+
+ this.setState(typeaheadOptionsState);
},
render: function() {
diff --git a/test/typeahead-test.js b/test/typeahead-test.js
index d62c871c..87a46ae3 100644
--- a/test/typeahead-test.js
+++ b/test/typeahead-test.js
@@ -580,6 +580,28 @@ describe('Typeahead Component', function() {
});
});
+ context('selectFirst', function() {
+ context('options are present', function() {
+ it('sets the selectionIndex to 0 (first option) by default', function() {
+ var component = TestUtils.renderIntoDocument();
+ component.componentWillReceiveProps({options: BEATLES})
+ assert.equal(0, component.state.selectionIndex);
+ });
+ });
+ context('options is empty', function() {
+ it('does not set selectionIndex', function() {
+ var component = TestUtils.renderIntoDocument();
+ component.componentWillReceiveProps({options: []})
+ assert.equal(null, component.state.selectionIndex);
+ });
+ });
+
+ });
+
context('showOptionsWhenEmpty', function() {
it('do not render options when value is empty by default', function() {
var component = TestUtils.renderIntoDocument(