/* eslint-disable jsx-a11y/no-static-element-interactions */
/** biome-ignore-all lint/a11y/noStaticElementInteractions: We know what we are doing */
import React from "react";
import { useId } from "../../../../utils-external/index.js";
import { ListboxGroup } from "../group/ListboxGroup.js";
import { ListboxInputSlot } from "../input-slot/ListboxInputSlot.js";
import { ListboxOption } from "../option/ListboxOption.js";
import { ListboxOptions } from "../options/ListboxOptions.js";
import { ListboxProvider } from "./Listbox.context.js";
import { findNextOption, findPrevOption } from "./domHelpers.js";
/**
 * Low level component for displaying a list of selectable options with optional grouping.
 * Keyboard navigation is implemented with virtual focus so that real focus can remain on an input field.
 */
function Listbox({ children, setVirtuallyFocusedOptionId }) {
    const id = useId();
    const activeId = `aksel-listbox-${id}-active`;
    const virtuallyFocusOption = (element) => {
        setVirtuallyFocusedOptionId((element === null || element === void 0 ? void 0 : element.dataset.id) || "");
        element === null || element === void 0 ? void 0 : element.scrollIntoView({ block: "nearest" });
    };
    return (React.createElement("div", { onKeyDown: (event) => {
            const listbox = event.currentTarget.querySelector('[role="listbox"]');
            if (!listbox) {
                return;
            }
            // Helper functions
            const getFirstOption = (suffix = "") => listbox.querySelector(`[role="option"]${suffix}`);
            const getLastOption = () => {
                const allOptions = listbox.querySelectorAll('[role="option"]');
                return allOptions[allOptions.length - 1];
            };
            const focusedOptionElm = getFirstOption('[data-virtual-focus="true"]');
            // Doesn't make sense to have real focus on one option and virtual focus on another at the same time.
            // Not sure if it matters, though 🤔
            const optionElmWithRealFocus = getFirstOption(":focus");
            if (optionElmWithRealFocus) {
                listbox.focus();
            }
            const virtuallyFocusWithFallback = (getNextElement, getFallback) => {
                event.preventDefault();
                if (!focusedOptionElm) {
                    virtuallyFocusOption(getFallback());
                    return;
                }
                const nextOption = getNextElement(focusedOptionElm);
                if (!nextOption) {
                    virtuallyFocusOption(getFallback());
                    return;
                }
                virtuallyFocusOption(nextOption);
            };
            switch (event.key) {
                case "ArrowDown":
                    virtuallyFocusWithFallback(findNextOption, getFirstOption);
                    break;
                case "ArrowUp":
                    virtuallyFocusWithFallback(findPrevOption, getLastOption);
                    break;
                case "Home":
                    event.preventDefault();
                    virtuallyFocusOption(getFirstOption());
                    break;
                case "End":
                    event.preventDefault();
                    virtuallyFocusOption(getLastOption());
                    break;
                case "Enter":
                case "Accept":
                    if (focusedOptionElm) {
                        focusedOptionElm.click();
                    }
                    break;
                // TODO: Consider implementing PageUp/PageDown too
            }
        } },
        React.createElement(ListboxProvider, { activeId: activeId, setVirtuallyFocusedOptionId: setVirtuallyFocusedOptionId }, children)));
}
Listbox.InputSlot = ListboxInputSlot;
Listbox.Options = ListboxOptions;
Listbox.Option = ListboxOption;
Listbox.Group = ListboxGroup;
export default Listbox;
//# sourceMappingURL=ListboxRoot.js.map