react-autocomplete-select
Version:
Auto Complete React component
372 lines (280 loc) • 14.7 kB
JavaScript
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 _templateObject = _taggedTemplateLiteralLoose(['\n * {\n box-sizing: border-box;\n}\n\nbody {\n font: 16px Arial; \n backgroundColor : \'black\'\n}\n\n/*the container must be positioned relative:*/\n.autocomplete {\n position: relative;\n display: inline-block;\n width:300px;\n}\n\ninput {\n border: 1px solid transparent;\n background-color: #f1f1f1;\n padding: 10px;\n font-size: 16px;\n width: 100%;\n}\n\n\n\n/*Dropdown options container css*/\n.___optionsDiv___ {\n\n position: absolute;\n border: 1px solid #d4d4d4;\n border-bottom: none;\n border-top: none;\n z-index: 99;\n /*position the autocomplete items to be the same width as the container:*/\n top: 100%;\n left: 0;\n right: 0;\n}\n\n\n/*Dropdown options each div css*/\n.___optionsDiv___ div {\n padding: 10px;\n cursor: pointer;\n background-color: #fff; \n border-bottom: 1px solid #d4d4d4; \n}\n\n/*Dropdown options each div on hover css*/\n\n.___optionsDiv___ div:hover {\n background-color: #e9e9e9; \n}\n\n\n/*when navigating through the items using the arrow keys:*/\n.autocomplete-active {\n background-color: DodgerBlue !important; \n color: #ffffff; \n}\n\n ', '\n'], ['\n * {\n box-sizing: border-box;\n}\n\nbody {\n font: 16px Arial; \n backgroundColor : \'black\'\n}\n\n/*the container must be positioned relative:*/\n.autocomplete {\n position: relative;\n display: inline-block;\n width:300px;\n}\n\ninput {\n border: 1px solid transparent;\n background-color: #f1f1f1;\n padding: 10px;\n font-size: 16px;\n width: 100%;\n}\n\n\n\n/*Dropdown options container css*/\n.___optionsDiv___ {\n\n position: absolute;\n border: 1px solid #d4d4d4;\n border-bottom: none;\n border-top: none;\n z-index: 99;\n /*position the autocomplete items to be the same width as the container:*/\n top: 100%;\n left: 0;\n right: 0;\n}\n\n\n/*Dropdown options each div css*/\n.___optionsDiv___ div {\n padding: 10px;\n cursor: pointer;\n background-color: #fff; \n border-bottom: 1px solid #d4d4d4; \n}\n\n/*Dropdown options each div on hover css*/\n\n.___optionsDiv___ div:hover {\n background-color: #e9e9e9; \n}\n\n\n/*when navigating through the items using the arrow keys:*/\n.autocomplete-active {\n background-color: DodgerBlue !important; \n color: #ffffff; \n}\n\n ', '\n']);
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; }
function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; }
import React, { Component, Fragment } from 'react';
import OptionsParent from './OptionsParent';
import Options from './Options';
import styled, { createGlobalStyle } from 'styled-components';
import PropTypes from 'prop-types';
import axios from 'axios';
var GlobalStyle = createGlobalStyle(_templateObject, function (props) {
return props.globalStyle;
});
export default Object.assign(function (_Component) {
_inherits(_class2, _Component);
function _class2() {
var _temp, _this, _ret;
_classCallCheck(this, _class2);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.state = {
inputValue: "",
currentActiveValue: "",
itemsData: [],
searchData: [],
searchPattern: "containsString",
placeholder: "Search",
selectOnBlur: false,
axiosConfig: false,
onChange: false,
onSelect: false,
maxOptionsLimit: 10,
getItemValue: false,
inputRef: false,
searchEnabled: false,
optionsJSX: false,
inputJSX: false,
defaultInputValue: false
}, _this.currentFocus = -1, _this.inputRef = React.createRef(), _this.optionRefs = [], _this.setRef = function (ref) {
_this.optionRefs.push(ref);
}, _this.closeAllItems = function () {
for (var _len2 = arguments.length, methodsToBeCalled = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
methodsToBeCalled[_key2 - 1] = arguments[_key2];
}
var withObject = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
setTimeout(function () {
_this.setState(_extends({}, _this.state, withObject, {
searchData: []
}), function () {
methodsToBeCalled.forEach(function (methodToCall) {
return methodToCall();
});
});
}, 1);
_this.optionRefs = [];
_this.currentFocus = -1;
}, _this.addClickEventListener = function () {
for (var i = 0; i < _this.optionRefs.length; i++) {
_this.optionRefs[i] && _this.optionRefs[i].addEventListener('mousedown', function (e) {
_this.closeAllItems({ inputValue: e.target.textContent, currentActiveValue: e.target.textContent }, _this.onSelect);
});
}
}, _this.setInputDefaultVal = function () {
if (_this.props.defaultInputValue && !_this.state.currentActiveValue) setTimeout(function () {
return _this.setState({
currentActiveValue: _this.props.defaultInputValue,
inputValue: _this.props.defaultInputValue
});
}, 10);
}, _this.onBlur = function () {
if (_this.state.selectOnBlur) _this.closeAllItems({ inputValue: _this.state.currentActiveValue }, _this.onSelect, _this.setInputDefaultVal);else setTimeout(function () {
_this.closeAllItems({ currentActiveValue: _this.state.inputValue }, _this.onChange, _this.setInputDefaultVal);
}, 1);
}, _this.onFocus = function (elem) {
var event = new Event('input', {
'bubbles': true,
'cancelable': true
});
elem.target.dispatchEvent(event);
}, _this.addActive = function () {
/*remove null values*/
_this.optionRefs = _this.optionRefs.filter(function (val) {
return val ? val : false;
});
/*start by removing the "active" class on all items:*/
var currentActiveValue = void 0;
_this.removeActive();
if (_this.currentFocus > _this.optionRefs.length) _this.currentFocus = 0;
if (_this.currentFocus < -1) _this.currentFocus = _this.optionRefs.length - 1;
if (_this.currentFocus == -1 || _this.currentFocus === _this.optionRefs.length) currentActiveValue = _this.state.inputValue;else currentActiveValue = _this.optionRefs[_this.currentFocus] && _this.optionRefs[_this.currentFocus].textContent || _this.state.inputValue;
_this.setState(_extends({}, _this.state, {
currentActiveValue: currentActiveValue
}), function () {
/* now calling onChange method */
_this.onChange();
});
if (_this.optionRefs[_this.currentFocus]) {
_this.optionRefs[_this.currentFocus].classList.add("autocomplete-active");
}
}, _this.onChange = function () {
if (_this.state.onChange) _this.state.onChange(_this.state.currentActiveValue);
}, _this.onSelect = function () {
if (_this.state.onSelect) _this.state.onSelect(_this.state.inputValue);
_this.onChange();
}, _this.removeActive = function () {
/*a function to remove the "active" class from all autocomplete items:*/
for (var i = 0; i < _this.optionRefs.length; i++) {
_this.optionRefs[i] && _this.optionRefs[i].classList.remove("autocomplete-active");
}
}, _this.isSearched = function (value, inpValue) {
if (!value) return;
value = value.toString().toUpperCase();
inpValue = inpValue.toString().toUpperCase();
if (_this.state.searchPattern === 'containsString' && value.indexOf(inpValue) > -1) return value;
if (_this.state.searchPattern === 'containsLetter') {
var letters = inpValue.split('');
var response = value;
for (var i = 0; i < letters.length; i++) {
if (!(value.indexOf(letters[i]) > -1)) {
response = false;
break;
}
}
return response;
}
if (_this.state.searchPattern === 'startsWith' && value.substr(0, inpValue.length) == inpValue) return value;
if (_this.state.searchPattern === 'endsWith' && value.substr(-inpValue.length) == inpValue) return value;
}, _this.makeAxiosRequest = function (inputValue) {
var axiosConfig = _this.state.axiosConfig && _this.state.axiosConfig(inputValue);
var self = _this;
if (axiosConfig instanceof Object) {
axios(axiosConfig).then(function (res) {
_this.setData(res.data, inputValue);
}).catch(function (err) {
console.log(err, ' error occured.');
});
return true;
} else return false;
}, _this.onInput = function () {
var inp = _this.inputRef.current;
var storeInState = [],
i = void 0,
val = inp.value;
/*close any already open item of autocompleted values*/
_this.closeAllItems({ inputValue: inp.value, currentActiveValue: inp.value }, _this.onChange);
if (!val || !_this.makeAxiosRequest(val) && _this.state.itemsData.length === 0) return;
/*for each item in the array...*/
_this.setData(_this.state.itemsData, val);
}, _this.setData = function (dataToMakeSearch, inpValue, type) {
var storeInState = [];
if (type === 'axios' && !_this.state.searchEnabled) ;else storeInState = _this.makeLocalSearch(dataToMakeSearch, inpValue);
setTimeout(function () {
_this.setState(_extends({}, _this.state, {
searchData: storeInState
}), function () {
_this.addClickEventListener();
});
}, 1);
}, _this.makeLocalSearch = function (dataToMakeSearch, inpValue) {
var storeInState = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
for (var i = 0; i < dataToMakeSearch.length; i++) {
/*check if the item starts with the same letters as the text field value:*/
if (_this.isSearched(_this.state.getItemValue(dataToMakeSearch[i]), inpValue)) {
if (storeInState.length < _this.state.maxOptionsLimit) {
storeInState.push(dataToMakeSearch[i]);
}
}
}
return storeInState;
}, _this.onKeyDown = function (e) {
var inp = _this.inputRef.current;
// let {currentFocus} = this.state;
if (_this.optionRefs.length === 0) return;
if (e.keyCode == 40) {
/*If the arrow DOWN key is pressed,
increase the currentFocus variable:*/
if (_this.state.searchData.length > 0) {
_this.currentFocus++;
_this.addActive();
}
} else if (e.keyCode == 38) {
//up
/*If the arrow UP key is pressed,
decrease the currentFocus variable:*/
if (_this.state.searchData.length > 0) {
_this.currentFocus--;
_this.addActive();
}
} else if (e.keyCode == 13) {
/*If the ENTER key is pressed, prevent the form from being submitted,*/
e.preventDefault();
if (_this.currentFocus > -1 && _this.optionRefs.length > 0 && _this.optionRefs[_this.currentFocus]) {
/*and simulate a click on the "active" item:*/
var event = new Event('mousedown');
_this.optionRefs[_this.currentFocus].dispatchEvent(event);
} else _this.closeAllItems(_extends({}, _this.state), _this.onSelect);
}
}, _this.handleChange = function (e) {
var value = e.target.value;
_this.setState(_extends({}, _this.state, {
inputValue: value,
currentActiveValue: value
}));
}, _this.inputJSX = function () {
var obj = {
ref: _this.props.inputRef || _this.inputRef,
onBlur: _this.onBlur,
onFocus: _this.onFocus,
onInput: _this.onInput,
value: _this.state.currentActiveValue,
onChange: _this.handleChange,
onKeyDown: _this.onKeyDown,
type: 'text',
placeholder: _this.state.placeholder
};
if (_this.state.inputJSX) return _this.state.inputJSX(obj);
return React.createElement('input', obj);
}, _temp), _possibleConstructorReturn(_this, _ret);
}
_class2.prototype.componentDidMount = function componentDidMount() {
if (this.props.inputRef) this.inputRef = this.props.inputRef;
this.setInputDefaultVal();
};
_class2.getDerivedStateFromProps = function getDerivedStateFromProps(props, state) {
var propsToBeState = ['searchPattern', 'data', 'placeholder', 'axiosConfig', 'selectOnBlur', 'onChange', 'onSelect', 'getItemValue', 'itemsData', 'inputRef', 'searchEnabled', 'optionsJSX', 'inputJSX'];
var stateObj = {};
Object.entries(props).forEach(function (_ref) {
var key = _ref[0],
val = _ref[1];
if (propsToBeState.indexOf(key) > -1) stateObj[key] = val;
});
return stateObj;
};
/* handling user level methods*/
_class2.prototype.render = function render() {
var _this2 = this;
return React.createElement(
Fragment,
null,
React.createElement(
'form',
{ autoComplete: 'off' },
React.createElement(
'div',
{ className: 'autocomplete' },
this.inputJSX(),
React.createElement(
OptionsParent,
null,
this.state.searchData.map(function (val, key) {
return key <= _this2.state.maxOptionsLimit ? React.createElement(Options, { ref: _this2.setRef, JSX: _this2.state.optionsJSX || function (value) {
return value;
}, key: key, value: _this2.state.getItemValue(val) }) : null;
})
)
)
),
React.createElement(GlobalStyle, { globalStyle: this.props.globalStyle })
);
};
return _class2;
}(Component), { propTypes: {
searchPattern: PropTypes.oneOf(['startsWith', 'endsWith', 'containsString', 'containsLetter']),
getItemValue: PropTypes.func.isRequired,
itemsData: PropTypes.array.isRequired,
inputJSX: PropTypes.func,
optionsJSX: PropTypes.func,
maxOptionsLimit: PropTypes.number,
searchEnabled: PropTypes.bool,
selectOnBlur: PropTypes.bool,
inputRef: PropTypes.object,
onChange: PropTypes.func,
onSelect: PropTypes.func,
axiosConfig: PropTypes.func,
placeholder: PropTypes.string,
defaultInputValue: PropTypes.string
} });