New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

react-typeahead

Package Overview
Dependencies
Maintainers
2
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-typeahead - npm Package Compare versions

Comparing version

to
2.0.0-alpha.3

68

lib/typeahead/index.js

@@ -23,2 +23,3 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

maxVisible: React.PropTypes.number,
resultsTruncatedMessage: React.PropTypes.string,
options: React.PropTypes.array,

@@ -68,3 +69,4 @@ allowCustomValues: React.PropTypes.number,

customListComponent: TypeaheadSelector,
showOptionsWhenEmpty: false
showOptionsWhenEmpty: false,
resultsTruncatedMessage: null
};

@@ -75,4 +77,4 @@ },

return {
// The currently visible set of options
visible: this.getOptionsForValue(this.props.initialValue, this.props.options),
// The options matching the entry value
searchResults: this.getOptionsForValue(this.props.initialValue, this.props.options),

@@ -86,3 +88,7 @@ // This should be called something else, "entryValue"

// Index of the selection
selectionIndex: null
selectionIndex: null,
// Keep track of the focus state of the input element, to determine
// whether to show options when empty (if showOptionsWhenEmpty is true)
isFocused: false
};

@@ -93,3 +99,7 @@ },

var emptyValue = !input || input.trim().length == 0;
return !this.props.showOptionsWhenEmpty && emptyValue;
// this.state must be checked because it may not be defined yet if this function
// is called from within getInitialState
var isFocused = this.state && this.state.isFocused;
return !(this.props.showOptionsWhenEmpty && isFocused) && emptyValue;
},

@@ -103,7 +113,3 @@

var filterOptions = this._generateFilterFunction();
var result = filterOptions(value, options);
if (this.props.maxVisible) {
result = result.slice(0, this.props.maxVisible);
}
return result;
return filterOptions(value, options);
},

@@ -121,3 +127,3 @@

