UNPKG

sailboat-design

Version:
140 lines (139 loc) 5.93 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 { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useEffect, useRef } from 'react'; import classNames from 'classnames'; import Input from '../Input/input'; import Icon from '../Icon/icon'; import Transition from '../Transition/transition'; import useDebounce from '../../hooks/useDebounce'; import useClickOutside from '../../hooks/useClickOutside'; /** * 输入框自动完成功能。当输入值需要自动完成时使用,支持同步和异步两种方式 * 支持 Input 组件的所有属性 支持键盘事件选择 * ### 引用方法 * * ~~~js * import { AutoComplete } from 'sailboatship' * ~~~ */ export var AutoComplete = function (props) { var fetchSuggestions = props.fetchSuggestions, onSelect = props.onSelect, onChange = props.onChange, value = props.value, renderOption = props.renderOption, restProps = __rest(props, ["fetchSuggestions", "onSelect", "onChange", "value", "renderOption"]); 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(false), showDropdown = _d[0], setShowDropdown = _d[1]; var _e = useState(-1), highlightIndex = _e[0], setHighlightIndex = _e[1]; var triggerSearch = useRef(false); var componentRef = useRef(null); var debouncedValue = useDebounce(inputValue, 300); 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 highlight = function (index) { if (index < 0) index = 0; 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: setShowDropdown(false); break; default: break; } }; var handleChange = function (e) { var value = e.target.value.trim(); setInputValue(value); if (onChange) { onChange(value); } triggerSearch.current = true; }; var handleSelect = function (item) { setInputValue(item.value); setShowDropdown(false); if (onSelect) { onSelect(item); } triggerSearch.current = false; }; var renderTemplate = function (item) { return renderOption ? renderOption(item) : item.value; }; var generateDropdown = function () { return (_jsx(Transition, __assign({ in: showDropdown || loading, animation: "zoom-in-top", timeout: 300, onExited: function () { setSuggestions([]); } }, { children: _jsxs("ul", __assign({ className: "sailboat-suggestion-list" }, { children: [loading && (_jsx("div", __assign({ className: "suggestion-loading-icon" }, { children: _jsx(Icon, { icon: "spinner", spin: true }) }))), suggestions.map(function (item, index) { var cNames = classNames('suggestion-item', { 'is-active': index === highlightIndex }); return (_jsx("li", __assign({ className: cNames, onClick: function () { return handleSelect(item); } }, { children: renderTemplate(item) }), index)); })] })) }))); }; return (_jsxs("div", __assign({ className: "sailboat-auto-complete", ref: componentRef }, { children: [_jsx(Input, __assign({}, restProps, { value: inputValue, onChange: handleChange, onKeyDown: handleKeyDown })), generateDropdown()] }))); }; export default AutoComplete;