samuca-libs
Version:
### Custom React Components
428 lines (383 loc) • 17.5 kB
JavaScript
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; }; }();
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
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; }
import PropTypes from 'prop-types';
import React from 'react';
import './multi-select-aria.css';
var typingTimer = void 0;
var MultiSelectAria = function (_React$Component) {
_inherits(MultiSelectAria, _React$Component);
function MultiSelectAria(props) {
_classCallCheck(this, MultiSelectAria);
var _this = _possibleConstructorReturn(this, (MultiSelectAria.__proto__ || Object.getPrototypeOf(MultiSelectAria)).call(this, props));
_initialiseProps.call(_this);
_this.refInputEl = React.createRef();
_this.hashId = btoa(new Date().getTime()).replace('==', '').toLowerCase().replace(/\d/g, '');
var selecteds = [];
if (props.multi) {
selecteds = [].concat(_toConsumableArray(props.selected));
} else if (!props.multi && props.selected) {
selecteds = [props.selected];
}
_this.state = {
width: 100,
options: props.options,
selecteds: selecteds,
optionSelected: 0,
showOptionList: false,
isLoading: false,
filter: '',
activedescendant: props.options.length > 0 ? props.options[0][props.labelKey] : null
};
return _this;
}
_createClass(MultiSelectAria, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(newProps) {
var selected = newProps.selected,
newIsLoading = newProps.isLoading,
newOptions = newProps.options,
statick = newProps.statick;
var _state = this.state,
selecteds = _state.selecteds,
isLoading = _state.isLoading,
options = _state.options,
filter = _state.filter;
var _props = this.props,
minimumInput = _props.minimumInput,
labelKey = _props.labelKey,
valueKey = _props.valueKey,
showOptionSelected = _props.showOptionSelected;
if (!Array.isArray(selected)) {
selected = selected && selected[valueKey] ? [selected] : [];
}
var state = Object.assign({}, this.state, { optionSelected: 0, activedescendant: this.hashId + '-item-' + 0, isLoading: newIsLoading });
var isOptionsEquals = this.isListEquals(newOptions, options);
var isSeletedsEquals = this.isListEquals(selected, selecteds);
var isInputMinimum = filter.length >= minimumInput;
var isLoadingEquals = newIsLoading !== isLoading;
if (!isOptionsEquals && isInputMinimum) {
if (!showOptionSelected) {
var _options = newOptions.filter(function (item) {
return selecteds.filter(function (selected) {
return item[labelKey] === selected[labelKey];
}).length === 0;
});
if (!isSeletedsEquals) {
this.setState(Object.assign({}, state, { options: _options, selecteds: selected }));
} else {
this.setState(Object.assign({}, state, { options: _options }));
}
} else {
if (!isSeletedsEquals) {
this.setState(Object.assign({}, state, { selecteds: selected, options: newOptions }));
} else {
this.setState(Object.assign({}, state, { options: newOptions }));
}
}
} else if (!isOptionsEquals && !isInputMinimum && statick) {
this.setState(Object.assign({}, this.state, { options: newOptions, isLoading: newIsLoading }));
} else if (isLoadingEquals) {
if (!isSeletedsEquals) {
this.setState(Object.assign({}, state, { selecteds: selected }));
} else {
this.setState(Object.assign({}, state));
}
} else if (!isSeletedsEquals) {
this.setState(Object.assign({}, this.state, { selecteds: selected }));
}
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
if (this.props.multi && this.props.initialValue) {
this.props.onSelect([].concat(_toConsumableArray(this.props.selected), [this.props.initialValue]));
} else if (!this.props.multi && !this.props.selected && this.props.initialValue) {
this.props.onSelect(this.props.initialValue);
}
document.addEventListener("mousedown", this.handleClickOutside);
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
document.removeEventListener("mousedown", this.handleOptionClick);
}
}, {
key: 'isListEquals',
value: function isListEquals(a, b) {
var _this2 = this;
return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every(function (val, index) {
return val[_this2.props.labelKey] === b[index][_this2.props.labelKey] && val[_this2.props.valueKey] === b[index][_this2.props.valueKey];
});
}
}, {
key: 'render',
value: function render() {
var _this3 = this;
return React.createElement(
'div',
{ style: { display: 'flex', alignItems: 'center' } },
React.createElement(
'div',
{ className: 'msa-container' },
React.createElement(
'div',
{
id: this.hashId,
className: 'msa-main ' + (this.props.classBox ? this.props.classBox : ''),
onClick: function onClick() {
return _this3.refInputEl.current.focus();
}
},
this.props.multi && this.state.selecteds.map(function (item, y) {
return React.createElement(
'span',
{ key: y, className: 'chip' },
item[_this3.props.labelKey]
);
}),
React.createElement('input', {
id: this.props.id ? this.props.id : undefined,
ref: this.refInputEl,
placeholder: this.props.multi || this.state.selecteds.length === 0 ? this.props.placeholder : '',
type: 'text',
value: this.state.filter,
className: this.hashId + ' msa-input ' + (this.props.classInput ? this.props.classInput : '') + ' ' + (this.props.multi || this.state.selecteds.length === 0 ? 'msa-input-multi' : ''),
onChange: function onChange(e) {
return _this3.onChange(e.target.value);
},
onFocus: this.handleListDisplay,
onKeyDown: this.onKeyControl,
style: {
width: !this.props.multi && this.state.selecteds.length > 0 ? '2px' : undefined
},
'aria-multiselectable': true,
'aria-haspopup': 'listbox',
'aria-expanded': this.state.showOptionList,
'aria-controls': this.props.listName ? this.props.listName : 'options-' + this.hashId,
'aria-owns': this.props.listName ? this.props.listName : 'options-' + this.hashId,
'aria-activedescendant': this.state.activedescendant,
'aria-autocomplete': 'list',
autoComplete: 'off'
}),
!this.props.multi && this.state.selecteds.length > 0 && this.state.selecteds[0] && this.state.selecteds[0].hasOwnProperty(this.props.labelKey) && React.createElement(
'span',
{ className: 'chip-single' },
this.state.selecteds[0][this.props.labelKey]
)
),
this.state.showOptionList && React.createElement(
'ul',
{
role: 'listbox',
className: 'select-options ' + (this.props.classOptions ? this.props.classOptions : ''),
style: { maxWidth: this.state.width, minWidth: this.state.width },
id: this.props.listName ? this.props.listName : 'options-' + this.hashId
},
!this.state.isLoading && this.state.options.map(function (option, i) {
return React.createElement(
'li',
{
id: _this3.hashId + '-item-' + i,
role: 'option',
className: _this3.hashId + ' custom-select-option \n ' + (_this3.props.classOptionsItem ? _this3.props.classOptionsItem : '') + ' \n ' + (_this3.state.optionSelected === i ? ' selected' : '') + '\n ',
'data-name': option[_this3.props.labelKey],
key: i,
onClick: function onClick() {
return _this3.handleOptionSelected(i);
},
onMouseOver: function onMouseOver() {
return _this3.onOptionOver(i);
},
'aria-selected': _this3.state.activedescendant === _this3.hashId + '-item-' + i
},
option[_this3.props.labelKey]
);
}),
this.state.options.length === 0 && !this.state.isLoading && !this.props.statick && React.createElement(
'li',
{
className: 'custom-select-option',
role: 'option',
'aria-selected': this.state.options.length === 0 && !this.state.isLoading && !this.props.statick,
id: this.hashId + '-item-' + 0
},
this.state.filter.length < this.props.minimumInput ? this.props.searchPromptText : this.props.noResultsText
),
this.state.isLoading && React.createElement(
'li',
{
className: 'custom-select-option',
role: 'option',
'aria-selected': this.state.isLoading,
id: this.hashId + '-item-' + 0
},
this.props.isLoadingText
)
)
),
React.createElement(
'button',
{
'aria-label': 'Clear',
className: 'clear ' + (this.props.cassClearButton ? this.props.cassClearButton : ''),
onClick: function onClick() {
return _this3.clearListOfSelecteds();
}
},
'x'
)
);
}
}]);
return MultiSelectAria;
}(React.Component);
var _initialiseProps = function _initialiseProps() {
var _this4 = this;
this.handleClickOutside = function (e) {
if (!e.target.classList.contains(_this4.hashId)) {
_this4.setState(Object.assign({}, _this4.state, {
showOptionList: false,
optionSelected: 0
}));
}
};
this.handleListDisplay = function () {
var width = document.getElementById(_this4.hashId).offsetWidth;
_this4.setState(Object.assign({}, _this4.state, { showOptionList: true, width: width, activedescendant: _this4.hashId + '-item-' + 0 }));
};
this.handleOptionSelected = function (index) {
var showOptionList = false;
if (_this4.props.multi) {
_this4.refInputEl.current.focus();
showOptionList = true;
}
var selecteds = _this4.props.multi ? [].concat(_toConsumableArray(_this4.state.selecteds), [_this4.state.options[index]]) : [_this4.state.options[index]];
if (_this4.props.statick) {
_this4.setState(Object.assign({}, _this4.state, { selecteds: selecteds, filter: '', showOptionList: showOptionList }));
} else {
_this4.setState(Object.assign({}, _this4.state, { selecteds: selecteds, options: [], filter: '', showOptionList: showOptionList }));
}
setTimeout(function () {
if (_this4.props.onSelect) {
if (_this4.props.multi) {
_this4.props.onSelect(selecteds);
} else {
_this4.props.onSelect(selecteds[0]);
}
if (_this4.props.onInputChange) {
_this4.props.onInputChange('');
}
}
}, 500);
};
this.clearListOfSelecteds = function () {
var selecteds = _this4.props.initialValue ? [_this4.props.initialValue] : [];
_this4.setState(Object.assign({}, _this4.state, { selecteds: selecteds, filter: '' }));
if (_this4.props.onSelect) {
if (_this4.props.multi && !_this4.props.statick) {
_this4.props.onSelect([]);
} else if (_this4.props.multi && _this4.props.statick) {
_this4.props.onSelect(selecteds);
} else if (!_this4.props.multi && _this4.props.statick) {
_this4.props.onSelect(_this4.props.initialValue);
} else {
_this4.props.onSelect(undefined);
}
}
setTimeout(function () {
_this4.refInputEl.current.focus();
}, 300);
};
this.onKeyControl = function (e) {
if (e.key === 'ArrowDown') {
if (_this4.state.optionSelected < _this4.state.options.length - 1) {
_this4.onOptionOver(_this4.state.optionSelected + 1);
} else {
_this4.onOptionOver(Object.assign({}, _this4.state, { optionSelected: 0 }));
}
} else if (e.key === 'ArrowUp') {
if (_this4.state.optionSelected > 0) {
_this4.onOptionOver(_this4.state.optionSelected - 1);
} else {
_this4.onOptionOver(_this4.state.options.length - 1);
}
}
if (e.key === 'Enter') {
if (_this4.state.options.length > 0) {
_this4.handleOptionSelected(_this4.state.optionSelected);
}
}
if (e.key === 'Tab') {
_this4.setState(Object.assign({}, _this4.state, { showOptionList: false }));
}
if (e.key === 'Backspace') {
if (_this4.state.filter.length === 0) {
var selecteds = _this4.state.selecteds.slice(0, _this4.state.selecteds.length - 1);
if (selecteds.length === 0 && _this4.props.initialValue) {
selecteds = [_this4.props.initialValue];
}
_this4.setState(Object.assign({}, _this4.state, { selecteds: selecteds }));
setTimeout(function () {
return _this4.props.onSelect(selecteds);
}, 300);
}
}
};
this.onChange = function (value) {
var options = _this4.props.statick ? _this4.state.options.filter(function (item) {
return item[_this4.props.labelKey].toLowerCase().includes(value.toLowerCase());
}) : _this4.state.options;
if (_this4.props.multi) {
_this4.setState(Object.assign({}, _this4.state, { options: options, filter: value }));
} else {
_this4.setState(Object.assign({}, _this4.state, { options: options, filter: value, selecteds: [] }));
setTimeout(function () {
return _this4.props.onSelect(undefined);
});
}
if (!_this4.props.statick) {
clearTimeout(typingTimer);
typingTimer = setTimeout(function () {
if (_this4.props.onInputChange && value.length >= _this4.props.minimumInput) {
_this4.props.onInputChange(value);
}
});
}
};
this.onOptionOver = function (index) {
var activedescendant = _this4.hashId + '-item-' + index;
_this4.setState(Object.assign({}, _this4.state, { optionSelected: index, activedescendant: activedescendant }));
};
this.optionsWithoutSelecteds = function () {
return _this4.state.options.filter(function (item) {
return _this4.state.selecteds.filter(function (selected) {
return item[_this4.props.labelKey] === selected[_this4.props.labelKey];
}).length === 0;
});
};
};
MultiSelectAria.propTypes = {
options: PropTypes.array.isRequired,
onSelect: PropTypes.func.isRequired,
selected: function selected(props, propName, componentName) {
if (!props.hasOwnProperty(propName)) {
return new Error('selected is required.');
}
if (props.multi && !Array.isArray(props.selected)) {
throw Error('selected should be a array for multi selections');
}
}
};
MultiSelectAria.defaultProps = {
isLoadingText: 'It\'s Loading',
noResultsText: 'It\'s empty',
placeholder: '',
searchPromptText: 'Type to search',
minimumInput: 3,
labelKey: 'label',
valueKey: 'value'
};
export default MultiSelectAria;