UNPKG

adwaita-web

Version:

A GTK inspired toolkit designed to build awesome web apps

102 lines (101 loc) 2.99 kB
import cx from "clsx"; import React, { useRef, useState } from "react"; import useControlled from "../utils/useControlled"; import { Box } from "./Box"; import { Expander } from "./Expander"; import { Input } from "./Input"; import { Label } from "./Label"; import { List } from "./List"; import { ListItem } from "./ListItem"; import { Popover } from "./Popover"; const Autocomplete = React.forwardRef(({ className, options = [], value: valueProp, defaultValue = "", enableFilter = true, onSearch, onChange: onChangeProp, ...rest }, refProp) => { const input = useRef(null); const [value, setValue] = useControlled(valueProp, defaultValue, onChangeProp); const [isFocused, setIsFocused] = useState(false); const open = isFocused && options.length > 0; const lowerCaseValue = value?.toString().toLowerCase(); const filteredOptions = enableFilter === false ? options : options.filter((o) => lowerCaseValue && o.value.toString().toLowerCase().includes(lowerCaseValue)); const onFocus = () => setIsFocused(true); const onBlur = (ev) => { const newValue = ev?.relatedTarget?.getAttribute("data-value"); if (newValue) { setValue(newValue); } setIsFocused(false); }; const elementClassName = cx("Autocomplete", className); const select = (option) => { setValue(option.value); if (input.current) input.current.querySelector("input")?.blur(); }; const onChange = (newValue) => { setValue(newValue); if (onSearch) onSearch(newValue); }; const onAccept = () => { if (filteredOptions.length > 0) { const opt = filteredOptions[0]; if (opt) select(opt); } }; const content = /* @__PURE__ */ React.createElement(Expander, { open, fitContent: true }, /* @__PURE__ */ React.createElement(List, { border: false, separators: false }, filteredOptions.map((o) => /* @__PURE__ */ React.createElement(ListItem, { key: o.value, activatable: true, onClick: () => select(o), "data-value": o.value }, o.label || o.value)), filteredOptions.length === 0 && /* @__PURE__ */ React.createElement(ListItem, { key: "empty" }, /* @__PURE__ */ React.createElement(Box, { justify: "center" }, /* @__PURE__ */ React.createElement(Label, { muted: true, italic: true }, "(No results found)"))))); return /* @__PURE__ */ React.createElement(Popover, { className: "Autocomplete__popover", open, content, arrow: false, placement: "bottom-start", width: "trigger-min", shouldAttachEarly: true }, /* @__PURE__ */ React.createElement(Input, { className: elementClassName, value: value ? value.toString() : "", onBlur, onFocus, onChange, onAccept, ...rest, ref: (ref) => { input.current = ref; if (refProp) { if (typeof refProp === "function") refProp(ref); else refProp.current = ref; } } })); }); export { Autocomplete };