/**  
 * @since Last modified: 2024-07-11 09:30:49
 * @class Popup
 * @description A bubble attached to a target node.
 * @param {getEl} elem - Target element.    
 * @param {object} [options] - Parameters 
 * 
 * @param {string} [options.insName] - The name of the instance, which can be retrieved through the "ax.instance.find" method after filling in, it should be a unique value.
 * @param {string} [options.storName] - The name of the cache, after filling in, it can automatically save the parameters of this instance, and refresh the page can also keep the original state, it should be a unique value.
 * @param {string[]} [options.storKeys=[]] - The fields of the cache, property set from options, default is null that is, automatically save the whole options object, you can customize the property set of options that need to be saved by this parameters, for example: storKeys:['content','placement']
 * @param {breakpoints} [options.breakpoints={}] - The breakpoints settings, set options for different terminals or different screen sizes, please refer to the function: "ax.breakpoints".
 * @param {object} [options.lang={}] - The module language packs, after filling in, will override the corresponding module language packs under "ax.lang", through "ax.lang" to see the language items that can be set in this module.
 * @param {function} [options.onReady=null] - The listener function, which is executed after completion of the constructor and before initialization begins, supports one parameter i.e. the callback function, which has no parameters.
 * @param {function} [options.onStart=null] - The listener function, after the completion of the constructor and just after the initialization of the execution, supports one parameter i.e. the callback function, which has no parameters.
 * @param {function} [options.onInit=null] - The listener function, executed after the completion of the initialization, supports one parameter i.e. the callback function, which has no parameters.
 * @param {function} [options.onDestroy=null] - The listener function, executed after the destruction of the instance, supports one parameter i.e. callback function, which has no parameters.
 * @param {function} [options.onReset=null] - The listener function,executed after resetting the parameters, supports one parameter i.e. callback function, which has no parameters.
 * @param {function} [options.onUpdate=null] - The listener function, which executes after updating the parameters, supports one two parameters: the user parameters and the callback function, which has one parameter i.e. the user parameters.
 * @param {function} [options.onSave=null] - The listener function, which executes after saving the parameters, supports one parameter i.e. the callback function which has one parameter i.e. the parameter being saved.
 * 
 * @param {string} [options.heading=''] - The popup title, optional, if not fill in the title node will not be displayed.
 * @param {boolean} [options.divider=false] - If or not show the split line between title and content, default is false that is not show, can use true that is show. 
 * @param {'top-start'|'top-center'|'top-end'|'bottom-start'|'bottom-center'|'bottom-end'|'left-start'|'left-center'|'left-end'|'right-start'|'right-center'|'right-end'|'top-max'|'bottom-max'|'left-max'|'right-max'|'max'|'center'|'left'|'right'|'top'|'bottom'} [options.placement='top'] - The display position of the popup.
 * @param {'click'|'hover'|'sticky'|'input'|'none'} [options.trigger='click'] - The trigger for opening a popup."click" is a mouse click;"hover" is the mouse over;"sticky" means that when you open a web page it shows;"input" means that when you are inputting it shows;"none" means do not trigger.
 * @param {boolean} [options.pageClose=true] - Whether or not to allow clicking outside the popup to close this popup.
 * @param {'sm'|'md'|'lg'|'xl'|'xxl'} [options.size='md'] - The popup width.
 * @param {number} [options.duration=0] - The animation duration to open and close the popup, if it is 0 then use the animation duration defined in css, in ms.
 * @param {'fadeIn'|'fadeInDown'|'fadeInUp'|'slideDown'|'fadeInLeft'|'fadeInRight'|'springIn'|'scaleIn'} [options.in='fadeIn'] - The name of the animation that opens the popup.
 * @param {'fadeOut'|'fadeOutDown'|'fadeOutUp'|'slideUp'|'fadeOutLeft'|'fadeOutRight'|'springOut'|'scaleOut'} [options.in='fadeIn'] - The name of the animation that closes the popup.
 * @param {boolean} [options.multiple=false] - Whether to allow multiple popups to open.
 * @param {boolean} [options.deadShow=false] - Does the popup not close after opening.
 * @param {classes} [options.classes=''] - The classes of the popup, can fill in more than one, write the same "ax.classes.add"
 * @param {string} [options.height=''] - The height of the content of the popup, when the "contType" is "iframe", it is necessary to set the parameter, such as 400px, but do not exceed 760px otherwise it will produce vertical scroll bar.
 * @param {string|boolean} [options.padding=true] - Whether or not to show the inner padding of the popup, can be a boolean value or a class name, default with padding, can be filled with false,true,"_p","_p-xxl", etc.
 * @param {getContent} [options.content=''] - The popup content, can be filled with a string (#id or html),a node,a json,an object,an array,a function name,a Promise or an AsyncFunction, the same as "getContent" function.
 * @param {'text'|'html'|'image'|'video'|'audio'|'iframe'|'form'|'async'|'auto'} [options.contType='text'] - Specify the type of popup content.If you fill in "auto", it means that the content is not text, and the system will automatically determine the content type, including "Function", "Promise", "AsyncFunction", "Object", "Array" and "HTMLElement".
 * @param {object} [options.ajax={}] - Other parameters of AJAX requests, including type, xhrName, and spinSel..
 * @param {object} [options.contData={}] - This parameter can be filled in if "contType" is "async" and "dataType" is "post"; this parameter can be used if you need to append attributes to the media node.
 * @param {string} [options.actClass='_opened'] - The class name added by target after opening the popup.
 * @param {string} [options.tplStr=''] - If the data obtained is an object or an array, the content needs to be created automatically by the template, the parameter can be filled with a template id or a complete template text.
 * @param {function|null} [options.tplEng=null] - If or not using a third-party template engine, fill in "template" for Art-template engine, "mustache.render" for Mustache engine, "_.template" for Underscore engine, "ejs.render" for EJS engine.
 * @param {boolean} [options.keepShow=false] - By triggering, whether the popup can only be displayed but not closed.
 * @param {number} [options.zIndex=0] - The popup level, the default is 0 that is, not set, if with other components occurs to obscure please set your own.
 * @param {boolean} [options.adaptive=true] - If or not the popup will be automatically displayed in "*-max" position in cell phone, default is true, you can choose false to keep the original position.
 * @param {object} [options.position={}] - The parameters of the positioning engine "ax.Position".
 * @param {object} [options.media={}] - The media data, used when contType is "image", "video", "audio" or "iframe".
 * @param {object} [options.media.caption] - The media caption/title.
 * @param {object} [options.media.brief] - The media brief/description.Multi-line text is allowed.
 * @param {object|boolean} [options.arrow=true] - Triangular Indicator Arrow Data.
 * @param {boolean} [options.arrow.enable=true] - Whether to display the triangular indicator arrow.
 * @param {string} [options.arrow.size='0.5rem'] - The width or height of the triangular indicator arrow, note that 1rem = 10px.
 * @param {string} [options.arrow.offset='2.8rem'] - Margins for triangular indicator arrow, used when "placement" is "*-start" or "*-end" and target size is more than half the size of bubble, in either px or rem, note that 1rem = 10px.
 * @param {string} [options.arrow.gap='0.8rem'] - The distance between the popup and the button, in either px or rem, note that 1rem=10px; if  "enable"=false, set gap to 0.4rem or 0.
 * @param {object} [options.wing] - Setting up additional buttons to open the popup.
 * @param {'click'|'hover'|'sticky'|'input'|'none'|''} [options.wing.trigger='click'] - Wing node trigger.If you don't fill it in, the target's trigger will be used instead.
 * @param {string} [options.wing.actClass=''] - The class name added by wing node after opening the popup.
 * @param {object|boolean} [options.tools=true] - The tools Data(In the upper right corner of the popup).
 * @param {boolean} [options.tools.enable=true] - Whether to display the tools.
 * @param {'inside'|'outside'} [options.tools.placement='inside'] - The placement of tools.
 * @param {createTools} [options.tools.children=['close']] - The placement of tools.Write the same as "ax.createTools".
 * @param {object|boolean} [options.footer=true] - The footer Data(In the bottom of the popup).
 * @param {boolean} [options.footer.enable=true] - Whether to display the footer.
 * @param {'center'|'plain'|'right'|'left'} [options.footer.layout='plain'] - Buttons of footer Layout.
 * @param {createTools} [options.footer.note=false] - Show or not show note.Write the same as "ax.createTools".
 * @param {boolean} [options.footer.divider=false] - Whether or not to show the splitter line between footer and content.
 * @param {boolean} [options.footer.padding=false] - Whether to show the inner padding of the footer.
 * @param {createTools} [options.footer.children=['cancel', 'confirm']] - The placement of tools.Write the same as "ax.createTools".
 * 
 * @param {function|null} [options.onBeforeFill=null] - The listener function, executed after getting the content and before setting it, takes one argument, content, which may be a string, an object, or an array.
 * @param {function|null} [options.onBeforeShow=null] - The listener function, executed before the popup is displayed, no parameters.
 * @param {function|null} [options.onBeforeHide=null] - The listener function, executed before the popup is closed, no parameters.
 * @param {function|null} [options.onShow=null] - The listener function, executed after the popup is displayed, no parameters.
 * @param {function|null} [options.onHide=null] - The listener function, executed after the popup is closed, no parameters.
 * @param {function|null} [options.onValid=null] - The listener function, executed after form validation, support for a parameter that is the result of validation.
 * @param {function|null} [options.onUpdateCont=null] - The listener function, executed after the content is updated (asynchronous behavior), support for a parameter content that is the content of the update.
 * @param {function|null} [options.onRepositionPosition=null] - The listener function, executed when the popup position is updated, supports one parameter placement.
 * @param {function|null} [options.onRepositionPosition=null] - The listener function, executed after the replacement popup host node is updated, supports two parameters i.e. the new host node and placement.
 * @param {function|null} [options.onConfirm=null] - The listener function, executed when the confirm button is clicked, supports one parameter, the button itself.
 * @param {function|null} [options.onCancel=null] - The listener function, executed when the cancel button is clicked, supports one parameter, the button itself.
 * 
 * @see {@link https://codepen.io/axui/pen/yLwbrvm|demo @ codepen}
 * @example
 * ax.Popup('#id');
 */
