"use client";
import { useRef } from "react";
import { useKeyboardMovementProvider } from "../movement/useKeyboardMovementProvider.js";
import { BELOW_CENTER_ANCHOR } from "../positioning/constants.js";
import { TRANSITION_CONFIG } from "../transition/config.js";
import { useEnsuredId } from "../useEnsuredId.js";
import { useEnsuredRef } from "../useEnsuredRef.js";
import { useToggle } from "../useToggle.js";
import { tryToSubmitRelatedForm } from "./utils.js";
const noop = ()=>{
// do nothing
};
/**
 * @remarks \@since 6.0.0
 */ export const getNonDisabledOptions = (container)=>[
        ...container.querySelectorAll('[role="option"]:not([aria-disabled])')
    ];
/**
 * @remarks \@since 6.0.0
 */ export function useCombobox(options) {
    const { form, popup = "listbox", onClick = noop, onFocus, onKeyDown, searchable, isNegativeOneAllowed, loopable, disabled, comboboxId: propComboboxId, comboboxRef: propComboboxRef, popupId: propPopupId, popupRef: propPopupRef, defaultVisible = false, onFocusChange = noop, extendKeyDown = noop, getFocusableElements = getNonDisabledOptions, getEnterDefaultFocusedIndex, getDefaultFocusedIndex } = options;
    const { toggled: visible, enable: show, disable: hide, setToggled: setVisible } = useToggle(defaultVisible);
    const popupId = useEnsuredId(propPopupId, "combobox-popup");
    const comboboxId = useEnsuredId(propComboboxId, "combobox");
    const [comboboxRef, comboboxRefCallback] = useEnsuredRef(propComboboxRef);
    const [popupRef, popupRefCallback] = useEnsuredRef(propPopupRef);
    const focusLast = useRef(false);
    const { movementProps, movementContext, currentFocusIndex, activeDescendantId, setActiveDescendantId } = useKeyboardMovementProvider({
        onFocus,
        onKeyDown,
        onClick (event) {
            onClick(event);
            if (disabled) {
                return;
            }
            show();
        },
        extendKeyDown (movementData) {
            extendKeyDown({
                ...movementData,
                show,
                hide,
                visible,
                focusLast
            });
            const { event } = movementData;
            if (event.isPropagationStopped()) {
                return;
            }
            if (visible) {
                switch(event.key){
                    case "Tab":
                    case "Escape":
                        event.stopPropagation();
                        hide();
                        break;
                    case "Enter":
                        event.preventDefault();
                        break;
                }
                // while visible, always use the default keyboard movement behavior
                return;
            }
            switch(event.key){
                case "ArrowUp":
                case "ArrowDown":
                    event.preventDefault();
                    event.stopPropagation();
                    focusLast.current = event.key === "ArrowUp";
                    show();
                    break;
                case "Enter":
                    tryToSubmitRelatedForm(event, form);
                    break;
            }
        },
        disabled,
        loopable,
        searchable,
        onFocusChange,
        programmatic: true,
        includeDisabled: false,
        tabIndexBehavior: "virtual",
        getFocusableElements (container, programmatic) {
            const popup = popupRef.current;
            if (!popup) {
                return [];
            }
            return getFocusableElements(popup || container, programmatic);
        },
        isNegativeOneAllowed,
        getDefaultFocusedIndex
    });
    const getTransitionCallbacks = (options = {})=>{
        const { onEntered, onEntering, onExiting, onExited, disableTransition } = options;
        const handleEntering = (callback = noop, skipped)=>(appearing)=>{
                callback(appearing);
                const popup = popupRef.current;
                if (!popup || skipped) {
                    // Chrome does not trigger the scrollIntoView behavior correctly while
                    // using a scale transition, so need to trigger this on the entered
                    // flow to really make sure the item is in view.
                    // An alternative would be to implement a custom scrollIntoView
                    // behavior again like the previous versions of react-md, but this is
                    // less lines of code
                    const activeOption = document.getElementById(activeDescendantId);
                    if (activeOption) {
                        activeOption.scrollIntoView({
                            block: "nearest"
                        });
                    }
                    return;
                }
                const focusables = getFocusableElements(popup, true);
                const index = getEnterDefaultFocusedIndex({
                    focusLast: focusLast.current,
                    focusables,
                    currentFocusIndex: currentFocusIndex.current
                });
                focusLast.current = false;
                currentFocusIndex.current = index;
                const option = focusables[index];
                if (!option) {
                    return;
                }
                onFocusChange({
                    index,
                    element: option
                });
                option.scrollIntoView({
                    block: "nearest"
                });
                setActiveDescendantId(option.id || "");
            };
        const handleExiting = (callback = noop, skipped)=>()=>{
                callback();
                if (!skipped) {
                    // since the menu is unmounted or set to hidden while not visible, need
                    // to clear the aria-activedescendant and current focus index when
                    // hiding
                    currentFocusIndex.current = -1;
                    setActiveDescendantId("");
                }
            };
        const isTransitionCompleteSkipped = !disableTransition && !TRANSITION_CONFIG.disabled;
        return {
            onEntering: handleEntering(onEntering, false),
            onEntered: handleEntering(onEntered, isTransitionCompleteSkipped),
            onExiting: handleExiting(onExiting, false),
            onExited: handleExiting(onExited, isTransitionCompleteSkipped)
        };
    };
    const popupProps = {
        id: popupId,
        ref: popupRefCallback,
        role: popup
    };
    return {
        show,
        hide,
        visible,
        setVisible,
        focusLast,
        popupRef,
        popupProps,
        comboboxRef,
        comboboxProps: {
            ...movementProps,
            "aria-controls": popupId,
            "aria-disabled": disabled || undefined,
            "aria-expanded": visible,
            "aria-haspopup": popup,
            id: comboboxId,
            ref: comboboxRefCallback,
            role: "combobox"
        },
        movementProps,
        movementContext,
        currentFocusIndex,
        activeDescendantId,
        setActiveDescendantId,
        getTransitionCallbacks,
        getMenuProps (props = {}) {
            const { sheetProps, disableTransition } = props;
            return {
                anchor: BELOW_CENTER_ANCHOR,
                width: "min",
                ...props,
                ...popupProps,
                fixedTo: comboboxRef,
                visible,
                onRequestClose: hide,
                ...getTransitionCallbacks(props),
                sheetProps: {
                    ...sheetProps,
                    ...getTransitionCallbacks({
                        ...sheetProps,
                        disableTransition: sheetProps?.disableTransition ?? disableTransition
                    })
                }
            };
        }
    };
}

//# sourceMappingURL=useCombobox.js.map