d2-ui
Version:
550 lines (461 loc) • 16.1 kB
JavaScript
'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; };
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
Object.defineProperty(exports, "__esModule", {
value: true
});
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
var _stylePropable = require('./mixins/style-propable');
var _stylePropable2 = _interopRequireDefault(_stylePropable);
var _keyCode = require('./utils/key-code');
var _keyCode2 = _interopRequireDefault(_keyCode);
var _textField = require('./text-field');
var _textField2 = _interopRequireDefault(_textField);
var _menu = require('./menus/menu');
var _menu2 = _interopRequireDefault(_menu);
var _menuItem = require('./menus/menu-item');
var _menuItem2 = _interopRequireDefault(_menuItem);
var _divider = require('./divider');
var _divider2 = _interopRequireDefault(_divider);
var _popover = require('./popover/popover');
var _popover2 = _interopRequireDefault(_popover);
var _propTypes = require('./utils/prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _deprecatedPropType = require('./utils/deprecatedPropType');
var _deprecatedPropType2 = _interopRequireDefault(_deprecatedPropType);
var _getMuiTheme = require('./styles/getMuiTheme');
var _getMuiTheme2 = _interopRequireDefault(_getMuiTheme);
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; }
var AutoComplete = _react2.default.createClass({
displayName: 'AutoComplete',
propTypes: {
/**
* Location of the anchor for the auto complete.
*/
anchorOrigin: _propTypes2.default.origin,
/**
* Whether or not the auto complete is animated as it is toggled.
*/
animated: _react2.default.PropTypes.bool,
/**
* Array of strings or nodes used to populate the list.
*/
dataSource: _react2.default.PropTypes.array,
/**
* Disables focus ripple when true.
*/
disableFocusRipple: _react2.default.PropTypes.bool,
/**
* Override style prop for error.
*/
errorStyle: _react2.default.PropTypes.object,
/**
* The error content to display.
*/
errorText: _react2.default.PropTypes.string,
/**
* Function used to filter the auto complete.
*/
filter: _react2.default.PropTypes.func,
/**
* The content to use for adding floating label element.
*/
floatingLabelText: _react2.default.PropTypes.string,
/**
* If true, the field receives the property `width: 100%`.
*/
fullWidth: _react2.default.PropTypes.bool,
/**
* The hint content to display.
*/
hintText: _react2.default.PropTypes.string,
/**
* Override style for list.
*/
listStyle: _react2.default.PropTypes.object,
/**
* Delay for closing time of the menu.
*/
menuCloseDelay: _react2.default.PropTypes.number,
/**
* Props to be passed to menu.
*/
menuProps: _react2.default.PropTypes.object,
/**
* Override style for menu.
*/
menuStyle: _react2.default.PropTypes.object,
/**
* Gets called when list item is clicked or pressed enter.
*/
onNewRequest: _react2.default.PropTypes.func,
/**
* Gets called each time the user updates the text field.
*/
onUpdateInput: _react2.default.PropTypes.func,
/**
* Auto complete menu is open if true.
*/
open: _react2.default.PropTypes.bool,
/**
* Text being input to auto complete.
*/
searchText: _react2.default.PropTypes.string,
showAllItems: (0, _deprecatedPropType2.default)(_react2.default.PropTypes.bool, 'showAllItems is deprecated, use noFilter instead'),
/**
* Override the inline-styles of the root element.
*/
style: _react2.default.PropTypes.object,
/**
* Origin for location of target.
*/
targetOrigin: _propTypes2.default.origin,
/**
* Delay for touch tap event closing of auto complete.
*/
touchTapCloseDelay: _react2.default.PropTypes.number,
/**
* If true, will update when focus event triggers.
*/
triggerUpdateOnFocus: _react2.default.PropTypes.bool,
updateWhenFocused: (0, _deprecatedPropType2.default)(_react2.default.PropTypes.bool, 'updateWhenFocused has been renamed to triggerUpdateOnFocus')
},
contextTypes: {
muiTheme: _react2.default.PropTypes.object
},
//for passing default theme context to children
childContextTypes: {
muiTheme: _react2.default.PropTypes.object
},
mixins: [_stylePropable2.default],
getDefaultProps: function getDefaultProps() {
return {
anchorOrigin: {
vertical: 'bottom',
horizontal: 'left'
},
targetOrigin: {
vertical: 'top',
horizontal: 'left'
},
animated: true,
fullWidth: false,
open: false,
searchText: '',
menuCloseDelay: 100,
disableFocusRipple: true,
onUpdateInput: function onUpdateInput() {},
onNewRequest: function onNewRequest() {},
filter: function filter(searchText, key) {
return searchText !== '' && key.includes(searchText);
},
triggerUpdateOnFocus: false
};
},
getInitialState: function getInitialState() {
return {
searchText: this.props.searchText,
open: this.props.open,
anchorEl: null,
muiTheme: this.context.muiTheme || (0, _getMuiTheme2.default)()
};
},
getChildContext: function getChildContext() {
return {
muiTheme: this.state.muiTheme
};
},
componentWillMount: function componentWillMount() {
this.focusOnInput = false;
this.requestsList = [];
},
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
if (this.props.searchText !== nextProps.searchText) {
this.setState({
searchText: nextProps.searchText
});
}
},
componentClickAway: function componentClickAway() {
this._close();
this.focusOnInput = false;
},
_open: function _open() {
this.setState({
open: true,
anchorEl: _reactDom2.default.findDOMNode(this.refs.searchTextField)
});
},
_close: function _close() {
this.setState({
open: false,
anchorEl: null
});
},
setValue: function setValue(textValue) {
this.setState({
searchText: textValue
});
},
getValue: function getValue() {
return this.state.searchText;
},
_updateRequests: function _updateRequests(searchText) {
this.setState({
searchText: searchText,
open: true,
anchorEl: _reactDom2.default.findDOMNode(this.refs.searchTextField)
});
this.focusOnInput = true;
this.props.onUpdateInput(searchText, this.props.dataSource);
},
_handleItemTouchTap: function _handleItemTouchTap(e, child) {
var _this = this;
setTimeout(function () {
_this._close();
}, this.props.touchTapCloseDelay);
var dataSource = this.props.dataSource;
var chosenRequest = undefined;
var index = undefined;
var searchText = undefined;
if (typeof dataSource[0] === 'string') {
chosenRequest = this.requestsList[parseInt(child.key, 10)];
index = dataSource.indexOf(chosenRequest);
searchText = dataSource[index];
} else {
chosenRequest = child.key;
index = dataSource.indexOf(dataSource.filter(function (item) {
return chosenRequest === item.text;
})[0]);
searchText = chosenRequest;
}
this.setState({ searchText: searchText });
this.props.onNewRequest(chosenRequest, index, dataSource);
},
_handleKeyDown: function _handleKeyDown(e) {
switch (e.keyCode) {
case _keyCode2.default.ESC:
this._close();
break;
case _keyCode2.default.DOWN:
if (this.focusOnInput && this.state.open) {
e.preventDefault();
this.focusOnInput = false;
this._open();
}
break;
default:
break;
}
},
render: function render() {
var _this2 = this;
var _props = this.props;
var anchorOrigin = _props.anchorOrigin;
var animated = _props.animated;
var style = _props.style;
var errorStyle = _props.errorStyle;
var floatingLabelText = _props.floatingLabelText;
var hintText = _props.hintText;
var fullWidth = _props.fullWidth;
var menuStyle = _props.menuStyle;
var menuProps = _props.menuProps;
var listStyle = _props.listStyle;
var targetOrigin = _props.targetOrigin;
var other = _objectWithoutProperties(_props, ['anchorOrigin', 'animated', 'style', 'errorStyle', 'floatingLabelText', 'hintText', 'fullWidth', 'menuStyle', 'menuProps', 'listStyle', 'targetOrigin']);
var _state = this.state;
var open = _state.open;
var anchorEl = _state.anchorEl;
var styles = {
root: {
display: 'inline-block',
position: 'relative',
width: this.props.fullWidth ? '100%' : 256
},
input: {},
error: {},
menu: {
width: '100%'
},
list: {
display: 'block',
width: this.props.fullWidth ? '100%' : 256
}
};
var textFieldProps = {
style: this.mergeStyles(styles.input, style),
floatingLabelText: floatingLabelText,
hintText: !hintText && !floatingLabelText ? '' : hintText,
fullWidth: true,
multiLine: false,
errorStyle: this.mergeStyles(styles.error, errorStyle)
};
var mergedRootStyles = this.mergeStyles(styles.root, style);
var mergedMenuStyles = this.mergeStyles(styles.menu, menuStyle);
var requestsList = [];
this.props.dataSource.map(function (item) {
//showAllItems is deprecated, will be removed in the future
if (_this2.props.showAllItems) {
requestsList.push(item);
return;
}
switch (typeof item === 'undefined' ? 'undefined' : _typeof(item)) {
case 'string':
if (_this2.props.filter(_this2.state.searchText, item, item)) {
requestsList.push(item);
}
break;
case 'object':
if (typeof item.text === 'string') {
if (_this2.props.filter(_this2.state.searchText, item.text, item)) {
requestsList.push(item);
}
}
break;
}
});
this.requestsList = requestsList;
var menu = open && requestsList.length > 0 ? _react2.default.createElement(
_menu2.default,
_extends({}, menuProps, {
ref: 'menu',
key: 'dropDownMenu',
autoWidth: false,
onEscKeyDown: this._close,
initiallyKeyboardFocused: false,
onItemTouchTap: this._handleItemTouchTap,
listStyle: this.mergeStyles(styles.list, listStyle),
style: mergedMenuStyles
}),
requestsList.map(function (request, index) {
switch (typeof request === 'undefined' ? 'undefined' : _typeof(request)) {
case 'string':
return _react2.default.createElement(_menuItem2.default, {
disableFocusRipple: _this2.props.disableFocusRipple,
innerDivStyle: { overflow: 'hidden' },
key: index,
value: request,
primaryText: request
});
case 'object':
if (typeof request.text === 'string') {
return _react2.default.cloneElement(request.value, {
key: request.text,
disableFocusRipple: _this2.props.disableFocusRipple
});
}
return _react2.default.cloneElement(request, {
key: index,
disableFocusRipple: _this2.props.disableFocusRipple
});
default:
return null;
}
})
) : null;
var popoverStyle = undefined;
if (anchorEl && fullWidth) {
popoverStyle = { width: anchorEl.clientWidth };
}
return _react2.default.createElement(
'div',
{
style: this.prepareStyles(mergedRootStyles),
onKeyDown: this._handleKeyDown
},
_react2.default.createElement(
'div',
{
style: {
width: '100%'
}
},
_react2.default.createElement(_textField2.default, _extends({}, other, {
ref: 'searchTextField',
value: this.state.searchText,
onEnterKeyDown: function onEnterKeyDown() {
setTimeout(function () {
_this2._close();
}, _this2.props.touchTapCloseDelay);
_this2.props.onNewRequest(_this2.state.searchText);
},
onChange: function onChange(e) {
var searchText = e.target.value;
_this2._updateRequests(searchText);
},
onBlur: function onBlur() {
if (_this2.focusOnInput && open) _this2.refs.searchTextField.focus();
},
onFocus: function onFocus() {
if (!open && (_this2.props.triggerUpdateOnFocus || _this2.props.updateWhenFocused //this line will be removed in the future
|| _this2.requestsList > 0)) {
_this2._updateRequests(_this2.state.searchText);
}
_this2.focusOnInput = true;
}
}, textFieldProps))
),
_react2.default.createElement(
_popover2.default,
{
style: popoverStyle,
anchorOrigin: anchorOrigin,
targetOrigin: targetOrigin,
open: open,
anchorEl: anchorEl,
useLayerForClickAway: false,
onRequestClose: this._close
},
menu
)
);
}
});
AutoComplete.levenshteinDistance = function (searchText, key) {
var current = [];
var prev = undefined;
var value = undefined;
for (var i = 0; i <= key.length; i++) {
for (var j = 0; j <= searchText.length; j++) {
if (i && j) {
if (searchText.charAt(j - 1) === key.charAt(i - 1)) value = prev;else value = Math.min(current[j], current[j - 1], prev) + 1;
} else {
value = i + j;
}
prev = current[j];
current[j] = value;
}
}
return current.pop();
};
AutoComplete.noFilter = function () {
return true;
};
AutoComplete.defaultFilter = AutoComplete.caseSensitiveFilter = function (searchText, key) {
return searchText !== '' && key.includes(searchText);
};
AutoComplete.caseInsensitiveFilter = function (searchText, key) {
return key.toLowerCase().includes(searchText.toLowerCase());
};
AutoComplete.levenshteinDistanceFilter = function (distanceLessThan) {
if (distanceLessThan === undefined) return AutoComplete.levenshteinDistance;else if (typeof distanceLessThan !== 'number') {
throw 'Error: AutoComplete.levenshteinDistanceFilter is a filter generator, not a filter!';
}
return function (s, k) {
return AutoComplete.levenshteinDistance(s, k) < distanceLessThan;
};
};
AutoComplete.fuzzyFilter = function (searchText, key) {
if (searchText.length === 0) return false;
var subMatchKey = key.substring(0, searchText.length);
var distance = AutoComplete.levenshteinDistance(searchText.toLowerCase(), subMatchKey.toLowerCase());
return searchText.length > 3 ? distance < 2 : distance === 0;
};
AutoComplete.Item = _menuItem2.default;
AutoComplete.Divider = _divider2.default;
exports.default = AutoComplete;
module.exports = exports['default'];