UNPKG

react-responsive-combo-box

Version:
410 lines (360 loc) 13.3 kB
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var React__default = _interopDefault(React); function _extends() { _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; }; return _extends.apply(this, arguments); } var initialState = { isFocus: false, focusIndex: -1 }; var focusReducer = function focusReducer(state, action) { switch (action.type) { case 'setFocusIndex': return _extends({}, state, { focusIndex: action.focusIndex }); case 'toggleFocus': return _extends({}, state, { isFocus: action.isFocus }); default: return state; } }; var styles = {"comboBox":"_3tcyg","comboBoxInput":"_3LDgJ","comboBoxPopover":"_WbEAz","comboBoxList":"_r3jpc","comboBoxOption":"_2iQTD","rightElement":"_1GXAI","leftElement":"_2e4AG"}; var useScroll = function useScroll(focusedIndex, scrollableContainer, listContainer) { React.useEffect(function () { if (listContainer.current && scrollableContainer.current && focusedIndex >= 0) { if (focusedIndex === 0) scrollableContainer.current.scrollTo({ top: 0 }); var children = listContainer.current.childNodes; var focusedChild = children && children.length ? children[focusedIndex] : null; if (focusedChild && focusedChild.getBoundingClientRect) { var _focusedChild$getBoun = focusedChild.getBoundingClientRect(), optionHeight = _focusedChild$getBoun.height; var _scrollableContainer$ = scrollableContainer.current.getBoundingClientRect(), listHeight = _scrollableContainer$.height; var scrollTop = scrollableContainer.current.scrollTop; var isAbove = focusedChild.offsetTop <= scrollTop; var isInView = focusedChild.offsetTop >= scrollTop && focusedChild.offsetTop + optionHeight <= scrollTop + listHeight; if (!isInView) { if (isAbove) { scrollableContainer.current.scrollTo({ top: focusedChild.offsetTop }); } else { scrollableContainer.current.scrollTo({ top: focusedChild.offsetTop - listHeight + optionHeight }); } } } } }, [focusedIndex, listContainer, scrollableContainer]); }; var UP_ARROW = 38; var DOWN_ARROW = 40; var ENTER_KEY = 13; var ESCAPE_KEY = 27; var ComboBox = function ComboBox(_ref) { var comboBoxOptions = _ref.options, onChange = _ref.onChange, defaultValue = _ref.defaultValue, placeholder = _ref.placeholder, onSelect = _ref.onSelect, onOptionsChange = _ref.onOptionsChange, optionsListMaxHeight = _ref.optionsListMaxHeight, renderOptions = _ref.renderOptions, style = _ref.style, inputClassName = _ref.inputClassName, className = _ref.className, listClassName = _ref.listClassName, optionsClassName = _ref.optionsClassName, popoverClassName = _ref.popoverClassName, highlightColor = _ref.highlightColor, selectedOptionColor = _ref.selectedOptionColor, enableAutocomplete = _ref.enableAutocomplete, inputStyles = _ref.inputStyles, name = _ref.name, onBlur = _ref.onBlur, _ref$editable = _ref.editable, editable = _ref$editable === void 0 ? true : _ref$editable, renderRightElement = _ref.renderRightElement, renderLeftElement = _ref.renderLeftElement; var optionMaxHeight = optionsListMaxHeight || 200; var suggestionListPositionStyles = {}; var _useState = React.useState(comboBoxOptions), options = _useState[0], setOptions = _useState[1]; var _useState2 = React.useState(defaultValue || ''), inputValue = _useState2[0], setInputValue = _useState2[1]; var _useReducer = React.useReducer(focusReducer, initialState), state = _useReducer[0], dispatch = _useReducer[1]; var isFocus = state.isFocus, focusIndex = state.focusIndex; var _useState3 = React.useState(false), isMouseInsideOptions = _useState3[0], setIsMouseInsideOptions = _useState3[1]; var _useState4 = React.useState(false), IsOptionsPositionedTop = _useState4[0], setIsOptionsPositionedTop = _useState4[1]; var _useState5 = React.useState(-1), selectedOptionIndex = _useState5[0], setSelectedOptionIndex = _useState5[1]; var dropdownRef = React.useRef(null); var optionsListRef = React.useRef(null); React.useEffect(function () { setOptions(comboBoxOptions); }, [comboBoxOptions]); React.useEffect(function () { if (!isFocus) setInputValue(defaultValue || ''); dispatch({ type: 'setFocusIndex', focusIndex: defaultValue ? options.indexOf(defaultValue.toString()) : -1 }); setSelectedOptionIndex(defaultValue ? options.indexOf(defaultValue.toString()) : -1); }, [defaultValue]); useScroll(focusIndex, dropdownRef, optionsListRef); React.useEffect(function () { var _optionsContainerElem, _optionsContainerElem2; var optionsContainerElement = dropdownRef.current; var offsetBottom = window.innerHeight - (optionsContainerElement === null || optionsContainerElement === void 0 ? void 0 : (_optionsContainerElem = optionsContainerElement.offsetParent) === null || _optionsContainerElem === void 0 ? void 0 : _optionsContainerElem.getBoundingClientRect().top); if (optionMaxHeight > offsetBottom && (optionsContainerElement === null || optionsContainerElement === void 0 ? void 0 : (_optionsContainerElem2 = optionsContainerElement.offsetParent) === null || _optionsContainerElem2 === void 0 ? void 0 : _optionsContainerElem2.getBoundingClientRect().top) > offsetBottom) { setIsOptionsPositionedTop(true); } else { setIsOptionsPositionedTop(false); } }, [isFocus]); if (IsOptionsPositionedTop) suggestionListPositionStyles = { bottom: '100%', marginBottom: '5px' };else suggestionListPositionStyles = { top: '100%', marginTop: '5px' }; var blurHandler = function blurHandler(event) { if (!isMouseInsideOptions) dispatch({ type: 'toggleFocus', isFocus: false }); if (onBlur) onBlur(event); }; var updateValue = function updateValue(index) { if (index === void 0) { index = focusIndex; } if (index !== -1) { setInputValue(options[index]); if (onOptionsChange) onOptionsChange(options[index]); } }; var resetFocusIndex = function resetFocusIndex() { comboBoxOptions.forEach(function (option, index) { if (option === options[focusIndex]) dispatch({ type: 'setFocusIndex', focusIndex: index }); }); }; var selectSuggestionHandler = function selectSuggestionHandler() { updateValue(); dispatch({ type: 'toggleFocus', isFocus: false }); setSelectedOptionIndex(focusIndex); resetFocusIndex(); setOptions(comboBoxOptions); if (onSelect) onSelect(options[focusIndex]); }; var keyHandler = function keyHandler(event) { var optionsContainerElement = dropdownRef.current; var newFocusIndex = focusIndex; switch (event.keyCode) { case DOWN_ARROW: { event.preventDefault(); if (!isFocus) { dispatch({ type: 'toggleFocus', isFocus: true }); } else { if (focusIndex >= options.length - 1) { newFocusIndex = 0; optionsContainerElement.scrollTop = 0; } else { newFocusIndex = focusIndex + 1; } } dispatch({ type: 'setFocusIndex', focusIndex: newFocusIndex }); if (onOptionsChange) onOptionsChange(options[newFocusIndex]); dropdownRef.current = optionsContainerElement; break; } case UP_ARROW: { event.preventDefault(); if (!isFocus) { dispatch({ type: 'toggleFocus', isFocus: true }); } else { if (focusIndex <= 0) { newFocusIndex = options.length - 1; if (optionsContainerElement) optionsContainerElement.scrollTop = optionsContainerElement.scrollHeight; } else { newFocusIndex = focusIndex - 1; } } dispatch({ type: 'setFocusIndex', focusIndex: newFocusIndex }); if (onOptionsChange) onOptionsChange(options[newFocusIndex]); dropdownRef.current = optionsContainerElement; break; } case ENTER_KEY: { event.preventDefault(); if (focusIndex > -1 && focusIndex < options.length) selectSuggestionHandler(); break; } case ESCAPE_KEY: { event.target.blur(); dispatch({ type: 'toggleFocus', isFocus: false }); break; } } }; var filterSuggestion = function filterSuggestion(filterText) { if (filterText.length === 0) setOptions(comboBoxOptions);else { var filteredSuggestion = comboBoxOptions.filter(function (option) { return option.toLowerCase().indexOf(filterText.toLowerCase()) !== -1; }); setOptions(filteredSuggestion); } }; var inputChangeHandler = function inputChangeHandler(event) { if (onChange) onChange(event); setInputValue(event.target.value); if (enableAutocomplete) filterSuggestion(event.target.value); }; var inputClickHandler = function inputClickHandler() { dispatch({ type: 'toggleFocus', isFocus: true }); dispatch({ type: 'setFocusIndex', focusIndex: options.indexOf(inputValue.toString()) }); }; var focusHandler = function focusHandler() { dispatch({ type: 'toggleFocus', isFocus: true }); }; var mouseEnterHandler = function mouseEnterHandler(index) { dispatch({ type: 'setFocusIndex', focusIndex: index }); if (onOptionsChange) onOptionsChange(options[index]); }; var backgroundColorSelector = function backgroundColorSelector(optionIndex) { if (optionIndex === focusIndex && optionIndex === selectedOptionIndex) return { backgroundColor: selectedOptionColor || '#63b3ed' };else if (optionIndex === focusIndex) { return { backgroundColor: highlightColor || '#bee3f8' }; } else if (optionIndex === selectedOptionIndex) { return { backgroundColor: selectedOptionColor || '#63b3ed' }; } else return {}; }; return React__default.createElement("div", { className: className ? styles.comboBox + " " + className : styles.comboBox, style: style }, renderLeftElement && React__default.createElement("div", { className: styles.leftElement }, renderLeftElement()), React__default.createElement("input", { onFocus: focusHandler, onChange: inputChangeHandler, placeholder: placeholder || '', onKeyDown: keyHandler, value: inputValue, className: inputClassName ? styles.comboBoxInput + " " + inputClassName : styles.comboBoxInput, onBlur: blurHandler, name: name, style: _extends({}, inputStyles, { cursor: editable ? 'text' : 'pointer', paddingLeft: renderLeftElement ? 30 : 10 }), readOnly: !editable, onClick: inputClickHandler }), renderRightElement && React__default.createElement("div", { className: styles.rightElement }, renderRightElement()), React__default.createElement("div", { className: popoverClassName ? styles.comboBoxPopover + " " + popoverClassName : styles.comboBoxPopover, style: _extends({ opacity: isFocus ? 1 : 0, visibility: isFocus ? 'visible' : 'hidden', maxHeight: isFocus ? optionMaxHeight : 0 }, suggestionListPositionStyles), ref: dropdownRef, onMouseEnter: function onMouseEnter() { return setIsMouseInsideOptions(true); }, onMouseLeave: function onMouseLeave() { return setIsMouseInsideOptions(false); } }, React__default.createElement("ul", { className: listClassName ? styles.comboBoxList + " " + listClassName : styles.comboBoxList, ref: optionsListRef }, options.map(function (option, index) { return React__default.createElement("li", { className: optionsClassName ? styles.comboBoxOption + " " + optionsClassName : styles.comboBoxOption, key: option, style: _extends({}, backgroundColorSelector(index)), onClick: function onClick() { return selectSuggestionHandler(); }, onMouseDown: function onMouseDown(e) { return e.preventDefault(); }, onMouseEnter: function onMouseEnter() { return mouseEnterHandler(index); } }, renderOptions ? renderOptions(option) : option); })))); }; module.exports = ComboBox; //# sourceMappingURL=index.js.map