import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Children, isValidElement, useEffect, useMemo, useRef, useState, } from "react";
import { Check, ChevronDown } from "lucide-react";
function cx(...parts) {
return parts.filter(Boolean).join(" ");
}
function parseOptions(children) {
const options = [];
Children.forEach(children, (child, index) => {
if (!isValidElement(child) || child.type !== "option") {
return;
}
const option = child;
options.push({
key: option.key?.toString() ?? `option-${index}-${String(option.props.value ?? "")}`,
value: String(option.props.value ?? ""),
label: option.props.children,
disabled: Boolean(option.props.disabled),
});
});
return options;
}
export function AppSelect({ children, className, disabled = false, onChange, optionClassName, menuClassName, placement = "bottom", title, value, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, }) {
const [open, setOpen] = useState(false);
const rootRef = useRef(null);
const buttonRef = useRef(null);
const options = useMemo(() => parseOptions(children), [children]);
const normalizedValue = String(value ?? "");
const selectedOption = options.find((option) => option.value === normalizedValue) ?? options[0] ?? null;
useEffect(() => {
if (!open) {
return;
}
function handlePointerDown(event) {
if (!rootRef.current?.contains(event.target)) {
setOpen(false);
}
}
function handleEscape(event) {
if (event.key === "Escape") {
setOpen(false);
buttonRef.current?.focus();
}
}
document.addEventListener("mousedown", handlePointerDown);
document.addEventListener("keydown", handleEscape);
return () => {
document.removeEventListener("mousedown", handlePointerDown);
document.removeEventListener("keydown", handleEscape);
};
}, [open]);
function commit(nextValue) {
onChange?.({ target: { value: nextValue } });
setOpen(false);
buttonRef.current?.focus();
}
return (_jsxs("div", { ref: rootRef, className: "relative", children: [_jsxs("button", { ref: buttonRef, id: id, type: "button", title: title ?? (typeof selectedOption?.label === "string" ? selectedOption.label : undefined), "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-haspopup": "listbox", "aria-expanded": open, disabled: disabled, onClick: () => {
if (!disabled) {
setOpen((current) => !current);
}
}, onKeyDown: (event) => {
if (disabled) {
return;
}
if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Enter" || event.key === " ") {
event.preventDefault();
setOpen(true);
}
}, className: cx("flex w-full items-center gap-2 text-left transition-colors", "hover:border-primary/30 hover:bg-surface/70", "focus:border-primary/40 focus:outline-none focus:ring-1 focus:ring-primary/20", "disabled:cursor-not-allowed disabled:opacity-60", open && "border-primary/45 bg-surface/85 shadow-[0_16px_36px_-24px] shadow-black/70", className, "pr-10"), children: [_jsx("span", { className: "min-w-0 flex-1 truncate", children: selectedOption?.label ?? _jsx("span", { className: "text-foreground-secondary/60", children: "\u00A0" }) }), _jsx(ChevronDown, { size: 14, className: cx("pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-foreground-secondary/60 transition-transform", open && "rotate-180") })] }), open && !disabled && (_jsx("div", { className: cx("hf-elevated-menu absolute left-0 z-50 w-full overflow-hidden rounded-xl border p-1 backdrop-blur-xl", placement === "top" ? "bottom-full mb-1.5" : "top-full mt-1.5", menuClassName), children: _jsx("div", { role: "listbox", className: "max-h-64 overflow-y-auto", children: options.map((option) => {
const selected = option.value === normalizedValue;
return (_jsxs("button", { type: "button", role: "option", "aria-selected": selected, disabled: option.disabled, onClick: () => commit(option.value), "data-selected": selected ? "true" : undefined, className: cx("hf-menu-item flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm transition-colors", selected ? "text-foreground" : "text-foreground-secondary hover:text-foreground", option.disabled && "cursor-not-allowed opacity-45", optionClassName), children: [_jsx("span", { className: cx("min-w-0 flex-1 truncate", selected && "font-medium"), children: option.label }), selected && _jsx(Check, { size: 14, className: "shrink-0 text-primary" })] }, option.key));
}) }) }))] }));
}
//# sourceMappingURL=AppSelect.js.map