UNPKG

@coreui/react-pro

Version:

UI Components Library for React.js

307 lines (303 loc) 17.6 kB
'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