UNPKG

lole-ui

Version:

React UI Component which like a love letter

138 lines (137 loc) 6.02 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import React, { useEffect, useState, useRef } from "react"; import classNames from "classnames"; import Input from "../Input/input"; import Icon from "../Icon/icon"; import useDebounce from "../../hooks/useDebounce"; import useClickOutside from "../../hooks/useClickOutside"; import Animator from "../Animator/animator"; var AutoComplete = function (props) { var fetchSuggestions = props.fetchSuggestions, onSelect = props.onSelect, value = props.value, renderOption = props.renderOption, delay = props.delay, items = props.items, width = props.width, theme = props.theme, size = props.size, restProps = __rest(props, ["fetchSuggestions", "onSelect", "value", "renderOption", "delay", "items", "width", "theme", "size"]); var _a = useState(value), inputValue = _a[0], setInputValue = _a[1]; var _b = useState([]), suggestions = _b[0], setSuggestions = _b[1]; var _c = useState(false), loading = _c[0], setLoading = _c[1]; var _d = useState(-1), highlightIndex = _d[0], setHighlightIndex = _d[1]; var _e = useState(false), showDropdown = _e[0], setShowDropdown = _e[1]; var triggerSearch = useRef(false); var componentRef = useRef(null); var debouncedValue = useDebounce(inputValue, delay); useClickOutside(componentRef, function () { setSuggestions([]); }); useEffect(function () { if (debouncedValue && triggerSearch.current) { setSuggestions([]); var results = fetchSuggestions(debouncedValue); if (results instanceof Promise) { setLoading(true); results.then(function (data) { setLoading(false); setSuggestions(data); if (data.length > 0) setShowDropdown(true); }); } else { setSuggestions(results); setShowDropdown(true); if (results.length > 0) setShowDropdown(true); } } else setShowDropdown(false); setHighlightIndex(-1); }, [debouncedValue, fetchSuggestions]); var handleOnChange = function (e) { var value = e.target.value.trim(); setInputValue(value); triggerSearch.current = true; }; var handleSelect = function (item) { setInputValue(item.value); setSuggestions([]); if (onSelect) onSelect(item); triggerSearch.current = false; }; var renderTemplate = function (item) { return renderOption ? renderOption(item) : item.value; }; var generateDropdown = function () { return (React.createElement(React.Fragment, null, React.createElement(Animator, { in: showDropdown || loading, animation: "zoom-in-top", timeout: 300, onExited: function () { setSuggestions([]); } }, React.createElement("ul", { className: 'xiOn-suggestion-list' }, suggestions.slice(0, items).map(function (item, index) { var classes = classNames('suggestion-item', { 'is-active': index === highlightIndex }); return (React.createElement("li", { className: classes, key: index, onClick: function () { return handleSelect(item); } }, renderTemplate(item))); }))))); }; var highlight = function (index) { if (index < 0) index = 0; else if (index >= suggestions.length) { index = suggestions.length - 1; } setHighlightIndex(index); }; var handleKeyDown = function (e) { switch (e.keyCode) { case 13: if (suggestions[highlightIndex]) handleSelect(suggestions[highlightIndex]); break; case 38: highlight(highlightIndex - 1); /** 向上 */ break; case 40: /** 向下 */ highlight(highlightIndex + 1); break; case 27: /** esc */ setSuggestions([]); break; default: break; } }; var loadIcon = function () { return (React.createElement(React.Fragment, null, loading && React.createElement("div", { className: 'suggestions-loading-icon' }, React.createElement(Icon, { icon: 'spinner', size: size, spin: true, theme: theme })))); }; return (React.createElement("div", { className: 'xiOn-auto-complete', style: { width: width }, ref: componentRef }, React.createElement(Input, __assign({ value: inputValue, onChange: handleOnChange, onKeyDown: handleKeyDown, width: width }, restProps)), loadIcon(), (suggestions.length > 0) && generateDropdown())); }; AutoComplete.defaultProps = { delay: 500, items: 5, theme: 'primary', size: '2x', width: '20vw', }; export default AutoComplete;