backpack-ui
Version:
Lonely Planet's Components
352 lines (281 loc) • 11.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperty2 = require("babel-runtime/helpers/defineProperty");
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
var _getPrototypeOf = require("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _createClass2 = require("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _inherits2 = require("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
var _propTypes = require("prop-types");
var _propTypes2 = _interopRequireDefault(_propTypes);
var _classnames = require("classnames");
var _classnames2 = _interopRequireDefault(_classnames);
var _typeahead = require("./typeahead");
var _typeahead2 = _interopRequireDefault(_typeahead);
var _typeaheadToken = require("./typeaheadToken");
var _typeaheadToken2 = _interopRequireDefault(_typeaheadToken);
var _accessor = require("./utils/accessor");
var _accessor2 = _interopRequireDefault(_accessor);
var _keyEvent = require("./utils/keyEvent");
var _keyEvent2 = _interopRequireDefault(_keyEvent);
var _classNames = require("./utils/classNames");
var _classNames2 = _interopRequireDefault(_classNames);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* A typeahead that, when an option is selected, instead of simply filling
* the text entry widget, prepends a renderable "token", that may be deleted
* by pressing backspace on the beginning of the line with the keyboard.
*/
var TypeaheadTokenizer = function (_Component) {
(0, _inherits3.default)(TypeaheadTokenizer, _Component);
(0, _createClass3.default)(TypeaheadTokenizer, null, [{
key: "arraysAreDifferent",
value: function arraysAreDifferent(firstArray, secondArray) {
if (firstArray.length !== secondArray.length) {
return true;
}
for (var index = secondArray.length - 1; index >= 0; index -= 1) {
if (secondArray[index] !== firstArray[index]) {
return true;
}
}
return false;
}
}]);
function TypeaheadTokenizer(props) {
(0, _classCallCheck3.default)(this, TypeaheadTokenizer);
var _this = (0, _possibleConstructorReturn3.default)(this, (TypeaheadTokenizer.__proto__ || (0, _getPrototypeOf2.default)(TypeaheadTokenizer)).call(this, props));
_this.state = {
selected: props.defaultSelected.slice(0)
};
_this.onKeyDown = _this.onKeyDown.bind(_this);
_this.getSelectedTokens = _this.getSelectedTokens.bind(_this);
_this.getOptionsForTypeahead = _this.getOptionsForTypeahead.bind(_this);
_this.handleBackspace = _this.handleBackspace.bind(_this);
_this.removeTokenForValue = _this.removeTokenForValue.bind(_this);
_this.addTokenForValue = _this.addTokenForValue.bind(_this);
_this.renderTokens = _this.renderTokens.bind(_this);
return _this;
}
(0, _createClass3.default)(TypeaheadTokenizer, [{
key: "componentWillReceiveProps",
value: function componentWillReceiveProps(nextProps) {
var arraysAreDifferent = TypeaheadTokenizer.arraysAreDifferent(this.props.defaultSelected, nextProps.defaultSelected);
if (arraysAreDifferent) {
this.setState({
selected: nextProps.defaultSelected.slice(0)
});
}
}
}, {
key: "onKeyDown",
value: function onKeyDown(event) {
// We only care about intercepting backspaces
if (event.keyCode === _keyEvent2.default.DOM_VK_BACKSPACE) {
return this.handleBackspace(event);
}
this.props.onKeyDown(event);
return null;
}
}, {
key: "getSelectedTokens",
value: function getSelectedTokens() {
return this.state.selected;
}
}, {
key: "getOptionsForTypeahead",
value: function getOptionsForTypeahead() {
// return this.props.options without this.selected
return this.props.options;
}
}, {
key: "focus",
value: function focus() {
this.typeahead.focus();
}
}, {
key: "handleBackspace",
value: function handleBackspace(event) {
var selected = this.state.selected;
// No tokens
if (!selected.length) {
return;
}
// Remove token ONLY when backspace pressed at
// beginning of line without a selection
var inputElement = this.typeahead.inputElement;
if (inputElement.selectionStart === inputElement.selectionEnd && inputElement.selectionStart === 0) {
this.removeTokenForValue(selected[selected.length - 1]);
event.preventDefault();
}
}
}, {
key: "removeTokenForValue",
value: function removeTokenForValue(value) {
var selected = this.state.selected;
var index = selected.indexOf(value);
if (index === -1) {
return;
}
// TODO: not sure we should be doing this to state
selected.splice(index, 1);
this.setState({
selected: selected
});
this.props.onTokenRemove(value);
}
}, {
key: "addTokenForValue",
value: function addTokenForValue(event, value) {
var selected = this.state.selected;
if (selected.indexOf(value) !== -1) {
return;
}
// TODO: not sure we should be doing this to state
selected.push(value);
this.setState({
selected: selected
});
this.typeahead.setEntryText("");
this.props.onTokenAdd(value);
}
// TODO: Support initialized tokens
}, {
key: "renderTokens",
value: function renderTokens() {
var _this2 = this;
var _props = this.props,
customClasses = _props.customClasses,
disableDefaultClassNames = _props.disableDefaultClassNames,
displayOption = _props.displayOption,
formInputOption = _props.formInputOption,
name = _props.name;
var tokenClasses = (0, _defineProperty3.default)({}, _classNames2.default.token, !disableDefaultClassNames);
tokenClasses[customClasses.token] = !!customClasses.token;
var result = this.state.selected.map(function (selected) {
var displayString = _accessor2.default.valueForOption(displayOption, selected);
var value = _accessor2.default.valueForOption(formInputOption || displayOption, selected);
return _react2.default.createElement(
_typeaheadToken2.default,
{
className: (0, _classnames2.default)(tokenClasses),
key: displayString,
onRemove: _this2.removeTokenForValue,
object: selected,
value: value,
name: name
},
displayString
);
});
return result;
}
}, {
key: "render",
value: function render() {
var _this3 = this;
var classes = {};
classes[this.props.customClasses.typeahead] = !!this.props.customClasses.typeahead;
var classList = (0, _classnames2.default)(classes);
var tokenizerClasses = [!this.props.disableDefaultClassNames && _classNames2.default.tokenizer];
tokenizerClasses[this.props.className] = !!this.props.className;
var tokenizerClassList = (0, _classnames2.default)(tokenizerClasses);
return _react2.default.createElement(
"div",
{ className: tokenizerClassList },
this.renderTokens(),
_react2.default.createElement(_typeahead2.default, {
ref: function ref(node) {
return _this3.typeahead = node;
},
className: classList,
placeholder: this.props.placeholder,
disabled: this.props.disabled,
inputProps: this.props.inputProps,
allowCustomValues: this.props.allowCustomValues,
customClasses: this.props.customClasses,
options: this.getOptionsForTypeahead(),
initialValue: this.props.initialValue,
maxVisible: this.props.maxVisible,
resultsTruncatedMessage: this.props.resultsTruncatedMessage,
onOptionSelected: this.addTokenForValue,
onKeyDown: this.onKeyDown,
onKeyPress: this.props.onKeyPress,
onKeyUp: this.props.onKeyUp,
onFocus: this.props.onFocus,
onBlur: this.props.onBlur,
displayOption: this.props.displayOption,
disableDefaultClassNames: this.props.disableDefaultClassNames,
filterOption: this.props.filterOption,
searchOptions: this.props.searchOptions
})
);
}
}]);
return TypeaheadTokenizer;
}(_react.Component);
TypeaheadTokenizer.propTypes = {
className: _propTypes2.default.string,
name: _propTypes2.default.string,
options: _propTypes2.default.arrayOf(_propTypes2.default.string),
customClasses: _propTypes2.default.objectOf(_propTypes2.default.string),
allowCustomValues: _propTypes2.default.number,
defaultSelected: _propTypes2.default.arrayOf(_propTypes2.default.string),
initialValue: _propTypes2.default.string,
placeholder: _propTypes2.default.string,
disabled: _propTypes2.default.bool,
inputProps: _propTypes2.default.objectOf(_propTypes2.default.string),
onTokenRemove: _propTypes2.default.func,
onKeyDown: _propTypes2.default.func,
onKeyPress: _propTypes2.default.func,
onKeyUp: _propTypes2.default.func,
onTokenAdd: _propTypes2.default.func,
onFocus: _propTypes2.default.func,
onBlur: _propTypes2.default.func,
filterOption: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.func]),
searchOptions: _propTypes2.default.func,
displayOption: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.func]),
formInputOption: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.func]),
maxVisible: _propTypes2.default.number,
resultsTruncatedMessage: _propTypes2.default.string,
disableDefaultClassNames: _propTypes2.default.bool
};
TypeaheadTokenizer.defaultProps = {
className: "",
name: null,
options: [],
defaultSelected: [],
customClasses: {},
allowCustomValues: 0,
initialValue: "",
placeholder: "",
disabled: false,
inputProps: {},
disableDefaultClassNames: false,
filterOption: null,
searchOptions: null,
displayOption: function displayOption(token) {
return token;
},
formInputOption: null,
onKeyDown: function onKeyDown() {},
onKeyPress: function onKeyPress() {},
onKeyUp: function onKeyUp() {},
onFocus: function onFocus() {},
onBlur: function onBlur() {},
onTokenAdd: function onTokenAdd() {},
onTokenRemove: function onTokenRemove() {},
maxVisible: 0,
resultsTruncatedMessage: ""
};
exports.default = TypeaheadTokenizer;