import React__default, { useState, useRef, useEffect, useCallback, useMemo, forwardRef } from 'react';
import { u as useFloating, b as autoUpdate, o as offset, f as flip, c as size, e as useListNavigation, d as useDismiss, g as useInteractions, r as useTransitionStyles, F as FloatingPortal, p as FloatingFocusManager } from '../floating-ui.react-es.js';
import classnames from 'classnames';
import { tokens } from '@jobber/design';
import { useCallbackRef, useDebounce, useSafeLayoutEffect, useIsMounted, useOnKeyDown } from '@jobber/hooks';
import { c as calculateMaxHeight } from '../maxHeight-es.js';
import { H as Heading } from '../Heading-es.js';
import { T as Text } from '../Text-es.js';
import { T as Typography } from '../Typography-es.js';
import { I as Icon } from '../Icon-es.js';
import { InputText } from '../InputText/index.mjs';
import { G as Glimmer } from '../Glimmer-es.js';
import { m as mergeRefs } from '../FormField-es.js';
import { f as filterDataAttributes } from '../filterDataAttributes-es.js';
import { _ as __rest, a as __awaiter } from '../tslib.es6-es.js';
import 'react/jsx-runtime';
import 'react-dom';
import 'react-hook-form';
import 'framer-motion';
import '../Button-es.js';
import 'react-router-dom';
import '../useFormFieldFocus-es.js';
import '../InputValidation-es.js';
import '../Spinner-es.js';
import '../Content-es.js';

var styles$1 = {"list":"_37kZB-nYE08-","loadingList":"ULib3TUQja0-","option":"h5-1Pp0eRyo-","defaultOptionContent":"iBkyj85vd-E-","icon":"I6wAbSJJHNQ-","optionActive":"_4yhnonWAWRY-","actionActive":"oGLMF6n8C74-","action":"LBrwH6TEUYA-","section":"DDOv4DR8bJQ-","emptyStateMessage":"Twgjn26oldE-","stickyTop":"mc1-CEwZtHE-","scrollRegion":"kOR88SFNOn0-","persistentHeader":"_0O-kEf3h9ZI-","persistentFooter":"rQ9ZS7Rb7Z4-","textPersistent":"vxk57ZhP8GU-","spinning":"_0d8hyvaCPAw-"};

function flattenMenu(menu) {
    const optionItems = [];
    const sections = [];
    const persistentsHeaders = [];
    const persistentsFooters = [];
    menu.forEach(item => {
        if (item.type === "header") {
            persistentsHeaders.push(item);
            return;
        }
        if (item.type === "footer") {
            persistentsFooters.push(item);
            return;
        }
        const group = item;
        sections.push(group);
        optionItems.push(...group.options);
    });
    return { optionItems, sections, persistentsHeaders, persistentsFooters };
}
function buildItemsForGroup(group, optionsFilter) {
    var _a;
    const isSection = group.type === "section";
    const filtered = optionsFilter ? optionsFilter(group.options) : group.options;
    const actions = (_a = group.actions) !== null && _a !== void 0 ? _a : [];
    const result = [];
    // Only render a section header when that section has at least one option after filtering
    if (isSection && filtered.length > 0) {
        result.push({
            kind: "section",
            section: group,
        });
    }
    if (filtered.length > 0) {
        result.push(...filtered.map(o => ({
            kind: "option",
            value: o,
        })));
    }
    // Only render actions for a group when that group has at least one option after filtering
    if (actions.length > 0 && filtered.length > 0) {
        result.push(...actions.map(action => ({
            kind: "action",
            action,
            origin: "menu",
        })));
    }
    return result;
}
function buildRenderableList(sections, optionsFilter) {
    const items = [];
    for (const group of sections) {
        items.push(...buildItemsForGroup(group, optionsFilter));
    }
    return items;
}
function getNavigableItemAtIndex(activeIndex, renderable) {
    if (activeIndex == null)
        return null;
    let navigableIndex = -1;
    for (const item of renderable) {
        // Ignore sections
        if (item.kind === "section")
            continue;
        navigableIndex += 1;
        if (navigableIndex === activeIndex)
            return item;
    }
    return null;
}
function findNavigableIndexForValue(renderable, equals, selectedValue) {
    let navigableIndex = -1;
    for (const item of renderable) {
        // Ignore sections
        if (item.kind === "section")
            continue;
        navigableIndex += 1;
        if (item.kind === "option" && equals(item.value, selectedValue)) {
            return navigableIndex;
        }
    }
    return null;
}
function invokeActiveItemOnEnter(event, activeIndex, renderable, onSelect, onAction) {
    const activeItem = getNavigableItemAtIndex(activeIndex, renderable);
    if (!activeItem)
        return;
    event.preventDefault();
    if (activeItem.kind === "option") {
        onSelect(activeItem.value);
    }
    else if (activeItem.kind === "action") {
        onAction({
            run: activeItem.action.onClick,
            closeOnRun: activeItem.action.shouldClose,
        });
    }
}

const MENU_OFFSET = tokens["space-small"];
const AUTOCOMPLETE_MAX_HEIGHT$1 = 300;
function useAutocompleteListNav({ navigableCount, shouldResetActiveIndexOnClose, onMenuClose, selectedIndex, }) {
    const [open, setOpen] = useState(false);
    const [activeIndex, setActiveIndex] = useState(null);
    const listRef = useRef([]);
    const { refs, floatingStyles, context } = useFloating({
        placement: "bottom",
        whileElementsMounted: autoUpdate,
        open,
        onOpenChange: (isOpen, _event, reason) => {
            setOpen(isOpen);
            if (isOpen === false) {
                if (shouldResetActiveIndexOnClose === null || shouldResetActiveIndexOnClose === void 0 ? void 0 : shouldResetActiveIndexOnClose()) {
                    setActiveIndex(null);
                }
                onMenuClose === null || onMenuClose === void 0 ? void 0 : onMenuClose(String(reason !== null && reason !== void 0 ? reason : ""));
            }
        },
        middleware: [
            offset(MENU_OFFSET),
            flip({ fallbackPlacements: ["top"] }),
            size({
                apply({ availableHeight, elements }) {
                    const maxHeight = calculateMaxHeight(availableHeight, {
                        maxHeight: AUTOCOMPLETE_MAX_HEIGHT$1,
                    });
                    Object.assign(elements.floating.style, {
                        maxHeight: `${maxHeight}px`,
                    });
                },
            }),
        ],
    });
    const listNav = useListNavigation(context, {
        listRef,
        activeIndex,
        selectedIndex,
        scrollItemIntoView: {
            behavior: "smooth",
            block: "end",
        },
        loop: true,
        onNavigate: setActiveIndex,
        virtual: true,
        enabled: open,
        openOnArrowKeyDown: false,
        focusItemOnOpen: "auto",
        focusItemOnHover: false,
    });
    const dismiss = useDismiss(context, {
        outsidePress: true,
        escapeKey: true,
        outsidePressEvent: "click",
    });
    const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([listNav, dismiss]);
    useEffect(() => {
        listRef.current.length = navigableCount;
        setActiveIndex(prev => {
            if (navigableCount <= 0)
                return null;
            if (prev == null)
                return null;
            return prev >= navigableCount ? navigableCount - 1 : prev;
        });
    }, [navigableCount, setActiveIndex, listRef]);
    return {
        refs,
        floatingStyles,
        context,
        getReferenceProps,
        getFloatingProps,
        getItemProps,
        activeIndex,
        setActiveIndex,
        listRef,
        open,
        setOpen,
        setReferenceElement: (el) => refs.setReference(el),
    };
}

