@coreui/react-pro
Version:
UI Components Library for React.js
307 lines (303 loc) • 17.6 kB
JavaScript
'use strict';
var tslib_es6 = require('../../node_modules/tslib/tslib.es6.js');
var React = require('react');
var index = require('../../_virtual/index.js');
var PropTypes = require('prop-types');
var CConditionalPortal = require('../conditional-portal/CConditionalPortal.js');
var CFormControlWrapper = require('../form/CFormControlWrapper.js');
var CAutocompleteOptions = require('./CAutocompleteOptions.js');
var usePopper = require('../../hooks/usePopper.js');
var isRTL = require('../../utils/isRTL.js');
var useForkedRef = require('../../hooks/useForkedRef.js');
var utils = require('./utils.js');
var CAutocomplete = React.forwardRef(function (_a, ref) {
var _b;
var _c = _a.allowOnlyDefinedOptions, allowOnlyDefinedOptions = _c === void 0 ? false : _c, className = _a.className, _d = _a.cleaner, cleaner = _d === void 0 ? false : _d, _e = _a.clearSearchOnSelect, clearSearchOnSelect = _e === void 0 ? true : _e, container = _a.container, disabled = _a.disabled, feedback = _a.feedback, feedbackInvalid = _a.feedbackInvalid, feedbackValid = _a.feedbackValid, _f = _a.highlightOptionsOnSearch, highlightOptionsOnSearch = _f === void 0 ? false : _f, id = _a.id, indicator = _a.indicator, invalid = _a.invalid, label = _a.label, loading = _a.loading, name = _a.name, onChange = _a.onChange, onHide = _a.onHide, onInput = _a.onInput, onShow = _a.onShow, options = _a.options, _g = _a.optionsMaxHeight, optionsMaxHeight = _g === void 0 ? 'auto' : _g, optionsTemplate = _a.optionsTemplate, optionsGroupsTemplate = _a.optionsGroupsTemplate, placeholder = _a.placeholder, _h = _a.portal, portal = _h === void 0 ? false : _h, readOnly = _a.readOnly, required = _a.required, _j = _a.resetSelectionOnOptionsChange, resetSelectionOnOptionsChange = _j === void 0 ? false : _j, search = _a.search, _k = _a.searchNoResultsLabel, searchNoResultsLabel = _k === void 0 ? false : _k, _l = _a.showHints, showHints = _l === void 0 ? false : _l, size = _a.size, text = _a.text, tooltipFeedback = _a.tooltipFeedback, valid = _a.valid, value = _a.value, virtualScroller = _a.virtualScroller, visible = _a.visible, _m = _a.visibleItems, visibleItems = _m === void 0 ? 10 : _m, rest = tslib_es6.__rest(_a, ["allowOnlyDefinedOptions", "className", "cleaner", "clearSearchOnSelect", "container", "disabled", "feedback", "feedbackInvalid", "feedbackValid", "highlightOptionsOnSearch", "id", "indicator", "invalid", "label", "loading", "name", "onChange", "onHide", "onInput", "onShow", "options", "optionsMaxHeight", "optionsTemplate", "optionsGroupsTemplate", "placeholder", "portal", "readOnly", "required", "resetSelectionOnOptionsChange", "search", "searchNoResultsLabel", "showHints", "size", "text", "tooltipFeedback", "valid", "value", "virtualScroller", "visible", "visibleItems"]);
var autoCompleteRef = React.useRef(null);
var autoCompleteForkedRef = useForkedRef.useForkedRef(ref, autoCompleteRef);
var dropdownRef = React.useRef(null);
var togglerRef = React.useRef(null);
var inputRef = React.useRef(null);
var inputHintRef = React.useRef(null);
var uniqueId = React.useId();
var _o = usePopper.usePopper(), initPopper = _o.initPopper, destroyPopper = _o.destroyPopper;
var _p = React.useState(visible), _visible = _p[0], setVisible = _p[1];
var _q = React.useState(), hint = _q[0], setHint = _q[1];
var _r = React.useState(''), searchValue = _r[0], setSearchValue = _r[1];
var _s = React.useState(null), selected = _s[0], setSelected = _s[1];
var filteredOptions = React.useMemo(function () { return (utils.isExternalSearch(search) ? options : utils.filterOptions(options, searchValue)); }, [options, searchValue, search]);
var popperConfig = React.useMemo(function () { return ({
placement: (isRTL.default(autoCompleteRef.current) ? 'bottom-end' : 'bottom-start'),
modifiers: [
{
name: 'preventOverflow',
options: {
boundary: 'clippingParents',
},
},
{
name: 'offset',
options: {
offset: [0, 2],
},
},
],
}); }, [autoCompleteRef.current]);
React.useEffect(function () {
if (resetSelectionOnOptionsChange) {
handleClear();
}
}, [options]);
React.useEffect(function () {
if (value && typeof value === 'string') {
handleSelect(value);
return;
}
if (value && typeof value === 'number') {
var foundOption = utils.getFirstOptionByValue(value, options);
if (foundOption) {
handleSelect(foundOption);
}
return;
}
var _selected = utils.flattenOptionsArray(filteredOptions).find(function (option) { return typeof option !== 'string' && option.selected === true; });
if (_selected) {
handleSelect(_selected);
}
}, [options, value]);
React.useEffect(function () {
if (!showHints) {
return;
}
var findOption = searchValue.length > 0
? filteredOptions.find(function (option) {
return utils.getOptionLabel(option).toLowerCase().startsWith(searchValue.toLowerCase());
})
: undefined;
setHint(findOption);
}, [filteredOptions, searchValue, showHints]);
React.useEffect(function () {
if (!searchNoResultsLabel &&
searchValue.length > 0 &&
filteredOptions.length === 0 &&
_visible) {
handleDropdownHide();
return;
}
if (searchValue.length > 0 && filteredOptions.length > 0 && !_visible) {
handleDropdownShow();
}
}, [filteredOptions]);
React.useEffect(function () {
if (visible === true) {
handleDropdownShow();
}
else if (visible === false) {
handleDropdownHide();
}
}, [visible]);
var handleClear = function () {
if (inputRef.current) {
inputRef.current.value = '';
}
setSearchValue('');
setSelected(null);
onChange === null || onChange === void 0 ? void 0 : onChange(null);
};
var handleGlobalSearch = function (event) {
if (utils.isGlobalSearch(search) &&
inputRef.current &&
(event.key.length === 1 || event.key === 'Backspace' || event.key === 'Delete')) {
inputRef.current.focus();
}
};
var handleInputChange = function (event) {
var value = event.target.value;
handleSearch(value);
if (selected !== null) {
onChange === null || onChange === void 0 ? void 0 : onChange(null);
setSelected(null);
}
};
var handleInputKeyDown = function (event) {
var _a, _b, _c, _d;
if (event.key === 'Escape') {
handleDropdownHide();
return;
}
if ((event.key === 'Down' || event.key === 'ArrowDown') &&
((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value.length) === ((_b = inputRef.current) === null || _b === void 0 ? void 0 : _b.selectionStart)) {
event.preventDefault();
handleDropdownShow();
var target = event.target;
var firstOption = (_d = (_c = target.parentElement) === null || _c === void 0 ? void 0 : _c.parentElement) === null || _d === void 0 ? void 0 : _d.querySelectorAll('.autocomplete-option')[0];
if (firstOption) {
firstOption.focus();
}
return;
}
if (showHints && hint && event.key === 'Tab') {
event.preventDefault();
handleSelect(hint);
handleDropdownHide();
return;
}
if (event.key === 'Enter') {
var input = event.target;
var foundOptions = utils.getFirstOptionByLabel(input.value, filteredOptions);
if (foundOptions) {
handleSelect(foundOptions);
}
else {
if (!allowOnlyDefinedOptions) {
handleSelect(input.value);
}
}
handleDropdownHide();
return;
}
if (event.key === 'Backspace' || event.key === 'Delete') {
if (selected !== null) {
setSelected(null);
onChange === null || onChange === void 0 ? void 0 : onChange(null);
}
return;
}
};
var handleKeyUp = React.useCallback(function (event) {
if (event.key === 'Escape') {
handleDropdownHide();
}
if (autoCompleteRef.current &&
!autoCompleteRef.current.contains(event.target)) {
handleDropdownHide();
}
}, []);
var handleMouseUp = React.useCallback(function (event) {
if (autoCompleteRef.current &&
autoCompleteRef.current.contains(event.target)) {
return;
}
handleDropdownHide();
}, []);
var handleOptionClick = function (option) {
handleSelect(option);
handleDropdownHide();
};
var handleSearch = function (search) {
onInput === null || onInput === void 0 ? void 0 : onInput(search);
setSearchValue(search);
};
var handleSelect = function (option) {
if (option && typeof option === 'object' && option.disabled) {
return;
}
if (inputRef.current) {
inputRef.current.value = option ? utils.getOptionLabel(option) : '';
}
if (clearSearchOnSelect) {
handleSearch('');
}
else {
setHint('');
}
setSelected(option !== null && option !== void 0 ? option : null);
onChange === null || onChange === void 0 ? void 0 : onChange(option !== null && option !== void 0 ? option : null);
};
var handleDropdownShow = React.useCallback(function () {
var _a;
if (disabled || readOnly || _visible) {
return;
}
if (!utils.isExternalSearch(search) &&
filteredOptions.length === 0 &&
searchNoResultsLabel === false) {
return;
}
if (portal && dropdownRef.current && togglerRef.current) {
dropdownRef.current.style.minWidth = "".concat(togglerRef.current.offsetWidth, "px");
}
setVisible(true);
onShow === null || onShow === void 0 ? void 0 : onShow();
window.addEventListener('mouseup', handleMouseUp);
window.addEventListener('keyup', handleKeyUp);
if (togglerRef.current && dropdownRef.current) {
setTimeout(function () {
initPopper(togglerRef.current, dropdownRef.current, popperConfig);
}, 1); // Allow DOM updates to complete before initializing Popper
}
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}, [
disabled,
readOnly,
_visible,
filteredOptions.length,
searchNoResultsLabel,
allowOnlyDefinedOptions,
onShow,
handleMouseUp,
handleKeyUp,
initPopper,
popperConfig,
]);
var handleDropdownHide = React.useCallback(function () {
var _a;
setVisible(false);
onHide === null || onHide === void 0 ? void 0 : onHide();
window.removeEventListener('mouseup', handleMouseUp);
window.removeEventListener('keyup', handleKeyUp);
destroyPopper();
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}, [onHide, handleMouseUp, handleKeyUp, destroyPopper]);
return (React.createElement(CFormControlWrapper.CFormControlWrapper, { describedby: rest['aria-describedby'], feedback: feedback, feedbackInvalid: feedbackInvalid, feedbackValid: feedbackValid, id: id || "autocomplete-".concat(uniqueId), invalid: invalid, label: label, text: text, tooltipFeedback: tooltipFeedback, valid: valid },
React.createElement("div", { className: index.default('autocomplete', (_b = {},
_b["autocomplete-".concat(size)] = size,
_b.disabled = disabled,
_b['is-invalid'] = invalid,
_b['is-valid'] = valid,
_b.show = _visible,
_b), className), onKeyDown: handleGlobalSearch, ref: autoCompleteForkedRef },
React.createElement("div", { className: "autocomplete-input-group", onClick: function () { return handleDropdownShow(); }, ref: togglerRef },
showHints && searchValue !== '' && (React.createElement("input", { className: "autocomplete-input autocomplete-input-hint", id: id || "autocomplete-hint-".concat(uniqueId), autoComplete: "off", readOnly: true, tabIndex: -1, "aria-hidden": "true", value: hint ? "".concat(searchValue).concat(utils.getOptionLabel(hint).slice(searchValue.length)) : '', ref: inputHintRef })),
React.createElement("input", tslib_es6.__assign({ type: "text", className: "autocomplete-input", disabled: disabled, id: id || "autocomplete-".concat(uniqueId), name: name || "autocomplete-".concat(uniqueId), onBlur: function (event) {
event.preventDefault();
event.stopPropagation();
if (allowOnlyDefinedOptions && selected === null && filteredOptions.length === 0) {
handleClear();
}
}, onChange: handleInputChange, onKeyDown: handleInputKeyDown, placeholder: placeholder, autoComplete: "off", required: required, "aria-autocomplete": "list", "aria-expanded": _visible, "aria-haspopup": "listbox" }, (portal && { 'aria-owns': "autocomplete-listbox-".concat(uniqueId) }), { readOnly: readOnly, role: "combobox", ref: inputRef })),
(cleaner || indicator) && (React.createElement("div", { className: "autocomplete-buttons" },
!disabled && !readOnly && cleaner && selected && (React.createElement("button", { type: "button", className: "autocomplete-cleaner", onClick: function (event) {
event.preventDefault();
event.stopPropagation();
handleClear();
} })),
React.createElement("button", { type: "button", className: "autocomplete-indicator", disabled: !(searchNoResultsLabel || filteredOptions.length > 0) &&
utils.isExternalSearch(search), onClick: function (event) {
event.preventDefault();
event.stopPropagation();
if (_visible) {
handleDropdownHide();
}
else {
handleDropdownShow();
}
} })))),
React.createElement(CConditionalPortal.CConditionalPortal, { container: container, portal: portal },
React.createElement("div", { className: index.default('autocomplete-dropdown', {
show: portal && _visible,
}), id: "autocomplete-listbox-".concat(uniqueId), role: "listbox", "aria-labelledby": id || "autocomplete-".concat(uniqueId), ref: dropdownRef },
React.createElement(CAutocompleteOptions.CAutocompleteOptions, { highlightOptionsOnSearch: highlightOptionsOnSearch, loading: loading, onOptionClick: function (option) {
return !disabled && !readOnly && handleOptionClick(option);
}, options: filteredOptions, optionsMaxHeight: optionsMaxHeight, optionsTemplate: optionsTemplate, optionsGroupsTemplate: optionsGroupsTemplate, searchNoResultsLabel: searchNoResultsLabel, searchValue: searchValue, selected: selected, virtualScroller: virtualScroller, visibleItems: visibleItems }))))));
});
CAutocomplete.propTypes = tslib_es6.__assign({ allowOnlyDefinedOptions: PropTypes.bool, className: PropTypes.string, clearSearchOnSelect: PropTypes.bool, cleaner: PropTypes.bool, container: PropTypes.any, disabled: PropTypes.bool, highlightOptionsOnSearch: PropTypes.bool, indicator: PropTypes.bool, loading: PropTypes.bool, name: PropTypes.string, onChange: PropTypes.func, onHide: PropTypes.func, onInput: PropTypes.func, onShow: PropTypes.func, options: PropTypes.array.isRequired, optionsMaxHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), optionsTemplate: PropTypes.func, optionsGroupsTemplate: PropTypes.func, placeholder: PropTypes.string, portal: PropTypes.bool, required: PropTypes.bool, resetSelectionOnOptionsChange: PropTypes.bool, search: PropTypes.oneOfType([
PropTypes.oneOf(['external', 'global']),
PropTypes.shape({
external: PropTypes.bool.isRequired,
global: PropTypes.bool.isRequired,
}),
]), searchNoResultsLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), showHints: PropTypes.bool, size: PropTypes.oneOf(['sm', 'lg']), value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), virtualScroller: PropTypes.bool, visible: PropTypes.bool, visibleItems: PropTypes.number }, CFormControlWrapper.CFormControlWrapper.propTypes);
CAutocomplete.displayName = 'CAutocomplete';
exports.CAutocomplete = CAutocomplete;
//# sourceMappingURL=CAutocomplete.js.map