analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
269 lines (267 loc) • 9.39 kB
JavaScript
import {
DropdownMenuContent,
DropdownMenuItem,
DropdownMenu_default,
createDropdownStore
} from "./chunk-DHHHYBOU.mjs";
// src/components/Search/Search.tsx
import { XIcon } from "@phosphor-icons/react/dist/csr/X";
import { MagnifyingGlassIcon } from "@phosphor-icons/react/dist/csr/MagnifyingGlass";
import {
forwardRef,
useState,
useId,
useMemo,
useEffect,
useRef
} from "react";
import { jsx, jsxs } from "react/jsx-runtime";
var filterOptions = (options, query) => {
if (!query || query.length < 1) return [];
return options.filter(
(option) => option.toLowerCase().includes(query.toLowerCase())
);
};
var updateInputValue = (value, ref, onChange) => {
if (!onChange) return;
if (ref && "current" in ref && ref.current) {
ref.current.value = value;
const event = new Event("input", { bubbles: true });
Object.defineProperty(event, "target", {
writable: false,
value: ref.current
});
onChange(event);
} else {
const event = {
target: { value },
currentTarget: { value }
};
onChange(event);
}
};
var Search = forwardRef(
({
options = [],
onSelect,
onSearch,
showDropdown: controlledShowDropdown,
onDropdownChange,
dropdownMaxHeight = 240,
noResultsText = "Nenhum resultado encontrado",
className = "",
containerClassName = "",
disabled,
readOnly,
id,
onClear,
value,
onChange,
placeholder = "Buscar...",
onKeyDown: userOnKeyDown,
debounceMs = 0,
...props
}, ref) => {
const [dropdownOpen, setDropdownOpen] = useState(false);
const [forceClose, setForceClose] = useState(false);
const justSelectedRef = useRef(false);
const dropdownStore = useRef(createDropdownStore()).current;
const dropdownRef = useRef(null);
const inputElRef = useRef(null);
const debounceTimer = useRef(null);
useEffect(() => {
return () => {
if (debounceTimer.current) clearTimeout(debounceTimer.current);
};
}, []);
const filteredOptions = useMemo(() => {
if (!options.length) {
return [];
}
const filtered = filterOptions(options, value || "");
return filtered;
}, [options, value]);
const showDropdown = !forceClose && (controlledShowDropdown ?? (dropdownOpen && value && String(value).length > 0));
const setOpenAndNotify = (open) => {
setDropdownOpen(open);
dropdownStore.setState({ open });
onDropdownChange?.(open);
};
useEffect(() => {
if (justSelectedRef.current) {
justSelectedRef.current = false;
return;
}
if (forceClose) {
setOpenAndNotify(false);
return;
}
const shouldShow = Boolean(value && String(value).length > 0);
setOpenAndNotify(shouldShow);
}, [value, forceClose, onDropdownChange, dropdownStore]);
const handleSelectOption = (option) => {
justSelectedRef.current = true;
setForceClose(true);
onSelect?.(option);
setOpenAndNotify(false);
updateInputValue(option, ref, onChange);
};
useEffect(() => {
const handleClickOutside = (event) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setOpenAndNotify(false);
}
};
if (showDropdown) {
document.addEventListener("click", handleClickOutside);
}
return () => {
document.removeEventListener("click", handleClickOutside);
};
}, [showDropdown, dropdownStore, onDropdownChange]);
const generatedId = useId();
const inputId = id ?? `search-${generatedId}`;
const dropdownId = `${inputId}-dropdown`;
const handleClear = () => {
if (debounceTimer.current) {
clearTimeout(debounceTimer.current);
debounceTimer.current = null;
}
if (onClear) {
onClear();
} else {
updateInputValue("", ref, onChange);
}
};
const handleClearClick = (e) => {
e.preventDefault();
e.stopPropagation();
handleClear();
};
const handleSearchIconClick = (e) => {
e.preventDefault();
e.stopPropagation();
setTimeout(() => {
inputElRef.current?.focus();
}, 0);
};
const handleInputChange = (e) => {
setForceClose(false);
onChange?.(e);
if (debounceMs > 0) {
if (debounceTimer.current) clearTimeout(debounceTimer.current);
const value2 = e.target.value;
debounceTimer.current = setTimeout(() => {
onSearch?.(value2);
}, debounceMs);
} else {
onSearch?.(e.target.value);
}
};
const handleKeyDown = (e) => {
userOnKeyDown?.(e);
if (e.defaultPrevented) return;
if (e.key === "Enter") {
e.preventDefault();
if (showDropdown && filteredOptions.length > 0) {
handleSelectOption(filteredOptions[0]);
} else if (value) {
onSearch?.(String(value));
setForceClose(true);
setOpenAndNotify(false);
}
}
};
const getInputStateClasses = (disabled2, readOnly2) => {
if (disabled2) return "cursor-not-allowed opacity-40";
if (readOnly2) return "cursor-default focus:outline-none !text-text-900";
return "hover:border-border-400";
};
const hasValue = String(value ?? "").length > 0;
const showClearButton = hasValue && !disabled && !readOnly;
const showSearchIcon = !hasValue && !disabled && !readOnly;
return /* @__PURE__ */ jsxs(
"div",
{
ref: dropdownRef,
className: `w-full max-w-lg md:w-[488px] ${containerClassName}`,
children: [
/* @__PURE__ */ jsxs("div", { className: "relative flex items-center", children: [
/* @__PURE__ */ jsx(
"input",
{
ref: (node) => {
if (ref) {
if (typeof ref === "function") ref(node);
else
ref.current = node;
}
inputElRef.current = node;
},
id: inputId,
type: "text",
className: `w-full py-0 px-4 pr-10 font-normal text-text-900 focus:outline-primary-950 border rounded-full bg-background focus:bg-primary-50 border-border-300 focus:border-2 focus:border-primary-950 h-10 placeholder:text-text-600 ${getInputStateClasses(disabled, readOnly)} ${className}`,
value,
onChange: handleInputChange,
onKeyDown: handleKeyDown,
disabled,
readOnly,
placeholder,
"aria-expanded": showDropdown ? "true" : void 0,
"aria-haspopup": options.length > 0 ? "listbox" : void 0,
"aria-controls": showDropdown ? dropdownId : void 0,
"aria-autocomplete": "list",
role: options.length > 0 ? "combobox" : void 0,
...props
}
),
showClearButton && /* @__PURE__ */ jsx("div", { className: "absolute right-3 top-1/2 transform -translate-y-1/2", children: /* @__PURE__ */ jsx(
"button",
{
type: "button",
className: "p-0 border-0 bg-transparent cursor-pointer",
onMouseDown: handleClearClick,
"aria-label": "Limpar busca",
children: /* @__PURE__ */ jsx("span", { className: "w-6 h-6 text-text-800 flex items-center justify-center hover:text-text-600 transition-colors", children: /* @__PURE__ */ jsx(XIcon, {}) })
}
) }),
showSearchIcon && /* @__PURE__ */ jsx("div", { className: "absolute right-3 top-1/2 transform -translate-y-1/2", children: /* @__PURE__ */ jsx(
"button",
{
type: "button",
className: "p-0 border-0 bg-transparent cursor-pointer",
onMouseDown: handleSearchIconClick,
"aria-label": "Buscar",
children: /* @__PURE__ */ jsx("span", { className: "w-6 h-6 text-text-800 flex items-center justify-center hover:text-text-600 transition-colors", children: /* @__PURE__ */ jsx(MagnifyingGlassIcon, {}) })
}
) })
] }),
showDropdown && /* @__PURE__ */ jsx(DropdownMenu_default, { open: showDropdown, onOpenChange: setDropdownOpen, children: /* @__PURE__ */ jsx(
DropdownMenuContent,
{
id: dropdownId,
className: "w-full mt-1",
style: { maxHeight: dropdownMaxHeight },
align: "start",
children: filteredOptions.length > 0 ? filteredOptions.map((option) => /* @__PURE__ */ jsx(
DropdownMenuItem,
{
onClick: () => handleSelectOption(option),
className: "text-text-700 text-base leading-6 cursor-pointer",
children: option
},
option
)) : /* @__PURE__ */ jsx("div", { className: "px-3 py-3 text-text-700 text-base", children: noResultsText })
}
) })
]
}
);
}
);
Search.displayName = "Search";
var Search_default = Search;
export {
Search_default
};
//# sourceMappingURL=chunk-YMDK7D7Z.mjs.map