// Keeping this hook cohesive improves readability by centralizing related
// interactions and state transitions.
// eslint-disable-next-line max-statements
function useAutocomplete(props) {
    const { menu, emptyActions, getOptionLabel: getOptionLabelProp, isOptionEqualToValue, inputValue, onInputChange, value, onChange, multiple, openOnFocus = true, readOnly = false, debounce: debounceMs = 300, } = props;
    // TODO: Clean up the types in these refs by enhancing the type system in useCallbackRef
    const getOptionLabelPropRef = useCallbackRef((opt) => getOptionLabelProp === null || getOptionLabelProp === void 0 ? void 0 : getOptionLabelProp(opt));
    const getOptionLabel = useCallback((opt) => {
        const maybe = getOptionLabelPropRef(opt);
        return maybe !== null && maybe !== void 0 ? maybe : opt.label;
    }, [getOptionLabelPropRef]);
    const isOptionEqualToValueRef = useCallbackRef((a, b) => isOptionEqualToValue === null || isOptionEqualToValue === void 0 ? void 0 : isOptionEqualToValue(a, b));
    const equals = useCallback((a, b) => {
        const custom = isOptionEqualToValueRef(a, b);
        return custom != null ? custom : getOptionLabel(a) === getOptionLabel(b);
    }, [isOptionEqualToValueRef, getOptionLabel]);
    const isOptionSelected = useCallback((opt) => {
        var _a;
        if (multiple) {
            const current = (_a = value) !== null && _a !== void 0 ? _a : [];
            return current.some(v => equals(v, opt));
        }
        const current = value;
        return current != null ? equals(current, opt) : false;
    }, [multiple, value, equals]);
    const flatInitial = useMemo(() => flattenMenu(menu), [menu]);
    const sections = flatInitial.sections;
    const optionItems = flatInitial.optionItems;
    const persistentsHeaders = flatInitial.persistentsHeaders;
    const persistentsFooters = flatInitial.persistentsFooters;
    // Stable wrappers for function props
    const inputEqualsOptionRef = useCallbackRef((text, o) => {
        const fn = props.inputEqualsOption;
        return fn ? fn(text, o) : undefined;
    });
    const inputEquals = useCallback((text, o) => {
        const custom = inputEqualsOptionRef(text, o);
        return custom != null ? custom : getOptionLabel(o) === text;
    }, [inputEqualsOptionRef, getOptionLabel]);
    // inputValue changes very often, is this worth memoizing?
    const exactLabelMatch = useMemo(() => {
        return optionItems.some(o => inputEquals(inputValue, o));
    }, [optionItems, inputEquals, inputValue]);
    const lastInputWasUser = useRef(false);
    const [debouncedInputValue, setDebouncedInputValue] = useState(inputValue);
    const debouncedSetter = useDebounce(setDebouncedInputValue, debounceMs);
    useEffect(() => {
        if (debounceMs === 0) {
            setDebouncedInputValue(inputValue);
            return;
        }
        debouncedSetter(inputValue);
    }, [inputValue, debounceMs, debouncedSetter]);
    const filterOptionsRef = useCallbackRef((opts, term) => {
        const fn = (typeof props.filterOptions === "function"
            ? props.filterOptions
            : undefined) || undefined;
        return fn ? fn(opts, term) : undefined;
    });
    const applyFilter = useCallback((opts, term) => {
        if (props.filterOptions === false)
            return opts;
        const override = filterOptionsRef(opts, term);
        if (override)
            return override;
        const lowered = term.toLowerCase();
        return opts.filter(opt => getOptionLabel(opt).toLowerCase().includes(lowered));
    }, [props.filterOptions, filterOptionsRef, getOptionLabel]);
    const renderable = useMemo(() => {
        const filter = (opts) => {
            if (exactLabelMatch && !lastInputWasUser.current)
                return opts;
            return applyFilter(opts, debouncedInputValue);
        };
        const items = buildRenderableList(sections, filter);
        const hasAnyOptions = items.some(i => i.kind === "option");
        if (!hasAnyOptions) {
            if (emptyActions) {
                const derived = typeof emptyActions === "function"
                    ? emptyActions({ inputValue })
                    : emptyActions;
                return derived.map(act => ({
                    kind: "action",
                    action: act,
                    origin: "empty",
                }));
            }
            // No options and no emptyActions: render empty state
            return [];
        }
        return items;
    }, [
        sections,
        applyFilter,
        debouncedInputValue,
        exactLabelMatch,
        emptyActions,
        inputValue,
    ]);
    // This is only options
    const optionCount = renderable.reduce((count, item) => count + (item.kind === "option" ? 1 : 0), 0);
    const hasSelection = useMemo(() => {
        var _a;
        if (multiple) {
            const current = (_a = value) !== null && _a !== void 0 ? _a : [];
            return Array.isArray(current) && current.length > 0;
        }
        return value != null;
    }, [multiple, value]);
    const headerInteractivePersistents = persistentsHeaders.filter(p => Boolean(p.onClick));
    const footerInteractivePersistents = persistentsFooters.filter(p => Boolean(p.onClick));
    const mainNavigableCount = renderable.reduce((c, i) => c + (i.kind === "section" ? 0 : 1), 0);
    const totalNavigableCount = headerInteractivePersistents.length +
        mainNavigableCount +
        footerInteractivePersistents.length;
    // Compute the currently selected index in the global navigable list (header -> middle -> footer)
    const selectedIndex = useMemo(() => {
        const selectedValue = multiple
            ? value === null || value === void 0 ? void 0 : value[0]
            : value;
        if (!selectedValue)
            return null;
        const middleIndex = findNavigableIndexForValue(renderable, equals, selectedValue);
        if (middleIndex == null)
            return null;
        return headerInteractivePersistents.length + middleIndex;
    }, [
        multiple,
        value,
        renderable,
        equals,
        headerInteractivePersistents.length,
    ]);
    const { refs, floatingStyles, context, getReferenceProps, getFloatingProps, getItemProps, activeIndex, setActiveIndex, listRef, open, setOpen, setReferenceElement, } = useAutocompleteListNav({
        navigableCount: totalNavigableCount,
        shouldResetActiveIndexOnClose: () => !hasSelection,
        selectedIndex,
        onMenuClose: () => {
            if (props.allowFreeForm !== true) {
                const hasText = inputValue.trim().length > 0;
                if (hasText && !hasSelection) {
                    lastInputWasUser.current = false;
                    onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange("");
                    setActiveIndex(null);
                }
            }
        },
    });
    const [inputFocused, setInputFocused] = useState(false);
    // Handles activeIndex reset and, in single-select mode only, clearing selection when input is empty
    useEffect(() => {
        const hasText = inputValue.trim().length > 0;
        if (hasText)
            return;
        // Always reset highlight when input is empty
        setActiveIndex(null);
        // In multiple mode, clearing the input should NOT clear the selection
        if (multiple)
            return;
        // For single-select, treat clearing input as clearing the selection
        if (hasSelection) {
            onChange === null || onChange === void 0 ? void 0 : onChange(undefined);
        }
    }, [inputValue, multiple, hasSelection, setActiveIndex, onChange, open]);
    function selectOption(option) {
        var _a;
        if (multiple) {
            const current = (_a = value) !== null && _a !== void 0 ? _a : [];
            const exists = current.some(v => equals(v, option));
            const next = exists
                ? current.filter(v => !equals(v, option))
                : [...current, option];
            onChange(next);
        }
        else {
            onChange(option);
            lastInputWasUser.current = false;
            onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(getOptionLabel(option));
        }
    }
    function tryCommitFreeFormOnEnter() {
        if (props.allowFreeForm !== true)
            return false;
        if (open && activeIndex != null)
            return false;
        const inputText = inputValue.trim();
        if (inputText.length === 0)
            return false;
        commitFromInputText(inputText);
        return true;
    }
    // Keep the selected item highlighted when deleting characters from the input
    const prevInputLengthRef = useRef(inputValue.length);
    useEffect(() => {
        const previousLength = prevInputLengthRef.current;
        prevInputLengthRef.current = inputValue.length;
        if (!open)
            return;
        if (!lastInputWasUser.current)
            return;
        if (previousLength <= inputValue.length)
            return; // only on deletion
        if (!hasSelection)
            return;
        const selectedValue = multiple
            ? value === null || value === void 0 ? void 0 : value[0]
            : value;
        if (!selectedValue)
            return;
        const idx = findNavigableIndexForValue(renderable, equals, selectedValue);
        if (idx != null)
            setActiveIndex(idx);
    }, [
        inputValue,
        renderable,
        equals,
        value,
        open,
        hasSelection,
        multiple,
        setActiveIndex,
    ]);
    useEffect(() => {
        if (!open)
            return;
        // When opening the menu, initialize the highlight consistently:
        // - If there is a current selection, highlight that option
        // - Otherwise, leave the highlight unset (null)
        const selectedValue = multiple
            ? value === null || value === void 0 ? void 0 : value[0]
            : value;
        if (selectedValue) {
            const selectedNavigableIndex = findNavigableIndexForValue(renderable, equals, selectedValue);
            if (selectedNavigableIndex != null) {
                setActiveIndex(selectedNavigableIndex);
                return;
            }
        }
        setActiveIndex(null);
    }, [open, multiple, value, renderable, equals, setActiveIndex]);
    const onSelection = useCallback((option) => {
        selectOption(option);
        // Might not always want to close on selection. Multi for example.
        setOpen(false);
    }, [selectOption, setOpen]);
    const onAction = useCallback((action) => {
        action.run();
        setActiveIndex(null);
        if (action.closeOnRun !== false)
            setOpen(false);
    }, [setOpen, setActiveIndex]);
    function commitFromInputText(inputText) {
        var _a;
        if (inputText.length === 0)
            return false;
        const match = optionItems.find(o => inputEquals(inputText, o));
        if (match) {
            onSelection(match);
            return true;
        }
        setOpen(false);
        if (props.allowFreeForm !== true)
            return false;
        const freeFormCreated = (_a = props.createFreeFormValue) === null || _a === void 0 ? void 0 : _a.call(props, inputText);
        if (!freeFormCreated)
            return false;
        props.onChange(freeFormCreated);
        return true;
    }
    const tryRestoreInputToSelectedLabel = useCallback(() => {
        if (props.allowFreeForm === true)
            return;
        const selectedValue = multiple
            ? value === null || value === void 0 ? void 0 : value[0]
            : value;
        if (!selectedValue)
            return;
        const selectedLabel = getOptionLabel(selectedValue);
        if (inputValue === selectedLabel)
            return;
        lastInputWasUser.current = false;
        onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(selectedLabel);
    }, [
        props.allowFreeForm,
        getOptionLabel,
        inputValue,
        onInputChange,
        multiple,
        value,
    ]);
    const onInputFocus = useCallback((event) => {
        var _a;
        setInputFocused(true);
        if (!readOnly && openOnFocus)
            setOpen(true);
        (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, event);
    }, [props.onFocus, readOnly, openOnFocus, setOpen]);
    const onInputBlur = useCallback((event) => {
        var _a, _b;
        setInputFocused(false);
        if (readOnly) {
            (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, event);
            return;
        }
        if (props.allowFreeForm === true) {
            const inputText = inputValue.trim();
            if (inputText.length > 0)
                commitFromInputText(inputText);
        }
        else {
            tryRestoreInputToSelectedLabel();
        }
        lastInputWasUser.current = false;
        (_b = props.onBlur) === null || _b === void 0 ? void 0 : _b.call(props, event);
    }, [
        readOnly,
        props.allowFreeForm,
        inputValue,
        props.onBlur,
        tryRestoreInputToSelectedLabel,
        setOpen,
    ]);
    function getRegionByActiveIndex(index) {
        const headerCount = headerInteractivePersistents.length;
        const mainCount = mainNavigableCount;
        if (index < headerCount)
            return { region: "header", regionIndex: index };
        const middleIndex = index - headerCount;
        if (middleIndex < mainCount) {
            return { region: "middle", regionIndex: middleIndex };
        }
        return {
            region: "footer",
            regionIndex: middleIndex - mainCount,
        };
    }
    function computeInitialIndexForArrowUp() {
        // If there are interactive footers, prefer the very last navigable item
        if (footerInteractivePersistents.length > 0) {
            return totalNavigableCount > 0 ? totalNavigableCount - 1 : null;
        }
        // Otherwise, prefer the last OPTION (not action), matching legacy behavior
        let navigable = -1;
        let lastOptionIdx = -1;
        for (const item of renderable) {
            if (item.kind === "section")
                continue;
            navigable += 1;
            if (item.kind === "option")
                lastOptionIdx = navigable;
        }
        if (lastOptionIdx >= 0) {
            return headerInteractivePersistents.length + lastOptionIdx;
        }
        return totalNavigableCount > 0 ? totalNavigableCount - 1 : null;
    }
    function handleArrowNavigation(key, event) {
        if (!open) {
            setOpen(true);
            return;
        }
        if (activeIndex == null) {
            setActiveIndex(key === "ArrowDown" ? 0 : computeInitialIndexForArrowUp());
            event.preventDefault();
        }
    }
    function handleEnterKey(event) {
        if (tryCommitFreeFormOnEnter()) {
            event.preventDefault();
            return;
        }
        if (!open || activeIndex == null)
            return;
        const { region, regionIndex } = getRegionByActiveIndex(activeIndex);
        if (region === "middle") {
            invokeActiveItemOnEnter(event, regionIndex, renderable, onSelection, onAction);
            return;
        }
        const persistent = region === "header"
            ? headerInteractivePersistents[regionIndex]
            : footerInteractivePersistents[regionIndex];
        if (persistent === null || persistent === void 0 ? void 0 : persistent.onClick) {
            onAction({
                run: persistent.onClick,
                closeOnRun: persistent.shouldClose,
            });
        }
    }
    const onInputKeyDown = useCallback((event) => {
        const key = event.key;
        if (key !== "ArrowDown" && key !== "ArrowUp" && key !== "Enter")
            return;
        if (key === "ArrowDown" || key === "ArrowUp") {
            handleArrowNavigation(key, event);
            return;
        }
        handleEnterKey(event);
    }, [open, onSelection, onAction]);
    const onInputChangeFromUser = useCallback((val) => {
        lastInputWasUser.current = true;
        // Reset highlight (activeIndex) on additions to the search term
        if (val.length > inputValue.length) {
            setActiveIndex(null);
        }
        // Important: update open state before propagating the change so that downstream effects
        // don’t see an intermediate state where inputValue changed but open was stale
        if (!readOnly) {
            const hasText = val.trim().length > 0;
            const mustSelectFromOptions = hasText && !props.allowFreeForm;
            const keepOpenOnEmpty = openOnFocus && inputFocused;
            setOpen(mustSelectFromOptions || keepOpenOnEmpty);
        }
        onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(val);
    }, [
        onInputChange,
        inputValue,
        setActiveIndex,
        readOnly,
        props.allowFreeForm,
        openOnFocus,
        inputFocused,
        setOpen,
    ]);
    return {
        // rendering data
        renderable,
        optionCount,
        persistentsHeaders,
        persistentsFooters,
        headerInteractiveCount: headerInteractivePersistents.length,
        middleNavigableCount: mainNavigableCount,
        getOptionLabel,
        isOptionSelected,
        // floating-ui
        refs,
        floatingStyles,
        context,
        getReferenceProps,
        getFloatingProps,
        getItemProps,
        // state
        open,
        setOpen,
        activeIndex,
        setActiveIndex,
        listRef,
        // actions
        onSelection,
        onAction,
        // input handlers
        onInputChangeFromUser,
        onInputBlur,
        onInputFocus,
        onInputKeyDown,
        // ref attachment
        setReferenceElement,
    };
}

