UNPKG

react-select

Version:

A Select control built with and for ReactJS

185 lines (164 loc) 6.06 kB
'use strict'; 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; }; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _Select = require('./Select'); var _Select2 = _interopRequireDefault(_Select); var _utilsStripDiacritics = require('./utils/stripDiacritics'); var _utilsStripDiacritics2 = _interopRequireDefault(_utilsStripDiacritics); var requestId = 0; function initCache(cache) { if (cache && typeof cache !== 'object') { cache = {}; } return cache ? cache : null; } function updateCache(cache, input, data) { if (!cache) return; cache[input] = data; } function getFromCache(cache, input) { if (!cache) return; for (var i = input.length; i >= 0; --i) { var cacheKey = input.slice(0, i); if (cache[cacheKey] && (input === cacheKey || cache[cacheKey].complete)) { return cache[cacheKey]; } } } function thenPromise(promise, callback) { if (!promise || typeof promise.then !== 'function') return; return promise.then(function (data) { callback(null, data); }, function (err) { callback(err); }); } var stringOrNode = _react2['default'].PropTypes.oneOfType([_react2['default'].PropTypes.string, _react2['default'].PropTypes.node]); var Async = _react2['default'].createClass({ displayName: 'Async', propTypes: { cache: _react2['default'].PropTypes.any, // object to use to cache results, can be null to disable cache ignoreAccents: _react2['default'].PropTypes.bool, // whether to strip diacritics when filtering (shared with Select) ignoreCase: _react2['default'].PropTypes.bool, // whether to perform case-insensitive filtering (shared with Select) isLoading: _react2['default'].PropTypes.bool, // overrides the isLoading state when set to true loadOptions: _react2['default'].PropTypes.func.isRequired, // function to call to load options asynchronously loadingPlaceholder: _react2['default'].PropTypes.string, // replaces the placeholder while options are loading minimumInput: _react2['default'].PropTypes.number, // the minimum number of characters that trigger loadOptions noResultsText: stringOrNode, // placeholder displayed when there are no matching search results (shared with Select) onInputChange: _react2['default'].PropTypes.func, // onInputChange handler: function (inputValue) {} placeholder: stringOrNode, // field placeholder, displayed when there's no value (shared with Select) searchPromptText: stringOrNode, // label to prompt for search input searchingText: _react2['default'].PropTypes.string }, // message to display while options are loading getDefaultProps: function getDefaultProps() { return { cache: true, ignoreAccents: true, ignoreCase: true, loadingPlaceholder: 'Loading...', minimumInput: 0, searchingText: 'Searching...', searchPromptText: 'Type to search' }; }, getInitialState: function getInitialState() { return { cache: initCache(this.props.cache), isLoading: false, options: [] }; }, componentWillMount: function componentWillMount() { this._lastInput = ''; }, componentDidMount: function componentDidMount() { this.loadOptions(''); }, componentWillReceiveProps: function componentWillReceiveProps(nextProps) { if (nextProps.cache !== this.props.cache) { this.setState({ cache: initCache(nextProps.cache) }); } }, focus: function focus() { this.select.focus(); }, resetState: function resetState() { this._currentRequestId = -1; this.setState({ isLoading: false, options: [] }); }, getResponseHandler: function getResponseHandler(input) { var _this = this; var _requestId = this._currentRequestId = requestId++; return function (err, data) { if (err) throw err; if (!_this.isMounted()) return; updateCache(_this.state.cache, input, data); if (_requestId !== _this._currentRequestId) return; _this.setState({ isLoading: false, options: data && data.options || [] }); }; }, loadOptions: function loadOptions(input) { if (this.props.onInputChange) { var nextState = this.props.onInputChange(input); // Note: != used deliberately here to catch undefined and null if (nextState != null) { input = '' + nextState; } } if (this.props.ignoreAccents) input = (0, _utilsStripDiacritics2['default'])(input); if (this.props.ignoreCase) input = input.toLowerCase(); this._lastInput = input; if (input.length < this.props.minimumInput) { return this.resetState(); } var cacheResult = getFromCache(this.state.cache, input); if (cacheResult) { return this.setState({ options: cacheResult.options }); } this.setState({ isLoading: true }); var responseHandler = this.getResponseHandler(input); var inputPromise = thenPromise(this.props.loadOptions(input, responseHandler), responseHandler); return inputPromise ? inputPromise.then(function () { return input; }) : input; }, render: function render() { var _this2 = this; var noResultsText = this.props.noResultsText; var _state = this.state; var isLoading = _state.isLoading; var options = _state.options; if (this.props.isLoading) isLoading = true; var placeholder = isLoading ? this.props.loadingPlaceholder : this.props.placeholder; if (isLoading) { noResultsText = this.props.searchingText; } else if (!options.length && this._lastInput.length < this.props.minimumInput) { noResultsText = this.props.searchPromptText; } return _react2['default'].createElement(_Select2['default'], _extends({}, this.props, { ref: function (ref) { return _this2.select = ref; }, isLoading: isLoading, noResultsText: noResultsText, onInputChange: this.loadOptions, options: options, placeholder: placeholder })); } }); module.exports = Async;