UNPKG

rui-react

Version:
135 lines (134 loc) 5.68 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 Input from "../Input/input"; import React, { useEffect, useRef, useState, } from "react"; import { scopedClass } from "../../helpers/utils"; import classNames from "classnames"; import useDebounce from "../../hooks/useDebounce"; import useClickOutside from "../../hooks/useClickOutside"; import { OptionList } from "./optionList"; var AutoComplete = function (props) { var _a; var fetchSuggestion = props.fetchSuggestion, onSelect = props.onSelect, delay = props.delay, size = props.size, restProps = __rest(props, ["fetchSuggestion", "onSelect", "delay", "size"]); var _b = useState([]), suggestions = _b[0], setSuggestions = _b[1]; var _c = useState(false), optionListVisible = _c[0], setOptionListVisible = _c[1]; var _d = useState(""), value = _d[0], setValue = _d[1]; var debouncedValue = useDebounce(value, delay); var triggerSuggestions = useRef(false); var _e = useState(false), isLoading = _e[0], setIsLoading = _e[1]; var _f = useState(-1), candidateIndex = _f[0], setCandidateIndex = _f[1]; var optionListRef = useRef(null); var inputWrapperRef = useRef(null); var componentRef = useRef(null); var clearSuggestions = function () { return setSuggestions([]); }; useEffect(function () { if (!triggerSuggestions.current) return; var results = fetchSuggestion(debouncedValue); if (results instanceof Promise) { setIsLoading(true); results .then(function (data) { if (data.length) { setSuggestions(data); } else { setOptionListVisible(false); } setIsLoading(false); }) .catch(function (error) { setIsLoading(false); setOptionListVisible(false); }); } else { if (results.length) { setSuggestions(results); } else { setOptionListVisible(false); } } }, [debouncedValue, fetchSuggestion]); useClickOutside(componentRef, function () { return setOptionListVisible(false); }); var handleChange = function (e) { setValue(e.target.value); setOptionListVisible(true); triggerSuggestions.current = true; }; var handleSelect = function (selectedValue) { setValue(selectedValue); if (onSelect) onSelect(selectedValue); setOptionListVisible(false); triggerSuggestions.current = false; }; var handleKeyDown = function (e) { if (optionListRef.current === null || inputWrapperRef.current === null) return; var listHeight = optionListRef.current.clientHeight; var itemHeight = inputWrapperRef.current.clientHeight; switch (e.key) { case "ArrowUp": e.preventDefault(); if (candidateIndex < 0) return; if ((candidateIndex + 1) * itemHeight > listHeight) optionListRef.current.scrollTop -= itemHeight; setCandidateIndex(function (index) { return index - 1; }); break; case "ArrowDown": e.preventDefault(); if (candidateIndex >= suggestions.length - 1) return; if ((candidateIndex + 2) * itemHeight > listHeight) optionListRef.current.scrollTop += itemHeight; setCandidateIndex(function (index) { return index + 1; }); break; case "Enter": if (candidateIndex < 0) return; handleSelect(suggestions[candidateIndex]); setCandidateIndex(-1); break; case "Escape": setOptionListVisible(false); setCandidateIndex(-1); break; default: break; } }; var sc = scopedClass("autoComplete"); var classes_list = classNames(sc("list"), (_a = {}, _a[sc("list", size)] = size, _a)); return (React.createElement("div", { ref: componentRef, className: sc("wrapper") }, React.createElement(Input, __assign({}, restProps, { size: size, value: value, onChange: handleChange, onKeyDown: handleKeyDown, ref: inputWrapperRef })), React.createElement(OptionList, { visible: optionListVisible, clearSuggestions: clearSuggestions, isLoading: isLoading, className: classes_list, suggestions: suggestions, candidateIndex: candidateIndex, handleSelect: handleSelect, ref: optionListRef }))); }; AutoComplete.defaultProps = { delay: 300, }; export default AutoComplete;