_hasCustomValue: function () {
if (this.props.allowCustomValues > 0 && this.state.entryValue.length >= this.props.allowCustomValues && this.state.visible.indexOf(this.state.entryValue) < 0) {
if (this.props.allowCustomValues > 0 && this.state.entryValue.length >= this.props.allowCustomValues && this.state.searchResults.indexOf(this.state.entryValue) < 0) {
return true;

@@ -147,3 +153,5 @@ }

return React.createElement(this.props.customListComponent, {
ref: 'sel', options: this.state.visible,
ref: 'sel', options: this.props.maxVisible ? this.state.searchResults.slice(0, this.props.maxVisible) : this.state.searchResults,
areResultsTruncated: this.props.maxVisible && this.state.searchResults.length > this.props.maxVisible,
resultsTruncatedMessage: this.props.resultsTruncatedMessage,
onOptionSelected: this._onOptionSelected,

@@ -167,3 +175,3 @@ allowCustomValues: this.props.allowCustomValues,

}
return this.state.visible[index];
return this.state.searchResults[index];
},

@@ -182,3 +190,3 @@

nEntry.value = optionString;
this.setState({ visible: this.getOptionsForValue(optionString, this.props.options),
this.setState({ searchResults: this.getOptionsForValue(optionString, this.props.options),
selection: formInputOptionString,

@@ -191,3 +199,3 @@ entryValue: optionString });

var value = this.refs.entry.value;
this.setState({ visible: this.getOptionsForValue(value, this.props.options),
this.setState({ searchResults: this.getOptionsForValue(value, this.props.options),
selection: '',

@@ -213,3 +221,3 @@ entryValue: value });

var selection = this.getSelection();
var option = selection ? selection : this.state.visible.length > 0 ? this.state.visible[0] : null;
var option = selection ? selection : this.state.searchResults.length > 0 ? this.state.searchResults[0] : null;

@@ -242,3 +250,3 @@ if (option === null && this._hasCustomValue()) {

var newIndex = this.state.selectionIndex === null ? delta == 1 ? 0 : delta : this.state.selectionIndex + delta;
var length = this.state.visible.length;
var length = this.props.maxVisible ? this.state.searchResults.slice(0, this.props.maxVisible).length : this.state.searchResults.length;
if (this._hasCustomValue()) {

@@ -294,3 +302,3 @@ length += 1;

this.setState({
visible: this.getOptionsForValue(this.state.entryValue, nextProps.options)
searchResults: this.getOptionsForValue(this.state.entryValue, nextProps.options)
});

@@ -325,4 +333,4 @@ },

onKeyUp: this.props.onKeyUp,
onFocus: this.props.onFocus,
onBlur: this.props.onBlur
onFocus: this._onFocus,
onBlur: this._onBlur
})),

@@ -333,2 +341,20 @@ this._renderIncrementalSearchResults()

_onFocus: function (event) {
this.setState({ isFocused: true }, function () {
this._onTextEntryUpdated();
}.bind(this));
if (this.props.onFocus) {
return this.props.onFocus(event);
}
},
_onBlur: function (event) {
this.setState({ isFocused: false }, function () {
this._onTextEntryUpdated();
}.bind(this));
if (this.props.onBlur) {
return this.props.onBlur(event);
}
},
_renderHiddenInput: function () {

@@ -370,3 +396,3 @@ if (!this.props.name) {

_hasHint: function () {
return this.state.visible.length > 0 || this._hasCustomValue();
return this.state.searchResults.length > 0 || this._hasCustomValue();
}

@@ -373,0 +399,0 @@ });

@@ -20,3 +20,5 @@ var React = require('react');

displayOption: React.PropTypes.func.isRequired,
defaultClassNames: React.PropTypes.bool
defaultClassNames: React.PropTypes.bool,
areResultsTruncated: React.PropTypes.bool,
resultsTruncatedMessage: React.PropTypes.string
},

@@ -76,2 +78,16 @@

if (this.props.areResultsTruncated && this.props.resultsTruncatedMessage !== null) {
var resultsTruncatedClasses = {
"results-truncated": this.props.defaultClassNames
};
resultsTruncatedClasses[this.props.customClasses.resultsTruncated] = this.props.customClasses.resultsTruncated;
var resultsTruncatedClassList = classNames(resultsTruncatedClasses);
results.push(React.createElement(
'li',
{ key: 'results-truncated', className: resultsTruncatedClassList },
this.props.resultsTruncatedMessage
));
}
return React.createElement(

@@ -78,0 +94,0 @@ 'ul',

{
"name": "react-typeahead",
"version": "2.0.0-alpha.2",
"version": "2.0.0-alpha.3",
"description": "React-based typeahead and typeahead-tokenizer",

@@ -5,0 +5,0 @@ "keywords": [

@@ -83,6 +83,12 @@ # react-typeahead

#### props.resultsTruncatedMessage
Type: `String`
If `maxVisible` is set, display this custom message at the bottom of the list of results when the result are truncated.
#### props.customClasses
Type: `Object`
Allowed Keys: `input`, `results`, `listItem`, `listAnchor`, `hover`
Allowed Keys: `input`, `results`, `listItem`, `listAnchor`, `hover`, `resultsTruncated`

@@ -89,0 +95,0 @@ An object containing custom class names for child elements. Useful for

@@ -19,2 +19,3 @@ var Accessor = require('../accessor');

maxVisible: React.PropTypes.number,
resultsTruncatedMessage: React.PropTypes.string,
options: React.PropTypes.array,

@@ -76,3 +77,4 @@ allowCustomValues: React.PropTypes.number,

customListComponent: TypeaheadSelector,
showOptionsWhenEmpty: false
showOptionsWhenEmpty: false,
resultsTruncatedMessage: null
};

@@ -83,4 +85,4 @@ },

return {
// The currently visible set of options
visible: this.getOptionsForValue(this.props.initialValue, this.props.options),
// The options matching the entry value
searchResults: this.getOptionsForValue(this.props.initialValue, this.props.options),

@@ -94,3 +96,7 @@ // This should be called something else, "entryValue"

// Index of the selection
selectionIndex: null
selectionIndex: null,
// Keep track of the focus state of the input element, to determine
// whether to show options when empty (if showOptionsWhenEmpty is true)
isFocused: false,
};

@@ -101,3 +107,7 @@ },

var emptyValue = !input || input.trim().length == 0;
return !this.props.showOptionsWhenEmpty && emptyValue;
// this.state must be checked because it may not be defined yet if this function
// is called from within getInitialState
var isFocused = this.state && this.state.isFocused;
return !(this.props.showOptionsWhenEmpty && isFocused) && emptyValue;
},

@@ -109,7 +119,3 @@

var filterOptions = this._generateFilterFunction();
var result = filterOptions(value, options);
if (this.props.maxVisible) {
result = result.slice(0, this.props.maxVisible);
}
return result;
return filterOptions(value, options);
},

@@ -129,3 +135,3 @@

this.state.entryValue.length >= this.props.allowCustomValues &&
this.state.visible.indexOf(this.state.entryValue) < 0) {
this.state.searchResults.indexOf(this.state.entryValue) < 0) {
return true;

@@ -156,3 +162,5 @@ }

<this.props.customListComponent
ref="sel" options={this.state.visible}
ref="sel" options={this.props.maxVisible ? this.state.searchResults.slice(0, this.props.maxVisible) : this.state.searchResults}
areResultsTruncated={this.props.maxVisible && this.state.searchResults.length > this.props.maxVisible}
resultsTruncatedMessage={this.props.resultsTruncatedMessage}
onOptionSelected={this._onOptionSelected}

@@ -177,3 +185,3 @@ allowCustomValues={this.props.allowCustomValues}

}
return this.state.visible[index];
return this.state.searchResults[index];
},