function MenuList({ items, activeIndex, indexOffset = 0, getItemProps, listRef, listboxId, customRenderOption, customRenderSection, customRenderAction, getOptionLabel, onSelect, onAction, isOptionSelected, slotOverrides, }) {
    let navigableIndex = -1;
    function renderItemNode(item) {
        var _a, _b, _c, _d, _e, _f;
        if (item.kind === "section") {
            return handleSectionRendering({
                section: item.section,
                customRenderSection,
                sectionClassName: (_a = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.section) === null || _a === void 0 ? void 0 : _a.className,
                sectionStyle: (_b = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.section) === null || _b === void 0 ? void 0 : _b.style,
            });
        }
        if (item.kind === "option") {
            const result = handleOptionRendering({
                option: item.value,
                activeIndex,
                navigableIndex,
                getItemProps,
                listRef,
                listboxId,
                isOptionSelected,
                customRenderOption,
                getOptionLabel,
                onSelect,
                indexOffset,
                optionClassName: (_c = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.option) === null || _c === void 0 ? void 0 : _c.className,
                optionStyle: (_d = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.option) === null || _d === void 0 ? void 0 : _d.style,
            });
            navigableIndex = result.nextNavigableIndex;
            return result.node;
        }
        const result = handleActionRendering({
            action: item.action,
            activeIndex,
            navigableIndex,
            getItemProps,
            listRef,
            listboxId,
            customRenderAction,
            onAction,
            indexOffset,
            actionClassName: (_e = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.action) === null || _e === void 0 ? void 0 : _e.className,
            actionStyle: (_f = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.action) === null || _f === void 0 ? void 0 : _f.style,
            origin: item.origin,
        });
        navigableIndex = result.nextNavigableIndex;
        return result.node;
    }
    return React__default.createElement(React__default.Fragment, null, items.map(renderItemNode));
}
function handleSectionRendering({ customRenderSection, section, sectionClassName, sectionStyle, }) {
    var _a;
    const headerContent = customRenderSection ? (customRenderSection(section)) : (React__default.createElement(DefaultSectionContent, { section: section }));
    return (React__default.createElement("div", { key: `section-${String((_a = section.key) !== null && _a !== void 0 ? _a : section.label)}`, role: "presentation", tabIndex: -1, "data-testid": "ATL-AutocompleteRebuilt-Section", className: classnames(styles$1.section, styles$1.stickyTop, sectionClassName), style: sectionStyle }, headerContent));
}
function DefaultSectionContent({ section, }) {
    return React__default.createElement(Heading, { level: 5 }, section.label);
}
function handleOptionRendering({ option, activeIndex, navigableIndex, getItemProps, listRef, listboxId, isOptionSelected, customRenderOption, getOptionLabel, onSelect, indexOffset = 0, optionClassName, optionStyle, }) {
    var _a;
    const nextNavigableIndex = navigableIndex + 1;
    const isActive = activeIndex === nextNavigableIndex;
    const isSelected = isOptionSelected(option);
    const optionContent = customRenderOption ? (customRenderOption({ value: option, isActive, isSelected })) : (React__default.createElement(DefaultOptionContent, { isSelected: isSelected, text: getOptionLabel(option) }));
    return {
        node: (React__default.createElement("div", Object.assign({ key: `option-${String((_a = option.key) !== null && _a !== void 0 ? _a : getOptionLabel(option))}` }, getItemProps({
            ref(node) {
                const idx = nextNavigableIndex + indexOffset;
                if (node)
                    listRef.current[idx] = node;
            },
            onClick: () => onSelect(option),
            className: classnames(styles$1.option, isActive && styles$1.optionActive, optionClassName),
            style: optionStyle,
        }), { role: "option", tabIndex: -1, "aria-selected": isSelected ? true : false, id: `${listboxId}-item-${nextNavigableIndex + indexOffset}`, "data-index": nextNavigableIndex + indexOffset, "data-active": isActive ? true : undefined }), optionContent)),
        nextNavigableIndex,
    };
}
function DefaultOptionContent({ isSelected, text, }) {
    return (React__default.createElement("div", { className: styles$1.defaultOptionContent },
        React__default.createElement("div", { className: styles$1.icon }, isSelected && React__default.createElement(Icon, { name: "checkmark", size: "small" })),
        React__default.createElement(Text, null, text)));
}
function handleActionRendering({ action, activeIndex, navigableIndex, getItemProps, listRef, listboxId, customRenderAction, onAction, indexOffset = 0, actionClassName, actionStyle, origin, }) {
    var _a;
    const nextNavigableIndex = navigableIndex + 1;
    const isActive = activeIndex === nextNavigableIndex;
    const actionContent = customRenderAction ? (customRenderAction({ value: action, isActive, origin })) : (React__default.createElement(DefaultActionContent, { textContent: action.label }));
    const computedIndex = nextNavigableIndex + indexOffset;
    const itemProps = getItemProps({
        ref(node) {
            if (node) {
                listRef.current[computedIndex] = node;
            }
        },
        onClick: () => {
            onAction({
                run: action.onClick,
                closeOnRun: action.shouldClose,
            });
        },
        className: classnames(styles$1.action, isActive && styles$1.actionActive, actionClassName),
        style: actionStyle,
    });
    return {
        node: (React__default.createElement("div", Object.assign({ key: `action-${String((origin !== null && origin !== void 0 ? origin : "menu") + "-" + ((_a = action.key) !== null && _a !== void 0 ? _a : action.label))}` }, itemProps, { role: "button", tabIndex: -1, "data-testid": "ATL-AutocompleteRebuilt-Action", id: `${listboxId}-item-${computedIndex}`, "data-index": computedIndex, "data-origin": origin, "data-active": isActive ? true : undefined }), actionContent)),
        nextNavigableIndex,
    };
}
function DefaultActionContent({ textContent, }) {
    return (React__default.createElement(Typography, { textColor: "interactive", fontWeight: "semiBold", underline: "solid color-interactive", UNSAFE_style: {
            textStyle: {
                textDecorationThickness: "var(--border-thick)",
                textUnderlineOffset: "var(--space-smallest)",
            },
        } }, textContent));
}

