import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Checkbox, IconBox, Input, Text } from '@citric/core';
import { ChevronDown } from '@citric/icons';
import { LoadingCircular } from '@citric/ui';
import { listToClass } from '@stack-spot/portal-theme';
import { useTranslate } from '@stack-spot/portal-translate';
import { intersection, uniq } from 'lodash';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
export const RawMultiselectField = ({ name, onChange, value, disabled, onBlur, options, isLoading = false, renderLabel, actions, showMissingValues }) => {
    const t = useTranslate(dictionary);
    const [isOpen, setOpen] = useState(false);
    const ref = useRef(null);
    const items = useMemo(() => (showMissingValues && value?.length ? uniq([...options, ...value]) : options).map(o => (_jsx("li", { children: _jsxs("label", { tabIndex: 0, onKeyDown: e => ['Enter', ' '].includes(e.key) && onToggleItem(o), children: [_jsx(Checkbox, { tabIndex: -1, checked: value?.includes(o), onChange: () => onToggleItem(o) }), renderLabel ? renderLabel(o) : _jsx(Text, { children: o })] }) }, o))), [JSON.stringify(options), value]);
    const actionItems = useMemo(() => actions?.map(a => (_jsx("li", { children: _jsx("label", { tabIndex: 0, onKeyDown: (e) => {
                if (['Enter', ' '].includes(e.key)) {
                    a.onSelect(e);
                    close();
                }
            }, onClick: (e) => {
                a.onSelect(e);
                close();
            }, "aria-label": a.label, children: a.element ?? _jsx(Text, { children: a.label }) }) }, a.label))), [actions]);
    useEffect(() => {
        if (!showMissingValues)
            onChange(intersection(value, options));
    }, [JSON.stringify(options)]);
    const close = useCallback(() => {
        setOpen(false);
        onBlur?.();
        document.removeEventListener('keydown', keyboardController);
        document.removeEventListener('click', mouseController);
    }, []);
    const keyboardController = useCallback((event) => {
        if (event.key === 'Escape') {
            close();
            ref.current?.querySelector('input')?.focus();
        }
        if (event.key === 'ArrowDown' || event.key === 'Tab') {
            const li = document.activeElement?.closest('li');
            if (!li?.nextElementSibling) {
                ref.current?.querySelector('input')?.focus();
                return close();
            }
            li.nextElementSibling.querySelector('label')?.focus?.();
            event.preventDefault();
        }
        if (event.key === 'ArrowUp') {
            const li = document.activeElement?.closest('li');
            if (!li?.previousElementSibling) {
                ref.current?.querySelector('input')?.focus();
                return close();
            }
            li.previousElementSibling.querySelector('label')?.focus?.();
        }
    }, []);
    const mouseController = useCallback((event) => {
        if (!ref.current?.querySelector('.option-box')?.contains(event.target))
            close();
    }, []);
    const open = useCallback(() => {
        if (disabled)
            return;
        setOpen(true);
        document.addEventListener('keydown', keyboardController);
        document.addEventListener('click', mouseController);
    }, [disabled]);
    const onInputKeyDown = useCallback((e) => {
        if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(e.key)) {
            open();
            e.preventDefault();
            e.stopPropagation();
            // we can't wait for React's next re-render to remove the attribute "inert", it would make it impossible to focus the first item.
            ref.current?.querySelector('.option-box')?.removeAttribute('inert');
            const firstCheckbox = ref.current?.querySelector('li label');
            firstCheckbox?.focus();
        }
        if (e.key !== 'Tab')
            e.preventDefault();
    }, []);
    const onToggleItem = useCallback((option) => {
        if (value?.includes(option))
            onChange(value.filter(v => v != option));
        else
            onChange([...(value ?? []), option]);
    }, [value]);
    return (_jsxs("div", { ref: ref, className: listToClass(['multiselect', isOpen && 'open']), children: [_jsx(Input, { "aria-label": t.help, name: name, value: value?.join(', '), onClick: (e) => {
                    e.stopPropagation();
                    isOpen ? close() : open();
                }, onKeyDown: onInputKeyDown, disabled: disabled || isLoading, autoComplete: "false", autoCorrect: "false" }), _jsx(IconBox, { className: "chevron", children: _jsx(ChevronDown, {}) }), isLoading && _jsx("div", { className: "loading", children: _jsx(LoadingCircular, { size: "sm" }) }), !disabled && !isLoading && _jsx("div", { className: "option-box", ...(isOpen ? {} : { inert: '' }), children: _jsxs("ul", { children: [items, actionItems] }) })] }));
};
const dictionary = {
    en: {
        help: 'Press enter to choose multiple values in the list.',
    },
    pt: {
        help: 'Pressione enter para escolher múltiplos valores na lista.',
    },
};
//# sourceMappingURL=RawMultiselectField.js.map