'use strict';

var React = require('react');
var floatingUi_react = require('./floating-ui.react-cjs.js');
var classnames = require('classnames');
var design = require('@jobber/design');
var jobberHooks = require('@jobber/hooks');
var maxHeight = require('./maxHeight-cjs.js');
var floatingUi_reactDom = require('./floating-ui.react-dom-cjs.js');
var Heading = require('./Heading-cjs.js');
var Text = require('./Text-cjs.js');
var Typography = require('./Typography-cjs.js');
var Icon = require('./Icon-cjs.js');
var Glimmer = require('./Glimmer-cjs.js');
var InputText = require('./InputText-cjs.js');
var FormFieldWrapper = require('./FormFieldWrapper-cjs.js');
require('./Button-cjs.js');
var mergeRefs = require('./mergeRefs-cjs.js');
var filterDataAttributes = require('./filterDataAttributes-cjs.js');

/** Stable empty array for cleared/empty selection state. Reuse to avoid reference churn. */
const EMPTY_SELECTED_VALUES = [];

var styles = {"list":"w5g7qggGrr4-","loadingList":"ELlB2Kio7q8-","option":"y9zhi8Wr8QA-","defaultOptionContent":"adJv-3bhYOQ-","icon":"K2phy6IC3TY-","optionActive":"p2CY3TGCdRc-","actionActive":"-tyLeCnCEUI-","action":"dXIHuZjqX84-","section":"gQ86NtBHt-Y-","emptyStateMessage":"uElGEScjH68-","stickyTop":"nXvoRgKgoz8-","scrollRegion":"Ey1zL5E-c74-","persistentHeader":"ei36u5racbA-","persistentFooter":"IDIz9ZHykRw-","textPersistent":"Wx--khA61eA-","multiSelectField":"COW3V1gDtwI-","chipArea":"_1iRpnGn3PaA-","inlineInput":"bHaScorkEaQ-","selectionChip":"sFMc1SJPOSM-","selectionChipActive":"_9Ljs17OW-QM-","selectionChipDisabled":"QYUKkbmNjLE-","chipDismiss":"Wv6D8g2MKPo-","limitText":"UAegmMck3-U-","spinning":"P9cQDL4MZ-s-"};

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 = design.tokens["space-small"];
const AUTOCOMPLETE_MAX_HEIGHT = 300;
function useStableSetReference(refs) {
    const latestRefs = React.useRef(refs);
    latestRefs.current = refs;
    return React.useCallback((el) => latestRefs.current.setReference(el), []);
}
function useAutocompleteListNav({ navigableCount, shouldResetActiveIndexOnClose, onMenuOpen, onMenuClose, selectedIndex, readOnly = false, disabled = false, outsidePressExcludeSelector, }) {
    const [open, setOpen] = React.useState(false);
    const [activeIndex, setActiveIndex] = React.useState(null);
    const listRef = React.useRef([]);
    const { refs, floatingStyles, context } = floatingUi_react.useFloating({
        placement: "bottom",
        whileElementsMounted: floatingUi_reactDom.autoUpdate,
        open,
        onOpenChange: (isOpen, _event, reason) => {
            setOpen(isOpen);
            if (isOpen) {
                onMenuOpen === null || onMenuOpen === void 0 ? void 0 : onMenuOpen();
            }
            else {
                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: [
            floatingUi_reactDom.offset(MENU_OFFSET),
            floatingUi_reactDom.flip({ fallbackPlacements: ["top"] }),
            floatingUi_reactDom.size({
                apply({ availableHeight, rects, elements }) {
                    const maxHeight$1 = maxHeight.calculateMaxHeight(availableHeight, {
                        maxHeight: AUTOCOMPLETE_MAX_HEIGHT,
                    });
                    Object.assign(elements.floating.style, {
                        maxHeight: `${maxHeight$1}px`,
                        width: `${rects.reference.width}px`,
                    });
                },
            }),
        ],
    });
    const enabled = !readOnly && !disabled;
    const click = floatingUi_react.useClick(context, {
        enabled,
        toggle: false, // Only open, never close on click
    });
    const listNav = floatingUi_react.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 = floatingUi_react.useDismiss(context, {
        outsidePress: outsidePressExcludeSelector
            ? (event) => {
                var _a, _b, _c, _d;
                const target = event.target;
                const insideRef = (_b = (_a = context.elements.domReference) === null || _a === void 0 ? void 0 : _a.contains(target)) !== null && _b !== void 0 ? _b : false;
                const insideFloating = (_d = (_c = context.elements.floating) === null || _c === void 0 ? void 0 : _c.contains(target)) !== null && _d !== void 0 ? _d : false;
                const insideExclude = event.target.closest(outsidePressExcludeSelector);
                return !(insideRef || insideFloating || insideExclude);
            }
            : true,
        escapeKey: true,
        outsidePressEvent: "click",
    });
    const { getReferenceProps, getFloatingProps, getItemProps } = floatingUi_react.useInteractions([click, listNav, dismiss]);
    React.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]);
    const setReferenceElement = useStableSetReference(refs);
    return {
        refs,
        floatingStyles,
        context,
        getReferenceProps,
        getFloatingProps,
        getItemProps,
        activeIndex,
        setActiveIndex,
        listRef,
        open,
        setOpen,
        setReferenceElement,
    };
}