function PersistentRegion({ items, position, activeIndex, indexOffset, getItemProps, listRef, customRenderHeader, customRenderFooter, className, style, onAction, }) {
    if (!items || items.length === 0)
        return null;
    let navigableIndex = -1;
    return (React__default.createElement("div", { className: className, style: style, "data-region": position, "data-testid": `ATL-AutocompleteRebuilt-${position}` }, items.map(persistent => {
        const result = handlePersistentRendering({
            persistent,
            position,
            activeIndex,
            indexOffset,
            getItemProps,
            customRenderHeader,
            customRenderFooter,
            listRef,
            onAction,
            navigableIndex,
        });
        navigableIndex = result.nextNavigableIndex;
        return result.node;
    })));
}
function handlePersistentRendering({ persistent, position, activeIndex, indexOffset, getItemProps, customRenderHeader, customRenderFooter, listRef, onAction, navigableIndex, }) {
    const interactive = Boolean(persistent.onClick);
    if (!interactive) {
        const node = handleTextPersistentRendering({
            persistent,
            position,
            customRenderHeader,
            customRenderFooter,
        });
        return { node, nextNavigableIndex: navigableIndex };
    }
    return handleActionPersistentRendering({
        persistent,
        position,
        activeIndex,
        indexOffset,
        getItemProps,
        customRenderHeader,
        customRenderFooter,
        listRef,
        onAction,
        navigableIndex,
    });
}
function handleTextPersistentRendering({ persistent, position, customRenderHeader, customRenderFooter, }) {
    var _a;
    let content;
    if (position === "header" && customRenderHeader) {
        content = customRenderHeader({ value: persistent });
    }
    else if (position === "footer" && customRenderFooter) {
        content = customRenderFooter({ value: persistent });
    }
    else {
        content = React__default.createElement(DefaultTextPersistentContent, { persistent: persistent });
    }
    return (React__default.createElement("div", { key: `persistent-${position}-${String((_a = persistent.key) !== null && _a !== void 0 ? _a : persistent.label)}`, role: "presentation", tabIndex: -1, className: styles$1.textPersistent }, content));
}
function handleActionPersistentRendering({ persistent, position, activeIndex, indexOffset, getItemProps, customRenderHeader, customRenderFooter, listRef, onAction, navigableIndex, }) {
    var _a;
    const nextNavigableIndex = navigableIndex + 1;
    const isActive = activeIndex === indexOffset + nextNavigableIndex;
    let content;
    if (position === "header" && customRenderHeader) {
        content = customRenderHeader({
            value: persistent,
            isActive,
        });
    }
    else if (position === "footer" && customRenderFooter) {
        content = customRenderFooter({
            value: persistent,
            isActive,
        });
    }
    else {
        content = React__default.createElement(DefaultActionContent, { textContent: persistent.label });
    }
    return {
        node: (React__default.createElement("div", Object.assign({ key: `persistent-${position}-${String((_a = persistent.key) !== null && _a !== void 0 ? _a : persistent.label)}`, "data-index": indexOffset + nextNavigableIndex, id: `${position}-persistent-${indexOffset + nextNavigableIndex}`, "data-active": isActive ? true : undefined }, getItemProps({
            ref(persistNode) {
                const idx = indexOffset + nextNavigableIndex;
                if (persistNode)
                    listRef.current[idx] = persistNode;
            },
            onClick: () => onAction({
                run: () => {
                    var _a;
                    (_a = persistent.onClick) === null || _a === void 0 ? void 0 : _a.call(persistent);
                },
                closeOnRun: persistent.shouldClose,
            }),
            className: classnames(styles$1.action, isActive && styles$1.actionActive),
        }), { role: "button", tabIndex: -1 }), content)),
        nextNavigableIndex,
    };
}
function DefaultTextPersistentContent({ persistent, }) {
    return React__default.createElement("div", { className: styles$1.textPersistent }, persistent.label);
}

