// components/Autocomplete.js import { $, Tag, For, Watch } from "sigpro"; export const Autocomplete = (props) => { const { class: className, items = [], value, onselect, placeholder, ...rest } = props; const query = $(() => { const v = typeof value === "function" ? value() : value; return v || ""; }); const isOpen = $(false); const cursor = $(-1); const filteredItems = $([]); Watch(() => { const q = String(query()).toLowerCase(); const allItems = typeof items === "function" ? items() : items; const filtered = q ? allItems.filter((item) => (typeof item === "string" ? item : item.label).toLowerCase().includes(q) ) : allItems; filteredItems(filtered); }); const pick = (item) => { const display = typeof item === "string" ? item : item.label; const actual = typeof item === "string" ? item : item.value; query(display); if (typeof value === "function") value(actual); onselect?.(item); isOpen(false); cursor(-1); }; const handleKeyDown = (e) => { const list = filteredItems(); if (e.key === "ArrowDown") { e.preventDefault(); isOpen(true); cursor(Math.min(cursor() + 1, list.length - 1)); } else if (e.key === "ArrowUp") { e.preventDefault(); cursor(Math.max(cursor() - 1, 0)); } else if (e.key === "Enter" && cursor() >= 0) { e.preventDefault(); pick(list[cursor()]); } else if (e.key === "Escape") { isOpen(false); } }; return Tag("div", { class: `relative w-full ${className || ''}`.trim() }, [ Tag("label", { class: "input input-bordered w-full" }, [ Tag("span", { class: "icon-[lucide--search]" }), Tag("input", { ...rest, type: "text", class: "grow", value: query, placeholder: placeholder || "Buscar...", onfocus: () => isOpen(true), onblur: () => setTimeout(() => isOpen(false), 150), onkeydown: handleKeyDown, oninput: (e) => { const newVal = e.target.value; query(newVal); if (typeof value === "function") value(newVal); isOpen(true); cursor(-1); } }) ]), Tag("ul", { class: "absolute left-0 w-full menu bg-base-100 rounded-box mt-1 p-2 shadow-xl max-h-60 overflow-y-auto border border-base-300 z-50", style: () => `display: ${isOpen() && filteredItems().length ? "block" : "none"};` }, [ For(filteredItems, (item, idx) => Tag("li", {}, [ Tag("a", { class: () => `block w-full ${cursor() === idx ? "active bg-primary text-primary-content" : ""}`, onclick: () => pick(item), onmouseenter: () => cursor(idx) }, typeof item === "string" ? item : item.label) ]), (item, idx) => (typeof item === "string" ? item : item.value) + idx ), () => filteredItems().length === 0 && Tag("li", { class: "p-2 text-center opacity-50" }, "Sin resultados") ]) ]); };