@@ -192,3 +200,3 @@

nEntry.value = optionString;
this.setState({visible: this.getOptionsForValue(optionString, this.props.options),
this.setState({searchResults: this.getOptionsForValue(optionString, this.props.options),
selection: formInputOptionString,

@@ -201,3 +209,3 @@ entryValue: optionString});

var value = this.refs.entry.value;
this.setState({visible: this.getOptionsForValue(value, this.props.options),
this.setState({searchResults: this.getOptionsForValue(value, this.props.options),
selection: '',

@@ -224,3 +232,3 @@ entryValue: value});

var option = selection ?
selection : (this.state.visible.length > 0 ? this.state.visible[0] : null);
selection : (this.state.searchResults.length > 0 ? this.state.searchResults[0] : null);

@@ -253,3 +261,3 @@ if (option === null && this._hasCustomValue()) {

var newIndex = this.state.selectionIndex === null ? (delta == 1 ? 0 : delta) : this.state.selectionIndex + delta;
var length = this.state.visible.length;
var length = this.props.maxVisible ? this.state.searchResults.slice(0, this.props.maxVisible).length : this.state.searchResults.length;
if (this._hasCustomValue()) {

@@ -305,3 +313,3 @@ length += 1;

this.setState({
visible: this.getOptionsForValue(this.state.entryValue, nextProps.options)
searchResults: this.getOptionsForValue(this.state.entryValue, nextProps.options)
});

@@ -335,4 +343,4 @@ },

onKeyUp={this.props.onKeyUp}
onFocus={this.props.onFocus}
onBlur={this.props.onBlur}
onFocus={this._onFocus}
onBlur={this._onBlur}
/>

@@ -344,2 +352,20 @@ { this._renderIncrementalSearchResults() }

_onFocus: function(event) {
this.setState({isFocused: true}, function () {
this._onTextEntryUpdated();
}.bind(this));
if ( this.props.onFocus ) {
return this.props.onFocus(event);
}
},
_onBlur: function(event) {
this.setState({isFocused: false}, function () {
this._onTextEntryUpdated();
}.bind(this));
if ( this.props.onBlur ) {
return this.props.onBlur(event);
}
},
_renderHiddenInput: function() {

@@ -381,3 +407,3 @@ if (!this.props.name) {

_hasHint: function() {
return this.state.visible.length > 0 || this._hasCustomValue();
return this.state.searchResults.length > 0 || this._hasCustomValue();
}

@@ -384,0 +410,0 @@ });

@@ -18,3 +18,5 @@ var React = require('react');

displayOption: React.PropTypes.func.isRequired,
defaultClassNames: React.PropTypes.bool
defaultClassNames: React.PropTypes.bool,
areResultsTruncated: React.PropTypes.bool,
resultsTruncatedMessage: React.PropTypes.string
},

@@ -74,2 +76,16 @@

if (this.props.areResultsTruncated && this.props.resultsTruncatedMessage !== null) {
var resultsTruncatedClasses = {
"results-truncated": this.props.defaultClassNames
};
resultsTruncatedClasses[this.props.customClasses.resultsTruncated] = this.props.customClasses.resultsTruncated;
var resultsTruncatedClassList = classNames(resultsTruncatedClasses);
results.push(
<li key="results-truncated" className={resultsTruncatedClassList}>
{this.props.resultsTruncatedMessage}
</li>
);
}
return (

@@ -76,0 +92,0 @@ <ul className={classList}>

@@ -167,2 +167,12 @@ var _ = require('lodash');

});
it('limits the result set based on the maxVisible option, and shows resultsTruncatedMessage when specified', function() {
var component = TestUtils.renderIntoDocument(<Typeahead
options={ BEATLES }
maxVisible={ 1 }
resultsTruncatedMessage='Results truncated'
></Typeahead>);
var results = simulateTextInput(component, 'o');
assert.equal(TestUtils.findRenderedDOMComponentWithClass(component, 'results-truncated').textContent, 'Results truncated');
});
});

@@ -596,3 +606,3 @@

it('render options when value is empty when set to true', function() {
it('do not render options when value is empty when set to true and not focused', function() {
var component = TestUtils.renderIntoDocument(

@@ -606,2 +616,15 @@ <Typeahead

var results = TestUtils.scryRenderedComponentsWithType(component, TypeaheadOption);
assert.equal(0, results.length);
});
it('render options when value is empty when set to true and focused', function() {
var component = TestUtils.renderIntoDocument(
<Typeahead
options={ BEATLES }
showOptionsWhenEmpty={ true }
/>
);
TestUtils.Simulate.focus(component.refs.entry);
var results = TestUtils.scryRenderedComponentsWithType(component, TypeaheadOption);
assert.equal(4, results.length);

@@ -608,0 +631,0 @@ });