const AutocompleteRebuilt = forwardRef(AutocompleteRebuiltInternal);
// eslint-disable-next-line max-statements
function AutocompleteRebuiltInternal(props, forwardedRef) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
    const { inputValue, placeholder, disabled, error, invalid, description, size: sizeProp, loading = false, } = props;
    const { renderable, optionCount, persistentsHeaders, persistentsFooters, headerInteractiveCount, middleNavigableCount, getOptionLabel, isOptionSelected, refs, floatingStyles, context, getReferenceProps, getFloatingProps, getItemProps, activeIndex, open, listRef, onSelection, onAction, onInputChangeFromUser, onInputBlur, onInputFocus, onInputKeyDown, setReferenceElement, } = useAutocomplete(props);
    const listboxId = React__default.useId();
    // Provides mount/unmount-aware transition styles for the floating element
    const { isMounted, styles: transitionStyles } = useTransitionStyles(context, {
        initial: { opacity: 0 },
        open: { opacity: 1 },
        close: { opacity: 0 },
        duration: { open: tokens["timing-base"], close: tokens["timing-base"] },
    });
    const [menuWidth, setMenuWidth] = React__default.useState(undefined);
    const [positionRefEl, setPositionRefEl] = React__default.useState(null);
    const composedReferenceProps = getReferenceProps({
        onKeyDown: onInputKeyDown,
        onFocus: onInputFocus,
        onBlur: onInputBlur,
    });
    const dataAttrs = filterDataAttributes(props);
    const inputProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ version: 2, value: inputValue, onChange: props.readOnly ? undefined : onInputChangeFromUser }, (props.readOnly ? { onFocus: onInputFocus, onBlur: onInputBlur } : {})), { placeholder,
        disabled, readOnly: props.readOnly, error: error !== null && error !== void 0 ? error : undefined, name: props.name, invalid, autoComplete: "off", autoFocus: props.autoFocus, description, size: sizeProp ? sizeProp : undefined, prefix: props.prefix, suffix: props.suffix }), (props.readOnly ? {} : composedReferenceProps)), { role: "combobox", "aria-autocomplete": "list", "aria-expanded": open ? true : false, "aria-controls": listboxId, "aria-activedescendant": open && activeIndex != null
            ? `${listboxId}-item-${activeIndex}`
            : undefined }), dataAttrs);
    const referenceInputRef = (node) => {
        setReferenceElement(node);
        // Workaround to get the width of the visual InputText element, which is not the same as
        // the literal input reference element when props like suffix/prefix/clearable are present.
        const visualInputTextElement = node === null || node === void 0 ? void 0 : node.closest("[data-testid='Form-Field-Wrapper']");
        if (visualInputTextElement) {
            setMenuWidth(visualInputTextElement.clientWidth);
            setPositionRefEl(visualInputTextElement);
        }
    };
    const mergedInputRef = mergeRefs([
        referenceInputRef,
        forwardedRef,
    ]);
    useEffect(() => {
        if (!positionRefEl)
            return;
        // Set the reference element to the visual InputText element so the menu aligns with the input.
        refs.setPositionReference(positionRefEl);
    }, [positionRefEl, refs]);
    const menuClassName = classnames(styles$1.list, (_a = props.UNSAFE_className) === null || _a === void 0 ? void 0 : _a.menu);
    const showEmptyStateMessage = optionCount === 0 && props.emptyStateMessage !== false;
    const activeIndexForMiddle = activeIndex != null ? activeIndex - headerInteractiveCount : null;
    return (React__default.createElement("div", { "data-testid": "ATL-AutocompleteRebuilt" },
        props.customRenderInput ? (props.customRenderInput({ inputRef: mergedInputRef, inputProps })) : (React__default.createElement(InputText, Object.assign({ ref: mergedInputRef }, inputProps))),
        isMounted && !props.readOnly && (React__default.createElement(FloatingPortal, null,
            React__default.createElement(FloatingFocusManager, { context: context, modal: false, initialFocus: -1, closeOnFocusOut: true, returnFocus: false },
                React__default.createElement("div", Object.assign({}, getFloatingProps({
                    ref(node) {
                        if (node)
                            refs.setFloating(node);
                    },
                    id: listboxId,
                    role: "listbox",
                    className: menuClassName,
                    style: Object.assign(Object.assign(Object.assign(Object.assign({}, floatingStyles), transitionStyles), (_b = props.UNSAFE_styles) === null || _b === void 0 ? void 0 : _b.menu), (menuWidth
                        ? { width: menuWidth, maxWidth: menuWidth }
                        : {})),
                })),
                    React__default.createElement(PersistentRegion, { items: persistentsHeaders, position: "header", activeIndex: activeIndex, indexOffset: 0, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderHeader: props.customRenderHeader, customRenderFooter: props.customRenderFooter, onAction: onAction, className: classnames(styles$1.persistentHeader, (_c = props.UNSAFE_className) === null || _c === void 0 ? void 0 : _c.header), style: (_d = props.UNSAFE_styles) === null || _d === void 0 ? void 0 : _d.header }),
                    React__default.createElement("div", { className: styles$1.scrollRegion }, loading ? ((_e = props.customRenderLoading) !== null && _e !== void 0 ? _e : React__default.createElement(LoadingContent, null)) : (React__default.createElement(React__default.Fragment, null,
                        showEmptyStateMessage && (React__default.createElement(EmptyStateMessage, { emptyState: props.emptyStateMessage })),
                        renderable.length > 0 && (React__default.createElement(MenuList, { items: renderable, activeIndex: activeIndexForMiddle, indexOffset: headerInteractiveCount, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderOption: props.customRenderOption, customRenderSection: props.customRenderSection, customRenderAction: props.customRenderAction, getOptionLabel: getOptionLabel, onSelect: onSelection, onAction: onAction, isOptionSelected: isOptionSelected, slotOverrides: {
                                option: {
                                    className: (_f = props.UNSAFE_className) === null || _f === void 0 ? void 0 : _f.option,
                                    style: (_g = props.UNSAFE_styles) === null || _g === void 0 ? void 0 : _g.option,
                                },
                                action: {
                                    className: (_h = props.UNSAFE_className) === null || _h === void 0 ? void 0 : _h.action,
                                    style: (_j = props.UNSAFE_styles) === null || _j === void 0 ? void 0 : _j.action,
                                },
                                section: {
                                    className: (_k = props.UNSAFE_className) === null || _k === void 0 ? void 0 : _k.section,
                                    style: (_l = props.UNSAFE_styles) === null || _l === void 0 ? void 0 : _l.section,
                                },
                            } }))))),
                    React__default.createElement(PersistentRegion, { items: persistentsFooters, position: "footer", activeIndex: activeIndex, indexOffset: headerInteractiveCount + middleNavigableCount, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderHeader: props.customRenderHeader, customRenderFooter: props.customRenderFooter, onAction: onAction, className: classnames(styles$1.persistentFooter, (_m = props.UNSAFE_className) === null || _m === void 0 ? void 0 : _m.footer), style: (_o = props.UNSAFE_styles) === null || _o === void 0 ? void 0 : _o.footer })))))));
}
function LoadingContent() {
    return (React__default.createElement("div", { className: styles$1.loadingList },
        React__default.createElement(Glimmer, { shape: "rectangle", size: "base" }),
        React__default.createElement(Glimmer, { shape: "rectangle", size: "base" }),
        React__default.createElement(Glimmer, { shape: "rectangle", size: "base" })));
}
function EmptyStateMessage({ emptyState, }) {
    const emptyStateDefault = "No options";
    const emptyStateContent = emptyState !== null && emptyState !== void 0 ? emptyState : emptyStateDefault;
    return React__default.createElement("div", { className: styles$1.emptyStateMessage }, emptyStateContent);
}