import getEl from '../utils/getEl';
import extend from '../utils/extend';
import isEmpty from '../utils/isEmpty';
import instance from '../utils/instance';
import preventDft from '../utils/preventDft';
import { T_el, T_fn, T_fn_obj, T_obj, T_required, T_sel } from '../../../types/ax';
import contains from '../utils/contains';
import getEls from '../utils/getEls';
import getContent from '../utils/getContent';
import getDataType from '../utils/getDataType';
import Position from './Position';
import createFooter from '../utils/createFooter';
import renderTpl from '../utils/renderTpl';
import tplToEl from '../utils/tplToEl';
import isMobi from '../utils/isMobi';
import style from '../utils/style';
import easeHeight from '../utils/easeHeight';
import PubBase from './PubBase';
import pipe from '../utils/pipe';
import PubListen from './PubListen';
import PubUpdate from './PubUpdate';
import PubCommon from './PubCommon';
import Hover from './Hover';
import createTools from '../utils/createTools';
import ax from '../ax';
import classes from '../utils/classes';
import deepClone from '../utils/deepClone';
import validTools from '../utils/validTools';
import formTools from '../utils/formTools';
import { T_popup } from '../../../types/popup';
import elState from '../utils/elState';
import { T_footer, T_btn_ft } from '../../../types/utils';
import delay from '../utils/delay';
import setContent from '../utils/setContent';
import optPopup from '../options/optPopup';
import prefix from '../global/prefix';
import bulletinTools from '../utils/bulletinTools';
import Bubble from './Bubble';
class Popup extends pipe(Bubble, PubListen, PubUpdate, PubCommon)(PubBase) {
    targetEl: any;
    options: T_required<T_popup<0>> | T_obj = {};
    destroyed: any;
    plans: any;
    storKeys: any;
    storObs: any;
    storTmp: any;
    dftOpts: any;
    rawOpts: any;
    mainEl: any;
    contEl: any;
    formEl: any;
    wrapEl: any;
    bodyEl: any;
    headEl: any;
    footEl: any;
    confirmEl: any;
    cancelEl: any;
    closeEl: any;
    state: any;
    canTrigger: any;
    triggerShow: any;
    toggleShow: any;
    wings: any;
    content: any;
    positionIns: any;
    template: any;
    hoverIns: any;
    duration: any;
    wrapHeight: any;
    contXhr: any;
    submitXhr: any;
    data: any;
    constructor(elem: T_sel, options: T_popup = {}, inital: boolean = ax.config.inital) {
        super();
        super.ready({
            options,
            host: elem,
            maps: optPopup,
            component: false,
            spread: ['arrow', 'tools', 'footer']
        });
        /**
        * @name Popup.targetEl
        * @description Target element.
        * @type getEl
        */
        /**
        * @name Popup.rawOpts
        * @description Raw Parameters of the instance from map.
        * @type object
        */
        /**
         * @name Popup.dftOpts
         * @description Default Parameters of the instance from merging.The reset method requires this variable.
         * @type object
         */
        /**
         * @name Popup.options
         * @description Parameters of the instance.
         * @type object
         */
        /**
         * @name Popup.destroyed
         * @description Destruction state.
         * @type boolean
         */
        /**
        * @name Popup.plans
        * @description Plans for listening.
        * @type object
        */
        /**
        * @name Popup.storKeys
        * @description The set of parameter fields to save.
        * @type array
        */
        /**
         * @name Popup.storTmp
         * @description Cache object.The "updateCache" method will update the variable.
         * @type object
         */
        /**
        * @name Popup.storObs
        * @description Cache listener(proxy) that listens for "storTmp" changes and automatically updates the local storage.
        * @type any
        */
        /**
        * @name Popup.timestamp
        * @description Instance creation time.
        * @type number
        */
        /**
        * @function Popup.save
        * @description Storing settings locally.
        * @param {fn_cb_options} [cb] - Callback execution after saving local storage.
        * @returns {any} Return the instance itself
        */
        /**
        * @function Popup.reset
        * @description Re-initialization of old parameters.
        * @param {fn_cb_none} [cb] - Call back after reset settings.
        * @returns {*} Return the instance itself
        */
        this.bubbleType ='popup';
        let _this = this;
        this.triggerShow = function () {
            let isWing = _this.wings.includes(this) ? true : false,
                trigger = isWing ? (_this.options.wing.trigger || _this.options.trigger) : _this.options.trigger;
            if (trigger === 'click') {
                if (_this.state === 'hidden') {
                    _this.show();
                    if (!_this.options.multiple) {
                        let items = instance.data.filter((i: any) => i.type === _this.constructor.name.toLowerCase() && i.ins !== _this && i.ins.state === 'shown');
                        items.forEach((i: any) => {
                            i.ins.hide();
                        });
                    } else {
                        _this.options.wing.actClass && _this.wings.includes(this) ? this.classList.add(_this.options.wing.actClass) : null;
                    }
                } else if (_this.state === 'shown') {
                    !_this.options.keepShow ? _this.hide() : null;
                }
            } else if (_this.options.trigger === 'input') {
                if (!_this.targetEl?.value) {
                    !_this.options.keepShow ? _this.hide() : null;
                } else {
                    _this.show();
                    _this.options.wing.actClass && _this.wings.includes(this) ? this.classList.add(_this.options.wing.actClass) : null;
                }
            }
        }
        this.toggleShow = (e: any) => {
            if (!contains(e.target, [this.mainEl, this.targetEl, ...this.wings]) && this.state === 'shown') {
                !this.options.keepShow ? this.hide() : null;
            }
        }
        this.triggerClose = () => {
            !this.options.keepShow ? this.hide() : null;
        }
        super.listen({ name: 'ready' });
        inital ? this.init() : null;
    }
    /**
    * @description Initialization instance.
    * @param {fn_cb_none} [cb] - Callback execution after initialization.
    * @returns {Promise<any>} - Returns a proimise whose argument is the instance itself.
    */
    async init(cb?: T_fn): Promise<any> {
        super.listen({ name: 'start' });
        this.setEmpty();
        /**
        * @name Popup.wings
        * @description Nodes associated with target node that can also open or close popup.
        * @type array
        */
        this.wings = getEls(this.options.wing.selector);
        this.renderBubble('popup');
        this.setAttrs();
        await getContent.call(this, {
            content: this.options.content,
            contType: this.options.contType,
            contData: this.options.contData,
            ajax: {
                xhrName: 'contXhr',
                spinSel: this.contEl,
                ...this.options.ajax
            },
            request:(data)=>{
                this.listen({ name: 'request', params: [data] });
            },
            cb: (data) => {
                this.data = data;
                this.renderContent(data);
            }
        });
        this.fixAni(this.options.placement);
        this.createPosition();
        this.handleFooter();
        this.handleTools();
        this.bindTrigger();
        this.contEl.querySelectorAll('[role="closebubble"]').forEach((k: any) => {
            k.removeEventListener('click', this.triggerClose);
            k.addEventListener('click', this.triggerClose, false);
        });
        super.listen({ name: 'init', cb });
        return this;
    }
    fixAni(placement: string) {
        this.aniIn = ['max', 'left-max', 'right-max'].includes(placement) && this.options.in === 'slideDown' ? 'fadeIn' : this.options.in;
        this.aniOut = ['max', 'left-max', 'right-max'].includes(placement) && this.options.out === 'slideUp' ? 'fadeOut' : this.options.out;
    }
    handleTools() {
        if (this.options.tools.enable) {
            this.options.tools.children.forEach((k: any) => {
                if (k.name === 'close') {
                    k.wrapEl.onclick = () => {console.log(300)
                        this.hide();
                    }
                } else if (k.name === 'enlarge') {
                    if (this.positionIns.placement === 'max') {
                        classes.replace(k.iconEl, k.swap, k.icon);
                        this.initalPlace = this.rawOpts.placement;
                    } else {
                        this.initalPlace = this.positionIns.placement;
                    }
                    k.wrapEl.onclick = () => {
                        if (this.positionIns.placement === 'max') {
                            classes.replace(k.iconEl, k.icon, k.swap);
                            this.reposition(this.initalPlace);
                        } else {
                            classes.replace(k.iconEl, k.swap, k.icon);
                            this.reposition('max');
                        }
                    }
                } else if (k.name === 'widen') {
                    if (this.positionIns.placement === 'top-max' || this.positionIns.placement === 'bottom-max') {
                        classes.replace(k.iconEl, k.swap, k.icon);
                        this.initalPlace = this.positionIns.placement.split('-')[0];
                    } else {
                        this.initalPlace = this.positionIns.placement;
                    }
                    k.wrapEl.onclick = () => {
                        if (!this.positionIns.placement.includes('top') && !this.positionIns.placement.includes('bottom')) {
                            console.warn('Only valid for placement=top-* and placement=bottom-*!');
                            return;
                        }
                        if (this.positionIns.placement.includes('-max')) {
                            classes.replace(k.iconEl, k.icon, k.swap);
                            this.reposition(this.initalPlace);
                        } else {
                            let position = this.positionIns.placement.split('-')[0];
                            classes.replace(k.iconEl, k.swap, k.icon);
                            this.reposition(position + '-max');
                        }
                    }
                } else if (k.name === 'heighten') {
                    if (this.positionIns.placement === 'left-max' || this.positionIns.placement === 'right-max') {
                        classes.replace(k.iconEl, k.swap, k.icon);
                        this.initalPlace = this.positionIns.placement.split('-')[0];
                    } else {
                        this.initalPlace = this.positionIns.placement;
                    }
                    k.wrapEl.onclick = () => {
                        if (!this.positionIns.placement.includes('left') && !this.positionIns.placement.includes('right')) {
                            console.warn('Only valid for placement=left-* and placement=right-*!');
                            return;
                        }
                        if (this.positionIns.placement.includes('-max')) {
                            classes.replace(k.iconEl, k.icon, k.swap);
                            this.reposition(this.initalPlace);
                        } else {
                            let position = this.positionIns.placement.split('-')[0];
                            classes.replace(k.iconEl, k.swap, k.icon);
                            this.reposition(position + '-max');
                        }
                    }
                } else {
                    k.action && k.action.call(this, k);
                }
            })
        }
    }
    setAttrs() {
        this.options.classes ? classes.add(this.mainEl, this.options.classes) : null;
        this.options.size ? this.mainEl.setAttribute('size', this.options.size) : null;
        this.options.contType ? this.mainEl.setAttribute('conttype', this.options.contType) : null;
        this.options.dedicated ? this.contEl.setAttribute('dedicated', '') : null;
        this.options.height ? this.contEl.style.height = this.options.height : null;
        this.options.zIndex ? this.mainEl.style.zIndex = this.options.zIndex : null;
        this.options.tools.enable ? this.mainEl.setAttribute('toolsplace', this.options.tools.placement) : null;
        this.options.theme ? this.mainEl.setAttribute('theme', this.options.theme) : null;
    }
    createPosition() {
        let tmpArr = this.options.placement.split('-'),
            placement = this.options.placement;
        if (tmpArr.length === 2 && this.options.adaptive && isMobi) {
            if (!tmpArr.includes('max') && !['top', 'bottom'].includes(tmpArr[0])) {
                placement = 'top-max';
            } else if (!tmpArr.includes('max') && ['top', 'bottom'].includes(tmpArr[0])) {
                placement = tmpArr[0] + '-max';
            }
        }
        /**
        * @name Popup.positionIns
        * @description Instance of a popup's position.
        * @type any
        */
        this.positionIns = new Position(this.targetEl, this.mainEl, extend({
            target: {
                placement,
                arrow: this.options.arrow,
                targetObserve: {
                    attrs: [],
                },
                bubbleObserve: {
                    attrs: [],
                },
                delay: 0,
            },
            source: this.options.position
        }));
    }
    bindTrigger() {
        if (this.options.trigger === 'click' || this.options.trigger === 'input') {
            if (!this.canTrigger) {
                this.targetEl.removeEventListener(this.options.trigger, this.triggerShow);
                this.targetEl.addEventListener(this.options.trigger, this.triggerShow, false);
            }
            if (this.wings.length > 0 && !this.canTrigger) {
                this.wings.forEach((item: any) => {
                    let trigger = this.options.wing.trigger || this.options.trigger;
                    item.removeEventListener(trigger, this.triggerShow);
                    item.addEventListener(trigger, this.triggerShow, false);
                });
            }
        } else if (this.options.trigger === 'hover') {
            /**
            * @name Popup.hoverIns
            * @description Instance of a popup's hover.
            * @type any
            */
            this.hoverIns = new Hover(this.targetEl, {
                onEnter: () => {
                    this.show();
                },
                onLeave: () => {
                    !this.options.keepShow ? this.hide() : null;
                },
                hold: this.mainEl,
            });
        } else if (this.options.trigger === 'sticky') {
            this.show();
        }
        if (this.options.pageClose && !this.options.multiple) {
            !this.canTrigger ? document.addEventListener('click', this.toggleShow, false) : null;
        }
        this.canTrigger = true;
    }
    unbindTrigger(mode: 'host' | 'all' = 'host') {
        this.canTrigger = false;
        if (this.options.trigger === 'click' || this.options.trigger === 'input') {
            this.targetEl.removeEventListener(this.options.trigger, this.triggerShow);
            if (this.wings.length > 0 && mode === 'all') {
                this.wings.forEach((item: any) => {
                    let trigger = this.options.wing.trigger || this.options.trigger;
                    item.removeEventListener(trigger, this.triggerShow);
                });
            }
        } else if (this.options.trigger === 'hover') {
            this.hoverIns.destroy();
        }
        if (this.options.pageClose && !this.options.multiple && mode === 'all') {
            document.removeEventListener('click', this.toggleShow, false)
        }
    }
    /**
     * @description Change popup placement.
     * @param {string} placement - The position to be replaced, with the same value as "options.placement".
     * @param {fn_cb_placement} [cb] - Callback execution after changing popup placement.
     * @returns {any} - Returns the instance itself.
     */
    reposition(placement: string, cb?: T_fn): any {
        if (this.destroyed || !placement) {
            return this;
        }
        this.positionIns.change(placement, (placement: string) => {
            this.fixAni(placement);
            this.updateCache({ placement });
            super.listen({ name: 'reposition', cb, params: [placement] });
        });
        return this;
    }
    /**
     * @description Show or open popup.
     * @param {fn_cb_none} [cb] - Callback execution after displaying popup.
     * @returns {Promise<any>} - Returns a proimise whose argument is the instance itself.
     */
    async show(cb?: T_fn): Promise<any> {
        if (this.destroyed || this.state !== 'hidden' || this.options.asleep) {
            return this;
        }
        this.state = 'ing';
        this.options.b4Show && await this.options.b4Show.call(this);
        elState(this.mainEl).isVirtual ? document.body.appendChild(this.mainEl) : null;
        this.wrapHeight = parseInt(style(this.wrapEl).height);
        this.duration = this.options.duration || (this.wrapHeight ? Math.floor(this.wrapHeight / 3 + 250) : parseFloat(style(this.mainEl).animationDuration) * 1000);
        this.positionIns.change();
        this.mainEl.setAttribute('visibility', 'visible');
        this.targetEl ? this.targetEl.classList.add(this.options.actClass) : null;
        if (this.aniIn === 'slideDown') {
            easeHeight({ el: this.wrapEl, height: this.wrapHeight, type: 'down', duration: this.duration });
        } else {
            this.options.duration ? this.mainEl.style.animationDuration = `${this.options.duration}ms` : null;
            this.aniIn ? this.mainEl.style.animationName = prefix + this.aniIn : null;
        }
        this.hoverIns ? this.hoverIns.isActive = true : null;
        await delay({
            duration: this.duration,
            done: () => {
                this.state = 'shown'
                super.listen({ name: 'show', cb });
            }
        });
        return this;
    }
    /**
     * @description Hide or close popup.
     * @param {fn_cb_none} [cb] - Callback execution after closing popup.
     * @returns {Promise<any>} - Returns a proimise whose argument is the instance itself.
     */
    async hide(cb?: T_fn): Promise<any> {console.log(this.destroyed ,this.state)
        if (this.destroyed || this.state !== 'shown') {
            return this;
        }
        this.state = 'ing';
        if (!this.options.deadShow) {
            this.options.b4Hide && await this.options.b4Hide.call(this);
            this.targetEl ? this.targetEl.classList.remove(this.options.actClass) : null;
            this.options.wing.actClass && this.wings.map((k: any) => { k.classList.remove(this.options.wing.actClass) });
            if (this.aniOut === 'slideUp') {
                easeHeight({ el: this.wrapEl, height: this.wrapHeight, type: 'up', duration: this.duration });
            } else {
                this.aniOut ? this.mainEl.style.animationName = prefix + this.aniOut : null;
            }
            this.mainEl.querySelectorAll('video,audio').forEach((k: any) => {
                k.pause();
            });
            this.hoverIns ? this.hoverIns.isActive = false : null;
            await delay({
                duration: this.duration,
                done: () => {
                    this.state = 'hidden';
                    this.mainEl.setAttribute('visibility', 'hidden');
                    this.mainEl.remove();
                    super.listen({ name: 'hide', cb });
                    this.aniOut === 'slideUp' ? this.wrapEl.style.height = 'auto' : null;
                }
            });
        }
        return this;
    }
}
export default Popup;
