function SearchForm({
uid = DOM.uid("autosuggestion").id,
placeholder = "",
label = "",
showLoading = true,
showResultCount = true,
format = (d) => d,
dataListFormat = null,
suggestion = () => [],
debounce = false,
debounceTime = 250,
debounceOptions = {}
} = {}) {
const input = htl.html`<input
type="search"
placeholder="${placeholder}"
list="${uid}"
autocomplete="off"
>`;
const form = htl.html`<form class="oi-ec050e">
${label ? htl.html`<label>${label}</label>` : null}
<div class="oi-ec050e-input">
${input}
<output id="${uid}-status"></output>
<datalist id="${uid}"></datalist>
</div>
</form>`;
let results = [];
form.value = "";
form.onsubmit = (event) => event.preventDefault();
form.onchange = (event) => {
clearStatus();
const value = event.target.value;
form.value = results.find((d) => format(d) == value) || "";
input.blur();
form.dispatchEvent(new CustomEvent("input", { bubbles: true }));
};
const options = new Map();
options.set("", []);
const clearStatus = () => {
d3.select(`#${uid}-status`).text("");
};
const setLoadingStatus = () => {
d3.select(`#${uid}-status`).text("Loading...");
};
const setResultStatus = (resultCount) => {
d3.select(`#${uid}-status`).text(`${resultCount} results`);
};
const updateDatalist = (r) => {
showResultCount ? setResultStatus(r.length) : clearStatus();
results = r;
d3.select(`#${uid}`)
.selectAll("option")
.data(r)
.join("option")
.attr("value", format);
};
const searchAndUpdate = async (text) => {
if (showLoading) setLoadingStatus();
options.set(text, await suggestion(text));
if (text != input.value) {
return;
}
updateDatalist(options.get(text));
};
const searchBouncer = _.debounce(
(value) => searchAndUpdate(value),
debounceTime,
debounceOptions
);
const handleInput = async (event) => {
if (event.inputType === undefined) {
return;
}
event.stopPropagation();
let value = event.target.value;
if (options.has(value)) {
searchBouncer.cancel();
updateDatalist(options.get(value));
if (value == "") clearStatus();
} else if (debounce) {
searchBouncer(value);
} else {
searchAndUpdate(value);
}
};
input.oninput = handleInput;
return form;
}