var styles = {"autocomplete":"_7mObJiwfPh4-","options":"dL5JShAJlKM-","heading":"PWZL-94hH7k-","visible":"_2RzcnTdaPyc-","option":"y9zhi8Wr8QA-","active":"_3Xg49dtL1Q8-","separator":"LIeh390F3W8-","icon":"K2phy6IC3TY-","text":"a6-LbUm5WnY-","label":"tQNbuxcE9nU-","details":"qacStG9-XbE-","spinning":"P9cQDL4MZ-s-"};

const AUTOCOMPLETE_MAX_HEIGHT = 300;

function useRepositionMenu(attachTo, visible, cssManagedVisibility) {
    const { refs, floatingStyles, update } = useFloating(Object.assign({ placement: "bottom", middleware: [
            offset(8),
            flip({ fallbackPlacements: ["top"] }),
            size({
                apply({ availableHeight, elements }) {
                    const maxHeight = calculateMaxHeight(availableHeight, {
                        maxHeight: AUTOCOMPLETE_MAX_HEIGHT,
                    });
                    Object.assign(elements.floating.style, {
                        maxHeight: `${maxHeight}px`,
                    });
                },
            }),
        ], elements: {
            reference: attachTo,
        } }, (!cssManagedVisibility
        ? {
            whileElementsMounted: autoUpdate,
        }
        : {})));
    // While DefaultMenu leverages conditional rendering, CustomMenu is hidden with CSS
    // We need to apply the correct update method to each case
    useSafeLayoutEffect(() => {
        if (cssManagedVisibility && visible && attachTo && refs.floating.current) {
            const cleanup = autoUpdate(attachTo, refs.floating.current, update);
            return cleanup;
        }
        return undefined;
    }, [
        cssManagedVisibility,
        visible,
        attachTo,
        refs.floating.current,
        update,
        autoUpdate,
    ]);
    const targetWidth = attachTo === null || attachTo === void 0 ? void 0 : attachTo.clientWidth;
    return {
        menuRef: refs.floating.current,
        setMenuRef: refs.setFloating,
        targetWidth,
        styles: {
            float: floatingStyles,
        },
    };
}

function BaseAutocompleteMenuWrapperInternal({ setMenuRef, floatStyles, targetWidth, visible, children, }) {
    return (React__default.createElement("div", { className: classnames(styles.options, { [styles.visible]: visible }), ref: setMenuRef, style: Object.assign(Object.assign({}, floatStyles.float), { width: targetWidth }), "data-elevation": "elevated" }, children));
}
/**
 * Provides a wrapper for the Autocomplete menu that handles positioning and visibility.
 * @param attachTo - The element that the menu should be attached to.
 */