/**
 * Handler that prevents default pointer behavior.
 * Used to prevent blur/focus issues when clicking on non-interactive menu elements.
 */
function preventDefaultPointerDown(e) {
    e.preventDefault();
}
/**
 * Creates a handler for pointer down events on interactive menu items (options/actions).
 * Prevents default to avoid blur and sets flag for focus management.
 *
 * @param isHandlingMenuInteractionRef - Ref to track if a menu interaction is in progress
 * @returns A pointer down event handler
 */
function createInteractionPointerDownHandler(isHandlingMenuInteractionRef) {
    return (e) => {
        e.preventDefault();
        // Set flag to prevent blur/focus handlers from interfering
        isHandlingMenuInteractionRef.current = true;
    };
}

// Keeping this hook cohesive improves readability by centralizing related
// interactions and state transitions.
// eslint-disable-next-line max-statements
function useAutocomplete(props, inputRef) {
    const { menu, emptyActions, getOptionLabel: getOptionLabelProp, isOptionEqualToValue, inputValue, onInputChange, value, onChange, multiple, openOnFocus = true, readOnly = false, disabled = false, debounce: debounceMs = 300, } = props;
    const isHandlingMenuInteractionRef = React.useRef(false);
    // TODO: Clean up the types in these refs by enhancing the type system in useCallbackRef
    const getOptionLabelPropRef = jobberHooks.useCallbackRef((opt) => getOptionLabelProp === null || getOptionLabelProp === void 0 ? void 0 : getOptionLabelProp(opt));
    const getOptionLabel = React.useCallback((opt) => {
        const maybe = getOptionLabelPropRef(opt);
        return maybe !== null && maybe !== void 0 ? maybe : opt.label;
    }, [getOptionLabelPropRef]);
    const isOptionEqualToValueRef = jobberHooks.useCallbackRef((a, b) => isOptionEqualToValue === null || isOptionEqualToValue === void 0 ? void 0 : isOptionEqualToValue(a, b));
    const equals = React.useCallback((a, b) => {
        const custom = isOptionEqualToValueRef(a, b);
        return custom != null ? custom : getOptionLabel(a) === getOptionLabel(b);
    }, [isOptionEqualToValueRef, getOptionLabel]);
    const isOptionSelected = React.useCallback((opt) => {
        var _a;
        if (multiple) {
            const current = (_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES;
            return current.some(v => equals(v, opt));
        }
        const current = value;
        return current != null ? equals(current, opt) : false;
    }, [multiple, value, equals]);
    const flatInitial = React.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 = jobberHooks.useCallbackRef((text, o) => {
        const fn = props.inputEqualsOption;
        return fn ? fn(text, o) : undefined;
    });
    const inputEquals = React.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 = React.useMemo(() => {
        return optionItems.some(o => inputEquals(inputValue, o));
    }, [optionItems, inputEquals, inputValue]);
    const lastInputWasUser = React.useRef(false);
    const [debouncedInputValue, setDebouncedInputValue] = React.useState(inputValue);
    const debouncedSetter = jobberHooks.useDebounce(setDebouncedInputValue, debounceMs);
    React.useEffect(() => {
        // Skip debounce when clearing input for immediate feedback, preventing flickering of last selected item
        if (debounceMs === 0 || inputValue === "") {
            setDebouncedInputValue(inputValue);
            // Cancel any pending debounced call so a stale intermediate value
            // (e.g. "P" while deleting "Pipe…") doesn't overwrite the immediate set.
            debouncedSetter.cancel();
            return;
        }
        debouncedSetter(inputValue);
    }, [inputValue, debounceMs, debouncedSetter]);
    const filterOptionsRef = jobberHooks.useCallbackRef((opts, term) => {
        const fn = (typeof props.filterOptions === "function"
            ? props.filterOptions
            : undefined) || undefined;
        return fn ? fn(opts, term) : undefined;
    });
    const applyFilter = React.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 = React.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 = React.useMemo(() => {
        var _a;
        if (multiple) {
            const current = (_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES;
            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).
    // In multiple mode this is always null — there is no single "selected" index, and
    // floating-ui would otherwise jump the highlight whenever the value array changes.
    const selectedIndex = React.useMemo(() => {
        if (multiple)
            return null;
        const selectedValue = 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,
        readOnly,
        disabled,
        outsidePressExcludeSelector: multiple
            ? "[data-testid='ATL-Autocomplete-chipArea']"
            : undefined,
        onMenuOpen: () => {
            if (multiple)
                return;
            const selectedValue = value;
            if (selectedValue) {
                const selectedNavigableIndex = findNavigableIndexForValue(renderable, equals, selectedValue);
                if (selectedNavigableIndex != null) {
                    setActiveIndex(selectedNavigableIndex);
                    return;
                }
            }
            setActiveIndex(null);
        },
        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 prevOpenRef = React.useRef(false);
    // TODO: Leverage FloatingUI useFocus, and onArrowKeyDown to manage open state and allow onOpenChange to be the source of truth
    // JOB-154442
    React.useEffect(() => {
        var _a, _b;
        if (open && !prevOpenRef.current) {
            (_a = props.onOpen) === null || _a === void 0 ? void 0 : _a.call(props);
        }
        else if (!open && prevOpenRef.current) {
            (_b = props.onClose) === null || _b === void 0 ? void 0 : _b.call(props);
        }
        prevOpenRef.current = open;
    }, [open, props.onOpen, props.onClose]);
    function selectOption(option) {
        var _a;
        if (multiple) {
            const current = (_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES;
            const exists = current.some(v => equals(v, option));
            const next = exists
                ? current.filter(v => !equals(v, option))
                : [...current, option];
            onChange((next.length === 0 ? EMPTY_SELECTED_VALUES : next));
            lastInputWasUser.current = false;
            onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange("");
        }
        else {
            onChange(option);
            lastInputWasUser.current = false;
            onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(getOptionLabel(option));
        }
    }
    function reHighlightSelectedItem() {
        const selectedValue = value;
        if (!selectedValue)
            return;
        const idx = findNavigableIndexForValue(renderable, equals, selectedValue);
        if (idx != null)
            setActiveIndex(idx);
    }
    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;
    }
    const onSelection = React.useCallback((option) => {
        var _a;
        selectOption(option);
        if (!multiple) {
            setOpen(false);
        }
        (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
    }, [selectOption, setOpen, multiple, inputRef]);
    const onAction = React.useCallback((action) => {
        var _a;
        action.run();
        setActiveIndex(null);
        if (action.closeOnRun !== false)
            setOpen(false);
        (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
    }, [setOpen, setActiveIndex, inputRef]);
    /**
     * Handler for mousedown on interactive menu items (options/actions)
     * Prevents default to avoid blur and sets flag for focus management
     */
    const onInteractionPointerDown = React.useMemo(() => createInteractionPointerDownHandler(isHandlingMenuInteractionRef), []);
    function applyFreeFormValue(freeFormCreated) {
        var _a;
        const nextValue = multiple
            ? [...((_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES), freeFormCreated]
            : freeFormCreated;
        props.onChange(nextValue);
        if (multiple) {
            lastInputWasUser.current = false;
            onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange("");
        }
    }
    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;
        applyFreeFormValue(freeFormCreated);
        return true;
    }
    const tryRestoreInputToSelectedLabel = React.useCallback(() => {
        if (props.allowFreeForm === true)
            return;
        if (multiple) {
            if (inputValue.trim().length > 0) {
                lastInputWasUser.current = false;
                onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange("");
            }
            return;
        }
        const selectedValue = 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 = React.useCallback((event) => {
        var _a;
        if (!readOnly && openOnFocus && !isHandlingMenuInteractionRef.current) {
            setOpen(true);
        }
        // Only call user's onFocus for genuine focus events, not programmatic restorations
        if (!isHandlingMenuInteractionRef.current) {
            (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, event);
        }
        isHandlingMenuInteractionRef.current = false;
    }, [props.onFocus, readOnly, openOnFocus, setOpen]);
    const onInputBlur = React.useCallback((event) => {
        var _a, _b;
        if (isHandlingMenuInteractionRef.current) {
            return;
        }
        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 removeLastSelection = React.useCallback(() => {
        var _a;
        if (!multiple || readOnly)
            return;
        const current = (_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES;
        if (current.length > 0) {
            const next = current.slice(0, -1);
            onChange((next.length === 0 ? EMPTY_SELECTED_VALUES : next));
        }
    }, [multiple, readOnly, value, onChange]);
    const removeSelection = React.useCallback((option) => {
        var _a;
        if (readOnly)
            return;
        if (multiple) {
            const current = (_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES;
            const next = current.filter(v => !equals(v, option));
            onChange((next.length === 0
                ? EMPTY_SELECTED_VALUES
                : next));
        }
        else {
            const current = value;
            if (current && equals(current, option)) {
                onChange(undefined);
            }
        }
    }, [readOnly, multiple, value, equals, onChange]);
    const onInputKeyDown = React.useCallback((event) => {
        const key = event.key;
        if (key === "Backspace" && multiple && inputValue === "") {
            removeLastSelection();
            return;
        }
        if (key !== "ArrowDown" && key !== "ArrowUp" && key !== "Enter")
            return;
        if (key === "ArrowDown" || key === "ArrowUp") {
            handleArrowNavigation(key, event);
            return;
        }
        handleEnterKey(event);
    }, [open, onSelection, onAction, multiple, inputValue, removeLastSelection]);
    const onInputChangeFromUser = React.useCallback((val) => {
        lastInputWasUser.current = true;
        const isEmpty = val.trim().length === 0;
        if (isEmpty) {
            setActiveIndex(null);
            if (!multiple && hasSelection) {
                onChange === null || onChange === void 0 ? void 0 : onChange(undefined);
            }
        }
        else if (val.length > inputValue.length) {
            setActiveIndex(null);
        }
        else if (val.length < inputValue.length &&
            !multiple &&
            open &&
            hasSelection) {
            reHighlightSelectedItem();
        }
        if (!readOnly) {
            setOpen((!isEmpty && !props.allowFreeForm) || openOnFocus);
        }
        onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(val);
    }, [
        onInputChange,
        inputValue,
        setActiveIndex,
        readOnly,
        props.allowFreeForm,
        openOnFocus,
        setOpen,
        multiple,
        hasSelection,
        onChange,
        open,
    ]);
    const clearAll = React.useCallback(() => {
        if (multiple) {
            onChange(EMPTY_SELECTED_VALUES);
        }
        else {
            onChange(undefined);
        }
        onInputChangeFromUser("");
    }, [multiple, onChange, onInputChangeFromUser]);
    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,
        onInteractionPointerDown,
        removeSelection,
        clearAll,
        // input handlers
        onInputChangeFromUser,
        onInputBlur,
        onInputFocus,
        onInputKeyDown,
        // ref attachment
        setReferenceElement,
    };
}

function useChipNavigation({ selectedValues, inputValue, readOnly, removeSelection, onInputKeyDown, onInputBlur, }) {
    const [rawActiveChipIndex, setRawActiveChipIndex] = React.useState(null);
    const [previousInputValue, setPreviousInputValue] = React.useState(inputValue);
    const activeChipIndex = clampActiveIndex(rawActiveChipIndex, selectedValues.length);
    if (previousInputValue !== inputValue) {
        setPreviousInputValue(inputValue);
        if (inputValue !== "" && rawActiveChipIndex !== null) {
            setRawActiveChipIndex(null);
        }
    }
    const handleActiveChipKey = React.useCallback(
    // eslint-disable-next-line max-statements
    (event) => {
        if (activeChipIndex === null)
            return false;
        const { key } = event;
        if (key === "ArrowLeft") {
            event.preventDefault();
            setRawActiveChipIndex(i => Math.max(0, (i !== null && i !== void 0 ? i : 0) - 1));
            return true;
        }
        if (key === "ArrowRight") {
            event.preventDefault();
            setRawActiveChipIndex(activeChipIndex + 1 >= selectedValues.length
                ? null
                : activeChipIndex + 1);
            return true;
        }
        if (key === "Backspace" || key === "Delete") {
            event.preventDefault();
            const option = selectedValues[activeChipIndex];
            const newLen = selectedValues.length - 1;
            if (newLen === 0) {
                setRawActiveChipIndex(null);
            }
            else if (activeChipIndex >= newLen) {
                setRawActiveChipIndex(newLen - 1);
            }
            removeSelection(option);
            return true;
        }
        if (key === "Escape") {
            setRawActiveChipIndex(null);
            return true;
        }
        setRawActiveChipIndex(null);
        return false;
    }, [activeChipIndex, selectedValues, removeSelection]);
    const onKeyDown = React.useCallback((event) => {
        if (handleActiveChipKey(event))
            return;
        if (event.key === "ArrowLeft" &&
            !readOnly &&
            inputValue === "" &&
            selectedValues.length > 0) {
            event.preventDefault();
            setRawActiveChipIndex(selectedValues.length - 1);
            return;
        }
        onInputKeyDown(event);
    }, [handleActiveChipKey, selectedValues, inputValue, readOnly, onInputKeyDown]);
    const onBlur = React.useCallback((event) => {
        setRawActiveChipIndex(null);
        onInputBlur(event);
    }, [onInputBlur]);
    return { activeChipIndex, onKeyDown, onBlur };
}
function clampActiveIndex(index, length) {
    if (index === null)
        return null;
    if (length === 0)
        return null;
    if (index >= length)
        return length - 1;
    return index;
}

function MenuList({ items, activeIndex, indexOffset = 0, getItemProps, listRef, listboxId, customRenderOption, customRenderSection, customRenderAction, getOptionLabel, onSelect, onAction, onInteractionPointerDown, 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,
                onInteractionPointerDown,
                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,
            onInteractionPointerDown,
            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.createElement(React.Fragment, null, items.map(renderItemNode));
}
function handleSectionRendering({ customRenderSection, section, sectionClassName, sectionStyle, }) {
    var _a;
    const headerContent = customRenderSection ? (customRenderSection(section)) : (React.createElement(DefaultSectionContent, { section: section }));
    return (React.createElement("div", { key: `section-${String((_a = section.key) !== null && _a !== void 0 ? _a : section.label)}`, role: "presentation", tabIndex: -1, "data-testid": "ATL-Autocomplete-Section", className: classnames(styles.section, styles.stickyTop, sectionClassName), style: sectionStyle, onPointerDown: preventDefaultPointerDown }, headerContent));
}
function DefaultSectionContent({ section, }) {
    return React.createElement(Heading.Heading, { level: 5 }, section.label);
}
function handleOptionRendering({ option, activeIndex, navigableIndex, getItemProps, listRef, listboxId, isOptionSelected, customRenderOption, getOptionLabel, onSelect, onInteractionPointerDown, 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.createElement(DefaultOptionContent, { isSelected: isSelected, text: getOptionLabel(option) }));
    return {
        node: (React.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),
            onPointerDown: onInteractionPointerDown,
            className: classnames(styles.option, isActive && styles.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.createElement("div", { className: styles.defaultOptionContent },
        React.createElement("div", { className: styles.icon, style: isSelected ? undefined : { visibility: "hidden" } },
            React.createElement(Icon.Icon, { name: "checkmark", size: "small" })),
        React.createElement(Text.Text, null, text)));
}
function handleActionRendering({ action, activeIndex, navigableIndex, getItemProps, listRef, listboxId, customRenderAction, onAction, onInteractionPointerDown, indexOffset = 0, actionClassName, actionStyle, origin, }) {
    var _a;
    const nextNavigableIndex = navigableIndex + 1;
    const isActive = activeIndex === nextNavigableIndex;
    const actionContent = customRenderAction ? (customRenderAction({ value: action, isActive, origin })) : (React.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,
            });
        },
        onPointerDown: onInteractionPointerDown,
        className: classnames(styles.action, isActive && styles.actionActive, actionClassName),
        style: actionStyle,
    });
    return {
        node: (React.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-Autocomplete-Action", id: `${listboxId}-item-${computedIndex}`, "data-index": computedIndex, "data-origin": origin, "data-active": isActive ? true : undefined }), actionContent)),
        nextNavigableIndex,
    };
}
function DefaultActionContent({ textContent, }) {
    return (React.createElement(Typography.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, onInteractionPointerDown, }) {
    if (!items || items.length === 0)
        return null;
    let navigableIndex = -1;
    return (React.createElement("div", { className: className, style: style, "data-region": position, "data-testid": `ATL-Autocomplete-${position}` }, items.map(persistent => {
        const result = handlePersistentRendering({
            persistent,
            position,
            activeIndex,
            indexOffset,
            getItemProps,
            customRenderHeader,
            customRenderFooter,
            listRef,
            onAction,
            onInteractionPointerDown,
            navigableIndex,
        });
        navigableIndex = result.nextNavigableIndex;
        return result.node;
    })));
}
function handlePersistentRendering({ persistent, position, activeIndex, indexOffset, getItemProps, customRenderHeader, customRenderFooter, listRef, onAction, onInteractionPointerDown, 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,
        onInteractionPointerDown,
        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.createElement(DefaultTextPersistentContent, { persistent: persistent });
    }
    return (React.createElement("div", { key: `persistent-${position}-${String((_a = persistent.key) !== null && _a !== void 0 ? _a : persistent.label)}`, role: "presentation", tabIndex: -1, className: styles.textPersistent, onPointerDown: preventDefaultPointerDown }, content));
}
function handleActionPersistentRendering({ persistent, position, activeIndex, indexOffset, getItemProps, customRenderHeader, customRenderFooter, listRef, onAction, onInteractionPointerDown, 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.createElement(DefaultActionContent, { textContent: persistent.label });
    }
    return {
        node: (React.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,
                });
            },
            onPointerDown: onInteractionPointerDown,
            className: classnames(styles.action, isActive && styles.actionActive),
        }), { role: "button", tabIndex: -1 }), content)),
        nextNavigableIndex,
    };
}
function DefaultTextPersistentContent({ persistent, }) {
    return React.createElement("div", { className: styles.textPersistent }, persistent.label);
}

function FloatingMenu({ context, getFloatingProps, refs, listboxId, className, floatingStyles, transitionStyles, menuStyle, renderable, persistentsHeaders, persistentsFooters, activeIndex, headerInteractiveCount, middleNavigableCount, getItemProps, listRef, onSelection, onAction, onInteractionPointerDown, getOptionLabel, isOptionSelected, loading, showEmptyStateMessage, emptyStateMessage, customRenderLoading, customRenderOption, customRenderSection, customRenderAction, customRenderHeader, customRenderFooter, slotOverrides, }) {
    var _a, _b, _c, _d;
    const activeIndexForMiddle = activeIndex != null ? activeIndex - headerInteractiveCount : null;
    return (React.createElement(floatingUi_react.FloatingPortal, null,
        React.createElement(floatingUi_react.FloatingFocusManager, { context: context, modal: false, initialFocus: -1, closeOnFocusOut: true, returnFocus: false },
            React.createElement("div", Object.assign({}, getFloatingProps({
                ref(node) {
                    if (node)
                        refs.setFloating(node);
                },
                id: listboxId,
                role: "listbox",
                className,
                style: Object.assign(Object.assign(Object.assign({}, floatingStyles), transitionStyles), menuStyle),
            })),
                React.createElement(PersistentRegion, { items: persistentsHeaders, position: "header", activeIndex: activeIndex, indexOffset: 0, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderHeader: customRenderHeader, customRenderFooter: customRenderFooter, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, className: classnames(styles.persistentHeader, (_a = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.header) === null || _a === void 0 ? void 0 : _a.className), style: (_b = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.header) === null || _b === void 0 ? void 0 : _b.style }),
                React.createElement("div", { className: styles.scrollRegion }, loading ? (customRenderLoading !== null && customRenderLoading !== void 0 ? customRenderLoading : React.createElement(LoadingContent, null)) : (React.createElement(React.Fragment, null,
                    showEmptyStateMessage && (React.createElement(EmptyStateMessage, { emptyState: emptyStateMessage })),
                    renderable.length > 0 && (React.createElement(MenuList, { items: renderable, activeIndex: activeIndexForMiddle, indexOffset: headerInteractiveCount, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderOption: customRenderOption, customRenderSection: customRenderSection, customRenderAction: customRenderAction, getOptionLabel: getOptionLabel, onSelect: onSelection, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, isOptionSelected: isOptionSelected, slotOverrides: slotOverrides }))))),
                React.createElement(PersistentRegion, { items: persistentsFooters, position: "footer", activeIndex: activeIndex, indexOffset: headerInteractiveCount + middleNavigableCount, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderHeader: customRenderHeader, customRenderFooter: customRenderFooter, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, className: classnames(styles.persistentFooter, (_c = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.footer) === null || _c === void 0 ? void 0 : _c.className), style: (_d = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.footer) === null || _d === void 0 ? void 0 : _d.style })))));
}
function LoadingContent() {
    return (React.createElement("div", { className: styles.loadingList, onPointerDown: preventDefaultPointerDown },
        React.createElement(Glimmer.Glimmer, { shape: "rectangle", size: "base" }),
        React.createElement(Glimmer.Glimmer, { shape: "rectangle", size: "base" }),
        React.createElement(Glimmer.Glimmer, { shape: "rectangle", size: "base" })));
}
function EmptyStateMessage({ emptyState, }) {
    const emptyStateDefault = "No options";
    const emptyStateContent = emptyState !== null && emptyState !== void 0 ? emptyState : emptyStateDefault;
    return (React.createElement("div", { className: styles.emptyStateMessage, onPointerDown: preventDefaultPointerDown }, emptyStateContent));
}

const Autocomplete = React.forwardRef(AutocompleteInternal);
// eslint-disable-next-line max-statements
function AutocompleteInternal(props, forwardedRef) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
    const { inputValue, placeholder, disabled, error, invalid, description, size: sizeProp, loading = false, } = props;
    const formFieldRef = React.useRef(null);
    // Ref for the multi-select input element, where we cannot use refs.domReference
    // since it is not attached to the literal input element, whereas single + InputText only offers a
    // ref to the literal input element.
    const internalInputRef = React.useRef(null);
    const { renderable, optionCount, persistentsHeaders, persistentsFooters, headerInteractiveCount, middleNavigableCount, getOptionLabel, isOptionSelected, refs, floatingStyles, context, getReferenceProps, getFloatingProps, getItemProps, activeIndex, open, listRef, onSelection, onAction, onInteractionPointerDown, removeSelection, onInputChangeFromUser, onInputBlur, onInputFocus, onInputKeyDown, setReferenceElement, clearAll, } = useAutocomplete(props, internalInputRef);
    const listboxId = React.useId();
    // Provides mount/unmount-aware transition styles for the floating element
    const { isMounted, styles: transitionStyles } = floatingUi_react.useTransitionStyles(context, {
        initial: { opacity: 0 },
        open: { opacity: 1 },
        close: { opacity: 0 },
        duration: { open: design.tokens["timing-base"], close: design.tokens["timing-base"] },
    });
    const [positionRefEl, setPositionRefEl] = React.useState(null);
    const inputId = React.useId();
    const descriptionId = `descriptionUUID--${inputId}`;
    const selectedValues = props.multiple
        ? ((_a = props.value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES)
        : EMPTY_SELECTED_VALUES;
    const { activeChipIndex, onKeyDown: chipKeyDown, onBlur: chipBlur, } = useChipNavigation({
        selectedValues,
        inputValue,
        readOnly: props.readOnly,
        removeSelection,
        onInputKeyDown,
        onInputBlur,
    });
    const focusInputOnPointerDown = React.useCallback((e) => {
        var _a;
        const target = e.target;
        if (target.closest("input, button"))
            return;
        e.preventDefault();
        (_a = internalInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
    }, []);
    const composedReferenceProps = getReferenceProps(Object.assign({ onKeyDown: props.multiple ? chipKeyDown : onInputKeyDown, onFocus: onInputFocus, onBlur: props.multiple ? chipBlur : onInputBlur }, (props.multiple ? { onPointerDown: focusInputOnPointerDown } : {})));
    const dataAttrs = filterDataAttributes.filterDataAttributes(props);
    const ariaProps = {
        role: "combobox",
        "aria-autocomplete": "list",
        "aria-expanded": open ? true : false,
        "aria-controls": listboxId,
        "aria-activedescendant": activeChipIndex === null && open && activeIndex != null
            ? `${listboxId}-item-${activeIndex}`
            : undefined,
    };
    const inputProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ 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, clearable: props.clearable, autoComplete: "off", autoFocus: props.autoFocus, description, size: sizeProp ? sizeProp : undefined, prefix: props.prefix, suffix: props.suffix }), (props.readOnly ? {} : composedReferenceProps)), ariaProps), dataAttrs);
    const chipAreaRef = React.useCallback((node) => {
        if (!node)
            return;
        // In multiple mode, we use the input as the reference so floating-ui's
        // useListNavigation treats it as a typeable combobox and allows Space.
        // Only use chipArea for positioning/sizing.
        if (!props.multiple) {
            setReferenceElement(node);
        }
        const multiContainer = node.closest("[data-testid='ATL-Autocomplete-multiSelectContainer']");
        if (multiContainer) {
            setPositionRefEl(multiContainer);
        }
    }, [setReferenceElement, props.multiple]);
    const referenceInputRef = React.useCallback((node) => {
        setReferenceElement(node);
        if (!props.multiple) {
            // Workaround to get the visual InputText element, which is not the same
            // as the literal input reference element when props like suffix/prefix
            // are present. Used to set the position reference for the floating menu.
            const visualInputTextElement = node === null || node === void 0 ? void 0 : node.closest("[data-testid='Form-Field-Wrapper']");
            if (visualInputTextElement) {
                setPositionRefEl(visualInputTextElement);
            }
        }
    }, [setReferenceElement, props.multiple]);
    const mergedInputRef = React.useMemo(() => mergeRefs.mergeRefs([
        referenceInputRef,
        internalInputRef,
        forwardedRef,
    ]), [referenceInputRef, forwardedRef]);
    React.useEffect(() => {
        if (!positionRefEl)
            return;
        refs.setPositionReference(positionRefEl);
    }, [positionRefEl, refs]);
    const menuClassName = classnames(styles.list, (_b = props.UNSAFE_className) === null || _b === void 0 ? void 0 : _b.menu);
    const showEmptyStateMessage = optionCount === 0 && props.emptyStateMessage !== false;
    const floatingMenu = isMounted && !props.readOnly && !disabled && (React.createElement(FloatingMenu, { context: context, getFloatingProps: getFloatingProps, refs: refs, listboxId: listboxId, className: menuClassName, floatingStyles: floatingStyles, transitionStyles: transitionStyles, menuStyle: (_c = props.UNSAFE_styles) === null || _c === void 0 ? void 0 : _c.menu, renderable: renderable, persistentsHeaders: persistentsHeaders, persistentsFooters: persistentsFooters, activeIndex: activeIndex, headerInteractiveCount: headerInteractiveCount, middleNavigableCount: middleNavigableCount, getItemProps: getItemProps, listRef: listRef, onSelection: onSelection, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, getOptionLabel: getOptionLabel, isOptionSelected: isOptionSelected, loading: loading, showEmptyStateMessage: showEmptyStateMessage, emptyStateMessage: props.emptyStateMessage, customRenderLoading: props.customRenderLoading, customRenderOption: props.customRenderOption, customRenderSection: props.customRenderSection, customRenderAction: props.customRenderAction, customRenderHeader: props.customRenderHeader, customRenderFooter: props.customRenderFooter, slotOverrides: {
            option: {
                className: (_d = props.UNSAFE_className) === null || _d === void 0 ? void 0 : _d.option,
                style: (_e = props.UNSAFE_styles) === null || _e === void 0 ? void 0 : _e.option,
            },
            action: {
                className: (_f = props.UNSAFE_className) === null || _f === void 0 ? void 0 : _f.action,
                style: (_g = props.UNSAFE_styles) === null || _g === void 0 ? void 0 : _g.action,
            },
            section: {
                className: (_h = props.UNSAFE_className) === null || _h === void 0 ? void 0 : _h.section,
                style: (_j = props.UNSAFE_styles) === null || _j === void 0 ? void 0 : _j.section,
            },
            header: {
                className: (_k = props.UNSAFE_className) === null || _k === void 0 ? void 0 : _k.header,
                style: (_l = props.UNSAFE_styles) === null || _l === void 0 ? void 0 : _l.header,
            },
            footer: {
                className: (_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,
            },
        } }));
    if (props.customRenderInput) {
        return (React.createElement("div", { "data-testid": "ATL-Autocomplete" },
            props.customRenderInput({ inputRef: mergedInputRef, inputProps }),
            floatingMenu));
    }
    if (props.multiple) {
        return (React.createElement(MultipleSelectionLayout, { selectedValues: selectedValues, inputValue: inputValue, disabled: disabled, error: error, invalid: invalid, sizeProp: sizeProp, inputId: inputId, descriptionId: descriptionId, description: description, placeholder: placeholder, clearable: props.clearable, prefix: props.prefix, suffix: props.suffix, readOnly: props.readOnly, name: props.name, autoFocus: props.autoFocus, formFieldRef: formFieldRef, chipAreaRef: chipAreaRef, mergedInputRef: mergedInputRef, internalInputRef: internalInputRef, activeChipIndex: activeChipIndex, getOptionLabel: getOptionLabel, customRenderValue: props.customRenderValue, removeSelection: removeSelection, clearAll: clearAll, onInputChangeFromUser: onInputChangeFromUser, chipAreaEventProps: props.readOnly
                ? { onFocus: onInputFocus, onBlur: chipBlur }
                : composedReferenceProps, inputAriaProps: ariaProps, inputDataAttrs: dataAttrs, limitVisibleSelections: props.limitVisibleSelections, limitSelectionText: props.limitSelectionText, unsafeClassName: (_p = props.UNSAFE_className) === null || _p === void 0 ? void 0 : _p.selection, unsafeStyle: (_q = props.UNSAFE_styles) === null || _q === void 0 ? void 0 : _q.selection }, floatingMenu));
    }
    return (React.createElement("div", { "data-testid": "ATL-Autocomplete" },
        React.createElement(InputText.InputText, Object.assign({ ref: mergedInputRef }, inputProps)),
        floatingMenu));
}
function SelectionChip({ value, active, disabled, getOptionLabel, customRenderValue, canDismiss, onDismiss, unsafeClassName, unsafeStyle, }) {
    return (React.createElement("span", { "data-selection-disabled": disabled, className: classnames(styles.selectionChip, {
            [styles.selectionChipActive]: active,
            [styles.selectionChipDisabled]: disabled,
        }, unsafeClassName), style: unsafeStyle, "data-testid": "ATL-Autocomplete-chip", onPointerDown: preventDefaultPointerDown },
        customRenderValue ? (customRenderValue({ value, getOptionLabel })) : (React.createElement(Typography.Typography, { size: "small" }, getOptionLabel(value))),
        canDismiss && (React.createElement("button", { type: "button", disabled: disabled, className: styles.chipDismiss, onClick: onDismiss, onPointerDown: preventDefaultPointerDown, "aria-label": `Remove ${getOptionLabel(value)}`, tabIndex: -1 },
            React.createElement(Icon.Icon, { size: "small", name: "remove" })))));
}
function SelectionChipsList({ selectedValues, isFocused, limitVisibleSelections = 6, limitSelectionText = (count) => `+${count}`, activeChipIndex, disabled, getOptionLabel, customRenderValue, canDismiss, removeSelection, unsafeClassName, unsafeStyle, }) {
    const shouldLimit = !isFocused &&
        limitVisibleSelections !== -1 &&
        selectedValues.length > limitVisibleSelections;
    const visibleValues = shouldLimit
        ? selectedValues.slice(0, limitVisibleSelections)
        : selectedValues;
    const hiddenCount = shouldLimit
        ? selectedValues.length - limitVisibleSelections
        : 0;
    return (React.createElement(React.Fragment, null,
        visibleValues.map((v, i) => {
            var _a;
            return (React.createElement(SelectionChip, { key: (_a = v.key) !== null && _a !== void 0 ? _a : getOptionLabel(v), value: v, active: activeChipIndex === i, disabled: disabled, getOptionLabel: getOptionLabel, customRenderValue: customRenderValue, canDismiss: canDismiss, onDismiss: () => removeSelection(v), unsafeClassName: unsafeClassName, unsafeStyle: unsafeStyle }));
        }),
        hiddenCount > 0 && (React.createElement("span", { className: styles.limitText, "data-testid": "ATL-Autocomplete-limitText" },
            React.createElement(Typography.Typography, { size: "small", element: "span" }, limitSelectionText(hiddenCount))))));
}
function MultipleSelectionLayout({ selectedValues, inputValue, disabled, error, invalid, sizeProp, inputId, descriptionId, description, placeholder, clearable, prefix, suffix, readOnly, name, autoFocus, formFieldRef, chipAreaRef, mergedInputRef, internalInputRef, activeChipIndex, getOptionLabel, customRenderValue, removeSelection, clearAll, onInputChangeFromUser, chipAreaEventProps, inputAriaProps, inputDataAttrs, limitVisibleSelections, limitSelectionText, unsafeClassName, unsafeStyle, children, }) {
    var _a;
    const [isFocused, setIsFocused] = React.useState(false);
    const hasValue = selectedValues.length > 0 || inputValue;
    const canDismissChip = !disabled && !readOnly;
    const handleFocusIn = React.useCallback(() => {
        setIsFocused(true);
    }, []);
    const handleFocusOut = React.useCallback((e) => {
        if (!e.currentTarget.contains(e.relatedTarget)) {
            setIsFocused(false);
        }
    }, []);
    return (React.createElement("div", { "data-testid": "ATL-Autocomplete", onFocus: handleFocusIn, onBlur: handleFocusOut },
        React.createElement("div", { className: styles.multiSelectField, "data-testid": "ATL-Autocomplete-multiSelectContainer" },
            React.createElement(FormFieldWrapper.FormFieldWrapper, { disabled: disabled, size: sizeProp ? sizeProp : undefined, error: (_a = error) !== null && _a !== void 0 ? _a : "", invalid: Boolean(error || invalid), identifier: inputId, descriptionIdentifier: descriptionId, description: description, clearable: clearable !== null && clearable !== void 0 ? clearable : "never", onClear: () => {
                    var _a;
                    clearAll();
                    (_a = internalInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
                }, type: "text", placeholder: placeholder, value: hasValue ? "has-value" : "", prefix: prefix, suffix: suffix, wrapperRef: formFieldRef },
                React.createElement("div", Object.assign({ ref: chipAreaRef, className: styles.chipArea, "data-testid": "ATL-Autocomplete-chipArea" }, chipAreaEventProps),
                    React.createElement(SelectionChipsList, { selectedValues: selectedValues, isFocused: isFocused, limitVisibleSelections: limitVisibleSelections, limitSelectionText: limitSelectionText, activeChipIndex: activeChipIndex, disabled: disabled, getOptionLabel: getOptionLabel, customRenderValue: customRenderValue, canDismiss: canDismissChip, removeSelection: removeSelection, unsafeClassName: unsafeClassName, unsafeStyle: unsafeStyle }),
                    React.createElement("input", Object.assign({ ref: mergedInputRef, className: styles.inlineInput, id: inputId, value: inputValue, onChange: readOnly
                            ? undefined
                            : e => onInputChangeFromUser(e.target.value), disabled: disabled, readOnly: readOnly, name: name, autoComplete: "off", autoFocus: autoFocus }, inputAriaProps, inputDataAttrs))))),
        children));
}

exports.Autocomplete = Autocomplete;
