import WUPPopupElement from "../popup/popupElement";
import WUPSpinElement from "../spinElement";
import WUPBaseComboControl, { MenuOpenCases } from "./baseCombo";
import WUPBaseControl, { SetValueReasons } from "./baseControl";
declare const tagName = "wup-select";
declare global {
    namespace WUP.Select {
        interface MenuItem<T> {
            /** Provide ordinary string for rendering as menuItem OR
             *  Use li.innerHTML to render value & return string required for input
             * @example
               el.$options.items = [
                { value: 1, text: "Item N 1"}, // this ordinary behavior
                {
                  value: 2,
                  text: (value, li, i, control) => {
                    li.innerHTML =
                    `<button class='delete'><button>Item N ${i+1}` // some custom HTML here
                    // li.textContent = `Item N ${i+1}`; // or use this for fastest render
                    const btn = li.querySelector('button')!;
                    btn.onclick = (e) => {
                      e.preventDefault();
                      control.$closeMenu();
                    }
                    return `Item N ${value}`; // this is text rendered in input when related item selected
                  },
                },
              ]; */
            text: string | ((value: T, li: HTMLElement, i: number, control: WUPBaseControl) => string);
            /** Value tied with menu item */
            value: T;
            /** Use `(e)=>e.preventDefault()` to prevent selection & closing menu and do custom action */
            onClick?: (e: MouseEvent, me: MenuItem<T>) => void;
        }
        interface MenuItemElement extends HTMLLIElement {
            _value: any;
            _text: string;
        }
        interface EventMap extends WUP.BaseCombo.EventMap {
        }
        interface ValidityMap extends WUP.BaseCombo.ValidityMap {
            /** Count of minimal values that must be selected (only for option `multi`) */
            minCount: number;
            /** Count of minimal values that must be selected (only for option `multi`) */
            maxCount: number;
        }
        interface NewOptions<T = any> {
            /** Items showed in dropdown-menu. Provide promise/api-call to show pending status when control retrieves data! */
            items: MenuItem<T>[] | Promise<MenuItem<T>[]> | (() => MenuItem<T>[] | Promise<MenuItem<T>[]>);
            /** Allow user to create new value if value not found in items
             * @defaultValue false */
            allowNewValue: boolean;
            /** Allow to select multiple values; in this case $value & $initValue must contain Array<ValueType>
             * * @defaultValue false */
            multiple: boolean;
        }
        interface Options<T = any, VM = ValidityMap> extends WUP.BaseCombo.Options<T, VM>, NewOptions<T> {
            /** Case when menu-popup to show
             * @defaultValue onPressArrowKey | onClick | onFocus | onInput */
            openCase: MenuOpenCases;
            /** Set `true` to make input not editable but allow select items via popup-menu (ordinary dropdown mode)
             * @tutorial
             * * set number X to enable autoMode where `input.readOnly = items.length < X` */
            readOnlyInput: boolean | number;
        }
        interface JSXProps<C = WUPSelectControl> extends WUP.BaseCombo.JSXProps<C>, WUP.Base.OnlyNames<NewOptions> {
            /** Items showed in dropdown-menu. Provide promise/api-call to show pending status when control retrieves data!
             * Global reference to object with array
             * @see  {@link MenuItems}
             * @example
             * ```js
             * window.myItems = [...];
             * <wup-select w-items="window.myItems"></wup-select>
             * ``` */
            "w-items"?: string;
            "w-allowNewValue"?: boolean | "";
            "w-multiple"?: boolean | "";
        }
    }
    interface HTMLElementTagNameMap {
        [tagName]: WUPSelectControl;
    }
}
declare module "react" {
    namespace JSX {
        interface IntrinsicElements {
            /** Form-control with dropdown/combobox behavior
             *  @see {@link WUPSelectControl} */
            [tagName]: WUP.Base.ReactHTML<WUPSelectControl> & WUP.Select.JSXProps;
        }
    }
}
declare module "preact/jsx-runtime" {
    namespace JSX {
        interface HTMLAttributes<RefType> {
        }
        interface IntrinsicElements {
            /** Form-control with dropdown/combobox behavior
             *  @see {@link WUPSelectControl} */
            [tagName]: HTMLAttributes<WUPSelectControl> & WUP.Select.JSXProps;
        }
    }
}
/** Form-control with dropdown/combobox behavior
 * @see demo {@link https://yegorich555.github.io/web-ui-pack/control/select}
 * @example
  const el = document.createElement("wup-select");
  el.$options.name = "gender";
  el.$options.items = [
    { value: 1, text: "Male" },
    { value: 2, text: "Female" },
    { value: 3, text: "Other/Skip" },
  ];
  el.$initValue = 3;
  el.$options.validations = { required: true };
  const form = document.body.appendChild(document.createElement("wup-form"));
  form.appendChild(el);
  // or HTML
  <wup-form>
    <wup-select w-name="gender" w-initvalue="3" w-validations="myValidations" w-items="myDropdownItems" />
  </wup-form>;
 * @tutorial innerHTML @example
 * <label>
 *   <span> // extra span requires to use with icons via label:before, label:after without adjustments
 *      <input/>
 *      <strong>{$options.label}</strong>
 *   </span>
 *   <button clear/>
 *   <wup-popup menu>
 *      <ul>
 *          <li>Item 1</li>
 *          <li>Item 2</li>
 *          // etc. /
 *      </ul>
 *   </wup-popup>
 * </label>
 */