function useAutocompleteMenu({ attachTo, }) {
    const [menuRef, setMenuRef] = React__default.useState(null);
    const AutocompleteMenuWrapper = useCallback(({ children, visible, }) => {
        const menuFloatProps = useRepositionMenu(attachTo, visible, true);
        useEffect(() => {
            setMenuRef(menuFloatProps.menuRef);
        }, [menuFloatProps.menuRef]);
        return (React__default.createElement(BaseAutocompleteMenuWrapper, { floatStyles: menuFloatProps.styles, setMenuRef: menuFloatProps.setMenuRef, targetWidth: menuFloatProps.targetWidth, visible: visible }, children));
    }, [attachTo]);
    return { MenuWrapper: AutocompleteMenuWrapper, menuRef };
}
function BaseAutocompleteMenuWrapper(props) {
    const mounted = useIsMounted();
    const menu = React__default.createElement(BaseAutocompleteMenuWrapperInternal, Object.assign({}, props));
    return mounted.current ? React__default.createElement(FloatingPortal, null, menu) : menu;
}

function isOptionSelected(selectedOption, option) {
    return Boolean(selectedOption && selectedOption.value === option.value);
}
/**
 * Helper function to determine if the option is a group. This is used to
 * determine if the option contains a list of options for rendering Section
 * Labels in the Autocomplete component.
 */
function isOptionGroup(option) {
    return "options" in option;
}

/**
 * The rendering of the default MenuOption
 */
function MenuOption({ isHighlighted, option, onOptionSelect, isSelected, addSeparators, UNSAFE_className = {}, UNSAFE_style = {}, }) {
    if (isOptionGroup(option)) {
        return (React__default.createElement(MenuGroupOptions, { UNSAFE_className: UNSAFE_className.groupOption, option: option, UNSAFE_style: UNSAFE_style.groupOption }));
    }
    return (React__default.createElement(BaseMenuOption, { UNSAFE_className: UNSAFE_className.option, UNSAFE_style: UNSAFE_style.option, option: option, isHighlighted: isHighlighted, onOptionSelect: onOptionSelect, addSeparators: addSeparators },
        React__default.createElement(MenuOptionContent, { option: option, isSelected: isSelected, UNSAFE_className: UNSAFE_className.content, UNSAFE_style: UNSAFE_style.content })));
}
function MenuOptionContent({ option, isSelected, UNSAFE_className = {}, UNSAFE_style = {}, }) {
    const iconClassName = classnames(styles.icon, UNSAFE_className.icon);
    const textClassName = classnames(styles.text, UNSAFE_className.text);
    const labelClassName = classnames(styles.label, UNSAFE_className.label);
    const detailsClassName = classnames(styles.details, UNSAFE_className.details);
    return (React__default.createElement(React__default.Fragment, null,
        React__default.createElement("div", { className: iconClassName, style: UNSAFE_style.icon }, isSelected && React__default.createElement(Icon, { name: "checkmark", size: "small" })),
        React__default.createElement("div", { className: textClassName, style: UNSAFE_style.text },
            React__default.createElement("div", { className: labelClassName, style: UNSAFE_style.label },
                React__default.createElement(Text, null, option.label),
                option.description !== undefined && (React__default.createElement(Text, { variation: "subdued" }, option.description))),
            option.details !== undefined && (React__default.createElement("div", { className: detailsClassName, style: UNSAFE_style.details },
                React__default.createElement(Text, null, option.details))))));
}
/**
 * The rendering of the default MenuGroupOption
 */
function MenuGroupOptions({ option, UNSAFE_className = {}, UNSAFE_style = {}, }) {
    return (React__default.createElement(BaseMenuGroupOption, { UNSAFE_className: UNSAFE_className.heading, UNSAFE_style: UNSAFE_style.heading },
        React__default.createElement(Heading, { level: 5 }, option.label)));
}
function BaseMenuGroupOption({ children, UNSAFE_className = "", UNSAFE_style = {}, }) {
    const headingClassName = classnames(styles.heading, UNSAFE_className);
    return (React__default.createElement("div", { className: headingClassName, style: UNSAFE_style }, children));
}
/**
 * Renders the base option component. The component takes children and renders them inside a button.
 */
function BaseMenuOption({ option, isHighlighted, onOptionSelect, addSeparators, children, UNSAFE_className = "", UNSAFE_style = {}, }) {
    const optionClass = classnames(styles.option, {
        [styles.active]: isHighlighted,
        [styles.separator]: addSeparators,
    }, UNSAFE_className);
    return (React__default.createElement("button", { role: "option", type: "button", className: optionClass, onMouseDown: onOptionSelect === null || onOptionSelect === void 0 ? void 0 : onOptionSelect.bind(undefined, option), style: UNSAFE_style }, children));
}

var KeyboardAction;
(function (KeyboardAction) {
    KeyboardAction[KeyboardAction["Previous"] = -1] = "Previous";
    KeyboardAction[KeyboardAction["Next"] = 1] = "Next";
    KeyboardAction[KeyboardAction["Select"] = 0] = "Select";
})(KeyboardAction || (KeyboardAction = {}));
/**
 * Hook to handle custom keyboard navigation for the Autocomplete component.
 * Use this hook if you are using components in the menu that aren't MenuOption or BaseMenuOption.
 */
function useCustomKeyboardNavigation({ onRequestHighlightChange, }) {
    useOnKeyDown((event) => {
        onRequestHighlightChange === null || onRequestHighlightChange === void 0 ? void 0 : onRequestHighlightChange(event, KeyboardAction.Next);
    }, "ArrowDown");
    useOnKeyDown((event) => {
        onRequestHighlightChange === null || onRequestHighlightChange === void 0 ? void 0 : onRequestHighlightChange(event, KeyboardAction.Previous);
    }, "ArrowUp");
    useOnKeyDown((event) => {
        onRequestHighlightChange === null || onRequestHighlightChange === void 0 ? void 0 : onRequestHighlightChange(event, KeyboardAction.Select);
    }, "Enter");
}
/**
 * Hook to handle keyboard navigation for the Menu in the Autocomplete component.
 * If using components in the menu that aren't MenuOption or BaseMenuOption, you should use the `useCustomKeyboardNavigation` hook.
 */
function useKeyboardNavigation({ options, onOptionSelect, menuRef, visible, }) {
    const [highlightedIndex, setHighlightedIndex] = useState(0);
    const initialHighlight = options.some(isOptionGroup) ? 1 : 0;
    useEffect(() => setHighlightedIndex(initialHighlight), [options]);
    useEffect(() => {
        var _a, _b;
        (_b = (_a = menuRef === null || menuRef === void 0 ? void 0 : menuRef.children[highlightedIndex]) === null || _a === void 0 ? void 0 : _a.scrollIntoView) === null || _b === void 0 ? void 0 : _b.call(_a, {
            behavior: "smooth",
            block: "nearest",
            inline: "start",
        });
    }, [highlightedIndex]);
    const onRequestHighlightChange = useCallback((event, direction) => {
        if (!visible)
            return;
        const indexChange = getRequestedIndexChange({
            event,
            options,
            direction,
            highlightedIndex,
        });
        switch (direction) {
            case KeyboardAction.Previous:
                setHighlightedIndex(prev => Math.max(0, prev + indexChange));
                break;
            case KeyboardAction.Next:
                setHighlightedIndex(prev => Math.min(options.length - 1, prev + indexChange));
                break;
            case KeyboardAction.Select:
                if (isOptionGroup(options[highlightedIndex]))
                    return;
                onOptionSelect(options[highlightedIndex]);
                break;
        }
    }, [highlightedIndex, options, onOptionSelect, visible]);
    useCustomKeyboardNavigation({ onRequestHighlightChange });
    return { highlightedIndex };
}
/**
 * Function to get the requested index change based on the current highlighted index and the direction of the keyboard action.
 * Accounts for groups in the options array.
 */
