1376 lines
49 KiB
JavaScript
1376 lines
49 KiB
JavaScript
'use strict';
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
|
|
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; };
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
|
|
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
|
|
var _react = require('react');
|
|
|
|
var _react2 = _interopRequireDefault(_react);
|
|
|
|
var _propTypes = require('prop-types');
|
|
|
|
var _propTypes2 = _interopRequireDefault(_propTypes);
|
|
|
|
var _reactDom = require('react-dom');
|
|
|
|
var _reactInputAutosize = require('react-input-autosize');
|
|
|
|
var _reactInputAutosize2 = _interopRequireDefault(_reactInputAutosize);
|
|
|
|
var _classnames = require('classnames');
|
|
|
|
var _classnames2 = _interopRequireDefault(_classnames);
|
|
|
|
var _defaultArrowRenderer = require('./utils/defaultArrowRenderer');
|
|
|
|
var _defaultArrowRenderer2 = _interopRequireDefault(_defaultArrowRenderer);
|
|
|
|
var _defaultFilterOptions = require('./utils/defaultFilterOptions');
|
|
|
|
var _defaultFilterOptions2 = _interopRequireDefault(_defaultFilterOptions);
|
|
|
|
var _defaultMenuRenderer = require('./utils/defaultMenuRenderer');
|
|
|
|
var _defaultMenuRenderer2 = _interopRequireDefault(_defaultMenuRenderer);
|
|
|
|
var _defaultClearRenderer = require('./utils/defaultClearRenderer');
|
|
|
|
var _defaultClearRenderer2 = _interopRequireDefault(_defaultClearRenderer);
|
|
|
|
var _Option = require('./Option');
|
|
|
|
var _Option2 = _interopRequireDefault(_Option);
|
|
|
|
var _Value = require('./Value');
|
|
|
|
var _Value2 = _interopRequireDefault(_Value);
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
|
|
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*!
|
|
Copyright (c) 2017 Jed Watson.
|
|
Licensed under the MIT License (MIT), see
|
|
http://jedwatson.github.io/react-select
|
|
*/
|
|
|
|
|
|
var stringifyValue = function stringifyValue(value) {
|
|
return typeof value === 'string' ? value : value !== null && JSON.stringify(value) || '';
|
|
};
|
|
|
|
var stringOrNode = _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.node]);
|
|
var stringOrNumber = _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]);
|
|
|
|
var instanceId = 1;
|
|
|
|
var Select = function (_React$Component) {
|
|
_inherits(Select, _React$Component);
|
|
|
|
function Select(props) {
|
|
_classCallCheck(this, Select);
|
|
|
|
var _this = _possibleConstructorReturn(this, (Select.__proto__ || Object.getPrototypeOf(Select)).call(this, props));
|
|
|
|
['clearValue', 'focusOption', 'handleInputBlur', 'handleInputChange', 'handleInputFocus', 'handleInputValueChange', 'handleKeyDown', 'handleMenuScroll', 'handleMouseDown', 'handleMouseDownOnArrow', 'handleMouseDownOnMenu', 'handleRequired', 'handleTouchOutside', 'handleTouchMove', 'handleTouchStart', 'handleTouchEnd', 'handleTouchEndClearValue', 'handleValueClick', 'getOptionLabel', 'onOptionRef', 'removeValue', 'selectValue'].forEach(function (fn) {
|
|
return _this[fn] = _this[fn].bind(_this);
|
|
});
|
|
|
|
_this.state = {
|
|
inputValue: '',
|
|
isFocused: false,
|
|
isOpen: false,
|
|
isPseudoFocused: false,
|
|
required: false
|
|
};
|
|
return _this;
|
|
}
|
|
|
|
_createClass(Select, [{
|
|
key: 'componentWillMount',
|
|
value: function componentWillMount() {
|
|
this._instancePrefix = 'react-select-' + (this.props.instanceId || ++instanceId) + '-';
|
|
var valueArray = this.getValueArray(this.props.value);
|
|
|
|
if (this.props.required) {
|
|
this.setState({
|
|
required: this.handleRequired(valueArray[0], this.props.multi)
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: 'componentDidMount',
|
|
value: function componentDidMount() {
|
|
if (typeof this.props.autofocus !== 'undefined' && typeof console !== 'undefined') {
|
|
console.warn('Warning: The autofocus prop has changed to autoFocus, support will be removed after react-select@1.0');
|
|
}
|
|
if (this.props.autoFocus || this.props.autofocus) {
|
|
this.focus();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'componentWillReceiveProps',
|
|
value: function componentWillReceiveProps(nextProps) {
|
|
var valueArray = this.getValueArray(nextProps.value, nextProps);
|
|
|
|
if (nextProps.required) {
|
|
this.setState({
|
|
required: this.handleRequired(valueArray[0], nextProps.multi)
|
|
});
|
|
} else if (this.props.required) {
|
|
// Used to be required but it's not any more
|
|
this.setState({ required: false });
|
|
}
|
|
}
|
|
}, {
|
|
key: 'componentDidUpdate',
|
|
value: function componentDidUpdate(prevProps, prevState) {
|
|
// focus to the selected option
|
|
if (this.menu && this.focused && this.state.isOpen && !this.hasScrolledToOption) {
|
|
var focusedOptionNode = (0, _reactDom.findDOMNode)(this.focused);
|
|
var menuNode = (0, _reactDom.findDOMNode)(this.menu);
|
|
|
|
var scrollTop = menuNode.scrollTop;
|
|
var scrollBottom = scrollTop + menuNode.offsetHeight;
|
|
var optionTop = focusedOptionNode.offsetTop;
|
|
var optionBottom = optionTop + focusedOptionNode.offsetHeight;
|
|
|
|
if (scrollTop > optionTop || scrollBottom < optionBottom) {
|
|
menuNode.scrollTop = focusedOptionNode.offsetTop;
|
|
}
|
|
|
|
// We still set hasScrolledToOption to true even if we didn't
|
|
// actually need to scroll, as we've still confirmed that the
|
|
// option is in view.
|
|
this.hasScrolledToOption = true;
|
|
} else if (!this.state.isOpen) {
|
|
this.hasScrolledToOption = false;
|
|
}
|
|
|
|
if (this._scrollToFocusedOptionOnUpdate && this.focused && this.menu) {
|
|
this._scrollToFocusedOptionOnUpdate = false;
|
|
var focusedDOM = (0, _reactDom.findDOMNode)(this.focused);
|
|
var menuDOM = (0, _reactDom.findDOMNode)(this.menu);
|
|
var focusedRect = focusedDOM.getBoundingClientRect();
|
|
var menuRect = menuDOM.getBoundingClientRect();
|
|
if (focusedRect.bottom > menuRect.bottom) {
|
|
menuDOM.scrollTop = focusedDOM.offsetTop + focusedDOM.clientHeight - menuDOM.offsetHeight;
|
|
} else if (focusedRect.top < menuRect.top) {
|
|
menuDOM.scrollTop = focusedDOM.offsetTop;
|
|
}
|
|
}
|
|
if (this.props.scrollMenuIntoView && this.menuContainer) {
|
|
var menuContainerRect = this.menuContainer.getBoundingClientRect();
|
|
if (window.innerHeight < menuContainerRect.bottom + this.props.menuBuffer) {
|
|
window.scrollBy(0, menuContainerRect.bottom + this.props.menuBuffer - window.innerHeight);
|
|
}
|
|
}
|
|
if (prevProps.disabled !== this.props.disabled) {
|
|
this.setState({ isFocused: false }); // eslint-disable-line react/no-did-update-set-state
|
|
this.closeMenu();
|
|
}
|
|
if (prevState.isOpen !== this.state.isOpen) {
|
|
this.toggleTouchOutsideEvent(this.state.isOpen);
|
|
var handler = this.state.isOpen ? this.props.onOpen : this.props.onClose;
|
|
handler && handler();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'componentWillUnmount',
|
|
value: function componentWillUnmount() {
|
|
this.toggleTouchOutsideEvent(false);
|
|
}
|
|
}, {
|
|
key: 'toggleTouchOutsideEvent',
|
|
value: function toggleTouchOutsideEvent(enabled) {
|
|
if (enabled) {
|
|
if (!document.addEventListener && document.attachEvent) {
|
|
document.attachEvent('ontouchstart', this.handleTouchOutside);
|
|
} else {
|
|
document.addEventListener('touchstart', this.handleTouchOutside);
|
|
}
|
|
} else {
|
|
if (!document.removeEventListener && document.detachEvent) {
|
|
document.detachEvent('ontouchstart', this.handleTouchOutside);
|
|
} else {
|
|
document.removeEventListener('touchstart', this.handleTouchOutside);
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'handleTouchOutside',
|
|
value: function handleTouchOutside(event) {
|
|
// handle touch outside on ios to dismiss menu
|
|
if (this.wrapper && !this.wrapper.contains(event.target)) {
|
|
this.closeMenu();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'focus',
|
|
value: function focus() {
|
|
if (!this.input) return;
|
|
this.input.focus();
|
|
}
|
|
}, {
|
|
key: 'blurInput',
|
|
value: function blurInput() {
|
|
if (!this.input) return;
|
|
this.input.blur();
|
|
}
|
|
}, {
|
|
key: 'handleTouchMove',
|
|
value: function handleTouchMove(event) {
|
|
// Set a flag that the view is being dragged
|
|
this.dragging = true;
|
|
}
|
|
}, {
|
|
key: 'handleTouchStart',
|
|
value: function handleTouchStart(event) {
|
|
// Set a flag that the view is not being dragged
|
|
this.dragging = false;
|
|
}
|
|
}, {
|
|
key: 'handleTouchEnd',
|
|
value: function handleTouchEnd(event) {
|
|
// Check if the view is being dragged, In this case
|
|
// we don't want to fire the click event (because the user only wants to scroll)
|
|
if (this.dragging) return;
|
|
|
|
// Fire the mouse events
|
|
this.handleMouseDown(event);
|
|
}
|
|
}, {
|
|
key: 'handleTouchEndClearValue',
|
|
value: function handleTouchEndClearValue(event) {
|
|
// Check if the view is being dragged, In this case
|
|
// we don't want to fire the click event (because the user only wants to scroll)
|
|
if (this.dragging) return;
|
|
|
|
// Clear the value
|
|
this.clearValue(event);
|
|
}
|
|
}, {
|
|
key: 'handleMouseDown',
|
|
value: function handleMouseDown(event) {
|
|
// if the event was triggered by a mousedown and not the primary
|
|
// button, or if the component is disabled, ignore it.
|
|
if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
|
|
return;
|
|
}
|
|
|
|
if (event.target.tagName === 'INPUT') {
|
|
if (!this.state.isFocused) {
|
|
this._openAfterFocus = this.props.openOnClick;
|
|
this.focus();
|
|
} else if (!this.state.isOpen) {
|
|
this.setState({
|
|
isOpen: true,
|
|
isPseudoFocused: false
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
|
|
// prevent default event handlers
|
|
event.preventDefault();
|
|
|
|
// for the non-searchable select, toggle the menu
|
|
if (!this.props.searchable) {
|
|
// TODO: This code means that if a select is searchable, onClick the options menu will not appear, only on subsequent click will it open.
|
|
this.focus();
|
|
return this.setState({
|
|
isOpen: !this.state.isOpen
|
|
});
|
|
}
|
|
|
|
if (this.state.isFocused) {
|
|
// On iOS, we can get into a state where we think the input is focused but it isn't really,
|
|
// since iOS ignores programmatic calls to input.focus() that weren't triggered by a click event.
|
|
// Call focus() again here to be safe.
|
|
this.focus();
|
|
|
|
var input = this.input;
|
|
if (typeof input.getInput === 'function') {
|
|
// Get the actual DOM input if the ref is an <AutosizeInput /> component
|
|
input = input.getInput();
|
|
}
|
|
|
|
// clears the value so that the cursor will be at the end of input when the component re-renders
|
|
input.value = '';
|
|
|
|
// if the input is focused, ensure the menu is open
|
|
this.setState({
|
|
isOpen: true,
|
|
isPseudoFocused: false
|
|
});
|
|
} else {
|
|
// otherwise, focus the input and open the menu
|
|
this._openAfterFocus = this.props.openOnClick;
|
|
this.focus();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'handleMouseDownOnArrow',
|
|
value: function handleMouseDownOnArrow(event) {
|
|
// if the event was triggered by a mousedown and not the primary
|
|
// button, or if the component is disabled, ignore it.
|
|
if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
|
|
return;
|
|
}
|
|
// If the menu isn't open, let the event bubble to the main handleMouseDown
|
|
if (!this.state.isOpen) {
|
|
this.setState({
|
|
isOpen: true
|
|
});
|
|
}
|
|
// prevent default event handlers
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
// close the menu
|
|
if (this.state.isOpen) {
|
|
this.closeMenu();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'handleMouseDownOnMenu',
|
|
value: function handleMouseDownOnMenu(event) {
|
|
// if the event was triggered by a mousedown and not the primary
|
|
// button, or if the component is disabled, ignore it.
|
|
if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
|
|
return;
|
|
}
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
|
|
this._openAfterFocus = true;
|
|
this.focus();
|
|
}
|
|
}, {
|
|
key: 'closeMenu',
|
|
value: function closeMenu() {
|
|
if (this.props.onCloseResetsInput) {
|
|
this.setState({
|
|
isOpen: false,
|
|
isPseudoFocused: this.state.isFocused && !this.props.multi,
|
|
inputValue: this.handleInputValueChange('')
|
|
});
|
|
} else {
|
|
this.setState({
|
|
isOpen: false,
|
|
isPseudoFocused: this.state.isFocused && !this.props.multi
|
|
});
|
|
}
|
|
this.hasScrolledToOption = false;
|
|
}
|
|
}, {
|
|
key: 'handleInputFocus',
|
|
value: function handleInputFocus(event) {
|
|
if (this.props.disabled) return;
|
|
var isOpen = this.state.isOpen || this._openAfterFocus || this.props.openOnFocus;
|
|
if (this.props.onFocus) {
|
|
this.props.onFocus(event);
|
|
}
|
|
this.setState({
|
|
isFocused: true,
|
|
isOpen: isOpen
|
|
});
|
|
this._openAfterFocus = false;
|
|
}
|
|
}, {
|
|
key: 'handleInputBlur',
|
|
value: function handleInputBlur(event) {
|
|
// The check for menu.contains(activeElement) is necessary to prevent IE11's scrollbar from closing the menu in certain contexts.
|
|
if (this.menu && (this.menu === document.activeElement || this.menu.contains(document.activeElement))) {
|
|
this.focus();
|
|
return;
|
|
}
|
|
|
|
if (this.props.onBlur) {
|
|
this.props.onBlur(event);
|
|
}
|
|
var onBlurredState = {
|
|
isFocused: false,
|
|
isOpen: false,
|
|
isPseudoFocused: false
|
|
};
|
|
if (this.props.onBlurResetsInput) {
|
|
onBlurredState.inputValue = this.handleInputValueChange('');
|
|
}
|
|
this.setState(onBlurredState);
|
|
}
|
|
}, {
|
|
key: 'handleInputChange',
|
|
value: function handleInputChange(event) {
|
|
var newInputValue = event.target.value;
|
|
|
|
if (this.state.inputValue !== event.target.value) {
|
|
newInputValue = this.handleInputValueChange(newInputValue);
|
|
}
|
|
|
|
this.setState({
|
|
isOpen: true,
|
|
isPseudoFocused: false,
|
|
inputValue: newInputValue
|
|
});
|
|
}
|
|
}, {
|
|
key: 'handleInputValueChange',
|
|
value: function handleInputValueChange(newValue) {
|
|
if (this.props.onInputChange) {
|
|
var nextState = this.props.onInputChange(newValue);
|
|
// Note: != used deliberately here to catch undefined and null
|
|
if (nextState != null && (typeof nextState === 'undefined' ? 'undefined' : _typeof(nextState)) !== 'object') {
|
|
newValue = '' + nextState;
|
|
}
|
|
}
|
|
return newValue;
|
|
}
|
|
}, {
|
|
key: 'handleKeyDown',
|
|
value: function handleKeyDown(event) {
|
|
if (this.props.disabled) return;
|
|
|
|
if (typeof this.props.onInputKeyDown === 'function') {
|
|
this.props.onInputKeyDown(event);
|
|
if (event.defaultPrevented) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch (event.keyCode) {
|
|
case 8:
|
|
// backspace
|
|
if (!this.state.inputValue && this.props.backspaceRemoves) {
|
|
event.preventDefault();
|
|
this.popValue();
|
|
}
|
|
return;
|
|
case 9:
|
|
// tab
|
|
if (event.shiftKey || !this.state.isOpen || !this.props.tabSelectsValue) {
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
this.selectFocusedOption();
|
|
return;
|
|
case 13:
|
|
// enter
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
if (this.state.isOpen) {
|
|
this.selectFocusedOption();
|
|
} else {
|
|
this.focusNextOption();
|
|
}
|
|
return;
|
|
break;
|
|
case 27:
|
|
// escape
|
|
if (this.state.isOpen) {
|
|
this.closeMenu();
|
|
event.stopPropagation();
|
|
} else if (this.props.clearable && this.props.escapeClearsValue) {
|
|
this.clearValue(event);
|
|
event.stopPropagation();
|
|
}
|
|
break;
|
|
case 32:
|
|
// space
|
|
if (this.props.searchable) {
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
if (!this.state.isOpen) {
|
|
this.focusNextOption();
|
|
return;
|
|
}
|
|
event.stopPropagation();
|
|
this.selectFocusedOption();
|
|
break;
|
|
case 38:
|
|
// up
|
|
this.focusPreviousOption();
|
|
break;
|
|
case 40:
|
|
// down
|
|
this.focusNextOption();
|
|
break;
|
|
case 33:
|
|
// page up
|
|
this.focusPageUpOption();
|
|
break;
|
|
case 34:
|
|
// page down
|
|
this.focusPageDownOption();
|
|
break;
|
|
case 35:
|
|
// end key
|
|
if (event.shiftKey) {
|
|
return;
|
|
}
|
|
this.focusEndOption();
|
|
break;
|
|
case 36:
|
|
// home key
|
|
if (event.shiftKey) {
|
|
return;
|
|
}
|
|
this.focusStartOption();
|
|
break;
|
|
case 46:
|
|
// delete
|
|
if (!this.state.inputValue && this.props.deleteRemoves) {
|
|
event.preventDefault();
|
|
this.popValue();
|
|
}
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
}
|
|
}, {
|
|
key: 'handleValueClick',
|
|
value: function handleValueClick(option, event) {
|
|
if (!this.props.onValueClick) return;
|
|
this.props.onValueClick(option, event);
|
|
}
|
|
}, {
|
|
key: 'handleMenuScroll',
|
|
value: function handleMenuScroll(event) {
|
|
if (!this.props.onMenuScrollToBottom) return;
|
|
var target = event.target;
|
|
|
|
if (target.scrollHeight > target.offsetHeight && target.scrollHeight - target.offsetHeight - target.scrollTop <= 0) {
|
|
this.props.onMenuScrollToBottom();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'handleRequired',
|
|
value: function handleRequired(value, multi) {
|
|
if (!value) return true;
|
|
return multi ? value.length === 0 : Object.keys(value).length === 0;
|
|
}
|
|
}, {
|
|
key: 'getOptionLabel',
|
|
value: function getOptionLabel(op) {
|
|
return op[this.props.labelKey];
|
|
}
|
|
|
|
/**
|
|
* Turns a value into an array from the given options
|
|
* @param {String|Number|Array} value - the value of the select input
|
|
* @param {Object} nextProps - optionally specify the nextProps so the returned array uses the latest configuration
|
|
* @returns {Array} the value of the select represented in an array
|
|
*/
|
|
|
|
}, {
|
|
key: 'getValueArray',
|
|
value: function getValueArray(value, nextProps) {
|
|
var _this2 = this;
|
|
|
|
/** support optionally passing in the `nextProps` so `componentWillReceiveProps` updates will function as expected */
|
|
var props = (typeof nextProps === 'undefined' ? 'undefined' : _typeof(nextProps)) === 'object' ? nextProps : this.props;
|
|
if (props.multi) {
|
|
if (typeof value === 'string') {
|
|
value = value.split(props.delimiter);
|
|
}
|
|
if (!Array.isArray(value)) {
|
|
if (value === null || value === undefined) return [];
|
|
value = [value];
|
|
}
|
|
return value.map(function (value) {
|
|
return _this2.expandValue(value, props);
|
|
}).filter(function (i) {
|
|
return i;
|
|
});
|
|
}
|
|
var expandedValue = this.expandValue(value, props);
|
|
return expandedValue ? [expandedValue] : [];
|
|
}
|
|
|
|
/**
|
|
* Retrieve a value from the given options and valueKey
|
|
* @param {String|Number|Array} value - the selected value(s)
|
|
* @param {Object} props - the Select component's props (or nextProps)
|
|
*/
|
|
|
|
}, {
|
|
key: 'expandValue',
|
|
value: function expandValue(value, props) {
|
|
var valueType = typeof value === 'undefined' ? 'undefined' : _typeof(value);
|
|
if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean') return value;
|
|
var options = props.options,
|
|
valueKey = props.valueKey;
|
|
|
|
if (!options) return;
|
|
for (var i = 0; i < options.length; i++) {
|
|
if (String(options[i][valueKey]) === String(value)) return options[i];
|
|
}
|
|
}
|
|
}, {
|
|
key: 'setValue',
|
|
value: function setValue(value) {
|
|
var _this3 = this;
|
|
|
|
if (this.props.autoBlur) {
|
|
this.blurInput();
|
|
}
|
|
if (this.props.required) {
|
|
var required = this.handleRequired(value, this.props.multi);
|
|
this.setState({ required: required });
|
|
}
|
|
if (this.props.onChange) {
|
|
if (this.props.simpleValue && value) {
|
|
value = this.props.multi ? value.map(function (i) {
|
|
return i[_this3.props.valueKey];
|
|
}).join(this.props.delimiter) : value[this.props.valueKey];
|
|
}
|
|
this.props.onChange(value);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'selectValue',
|
|
value: function selectValue(value) {
|
|
var _this4 = this;
|
|
|
|
// NOTE: we actually add/set the value in a callback to make sure the
|
|
// input value is empty to avoid styling issues in Chrome
|
|
if (this.props.closeOnSelect) {
|
|
this.hasScrolledToOption = false;
|
|
}
|
|
if (this.props.multi) {
|
|
var updatedValue = this.props.onSelectResetsInput ? '' : this.state.inputValue;
|
|
this.setState({
|
|
focusedIndex: null,
|
|
inputValue: this.handleInputValueChange(updatedValue),
|
|
isOpen: !this.props.closeOnSelect
|
|
}, function () {
|
|
var valueArray = _this4.getValueArray(_this4.props.value);
|
|
if (valueArray.some(function (i) {
|
|
return i[_this4.props.valueKey] === value[_this4.props.valueKey];
|
|
})) {
|
|
_this4.removeValue(value);
|
|
} else {
|
|
_this4.addValue(value);
|
|
}
|
|
});
|
|
} else {
|
|
this.setState({
|
|
inputValue: this.handleInputValueChange(''),
|
|
isOpen: !this.props.closeOnSelect,
|
|
isPseudoFocused: this.state.isFocused
|
|
}, function () {
|
|
_this4.setValue(value);
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: 'addValue',
|
|
value: function addValue(value) {
|
|
var valueArray = this.getValueArray(this.props.value);
|
|
var visibleOptions = this._visibleOptions.filter(function (val) {
|
|
return !val.disabled;
|
|
});
|
|
var lastValueIndex = visibleOptions.indexOf(value);
|
|
this.setValue(valueArray.concat(value));
|
|
if (visibleOptions.length - 1 === lastValueIndex) {
|
|
// the last option was selected; focus the second-last one
|
|
this.focusOption(visibleOptions[lastValueIndex - 1]);
|
|
} else if (visibleOptions.length > lastValueIndex) {
|
|
// focus the option below the selected one
|
|
this.focusOption(visibleOptions[lastValueIndex + 1]);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'popValue',
|
|
value: function popValue() {
|
|
var valueArray = this.getValueArray(this.props.value);
|
|
if (!valueArray.length) return;
|
|
if (valueArray[valueArray.length - 1].clearableValue === false) return;
|
|
this.setValue(this.props.multi ? valueArray.slice(0, valueArray.length - 1) : null);
|
|
}
|
|
}, {
|
|
key: 'removeValue',
|
|
value: function removeValue(value) {
|
|
var _this5 = this;
|
|
|
|
var valueArray = this.getValueArray(this.props.value);
|
|
this.setValue(valueArray.filter(function (i) {
|
|
return i[_this5.props.valueKey] !== value[_this5.props.valueKey];
|
|
}));
|
|
this.focus();
|
|
}
|
|
}, {
|
|
key: 'clearValue',
|
|
value: function clearValue(event) {
|
|
// if the event was triggered by a mousedown and not the primary
|
|
// button, ignore it.
|
|
if (event && event.type === 'mousedown' && event.button !== 0) {
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
this.setValue(this.getResetValue());
|
|
this.setState({
|
|
isOpen: false,
|
|
inputValue: this.handleInputValueChange('')
|
|
}, this.focus);
|
|
}
|
|
}, {
|
|
key: 'getResetValue',
|
|
value: function getResetValue() {
|
|
if (this.props.resetValue !== undefined) {
|
|
return this.props.resetValue;
|
|
} else if (this.props.multi) {
|
|
return [];
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'focusOption',
|
|
value: function focusOption(option) {
|
|
this.setState({
|
|
focusedOption: option
|
|
});
|
|
}
|
|
}, {
|
|
key: 'focusNextOption',
|
|
value: function focusNextOption() {
|
|
this.focusAdjacentOption('next');
|
|
}
|
|
}, {
|
|
key: 'focusPreviousOption',
|
|
value: function focusPreviousOption() {
|
|
this.focusAdjacentOption('previous');
|
|
}
|
|
}, {
|
|
key: 'focusPageUpOption',
|
|
value: function focusPageUpOption() {
|
|
this.focusAdjacentOption('page_up');
|
|
}
|
|
}, {
|
|
key: 'focusPageDownOption',
|
|
value: function focusPageDownOption() {
|
|
this.focusAdjacentOption('page_down');
|
|
}
|
|
}, {
|
|
key: 'focusStartOption',
|
|
value: function focusStartOption() {
|
|
this.focusAdjacentOption('start');
|
|
}
|
|
}, {
|
|
key: 'focusEndOption',
|
|
value: function focusEndOption() {
|
|
this.focusAdjacentOption('end');
|
|
}
|
|
}, {
|
|
key: 'focusAdjacentOption',
|
|
value: function focusAdjacentOption(dir) {
|
|
var options = this._visibleOptions.map(function (option, index) {
|
|
return { option: option, index: index };
|
|
}).filter(function (option) {
|
|
return !option.option.disabled;
|
|
});
|
|
this._scrollToFocusedOptionOnUpdate = true;
|
|
if (!this.state.isOpen) {
|
|
this.setState({
|
|
isOpen: true,
|
|
inputValue: '',
|
|
focusedOption: this._focusedOption || (options.length ? options[dir === 'next' ? 0 : options.length - 1].option : null)
|
|
});
|
|
return;
|
|
}
|
|
if (!options.length) return;
|
|
var focusedIndex = -1;
|
|
for (var i = 0; i < options.length; i++) {
|
|
if (this._focusedOption === options[i].option) {
|
|
focusedIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
if (dir === 'next' && focusedIndex !== -1) {
|
|
focusedIndex = (focusedIndex + 1) % options.length;
|
|
} else if (dir === 'previous') {
|
|
if (focusedIndex > 0) {
|
|
focusedIndex = focusedIndex - 1;
|
|
} else {
|
|
focusedIndex = options.length - 1;
|
|
}
|
|
} else if (dir === 'start') {
|
|
focusedIndex = 0;
|
|
} else if (dir === 'end') {
|
|
focusedIndex = options.length - 1;
|
|
} else if (dir === 'page_up') {
|
|
var potentialIndex = focusedIndex - this.props.pageSize;
|
|
if (potentialIndex < 0) {
|
|
focusedIndex = 0;
|
|
} else {
|
|
focusedIndex = potentialIndex;
|
|
}
|
|
} else if (dir === 'page_down') {
|
|
var potentialIndex = focusedIndex + this.props.pageSize;
|
|
if (potentialIndex > options.length - 1) {
|
|
focusedIndex = options.length - 1;
|
|
} else {
|
|
focusedIndex = potentialIndex;
|
|
}
|
|
}
|
|
|
|
if (focusedIndex === -1) {
|
|
focusedIndex = 0;
|
|
}
|
|
|
|
this.setState({
|
|
focusedIndex: options[focusedIndex].index,
|
|
focusedOption: options[focusedIndex].option
|
|
});
|
|
}
|
|
}, {
|
|
key: 'getFocusedOption',
|
|
value: function getFocusedOption() {
|
|
return this._focusedOption;
|
|
}
|
|
}, {
|
|
key: 'selectFocusedOption',
|
|
value: function selectFocusedOption() {
|
|
if (this._focusedOption) {
|
|
return this.selectValue(this._focusedOption);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'renderLoading',
|
|
value: function renderLoading() {
|
|
if (!this.props.isLoading) return;
|
|
return _react2.default.createElement(
|
|
'span',
|
|
{ className: 'Select-loading-zone', 'aria-hidden': 'true' },
|
|
_react2.default.createElement('span', { className: 'Select-loading' })
|
|
);
|
|
}
|
|
}, {
|
|
key: 'renderValue',
|
|
value: function renderValue(valueArray, isOpen) {
|
|
var _this6 = this;
|
|
|
|
var renderLabel = this.props.valueRenderer || this.getOptionLabel;
|
|
var ValueComponent = this.props.valueComponent;
|
|
if (!valueArray.length) {
|
|
return !this.state.inputValue ? _react2.default.createElement(
|
|
'div',
|
|
{ className: 'Select-placeholder' },
|
|
this.props.placeholder
|
|
) : null;
|
|
}
|
|
var onClick = this.props.onValueClick ? this.handleValueClick : null;
|
|
if (this.props.multi) {
|
|
return valueArray.map(function (value, i) {
|
|
return _react2.default.createElement(
|
|
ValueComponent,
|
|
{
|
|
id: _this6._instancePrefix + '-value-' + i,
|
|
instancePrefix: _this6._instancePrefix,
|
|
disabled: _this6.props.disabled || value.clearableValue === false,
|
|
key: 'value-' + i + '-' + value[_this6.props.valueKey],
|
|
onClick: onClick,
|
|
onRemove: _this6.removeValue,
|
|
value: value
|
|
},
|
|
renderLabel(value, i),
|
|
_react2.default.createElement(
|
|
'span',
|
|
{ className: 'Select-aria-only' },
|
|
'\xA0'
|
|
)
|
|
);
|
|
});
|
|
} else if (!this.state.inputValue) {
|
|
if (isOpen) onClick = null;
|
|
return _react2.default.createElement(
|
|
ValueComponent,
|
|
{
|
|
id: this._instancePrefix + '-value-item',
|
|
disabled: this.props.disabled,
|
|
instancePrefix: this._instancePrefix,
|
|
onClick: onClick,
|
|
value: valueArray[0]
|
|
},
|
|
renderLabel(valueArray[0])
|
|
);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'renderInput',
|
|
value: function renderInput(valueArray, focusedOptionIndex) {
|
|
var _classNames,
|
|
_this7 = this;
|
|
|
|
var className = (0, _classnames2.default)('Select-input', this.props.inputProps.className);
|
|
var isOpen = !!this.state.isOpen;
|
|
|
|
var ariaOwns = (0, _classnames2.default)((_classNames = {}, _defineProperty(_classNames, this._instancePrefix + '-list', isOpen), _defineProperty(_classNames, this._instancePrefix + '-backspace-remove-message', this.props.multi && !this.props.disabled && this.state.isFocused && !this.state.inputValue), _classNames));
|
|
var inputProps = _extends({}, this.props.inputProps, {
|
|
role: 'combobox',
|
|
'aria-expanded': '' + isOpen,
|
|
'aria-owns': ariaOwns,
|
|
'aria-haspopup': '' + isOpen,
|
|
'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
|
|
'aria-describedby': this.props['aria-describedby'],
|
|
'aria-labelledby': this.props['aria-labelledby'],
|
|
'aria-label': this.props['aria-label'],
|
|
className: className,
|
|
tabIndex: this.props.tabIndex,
|
|
onBlur: this.handleInputBlur,
|
|
onChange: this.handleInputChange,
|
|
onFocus: this.handleInputFocus,
|
|
ref: function ref(_ref) {
|
|
return _this7.input = _ref;
|
|
},
|
|
required: this.state.required,
|
|
value: this.state.inputValue
|
|
});
|
|
|
|
if (this.props.inputRenderer) {
|
|
return this.props.inputRenderer(inputProps);
|
|
}
|
|
|
|
if (this.props.disabled || !this.props.searchable) {
|
|
var _props$inputProps = this.props.inputProps,
|
|
inputClassName = _props$inputProps.inputClassName,
|
|
divProps = _objectWithoutProperties(_props$inputProps, ['inputClassName']);
|
|
|
|
var _ariaOwns = (0, _classnames2.default)(_defineProperty({}, this._instancePrefix + '-list', isOpen));
|
|
return _react2.default.createElement('div', _extends({}, divProps, {
|
|
role: 'combobox',
|
|
'aria-expanded': isOpen,
|
|
'aria-owns': _ariaOwns,
|
|
'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
|
|
'aria-labelledby': this.props['aria-labelledby'],
|
|
'aria-label': this.props['aria-label'],
|
|
className: className,
|
|
tabIndex: this.props.tabIndex || 0,
|
|
onBlur: this.handleInputBlur,
|
|
onFocus: this.handleInputFocus,
|
|
ref: function ref(_ref2) {
|
|
return _this7.input = _ref2;
|
|
},
|
|
'aria-disabled': '' + !!this.props.disabled,
|
|
style: { border: 0, width: 1, display: 'inline-block' } }));
|
|
}
|
|
|
|
if (this.props.autosize) {
|
|
return _react2.default.createElement(_reactInputAutosize2.default, _extends({ id: this.props.id }, inputProps, { minWidth: '5' }));
|
|
}
|
|
return _react2.default.createElement(
|
|
'div',
|
|
{ className: className, key: 'input-wrap' },
|
|
_react2.default.createElement('input', _extends({ id: this.props.id }, inputProps))
|
|
);
|
|
}
|
|
}, {
|
|
key: 'renderClear',
|
|
value: function renderClear() {
|
|
var valueArray = this.getValueArray(this.props.value);
|
|
if (!this.props.clearable || !valueArray.length || this.props.disabled || this.props.isLoading) return;
|
|
var clear = this.props.clearRenderer();
|
|
|
|
return _react2.default.createElement(
|
|
'span',
|
|
{ className: 'Select-clear-zone', title: this.props.multi ? this.props.clearAllText : this.props.clearValueText,
|
|
'aria-label': this.props.multi ? this.props.clearAllText : this.props.clearValueText,
|
|
onMouseDown: this.clearValue,
|
|
onTouchStart: this.handleTouchStart,
|
|
onTouchMove: this.handleTouchMove,
|
|
onTouchEnd: this.handleTouchEndClearValue
|
|
},
|
|
clear
|
|
);
|
|
}
|
|
}, {
|
|
key: 'renderArrow',
|
|
value: function renderArrow() {
|
|
if (!this.props.arrowRenderer) return;
|
|
|
|
var onMouseDown = this.handleMouseDownOnArrow;
|
|
var isOpen = this.state.isOpen;
|
|
var arrow = this.props.arrowRenderer({ onMouseDown: onMouseDown, isOpen: isOpen });
|
|
|
|
if (!arrow) {
|
|
return null;
|
|
}
|
|
|
|
return _react2.default.createElement(
|
|
'span',
|
|
{
|
|
className: 'Select-arrow-zone',
|
|
onMouseDown: onMouseDown
|
|
},
|
|
arrow
|
|
);
|
|
}
|
|
}, {
|
|
key: 'filterOptions',
|
|
value: function filterOptions(excludeOptions) {
|
|
var filterValue = this.state.inputValue;
|
|
var options = this.props.options || [];
|
|
if (this.props.filterOptions) {
|
|
// Maintain backwards compatibility with boolean attribute
|
|
var filterOptions = typeof this.props.filterOptions === 'function' ? this.props.filterOptions : _defaultFilterOptions2.default;
|
|
|
|
return filterOptions(options, filterValue, excludeOptions, {
|
|
filterOption: this.props.filterOption,
|
|
ignoreAccents: this.props.ignoreAccents,
|
|
ignoreCase: this.props.ignoreCase,
|
|
labelKey: this.props.labelKey,
|
|
matchPos: this.props.matchPos,
|
|
matchProp: this.props.matchProp,
|
|
valueKey: this.props.valueKey,
|
|
trimFilter: this.props.trimFilter
|
|
});
|
|
} else {
|
|
return options;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'onOptionRef',
|
|
value: function onOptionRef(ref, isFocused) {
|
|
if (isFocused) {
|
|
this.focused = ref;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'renderMenu',
|
|
value: function renderMenu(options, valueArray, focusedOption) {
|
|
if (options && options.length) {
|
|
return this.props.menuRenderer({
|
|
focusedOption: focusedOption,
|
|
focusOption: this.focusOption,
|
|
inputValue: this.state.inputValue,
|
|
instancePrefix: this._instancePrefix,
|
|
labelKey: this.props.labelKey,
|
|
onFocus: this.focusOption,
|
|
onSelect: this.selectValue,
|
|
optionClassName: this.props.optionClassName,
|
|
optionComponent: this.props.optionComponent,
|
|
optionRenderer: this.props.optionRenderer || this.getOptionLabel,
|
|
options: options,
|
|
selectValue: this.selectValue,
|
|
removeValue: this.removeValue,
|
|
valueArray: valueArray,
|
|
valueKey: this.props.valueKey,
|
|
onOptionRef: this.onOptionRef
|
|
});
|
|
} else if (this.props.noResultsText) {
|
|
return _react2.default.createElement(
|
|
'div',
|
|
{ className: 'Select-noresults' },
|
|
this.props.noResultsText
|
|
);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'renderHiddenField',
|
|
value: function renderHiddenField(valueArray) {
|
|
var _this8 = this;
|
|
|
|
if (!this.props.name) return;
|
|
if (this.props.joinValues) {
|
|
var value = valueArray.map(function (i) {
|
|
return stringifyValue(i[_this8.props.valueKey]);
|
|
}).join(this.props.delimiter);
|
|
return _react2.default.createElement('input', {
|
|
type: 'hidden',
|
|
ref: function ref(_ref3) {
|
|
return _this8.value = _ref3;
|
|
},
|
|
name: this.props.name,
|
|
value: value,
|
|
disabled: this.props.disabled });
|
|
}
|
|
return valueArray.map(function (item, index) {
|
|
return _react2.default.createElement('input', { key: 'hidden.' + index,
|
|
type: 'hidden',
|
|
ref: 'value' + index,
|
|
name: _this8.props.name,
|
|
value: stringifyValue(item[_this8.props.valueKey]),
|
|
disabled: _this8.props.disabled });
|
|
});
|
|
}
|
|
}, {
|
|
key: 'getFocusableOptionIndex',
|
|
value: function getFocusableOptionIndex(selectedOption) {
|
|
var options = this._visibleOptions;
|
|
if (!options.length) return null;
|
|
|
|
var valueKey = this.props.valueKey;
|
|
var focusedOption = this.state.focusedOption || selectedOption;
|
|
if (focusedOption && !focusedOption.disabled) {
|
|
var focusedOptionIndex = -1;
|
|
options.some(function (option, index) {
|
|
var isOptionEqual = option[valueKey] === focusedOption[valueKey];
|
|
if (isOptionEqual) {
|
|
focusedOptionIndex = index;
|
|
}
|
|
return isOptionEqual;
|
|
});
|
|
if (focusedOptionIndex !== -1) {
|
|
return focusedOptionIndex;
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < options.length; i++) {
|
|
if (!options[i].disabled) return i;
|
|
}
|
|
return null;
|
|
}
|
|
}, {
|
|
key: 'renderOuter',
|
|
value: function renderOuter(options, valueArray, focusedOption) {
|
|
var _this9 = this;
|
|
|
|
var menu = this.renderMenu(options, valueArray, focusedOption);
|
|
if (!menu) {
|
|
return null;
|
|
}
|
|
|
|
return _react2.default.createElement(
|
|
'div',
|
|
{ ref: function ref(_ref5) {
|
|
return _this9.menuContainer = _ref5;
|
|
}, className: 'Select-menu-outer', style: this.props.menuContainerStyle },
|
|
_react2.default.createElement(
|
|
'div',
|
|
{ ref: function ref(_ref4) {
|
|
return _this9.menu = _ref4;
|
|
}, role: 'listbox', tabIndex: -1, className: 'Select-menu', id: this._instancePrefix + '-list',
|
|
style: this.props.menuStyle,
|
|
onScroll: this.handleMenuScroll,
|
|
onMouseDown: this.handleMouseDownOnMenu },
|
|
menu
|
|
)
|
|
);
|
|
}
|
|
}, {
|
|
key: 'render',
|
|
value: function render() {
|
|
var _this10 = this;
|
|
|
|
var valueArray = this.getValueArray(this.props.value);
|
|
var options = this._visibleOptions = this.filterOptions(this.props.multi && this.props.removeSelected ? valueArray : null);
|
|
var isOpen = this.state.isOpen;
|
|
if (this.props.multi && !options.length && valueArray.length && !this.state.inputValue) isOpen = false;
|
|
var focusedOptionIndex = this.getFocusableOptionIndex(valueArray[0]);
|
|
|
|
var focusedOption = null;
|
|
if (focusedOptionIndex !== null) {
|
|
focusedOption = this._focusedOption = options[focusedOptionIndex];
|
|
} else {
|
|
focusedOption = this._focusedOption = null;
|
|
}
|
|
var className = (0, _classnames2.default)('Select', this.props.className, {
|
|
'Select--multi': this.props.multi,
|
|
'Select--single': !this.props.multi,
|
|
'is-clearable': this.props.clearable,
|
|
'is-disabled': this.props.disabled,
|
|
'is-focused': this.state.isFocused,
|
|
'is-loading': this.props.isLoading,
|
|
'is-open': isOpen,
|
|
'is-pseudo-focused': this.state.isPseudoFocused,
|
|
'is-searchable': this.props.searchable,
|
|
'has-value': valueArray.length,
|
|
'Select--rtl': this.props.rtl
|
|
});
|
|
|
|
var removeMessage = null;
|
|
if (this.props.multi && !this.props.disabled && valueArray.length && !this.state.inputValue && this.state.isFocused && this.props.backspaceRemoves) {
|
|
removeMessage = _react2.default.createElement(
|
|
'span',
|
|
{ id: this._instancePrefix + '-backspace-remove-message', className: 'Select-aria-only', 'aria-live': 'assertive' },
|
|
this.props.backspaceToRemoveMessage.replace('{label}', valueArray[valueArray.length - 1][this.props.labelKey])
|
|
);
|
|
}
|
|
|
|
return _react2.default.createElement(
|
|
'div',
|
|
{ ref: function ref(_ref7) {
|
|
return _this10.wrapper = _ref7;
|
|
},
|
|
className: className,
|
|
style: this.props.wrapperStyle },
|
|
this.renderHiddenField(valueArray),
|
|
_react2.default.createElement(
|
|
'div',
|
|
{ ref: function ref(_ref6) {
|
|
return _this10.control = _ref6;
|
|
},
|
|
className: 'Select-control',
|
|
style: this.props.style,
|
|
onKeyDown: this.handleKeyDown,
|
|
onMouseDown: this.handleMouseDown,
|
|
onTouchEnd: this.handleTouchEnd,
|
|
onTouchStart: this.handleTouchStart,
|
|
onTouchMove: this.handleTouchMove
|
|
},
|
|
_react2.default.createElement(
|
|
'span',
|
|
{ className: 'Select-multi-value-wrapper', id: this._instancePrefix + '-value' },
|
|
this.renderValue(valueArray, isOpen),
|
|
this.renderInput(valueArray, focusedOptionIndex)
|
|
),
|
|
removeMessage,
|
|
this.renderLoading(),
|
|
this.renderClear(),
|
|
this.renderArrow()
|
|
),
|
|
isOpen ? this.renderOuter(options, valueArray, focusedOption) : null
|
|
);
|
|
}
|
|
}]);
|
|
|
|
return Select;
|
|
}(_react2.default.Component);
|
|
|
|
;
|
|
|
|
Select.propTypes = {
|
|
'aria-describedby': _propTypes2.default.string, // html id(s) of element(s) that should be used to describe this input (for assistive tech)
|
|
'aria-label': _propTypes2.default.string, // aria label (for assistive tech)
|
|
'aria-labelledby': _propTypes2.default.string, // html id of an element that should be used as the label (for assistive tech)
|
|
arrowRenderer: _propTypes2.default.func, // create the drop-down caret element
|
|
autoBlur: _propTypes2.default.bool, // automatically blur the component when an option is selected
|
|
autoFocus: _propTypes2.default.bool, // autofocus the component on mount
|
|
autofocus: _propTypes2.default.bool, // deprecated; use autoFocus instead
|
|
autosize: _propTypes2.default.bool, // whether to enable autosizing or not
|
|
backspaceRemoves: _propTypes2.default.bool, // whether backspace removes an item if there is no text input
|
|
backspaceToRemoveMessage: _propTypes2.default.string, // message to use for screenreaders to press backspace to remove the current item - {label} is replaced with the item label
|
|
className: _propTypes2.default.string, // className for the outer element
|
|
clearAllText: stringOrNode, // title for the "clear" control when multi: true
|
|
clearRenderer: _propTypes2.default.func, // create clearable x element
|
|
clearValueText: stringOrNode, // title for the "clear" control
|
|
clearable: _propTypes2.default.bool, // should it be possible to reset value
|
|
closeOnSelect: _propTypes2.default.bool, // whether to close the menu when a value is selected
|
|
deleteRemoves: _propTypes2.default.bool, // whether delete removes an item if there is no text input
|
|
delimiter: _propTypes2.default.string, // delimiter to use to join multiple values for the hidden field value
|
|
disabled: _propTypes2.default.bool, // whether the Select is disabled or not
|
|
escapeClearsValue: _propTypes2.default.bool, // whether escape clears the value when the menu is closed
|
|
filterOption: _propTypes2.default.func, // method to filter a single option (option, filterString)
|
|
filterOptions: _propTypes2.default.any, // boolean to enable default filtering or function to filter the options array ([options], filterString, [values])
|
|
id: _propTypes2.default.string, // html id to set on the input element for accessibility or tests
|
|
ignoreAccents: _propTypes2.default.bool, // whether to strip diacritics when filtering
|
|
ignoreCase: _propTypes2.default.bool, // whether to perform case-insensitive filtering
|
|
inputProps: _propTypes2.default.object, // custom attributes for the Input
|
|
inputRenderer: _propTypes2.default.func, // returns a custom input component
|
|
instanceId: _propTypes2.default.string, // set the components instanceId
|
|
isLoading: _propTypes2.default.bool, // whether the Select is loading externally or not (such as options being loaded)
|
|
joinValues: _propTypes2.default.bool, // joins multiple values into a single form field with the delimiter (legacy mode)
|
|
labelKey: _propTypes2.default.string, // path of the label value in option objects
|
|
matchPos: _propTypes2.default.string, // (any|start) match the start or entire string when filtering
|
|
matchProp: _propTypes2.default.string, // (any|label|value) which option property to filter on
|
|
menuBuffer: _propTypes2.default.number, // optional buffer (in px) between the bottom of the viewport and the bottom of the menu
|
|
menuContainerStyle: _propTypes2.default.object, // optional style to apply to the menu container
|
|
menuRenderer: _propTypes2.default.func, // renders a custom menu with options
|
|
menuStyle: _propTypes2.default.object, // optional style to apply to the menu
|
|
multi: _propTypes2.default.bool, // multi-value input
|
|
name: _propTypes2.default.string, // generates a hidden <input /> tag with this field name for html forms
|
|
noResultsText: stringOrNode, // placeholder displayed when there are no matching search results
|
|
onBlur: _propTypes2.default.func, // onBlur handler: function (event) {}
|
|
onBlurResetsInput: _propTypes2.default.bool, // whether input is cleared on blur
|
|
onChange: _propTypes2.default.func, // onChange handler: function (newValue) {}
|
|
onClose: _propTypes2.default.func, // fires when the menu is closed
|
|
onCloseResetsInput: _propTypes2.default.bool, // whether input is cleared when menu is closed through the arrow
|
|
onFocus: _propTypes2.default.func, // onFocus handler: function (event) {}
|
|
onInputChange: _propTypes2.default.func, // onInputChange handler: function (inputValue) {}
|
|
onInputKeyDown: _propTypes2.default.func, // input keyDown handler: function (event) {}
|
|
onMenuScrollToBottom: _propTypes2.default.func, // fires when the menu is scrolled to the bottom; can be used to paginate options
|
|
onOpen: _propTypes2.default.func, // fires when the menu is opened
|
|
onSelectResetsInput: _propTypes2.default.bool, // whether input is cleared on select (works only for multiselect)
|
|
onValueClick: _propTypes2.default.func, // onClick handler for value labels: function (value, event) {}
|
|
openOnClick: _propTypes2.default.bool, // boolean to control opening the menu when the control is clicked
|
|
openOnFocus: _propTypes2.default.bool, // always open options menu on focus
|
|
optionClassName: _propTypes2.default.string, // additional class(es) to apply to the <Option /> elements
|
|
optionComponent: _propTypes2.default.func, // option component to render in dropdown
|
|
optionRenderer: _propTypes2.default.func, // optionRenderer: function (option) {}
|
|
options: _propTypes2.default.array, // array of options
|
|
pageSize: _propTypes2.default.number, // number of entries to page when using page up/down keys
|
|
placeholder: stringOrNode, // field placeholder, displayed when there's no value
|
|
removeSelected: _propTypes2.default.bool, // whether the selected option is removed from the dropdown on multi selects
|
|
required: _propTypes2.default.bool, // applies HTML5 required attribute when needed
|
|
resetValue: _propTypes2.default.any, // value to use when you clear the control
|
|
rtl: _propTypes2.default.bool, // set to true in order to use react-select in right-to-left direction
|
|
scrollMenuIntoView: _propTypes2.default.bool, // boolean to enable the viewport to shift so that the full menu fully visible when engaged
|
|
searchable: _propTypes2.default.bool, // whether to enable searching feature or not
|
|
simpleValue: _propTypes2.default.bool, // pass the value to onChange as a simple value (legacy pre 1.0 mode), defaults to false
|
|
style: _propTypes2.default.object, // optional style to apply to the control
|
|
tabIndex: stringOrNumber, // optional tab index of the control
|
|
tabSelectsValue: _propTypes2.default.bool, // whether to treat tabbing out while focused to be value selection
|
|
trimFilter: _propTypes2.default.bool, // whether to trim whitespace around filter value
|
|
value: _propTypes2.default.any, // initial field value
|
|
valueComponent: _propTypes2.default.func, // value component to render
|
|
valueKey: _propTypes2.default.string, // path of the label value in option objects
|
|
valueRenderer: _propTypes2.default.func, // valueRenderer: function (option) {}
|
|
wrapperStyle: _propTypes2.default.object // optional style to apply to the component wrapper
|
|
};
|
|
|
|
Select.defaultProps = {
|
|
arrowRenderer: _defaultArrowRenderer2.default,
|
|
autosize: true,
|
|
backspaceRemoves: true,
|
|
backspaceToRemoveMessage: 'Press backspace to remove {label}',
|
|
clearable: true,
|
|
clearAllText: 'Clear all',
|
|
clearRenderer: _defaultClearRenderer2.default,
|
|
clearValueText: 'Clear value',
|
|
closeOnSelect: true,
|
|
deleteRemoves: true,
|
|
delimiter: ',',
|
|
disabled: false,
|
|
escapeClearsValue: true,
|
|
filterOptions: _defaultFilterOptions2.default,
|
|
ignoreAccents: true,
|
|
ignoreCase: true,
|
|
inputProps: {},
|
|
isLoading: false,
|
|
joinValues: false,
|
|
labelKey: 'label',
|
|
matchPos: 'any',
|
|
matchProp: 'any',
|
|
menuBuffer: 0,
|
|
menuRenderer: _defaultMenuRenderer2.default,
|
|
multi: false,
|
|
noResultsText: 'No results found',
|
|
onBlurResetsInput: true,
|
|
onSelectResetsInput: true,
|
|
onCloseResetsInput: true,
|
|
openOnClick: true,
|
|
optionComponent: _Option2.default,
|
|
pageSize: 5,
|
|
placeholder: 'Select...',
|
|
removeSelected: true,
|
|
required: false,
|
|
rtl: false,
|
|
scrollMenuIntoView: true,
|
|
searchable: true,
|
|
simpleValue: false,
|
|
tabSelectsValue: true,
|
|
trimFilter: true,
|
|
valueComponent: _Value2.default,
|
|
valueKey: 'value'
|
|
};
|
|
|
|
exports.default = Select; |