export default class WUPSelectControl<ValueType = any | any[], ItemType = ValueType, TOptions extends WUP.Select.Options = WUP.Select.Options, EventMap extends WUP.Select.EventMap = WUP.Select.EventMap> extends WUPBaseComboControl<ValueType, TOptions, EventMap> {
    #private;
    static get $style(): string;
    /** Text for listbox when no items are displayed */
    static $textNoItems: string | undefined;
    /** Text for aria-label of <ul> element */
    static $ariaLabelItems: string;
    static $isEqual(v1: unknown, v2: unknown, c: WUPSelectControl): boolean;
    /** Function to filter menuItems based on inputValue
     * @param menuItemText textcontent in lowercase
     * @param menuItemValue value related to items[x].value
     * @param inputValue normalized input value (trimStart + lowercase)
     * @param inputRawValue input value without normalization
     * @returns true if menuItem must be visible in menu
     */
    static $filterMenuItem(this: WUPSelectControl, menuItemText: string, menuItemValue: any, inputValue: string, inputRawValue: string): boolean;
    static $defaults: WUP.Select.Options;
    static cloneDefaults<T extends Record<string, any>>(): T;
    /** Returns whether control in pending state or not (shows spinner) */
    get $isPending(): boolean;
    /** Called when need to parse attr [initValue] */
    parse(attrValue: string): ValueType | undefined;
    parseInput(text: string): ValueType | undefined;
    /** Returns string for storage */
    valueToStrCompare(a: WUP.Select.MenuItem<ValueType>): string | null;
    valueFromStorage(str: string, skipMultiple?: boolean): ValueType | undefined;
    /** Store value to storage; if item.text is not function then stored text, otherwise value.toString()
     *  @see {@link valueToStrCompare} */
    valueToStorage(v: ValueType, skipMultiple?: boolean): string | null;
    /** It's called with option allowNewValue to find value related to text */
    protected findValueByText(txt: string): ValueType | undefined;
    /** Called on every spin-render */
    renderSpin(): WUPSpinElement;
    /** Required to wait for fetching items to setup initValue */
    _onPendingInitValue?: () => void;
    /** Called to get/fetch items based on $options.items */
    fetchItems(): Promise<WUP.Select.MenuItem<ValueType>[]> | WUP.Select.MenuItem<ValueType>[];
    protected gotChanges(propsChanged: Array<keyof WUP.Select.Options> | null): void;
    setupInputReadonly(): void;
    setupInitValue(propsChanged: Array<keyof WUP.Select.Options> | null): void;
    /** Change pending state */
    protected changePending(v: boolean): void;
    /** All items of current menu */
    _menuItems?: {
        all: WUP.Select.MenuItemElement[];
        /** Index of items filtered by input */
        filtered?: Array<number>;
        /** Index (in 'filtered' otherwise in 'all' array) of item that has virtual-focus; */
        focused: number;
    };
    /** Items resolved from options */
    _cachedItems?: WUP.Select.MenuItem<ValueType>[];
    /** Called when NoItems need to show */
    protected renderMenuNoItems(popup: WUPPopupElement, isReset: boolean): void;
    protected renderMenu(popup: WUPPopupElement, menuId: string): HTMLElement;
    /** Method returns items defined based on $options.items */
    protected getItems(): WUP.Select.MenuItem<ValueType>[];
    protected valueToText(v: ItemType, items: WUP.Select.MenuItem<ItemType>[]): string;
    protected setInputValue(v: ValueType | undefined, reason: SetValueReasons): void;
    protected valueToInput(v: ValueType | undefined): string;
    /** Create menuItems as array of HTMLLiElement with option _text required to filtering by input (otherwise content can be html-structure) */
    protected renderMenuItems(ul: HTMLUListElement): WUP.Select.MenuItemElement[];
    protected gotMenuClick(e: MouseEvent): void;
    /** Called when need to setValue & close base on clicked item */
    protected gotMenuItemClick(e: MouseEvent, li: WUP.Select.MenuItemElement): void;
    protected selectValue(v: ValueType, canCloseMenu?: boolean): void;
    canOpenMenu(openCase: MenuOpenCases, e?: MouseEvent | FocusEvent | KeyboardEvent | null): boolean;
    protected goOpenMenu(openCase: MenuOpenCases, e?: MouseEvent | FocusEvent | KeyboardEvent | null): Promise<WUPPopupElement | null>;
    /** Returns first selected visible item */
    protected getFirstSelected(): WUP.Select.MenuItemElement | undefined;
    protected selectMenuItem(next: HTMLElement | null): void;
    /** Select menu item if value !== undefined and menu is opened */
    protected selectMenuItemByValue(v: ValueType | undefined): void;
    protected focusMenuItem(next: HTMLElement | null): void;
    /** Focus item by index or reset is index is null (via aria-activedescendant).
     *  If menuItems is filtered by input-text than index must point on filtered array */
    protected focusMenuItemByIndex(index: number): void;
    protected focusMenuItemByKeydown(e: KeyboardEvent): void;
    protected gotKeyDown(e: KeyboardEvent): void;
    /** Called to filter menuItems (on input change etc.) */
    protected filterMenuItems(): void;
    /** Called on showMenu when user opened it without input-change */
    protected clearFilterMenuItems(): void;
    /** Called to hide/show menuItem */
    protected filterMenuItem(el: HTMLElement, hide: boolean): void;
    /** Returns if possible to de-select menu items when input is empty */
    private get canClearSelection();
    protected gotBeforeInput(e: WUP.Text.GotInputEvent): void;
    /** Called on input change to update menu if possible */
    protected tryUpdateMenu(): void;
    clearValue(): void;
    protected gotInput(e: WUP.Text.GotInputEvent): void;
    protected gotFocus(e: FocusEvent): Array<() => void>;
    protected gotFocusLost(): void;
    protected setValue(v: ValueType | undefined, reason: SetValueReasons, skipInput?: boolean): boolean | null;
    protected removePopup(): void;
}
export {};