function getRequestedIndexChange({ event, options, direction, highlightedIndex, }) {
    event.preventDefault();
    const requestedIndex = options[highlightedIndex + direction];
    return requestedIndex && isOptionGroup(requestedIndex)
        ? direction + direction
        : direction;
}

/**
 * Renders the default Menu for the Autocomplete component.
 */
function DefaultMenu({ options, selectedOption, onOptionSelect, attachTo, visible, }) {
    const { menuRef, setMenuRef, styles: floatStyles, targetWidth, } = useRepositionMenu(attachTo, visible, false);
    const detectSeparatorCondition = (option) => option.description || option.details;
    const addSeparators = options.some(detectSeparatorCondition);
    const { highlightedIndex } = useKeyboardNavigation({
        onOptionSelect,
        options,
        visible,
        menuRef,
    });
    return (React__default.createElement(BaseAutocompleteMenuWrapper, { setMenuRef, floatStyles, targetWidth, visible }, options === null || options === void 0 ? void 0 : options.map((option, index) => {
        return (React__default.createElement(MenuOption, { key: index, option: option, isHighlighted: index === highlightedIndex, onOptionSelect: onOptionSelect, isSelected: isOptionSelected(selectedOption, option), addSeparators: addSeparators }));
    })));
}

function Menu({ options, selectedOption, onOptionSelect, inputFocused, attachTo, inputRef, customRenderMenu, }) {
    if (customRenderMenu) {
        return (React__default.createElement(CustomMenu, { attachTo: attachTo, inputFocused: inputFocused, inputRef: inputRef, customRenderMenu: customRenderMenu, options: options, onOptionSelect: onOptionSelect, selectedOption: selectedOption }));
    }
    if (!inputFocused || !options.length)
        return null;
    return (React__default.createElement(DefaultMenu, { attachTo: attachTo, options: options, onOptionSelect: onOptionSelect, selectedOption: selectedOption, visible: inputFocused }));
}
/**
 * Renders the custom Menu for the Autocomplete component.
 * Provides the menuRef and MenuWrapper to the customRenderMenu function.
 */
function CustomMenu({ options, selectedOption, onOptionSelect, customRenderMenu, attachTo, inputFocused, inputRef, }) {
    const { MenuWrapper, menuRef } = useAutocompleteMenu({ attachTo });
    const menuContent = customRenderMenu({
        options,
        menuRef,
        onOptionSelect,
        selectedOption,
        inputFocused,
        MenuWrapper,
        inputRef,
    });
    return menuContent;
}

// Max statements increased to make room for the debounce functions
// eslint-disable-next-line max-statements
function AutocompleteInternal(_a, ref) {
    var _b;
    var { initialOptions = [], value, allowFreeForm = true, size = undefined, debounce: debounceRate = 300, onChange, getOptions, placeholder, onBlur, onFocus, validations, customRenderMenu } = _a, inputProps = __rest(_a, ["initialOptions", "value", "allowFreeForm", "size", "debounce", "onChange", "getOptions", "placeholder", "onBlur", "onFocus", "validations", "customRenderMenu"]);
    const initialOptionsMemo = useMemo(() => mapToOptions(initialOptions), [initialOptions]);
    const [options, setOptions] = useState(initialOptionsMemo);
    const [inputFocused, setInputFocused] = useState(false);
    const [inputText, setInputText] = useState((_b = value === null || value === void 0 ? void 0 : value.label) !== null && _b !== void 0 ? _b : "");
    const [autocompleteRef, setAutocompleteRef] = useState(null);
    const delayedSearch = useDebounce(updateSearch, debounceRate);
    const inputRef = useRef(null);
    useEffect(() => {
        delayedSearch();
    }, [inputText]);
    useEffect(() => {
        var _a;
        updateInput((_a = value === null || value === void 0 ? void 0 : value.label) !== null && _a !== void 0 ? _a : "");
    }, [value]);
    return (React__default.createElement("div", { className: styles.autocomplete, ref: setAutocompleteRef },
        React__default.createElement(InputText, Object.assign({ ref: mergeRefs([ref, inputRef]), autocomplete: false, size: size, value: inputText, onChange: handleInputChange, placeholder: placeholder, onFocus: handleInputFocus, onBlur: handleInputBlur, validations: validations }, inputProps)),
        React__default.createElement(Menu, { attachTo: autocompleteRef, inputRef: inputRef, inputFocused: inputFocused, options: options, customRenderMenu: customRenderMenu, selectedOption: value, onOptionSelect: handleMenuChange })));
    function updateInput(newText) {
        setInputText(newText);
        if (newText === "") {
            setOptions(mapToOptions(initialOptions));
        }
    }
    function updateSearch() {
        return __awaiter(this, void 0, void 0, function* () {
            const updatedOptions = yield getOptions(inputText);
            const filteredOptions = updatedOptions.filter(option => isOptionGroup(option) ? option.options.length > 0 : true);
            setOptions(mapToOptions(filteredOptions));
        });
    }
    function handleMenuChange(chosenOption) {
        var _a;
        onChange(chosenOption);
        updateInput((_a = chosenOption === null || chosenOption === void 0 ? void 0 : chosenOption.label) !== null && _a !== void 0 ? _a : "");
        setInputFocused(false);
    }
    function handleInputChange(newText) {
        updateInput(newText);
        if (allowFreeForm) {
            onChange({ label: newText });
        }
    }
    function handleInputBlur() {
        setInputFocused(false);
        if (value == undefined || value.label !== inputText) {
            setInputText("");
            onChange(undefined);
        }
        onBlur && onBlur();
    }
    function handleInputFocus() {
        setInputFocused(true);
        if (onFocus) {
            onFocus();
        }
    }
}
function mapToOptions(items) {
    const retVal = items.reduce((result, item) => {
        result.push(item);
        if (isOptionGroup(item) && item.options) {
            result = result.concat(item.options);
        }
        return result;
    }, []);
    return retVal;
}
// Casts the Generics to the forward ref so autocomplete works as expected for consumers
const Autocomplete$1 = forwardRef(AutocompleteInternal);

// Convenience builder helpers (optional usage)
// Helper to improve inference from inline menu literals
function defineMenu(menu) {
    return menu;
}

function isNewAutocompleteProps(props) {
    return props.version === 2;
}
function AutocompleteShim(props, ref) {
    if (isNewAutocompleteProps(props)) {
        return (React__default.createElement(AutocompleteRebuilt, Object.assign({}, props, { ref: ref })));
    }
    return React__default.createElement(Autocomplete$1, Object.assign({}, props, { ref: ref }));
}
const AutocompleteForwarded = forwardRef(AutocompleteShim);
AutocompleteForwarded.displayName = "Autocomplete";
const Autocomplete = AutocompleteForwarded;

export { Autocomplete, BaseAutocompleteMenuWrapper, BaseMenuGroupOption, BaseMenuOption, KeyboardAction, MenuOption, defineMenu, getRequestedIndexChange, isOptionGroup, isOptionSelected, useAutocompleteMenu, useCustomKeyboardNavigation, useKeyboardNavigation, useRepositionMenu };
