import WUPBaseElement, { AttributeMap } from "../baseElement";
import WUPFormElement from "../formElement";
import WUPPopupElement from "../popup/popupElement";
import IBaseControl from "./baseControl.i";
export declare const enum SetValueReasons {
    /** When `control.$value = 'some value'` */
    manual = 1,
    /** When clearing happened (by Esc or ClearButton click) OR reset to previous value */
    clear = 2,
    /** When user changes on UI */
    userInput = 3,
    /** When user selected existed option on UI and don't need to call selectMenuItem again (for combobox) */
    userSelect = 4,
    /** When $initValue is changed */
    initValue = 5,
    /** When value changed from storage (on init if `$options.storageKey` is pointed) */
    storage = 6
}
/** Cases of validation for WUP Controls */
export declare const enum ValidationCases {
    none = 0,
    /** Wait for first user-change > wait for valid > wait for invalid >> show error;
     *  When invalid: wait for valid > hide error > wait for invalid > show error
     *  Also you can check $options.validateDebounceMs */
    onChangeSmart = 1,
    /** Validate when user changed value (via type,select etc.); Also you can check $options.validateDebounceMs */
    onChange = 2,
    /** Validate when control lost focus */
    onFocusLost = 4,
    /** Validate if control has value and gets focus (recommended option for password with $options.validationShowAll) */
    onFocusWithValue = 8,
    /** Validate when got state 'isReady' and initValue is not empty */
    onInit = 16
}
/** Actions when user pressed ESC or button-clear */
export declare const enum ClearActions {
    /** Only clear without extra logic */
    clear = 0,
    /** Pressing Esc/buttonClear: 1st: clear, 2nd: revert clearing (it helps to avoid accidental action) */
    clearBack = 1,
    /** Pressing Esc/buttonClear: 1st: rollback to init, 2nd: clear, 3rd: revert clearing (it helps to avoid accidental action) */
    initClearBack = 2
}
/** Points on what called validation */
export declare const enum ValidateFromCases {
    /** When element appended to layout */
    onInit = 0,
    /** When control gets focus */
    onFocus = 1,
    /** When control loses focus (including document.activeElement) */
    onFocusLost = 2,
    /** When value changed */
    onChange = 3,
    /** When form.submit is called (via button submit or somehow else); It's impossible to disable */
    onSubmit = 4,
    /** When $validate() is called programmatically */
    onManualCall = 5
}
declare global {
    namespace WUP.BaseControl {
        type AutoComplete = AutoFill;
        interface EventMap extends WUP.Base.EventMap {
            /** Called on value change */
            $change: CustomEvent<{
                reason: SetValueReasons;
            }>;
        }
        interface ValidityMap {
            /** If $value is empty shows message 'This field is required` */
            required: boolean;
        }
        type ValidityFunction<T> = (value: T | undefined, control: IBaseControl, reason: ValidateFromCases | null) => false | string;
        interface Options<T = any, VM = ValidityMap> {
            /** Title/label of control;
             * @defaultValue null that means auto=>parsed from option [name]. To skip point `label=''` (empty string) */
            label: string | undefined | null;
            /** Property/key of model (collected by form); For name `firstName` >> `model.firstName`; for `nested.firstName` >> `model.nested.firstName` etc.
             * * @tutorial
             * * point `null` or `undefined` to completely detach from FormElement
             * * point `''`(empty string) to partially detach (exclude from `form.$model`, `form.$isChanged`, but include in validations & submit) */
            name: string | undefined | null;
            /** Focus element when it's appended to layout @defaultValue false */
            autoFocus: boolean;
            /** Name to autocomplete by browser; Point `true` to inherit from `$options.name` or some string
             *  if control has no autocomplete option then it's inherited from `form`
             * @see {@link HTMLInputElement.autocomplete}
             * @defaultValue null - means false if form.$options.autoComplete false also */
            autoComplete: AutoComplete | boolean | null;
            /** Disallow edit/copy value; adds attr [disabled] for styling */
            disabled: boolean;
            /** Disallow copy value; adds attr [readonly] for styling @defaultValue false */
            readOnly: boolean;
            /** Debounce option for onFocusLost event (for validationCases.onFocusLost);
             * @see {@link onFocusLostOptions.debounceMs} in helpers/onFocusLost;
             * @defaultValue 100ms */
            focusDebounceMs: number;
            /** Behavior that expected for clearing value inside control (via pressEsc or btnClear)
             * @defaultValue ClearActions.initClearBack */
            clearActions: ClearActions;
            /** Rules defined for control. Impossible to override via `$options`. Use static `$defaults` instead
             * * all functions must return error-message when value === undefined
             * * all functions must return error-message if setValue is `true/enabled` or value doesn't fit a rule
             * * value can be undefined only when a rule named as 'required' or need to collect error-messages @see {@link Options.validationShowAll}
             * @example
             * ```
             * WUPTextControl.$defaults.validationRules.isNumber = (v === undefined || !/^[0-9]*$/.test(v)) && "Please enter a valid number";
             *
             * const el = document.body.appendChild(document.createElement("wup-text"));
             * el.$options.validations = {
                isNumber: true,
              };
             * ``` */
            validationRules: {
                [K in keyof VM]?: (value: T, setValue: VM[K], control: IBaseControl, reason: ValidateFromCases | null) => false | string;
            };
            /** Rules enabled for current control (related to $defaults.validationRules)
             * @example
             * ```
             * const el = document.body.appendChild(document.createElement("wup-text"));
               el.$options.validations = {
                 min: 10, // set min 10symbols for $default.validationRules.min
                 custom: (value: string | undefined) => (value === un\defined || value === "test-me") && "This is custom error", // custom validation for single element
               };
             * ```
             * @tutorial Troubleshooting
             ** If setup validations via attr it doesn't affect on $options.validations directly. Instead use el.validations getter instead */
            validations: {
                [K in keyof VM]?: VM[K] | ValidityFunction<T>;
            } | {
                [k: string]: ValidityFunction<T>;
            } | null | undefined;
            /** When to validate control and show error. Validation by onSubmit impossible to disable
             *  @defaultValue onChangeSmart | onFocusLost | onFocusWithValue | onSubmit */
            validationCase: ValidationCases;
            /** Wait for pointed time after valueChange before showError (it's summarized with $options.debounce); WARN: hide error without debounce
             *  @defaultValue 500 */
            validateDebounceMs: number;
            /** Show all validation-rules with checkpoints as list instead of single error @defaultValue false;
             * @tutorial rules
             * * All listed rules must return error-message when value === undefined OR
             * * To skip rule from listing name with underscore, for example `_old: (v,c) => ...` */
            validationShowAll: boolean;
            /** Storage key for auto saving value in storage;
             * @tutorial rules
             * * On init value from storage applies to `$value` and triggers onChange event
             * * Point empty string or `true` to inherit from $options.name
             * * Expected value can be converted toString & parsed from string itself.
             * * Override `valueFromStorage` & `valueToStorage` to change serializing (for complex objects, arrays etc.)
             * * Before API-call gather form.$model on init OR use $onChange event
             * @see {@link WUP.BaseControl.Options.storage}
             * @defaultValue emptyString (means `false`) */
            storageKey?: boolean | string | null;
            /** Type of storage for saving value (if pointed storageKey)
             * @see {@link WUP.BaseControl.Options.storekey}
             * @defaultValue "local" */
            storage?: "local" | "session" | "url";
        }
        interface JSXProps<C = WUPBaseControl> extends WUP.Base.OnlyNames<Options> {
            /** Default value in string/boolean/number representation (depends on `control.prototype.parse()`) */
            "w-initValue"?: string | boolean | number;
            "w-label"?: string;
            "w-name"?: string;
            "w-autoFocus"?: boolean;
            "w-autoComplete"?: string | boolean;
            /** @deprecated use [disabled] instead since related to CSS-styles */
            "w-disabled"?: boolean | "";
            disabled?: boolean | "";
            /** @deprecated use [disabled] instead since related to CSS-styles */
            "w-readonly"?: boolean | "";
            readonly?: boolean | "";
            "w-clearActions"?: ClearActions | number;
            /** @deprecated use static `.$defaults.validationCase` instead */
            "w-validationCase"?: never;
            /** @deprecated use static `.$defaults.validationCase` instead */
            "w-focusDebounceMs"?: never;
            /** @deprecated use static `.$defaults.validationCase` instead */
            "w-validationRules"?: never;
            /** Rules enabled for current control (related to $defaults.validationRules);
             * * Point Global reference to object
             * @example
             * ```js
             * window.someRules = { required: true };
             * <wup-text w-validations="window.someRules"></wup-text>
             * ```
             * @defaultValue [4,4] */
            "w-validations"?: string;
            "w-validateDebounceMs"?: number;
            "w-validationShowAll"?: boolean | "";
            "w-storageKey"?: boolean | string;
            "w-storage"?: "local" | "session" | "url";
            /** @deprecated Use [required] for styling */
            readonly required?: "";
            /** @readonly Use [invalid] for styling */
            readonly invalid?: boolean;
            /** @deprecated SyntheticEvent is not supported. Use ref.addEventListener('$change') instead */
            onChange?: never;
        }
    }
}
/** Base abstract form-control */
export default abstract class WUPBaseControl<ValueType = any, TOptions extends WUP.BaseControl.Options = WUP.BaseControl.Options, Events extends WUP.BaseControl.EventMap = WUP.BaseControl.EventMap> extends WUPBaseElement<TOptions, Events> implements IBaseControl<ValueType> {
    #private;
    /** Text announced by screen-readers when control cleared; @defaultValue `cleared` */
    static $ariaCleared: string;
    /** Text announced by screen-readers; @defaultValue `Error for` */
    static $ariaError: string;
    /** CSS-variables related to component */
    static get $styleRoot(): string;
    /** StyleContent related to component */
    static get $style(): string;
    /** Default function to compare values/changes; It compares by valueOf() & by {id}
     *  Redefine/define `valueOf()` for complex values to improve comparison */
    static $isEqual(v1: unknown, v2: unknown, control: WUPBaseControl): boolean;
    /** Provide logic to check if control is empty (by comparison with value) */
    static $isEmpty(v: unknown): boolean;
    static get observedAttributes(): Array<string>;
    static get mappedAttributes(): Record<string, AttributeMap>;
    static $defaults: WUP.BaseControl.Options;
    static cloneDefaults<T extends Record<string, any>>(): T;
    /** Called on value change */
    $onChange?: (e: WUP.BaseControl.EventMap["$change"]) => void;
    /** Current value of control; You can change it without affecting on $isDirty state */
    get $value(): ValueType | undefined;
    set $value(v: ValueType | undefined);
    /** Default/init value; used to define isChanged & to reset by keyEsc/buttonClear;
     *  If control not $isDirty and not changed $value is updated according to $initValue */
    get $initValue(): ValueType | undefined;
    set $initValue(v: ValueType | undefined);
    /** True if control is touched by user */
    get $isDirty(): boolean;
    set $isDirty(v: boolean);
    /** Returns true if value is empty string or undefined */
    get $isEmpty(): boolean;
    /** Returns if value changed (by comparisson with $initValue via static.isEqual option)
     *  By default values compared by valueOf if it's possible */
    get $isChanged(): boolean;
    _isValid?: boolean;
    /** Returns true if control is valid */
    get $isValid(): boolean;
    /** Returns if related form or control disabled (true even if form.$options.disabled && !control.$options.disabled) */
    get $isDisabled(): boolean;
    /** Returns if related form or control readonly (true even if form.$options.readOnly && !control.$options.readOnly) */
    get $isReadOnly(): boolean;
    /** Returns if value is required - can't be undefined (depends on $options.validations.required) */
    get $isRequired(): boolean;
    /** Returns autoComplete name if related form or control option is enabled (and control.$options.autoComplete !== false ) */
    get $autoComplete(): WUP.BaseControl.AutoComplete | false;
    /** Check validity and show error if silent is false (by default)
     * @returns errorMessage or false (if valid) */
    $validate(silent?: boolean): string | false;
    /** Check validity and show error
     * @returns errorMessage or false (if valid) */
    validateBySubmit(): string | false;
    $showError(err: string): void;
    $hideError(): void;
    /** Add (replace) description of control to be announced by screen-readers */
    $ariaDetails(text: string | null): void;
    /** Announce text by screenReaders if element is focused */
    $ariaSpeak(text: string, delayMs?: number): void;
    $form?: WUPFormElement;
    /** Reference to nested HTMLElement */
    $refLabel: HTMLLabelElement;
    /** Reference to nested HTMLElement */
    $refInput: HTMLInputElement;
    /** Reference to nested HTMLElement tied with $options.label */
    $refTitle: HTMLElement;
    /** Reference to nested HTMLElement tied with errorMessage */
    $refError?: WUPPopupElement;
    protected gotChanges(propsChanged: Array<keyof WUP.BaseControl.Options | any> | null): void;
    /** Called on control/form Init and every time as control/form options changed. Method contains changes related to form `disabled`,`readonly` etc. */
    gotFormChanges(propsChanged: Array<string> | null): void;
    /** Called to update disabled/readonly/autocomplete options on input */
    setupInput(): void;
    /** Called to update readonly option on input */
    setupInputReadonly(): void;
    /** Called on Init and options/attributes changes to update $initValue or $value (if pointed storageKey) */
    setupInitValue(propsChanged: Array<keyof WUP.BaseControl.Options | any> | null): void;
    /** Returns true on !$isDisabled */
    get canShowError(): boolean;
    /** Use this to append elements; called single time when element isConnected/appended to layout but not ready yet
     * Attention: this.$refInput is already defined */
    protected abstract renderControl(): void;
    /** Called when need to parse inputValue or attr [initValue] */
    abstract parse(text: string): ValueType | undefined;
    protected gotReady(): void;
    protected gotRender(): void;
    protected connectedCallback(): void;
    protected gotRemoved(): void;
    /** Returns validations enabled by user & defaults */
    protected get validations(): WUP.BaseControl.Options["validations"] | undefined;
    /** Returns validations functions ready for checking */
    protected get validationsRules(): Array<(v: ValueType | undefined, reason: ValidateFromCases | null) => string | false>;
    /** Current name of failed validation */
    _errName?: string;
    _wasValidNotEmpty?: boolean;
    protected _validTimer?: ReturnType<typeof setTimeout>;
    /** Method called to check control based on validation rules and current value */
    protected goValidate(fromCase: ValidateFromCases, silent?: boolean): string | false;
    /** Show (append/update) all validation-rules with checkpoints to existed error-element */
    protected renderValidations(parent: WUPPopupElement | HTMLElement, skipRules?: string[]): void;
    protected renderError(): WUPPopupElement;
    /** Current error message */
    _errMsg?: string;
    /** Method called to show error and set invalid state on input; point null to show all validation rules with checkpoints */
    protected goShowError(err: string, target: HTMLElement): void;
    /** Method called to hide error and set valid state on input */
    protected goHideError(): void;
    /** Called to serialize value from URL/storage; override it if you have object */
    valueFromStorage(str: string): ValueType | undefined;
    /** Called to serialize value to URL/storage & must return null if need to remove */
    valueToStorage(v: ValueType | null): string | null;
    /** Returns storage key based on options `storageKey` and `name` */
    get storageKey(): string | undefined | null | false;
    /** Get & parse value from storage according to options `storageKey`, `storage` and `name` */
    protected storageGet(): ValueType | undefined;
    /** Save value to storage storage according to options `storageKey`, `storage` and `name` */
    protected storageSet(v: ValueType | undefined): void;
    /** Fire this method to update value & validate; returns null when not $isReady, true if changed */
    protected setValue(v: ValueType | undefined, reason: SetValueReasons): boolean | null;
    /** Called after value is changed */
    protected validateAfterChange(): void;
    _nextClearValue?: ValueType;
    /** Called every time on value-change to update clear-state & buttonClear
     * @returns nextClearValue */
    protected setClearState(): ValueType | undefined;
    clearValue(): void;
    /** Called when element got focus; must return array of RemoveFunctions called on FocusLost */
    protected gotFocus(ev: FocusEvent): Array<() => void>;
    /** Called when element completely lost focus; despite on blur it has debounce filter */
    protected gotFocusLost(): void;
    /** Called when user pressed key */
    protected gotKeyDown(e: KeyboardEvent & {
        submitPrevented?: boolean;
    }): void;
}
