adwaita-web
Version:
A GTK inspired toolkit designed to build awesome web apps
102 lines (101 loc) • 2.99 kB
JavaScript
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
};