
/*!
 * @since Last modified: 2025-5-24 23:38:17
 * @name OrcaUI front-end framework.
 * @version 1.0.1
 * @author OrcaUI development team <orcasaga@outlook.com>
 * @description OrcaUI is a self-contained UI framework that delivers the power and elegance of native Web Components. Like its namesake orca, it combines comprehensive features with intuitive usability - offering ready-to-use components that work across all modern browsers. Designed for developers who need production-ready UI solutions without framework dependencies.
 * @see {@link https://www.orcaui.com|Official website}
 * @see {@link https://github.com/orcasaga/orcaui/issues|github issues}
 * @see {@link https://gitee.com/orcasaga/orcaui/issues|Gitee issues}
 * @see {@link https://www.npmjs.com/package/orcaui|NPM}
 * @issue Discord Group https://discord.gg/ffwSrF5D
 * @copyright This software supports the MIT License, allowing free learning and commercial use, but please retain the terms 'OrcaUI' & 'ORCAUI' within the software.
 * @license MIT license
*/

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.orca = factory());
})(this, (function () { 'use strict';

    const isNull = (data) => [undefined, null, 'undefined', 'null'].includes(data);

    const augment = function (arg) {
        if (isNull(arg) || !arg.name)
            return;
        let target;
        if (!arg.target || arg.target === 'orca') {
            target = this;
        }
        else {
            for (let k in this) {
                if (this[k].name === arg.target) {
                    target = this[k];
                    break;
                }
            }
            if (!target)
                throw new Error(`Cannot find the ${arg.target} property in the orca object!`);
        }
        if (arg.type === 'method') {
            target[target.prototype ? 'prototype' : '__proto__'][arg.name] = arg.data;
        }
        else {
            Reflect.set(target, arg.name, arg.data);
        }
    };

    const _style = getComputedStyle(document.documentElement), _getCssVar = (prop) => _style.getPropertyValue(prop).trim(), _prefix = _getCssVar(`--PREFIX`).trim();
    const orca = {
        frame: 0,
        ajaxStor: [],
        styles: _style,
        cssVar: _getCssVar,
        prefix: _prefix,
        alias: _getCssVar(`--${_prefix}alias`),
        screen: _getCssVar(`--${_prefix}screen`),
        fullGap: _getCssVar(`--${_prefix}g-full`),
        fsRoot: _getCssVar(`--${_prefix}fs-root`),
        images: {
            spin: _getCssVar(`--${_prefix}spin`).split('"')[1],
            spinDk: _getCssVar(`--${_prefix}spin-dk`).split('"')[1],
            blank: _getCssVar(`--${_prefix}blank`).split('"')[1],
            avatar: _getCssVar(`--${_prefix}avatar`).split('"')[1],
            empty: _getCssVar(`--${_prefix}empty`).split('"')[1],
            none: _getCssVar(`--${_prefix}none`).split('"')[1],
        },
        curves: {
            linear: _getCssVar(`--${_prefix}bez-linear`),
            ease: _getCssVar(`--${_prefix}bez-ease`),
            easeOut: _getCssVar(`--${_prefix}bez-eo`),
            easeIn: _getCssVar(`--${_prefix}bez-ei`),
            easeInOut: _getCssVar(`--${_prefix}bez-eio`),
            easeOutIn: _getCssVar(`--${_prefix}bez-eoi`)
        },
        isNarrowScr: ~~(_getCssVar(`--${_prefix}isnarrow`)),
        isTouchScr: ('ontouchstart' in document.documentElement),
        dragNode: null,
        compSign: 'comp',
        embedSign: 'embed',
        namePfx: 'TMP_',
        messages: [],
        valids: [],
        augment,
        tasks: [],
    };

    const fieldTypes = ['input', 'file', 'textarea', 'range', 'number', 'datetime', 'upload', 'select', 'radio', 'checkbox', 'radios', 'checkboxes', 'editor'];

    const lang = {
        name: 'en-US',
        support: {
            content: 'ORCAUI uses the <code>:has</code> CSS pseudo-class selector, which requires a modern browser. Please update to a browser with <code>Chrome 105</code> or higher!',
            cancel: 'Remind me later',
            confirm: 'I understand'
        },
        privacy: {
            content: 'We use cookies to ensure you get the best experience on our website and to provide personalized services. By continuing to browse, you agree to our Cookie Policy.',
            cancel: 'Decline',
            confirm: 'Accept'
        },
        ajax: {
            abort: `<i class="${orca.prefix}c-warn">Request aborted!</i>`,
            timeout: `<i class="${orca.prefix}c-error">Request timed out!</i>`,
            error: `<i class="${orca.prefix}c-error">Error status: {{this.status}}</i>`,
            submit: {
                btn: 'Submitting',
                succ: 'Submission successful!',
                fail: 'Submission failed!',
            }
        },
        more: {
            unfold: 'Collapse',
            fold: 'Expand',
        },
        button: {
            default: 'New Button',
            confirm: 'Confirm',
            cancel: 'Cancel',
            clear: 'Clear',
            close: 'Close',
            reset: 'Reset',
            submit: 'Submit',
            now: 'Now',
            prev: 'Prev',
            next: 'Next'
        },
        placehold: {
            note: 'Please enter your notes...',
            fileName: 'New File',
            downloadName: 'Download-File',
        },
        form: {
            placeholder: 'Please enter...',
            fileLabel: 'Choose files...',
            fileMulti: '{{this.data}} files:',
            maxLength: 'Maximum {{this.total}} characters, {{this.value}} entered, {{this.remaining}} remaining.',
            minLength: 'Minimum {{this.min}} characters, {{this.value}} entered, {{this.remaining}} more needed.',
            limitLength: 'Enter between {{this.min}} and {{this.max}} characters, currently {{this.value}}.',
            maxNumber: 'Maximum value: {{this.max}}.',
            minNumber: 'Minimum value: {{this.min}}.',
            limitNumber: 'Value range: {{this.min}} ~ {{this.max}}.',
            exceed: 'Limit exceeded.',
            range: 'Valid range: {{this.min}} ~ {{this.max}}.',
        },
        range: {
            result: `Result: {{this.multiple?this.range[0]+'-'+this.range[1]:this.value}}`,
        },
        valid: {
            regLocal: '\u4e00-\u9fa5',
            types: {
                'a': 'lowercase letters',
                'A': 'uppercase letters',
                'd': 'numbers',
                '~': 'special characters',
                '@': 'Locale characters',
            },
            message: {
                wrongRule: 'Invalid validation rule, please correct!',
                wrongFormat: 'Invalid value format, text format required!',
                noValids: 'No validation fields in form!',
            },
            strFormat: 'Invalid value format, text format required!',
            arrFormat: 'Invalid parameter format, array format required!',
            succ: '{{ this.label || "" }} validation passed!',
            fail: '{{ this.label || "" }} validation failed!',
            required: '{{ this.label }} is required!',
            email: '{{ this.label }} must be a valid email address!',
            cellphone: '{{ this.label }} must be a valid phone number!',
            landline: '{{ this.label }} must be a valid landline number!',
            ip: '{{ this.label }} must be a valid IP address!',
            id: '{{ this.label }} must be a valid ID number!',
            zip: '{{ this.label }} must be a postal code!',
            url: '{{ this.label }} must be a valid domain name!',
            plate: '{{ this.label }} must be a valid license plate number!',
            locale: '{{ this.label }} must contain only Locale characters!',
            letter: '{{ this.label }} must contain only letters!',
            string: '{{ this.label }} must contain only letters and numbers!',
            password: '{{ this.label }} must contain letters, numbers, and special characters!',
            ymdhms: '{{ this.label }} must be in format YYYY-MM-DD HH:mm:ss (e.g., 2022-11-13 2:56:12)!',
            ymd: '{{ this.label }} must be in format YYYY-MM-DD (e.g., 2022-11-13)!',
            hms: '{{ this.label }} must be in format HH:mm:ss (e.g., 2:56:12)!',
            ym: '{{ this.label }} must be in format YYYY-MM (e.g., 2022-11)!',
            y: '{{ this.label }} must be a 4-digit year!',
            m: '{{ this.label }} must be a month between 1-12!',
            d: '{{ this.label }} must be a day between 1-31!',
            date: '{{ this.label }} must be a valid date!',
            integer: '{{ this.label }} must be a positive integer not starting with 0!',
            number: '{{ this.label }} must be a number (positive, negative, integer, or decimal)!',
            'date=': '{{ this.label }} must be {{ this.data }}!',
            'date>': '{{ this.label }} must be after {{ this.data }}!',
            'date>=': '{{ this.label }} must not be earlier than {{ this.data }}!',
            'date<': '{{ this.label }} must not be after {{ this.data }}!',
            'date<=': '{{ this.label }} must not be later than {{ this.data }}!',
            'date><': '{{ this.label }} must be between {{ this.data[0] }} and {{ this.data[1] }}!',
            'date><=': '{{ this.label }} must be after {{ this.data[0] }} and before or equal to {{ this.data[1] }}!',
            'date>=<': '{{ this.label }} must be after or equal to {{ this.data[0] }} and before {{ this.data[1] }}!',
            'date>=<=': '{{ this.label }} must be between {{ this.data[0] }} and {{ this.data[1] }} inclusive!',
            'than=': '{{ this.label }} must equal {{ this.data }}!',
            'than>': '{{ this.label }} must be greater than {{ this.data }}!',
            'than>=': '{{ this.label }} must be greater than or equal to {{ this.data }}!',
            'than<': '{{ this.label }} must be less than {{ this.data }}!',
            'than<=': '{{ this.label }} must be less than or equal to {{ this.data }}!',
            'than><': '{{ this.label }} must be between {{ this.data[0] }} and {{ this.data[1] }}!',
            'than><=': '{{ this.label }} must be greater than {{ this.data[0] }} and less than or equal to {{ this.data[1] }}!',
            'than>=<': '{{ this.label }} must be greater than or equal to {{ this.data[0] }} and less than {{ this.data[1] }}!',
            'than>=<=': '{{ this.label }} must be between {{ this.data[0] }} and {{ this.data[1] }} inclusive!',
            'length=': '{{ this.label }} must be exactly {{ this.data }} characters (currently {{ this.value.length }})!',
            'length>': '{{ this.label }} must be more than {{ this.data }} characters (currently {{ this.value.length }})!',
            'length>=': '{{ this.label }} must be at least {{ this.data }} characters (currently {{ this.value.length }})!',
            'length<': '{{ this.label }} must be less than {{ this.data }} characters (currently {{ this.value.length }})!',
            'length<=': '{{ this.label }} must not exceed {{ this.data }} characters (currently {{ this.value.length }})!',
            'length><': '{{ this.label }} must be between {{ this.data[0] }} and {{ this.data[1] }} characters (currently {{ this.value.length }})!',
            'length><=': '{{ this.label }} must be more than {{ this.data[0] }} and at most {{ this.data[1] }} characters (currently {{ this.value.length }})!',
            'length>=<': '{{ this.label }} must be at least {{ this.data[0] }} and less than {{ this.data[1] }} characters (currently {{ this.value.length }})!',
            'length>=<=': '{{ this.label }} must be between {{ this.data[0] }} and {{ this.data[1] }} characters inclusive (currently {{ this.value.length }})!',
            'count=': '{{ this.label }}: exactly {{ this.data }} items must be selected (currently {{ this.value }})!',
            'count>': '{{ this.label }}: more than {{ this.data }} items must be selected (currently {{ this.value }})!',
            'count>=': '{{ this.label }}: at least {{ this.data }} items must be selected (currently {{ this.value }})!',
            'count<': '{{ this.label }}: fewer than {{ this.data }} items must be selected (currently {{ this.value }})!',
            'count<=': '{{ this.label }}: at most {{ this.data }} items can be selected (currently {{ this.value }})!',
            'count><': '{{ this.label }}: select between {{ this.data[0] }} and {{ this.data[1] }} items (currently {{ this.value }})!',
            'count><=': '{{ this.label }}: select more than {{ this.data[0] }} and at most {{ this.data[1] }} items (currently {{ this.value }})!',
            'count>=<': '{{ this.label }}: select at least {{ this.data[0] }} and fewer than {{ this.data[1] }} items (currently {{ this.value }})!',
            'count>=<=': '{{ this.label }}: select between {{ this.data[0] }} and {{ this.data[1] }} items inclusive (currently {{ this.value }})!',
            include: '{{ this.label }} must be one of: "{{ this.data }}"!',
            exclude: '{{ this.label }} must not be one of: "{{ this.data }}"!',
            same: '{{ this.label }} must match "{{ this.data[1] || this.data[0] }}"!',
            different: '{{ this.label }} must not match "{{ this.data[1] || this.data[0] }}"!',
            strength: '{{ this.label }} current strength is {{ this.value }}, required strength is {{ this.data }}!',
            specific: `{{ this.label }} requirements: {{ for(let k in this.data){/}}{{k+' minimum '+this.data[k]}}{{ (Object.keys(this.data).slice(-1)[0] !== k)? ', ':''}}{{}/}}!`,
            combine: `{{ this.label }} must contain at least {{ this.data.total }} of the following types: {{ this.data.types.join(', ') }}!`,
        },
        status: {
            warn: 'Warning',
            succ: 'Success',
            error: 'Error',
            issue: 'Question',
            info: 'Info',
            confirm: 'Confirmed',
            cancel: 'Canceled',
            forbid: 'Disabled'
        },
        message: {
            heading: {
                warn: 'Warning!',
                succ: 'Success!',
                error: 'Error!',
                issue: 'Question!',
                info: 'Information!',
            },
            content: {
                warn: 'Warning! Potential issues detected during operation, please check!',
                succ: 'Operation completed successfully!',
                error: 'Operation failed! An error occurred!',
                issue: 'Please confirm this operation!',
                info: 'System notification!',
            },
        },
        tree: {
            empty: 'No tree data available',
            label: 'New Branch',
            title: {
                folder: 'Add Parent Branch',
                file: 'Add Leaf Branch',
                edit: 'Edit Branch',
                remove: 'Delete Branch',
                arrow: 'Click to collapse or expand'
            },
            message: {
                remove: 'Are you sure you want to delete the branch "{{this.label}}"?'
            },
            paginated: {
                more: 'View More',
                next: 'Next Page',
                first: 'Go to First Page',
                info: '"{{this.label}}" has {{this.rest}} items left',
                main: 'Main Branch'
            },
            result: `<i ${orca.alias}="holder">Not selected yet...</i>`
        },
        accordion: {
            label: 'New Panel',
            content: 'New Content',
            extra: 'More Content',
            title: {
                add: 'Add Panel',
                edit: 'Edit Panel',
                remove: 'Delete Panel',
                arrow: 'Click to collapse or expand'
            },
            message: {
                remove: 'Are you sure you want to delete the panel "{{this.label}}"?'
            }
        },
        tab: {
            label: 'New Tab',
            content: 'New Content',
            title: {
                add: 'Add Tab',
                edit: 'Edit Tab',
                close: 'Delete Tab',
                move: 'Move Tab',
                update: 'Update Tab'
            },
            message: {
                add: 'Are you sure you want to add the tab "{{this.label}}"?',
                edit: 'Are you sure you want to edit the tab "{{this.label}}"?',
                close: 'Are you sure you want to delete the tab "{{this.label}}"?',
                move: 'Are you sure you want to move the tab "{{this.label}}"?',
                update: 'Are you sure you want to update the tab "{{this.label}}"?'
            }
        },
        flat: {
            label: 'New Item'
        },
        spy: {
            isObserved: `Media file {{ this.src }} is already being observed. No need to add observer.`,
            isUnobserved: `Media file {{ this.src }} is not being observed. No need to remove observer.`
        },
        tags: {
            emptyholder: 'No tags created yet!',
            placeholder: 'Please enter...',
            includePart: 'Includes duplicate tags!',
            includeFull: 'Tag fully duplicated. Add failed!'
        },
        retrieval: {
            status: `There are <u>{{this.value}}</u> results matching <s>{{this.keys}}</s>.`,
            nullKeys: 'No search keywords and no results found!'
        },
        drag: {
            holderDrag: 'Moving...',
            holderDrop: 'Drop here...',
            holderEmpty: 'Can be dragged here'
        },
        progress: {
            complete: 'Completed!',
            tips: 'Current Progress'
        },
        infinite: {
            finish: 'No more content.',
            error: 'Request terminated. Loading stopped.',
            next: '<oc-btn width="5">Load More</oc-btn>',
            preload: 'Loading data...',
            loading: 'Loading data...',
            loaded: 'Page data loaded successfully!'
        },
        virtualize: {
            preload: 'Loading data...'
        },
        pagination: {
            first: 'First',
            last: 'Last',
            prev: 'Prev',
            next: 'Next',
            ellipsis: '...',
            tips: '{{this.current}}/{{this.pages}}',
            total: 'Total {{this.total}} records',
            locate: 'Jump to',
            count: 'Per page',
            page: 'Page',
            unit: 'items'
        },
        datetime: {
            month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
            week: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
            weeks: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
            year: {
                prev: 'Prev',
                next: 'Next',
                placeholder: 'Enter year'
            },
            range: {
                hyphen: 'to',
                checkbox: 'Select same day'
            },
            unit: {
                Y: 'Year',
                M: 'Month',
                D: 'Day',
                W: 'Week',
                h: 'Hour',
                m: 'Minute',
                s: 'Second'
            },
            bc: 'BC',
            daytime: {
                select: 'Time Selection',
                start: 'Start Time',
                end: 'End Time'
            },
            toolTip: {
                restore: 'Restore initial value',
                reset: 'Reset to zero',
                now: 'Set to current time',
                close: 'Close date picker'
            },
            empty: `<i class="${orca.prefix}c-caption">Date not selected yet!</i>`,
            message: {
                requireTwoValue: 'At least two dates are required in range mode!',
                requireYearFormat: 'Please enter a valid year format!',
                requireOneSelected: 'At least one date must be selected!'
            },
            noEvent: `<i class="${orca.prefix}c-ignore">No events scheduled today!</i>`
        },
        rate: {
            title: {
                dft: 'No rating',
                clear: 'Reset rating'
            },
            template: {
                result: `{{this.stars}} star(s)`,
                tooltip: `{{this.stars}} star(s), Total score: {{this.value}}`
            },
            star: 'star'
        },
        editor: {
            defer: 'Click to load content',
            placeholder: 'Please enter...',
            path: 'Path:',
            chars: 'Characters:',
            paras: 'Paragraphs:',
            fontsizeDft: 'Default Font Size',
            alignDft: 'Default Alignment',
            tagsDft: 'Special Tags',
            tips: {
                bold: 'Bold',
                italic: 'Italic',
                through: 'Strikethrough',
                underline: 'Underline',
                alignDft: 'Default Align',
                alignLeft: 'Align Left',
                alignRight: 'Align Right',
                alignCenter: 'Center Align',
                alignJustify: 'Justify Align',
                indentMore: 'Increase Indent',
                indentLess: 'Decrease Indent',
                sub: 'Subscript',
                sup: 'Superscript',
                highlight: 'Highlight (MARK)',
                em: 'Emphasis (EM)',
                ruby: 'Ruby Text (RUBY)',
                rt: 'Pronunciation (RT)',
                address: 'Address (ADDRESS)',
                time: 'Time (TIME)',
                blockquote: 'Blockquote (BLOCKQUOTE)',
                cite: 'Citation (CITE)',
                codeInline: 'Inline Code (CODE)',
                codeBlock: 'Code Block (PRE+CODE)',
                source: 'Source Mode',
                heading: 'Set Heading',
                hr: 'Insert Horizontal Rule (HR)',
                br: 'Insert Line Break (BR)',
                p: 'Insert Paragraph (P)',
                listOl: 'Ordered List (OL+LI)',
                listUl: 'Unordered List (UL+LI)',
                listCheck: 'Task List (CHECKBOX)',
                paragraph: 'Insert Paragraph (DIV+BR)',
                fontSet: 'Font Settings',
                fontSize: 'Font Size',
                fontColor: 'Font Color',
                fontBg: 'Background Color',
                h1: 'Heading 1',
                h2: 'Heading 2',
                h3: 'Heading 3',
                h4: 'Heading 4',
                h5: 'Heading 5',
                h6: 'Heading 6',
                text: 'Normal Text'
            }
        },
        select: {
            empty: 'No options available',
            placeholder: 'Please select...',
            title: {
                close: 'Clear'
            },
            search: {
                fail: `No options match "{{this.keys}}"`,
                succ: `Found {{this.value}} options matching "{{this.keys}}"`,
                start: 'No keyword entered yet',
                placeholder: 'Enter keyword...'
            },
            check: {
                ed: 'None selected, select all',
                ing: 'Some selected, select all',
                none: 'All selected, deselect all'
            },
            stats: `{{this.value}}/{{this.total}} selected`
        },
        upload: {
            paste: {
                before: 'Click here to paste upload',
                ing: 'Use Ctrl+V to paste',
                after: 'Paste completed!'
            },
            tips: {
                suffix: `Supports {{this.value}} format`,
                size: `File size must not exceed {{this.value}}MB`,
                min: `At least {{this.value}} files must be uploaded`,
                max: `Maximum of {{this.value}} files allowed`,
                free: 'No restrictions applied'
            },
            progress: {
                passed: 'File accepted',
                notPassed: 'File rejected',
                rendered: 'Waiting for upload',
                uploading: 'Uploading',
                uploaded: 'Uploaded',
                received: 'Received',
                getAuth: 'Authorization in progress',
                authorized: 'Authorized',
                unauthorized: 'Unauthorized',
                failed: 'Upload failed'
            },
            summary: `Submitted {{this.total}} files, successfully uploaded {{this.count}}, total size: {{this.size}}`,
            message: {
                single: {
                    passed: 'Validation passed!',
                    max: 'Too many files, please remove some!',
                    size: 'File too large, please remove!',
                    suffix: 'Invalid file type, please remove!',
                    success: 'Upload succeeded!',
                    failed: 'Upload URL might be incorrect, please remove!'
                },
                global: {
                    passed: 'All files passed validation!',
                    min: 'Please upload at least {{this.value}} files!',
                    max: 'You can only upload up to {{this.value}} files. Remove some before adding more!'
                }
            },
            button: {
                choose: 'Select File',
                upload: 'Batch Upload',
                clear: 'Batch Delete',
                gallery: 'Click or drag to upload',
                picture: 'Select File'
            },
            thead: ['Preview', 'Filename', 'Size', 'Progress', 'Message', 'Status', 'Actions']
        },
        confirm: {
            heading: '',
        },
        twilight: {
            day: 'Day',
            night: 'Night'
        },
    };

    const getDataType = (obj) => {
        let tmp = Object.prototype.toString.call(obj).slice(8, -1), result;
        if (tmp === 'Function' && /^\s*class\s+/.test(obj.toString())) {
            result = 'Class';
        }
        else if (tmp === 'Object' && Object.getPrototypeOf(obj) !== Object.prototype) {
            result = 'Instance';
        }
        else {
            result = tmp;
        }
        return result;
    };

    const isEmpty = (data) => {
        let type = getDataType(data), flag;
        if (!data) {
            flag = true;
        }
        else {
            flag = (type === 'Object') ? (Object.keys(data).length === 0) :
                (type === 'Array') ? data.join('') === '' :
                    (type === 'Function') ? (data.toString().replace(/\s+/g, '').match(/{.*}/g)[0] === '{}') :
                        (type === 'Symbol') ? (data.toString().replace(/\s+/g, '').match(/\(.*\)/g)[0] === '()') : false;
        }
        return flag;
    };

    const deepClone = (data) => {
        let dataType = getDataType(data), result;
        if (dataType === 'Object') {
            let newObj = {}, symbols = Object.getOwnPropertySymbols(data);
            for (let k in data) {
                newObj[k] = deepClone(data[k]);
            }
            if (symbols.length > 0) {
                for (let k of symbols) {
                    newObj[k] = deepClone(data[k]);
                }
            }
            result = newObj;
        }
        else if (dataType === 'Array') {
            result = data.map((k) => deepClone(k));
        }
        else if (dataType === 'Date') {
            result = new Date(data);
        }
        else {
            result = data;
        }
        return result;
    };

    const deepMerge = (target, source, opt) => {
        let targetType = getDataType(target), sourceType = getDataType(source), options = Object.assign({ arrAppend: false, propAppend: true, targetClone: false, override: 'partial' }, opt), result = options.targetClone ? deepClone(target) : target;
        if (targetType !== 'Object' || sourceType !== 'Object') {
            return result;
        }
        for (let k in source) {
            if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
                let _resultType = getDataType(result[k]), _sourceType = getDataType(source[k]);
                if (_resultType !== _sourceType) {
                    if (options.override === 'partial' && result.hasOwnProperty(k) && result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
                        if (result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
                            result[k].enable = source[k];
                        }
                        else if (source[k]?.hasOwnProperty('enable') && typeof result[k] === 'boolean') {
                            result = Object.assign({ enable: result[k] }, source[k]);
                        }
                        else {
                            result[k] = source[k];
                        }
                    }
                    else {
                        result[k] = source[k];
                    }
                }
                else {
                    if (_sourceType === 'Object') {
                        result[k] = deepMerge(result[k], source[k], options);
                    }
                    else if (_sourceType === 'Array' && options.arrAppend) {
                        result[k].push(...source[k]);
                    }
                    else {
                        result[k] = source[k];
                    }
                }
            }
            else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.propAppend) {
                result[k] = source[k];
            }
        }
        let symbols = Object.getOwnPropertySymbols(source);
        if (symbols.length > 0) {
            for (let k of symbols) {
                result[k] = source[k];
            }
        }
        return result;
    };

    const config = {
        initial: true,
        support: false,
        privacy: false,
        lang,
        attrs: {
            ajaxSpin: `spinning`,
            ajaxState: `ajax`,
        },
        debounce: 200,
        throttle: 500,
        rootStart: -1,
        idStart: 0,
        floorStart: 0,
        pathHyphen: '~',
        rangeHyphen: '~',
        labelHyphen: '/',
        splitHyphen: ',',
        wordHyphen: ' ',
        actClass: `${orca.prefix}opened`,
        reqProp: 'REQRETRY',
        parser: 'new Function',
        warn: {
            init: 'The initialization process of the instance has been stopped. You will need to manually initialize it using the init() method later!',
            emptyCont: 'Data was not obtained, but execution was not halted!',
        },
        error: {
            parse: 'Getting data from HTML resulted in an error, an empty array was returned, but execution was not interrupted!',
        },
        message: {},
        valid: {
            regChars: '~!@#$%^&*',
            lengthStr: 6,
        },
        popup: {},
        alert: {},
        more: {},
        menu: {},
        tree: {},
        drawer: {},
    };
    orca.config = config;
    orca.install = (vue, options) => {
        !isEmpty(options) && deepMerge(config, options);
        vue.config.globalProperties.$orca = orca;
    };

    const requireTypes = (data, require, cb) => {
        let type = getDataType(data).toLowerCase(), types = typeof require === 'string' ? [require] : require;
        type.includes('html') ? type = 'element' : null;
        types = types.map((k) => k.toLowerCase());
        if (cb) {
            try {
                if (!types.includes(type)) {
                    throw new Error(`Wrong data type,Require types: "${'' + types}"!`);
                }
            }
            catch (error) {
                cb(error);
            }
        }
        else {
            if (!types.includes(type)) {
                throw new Error(`Wrong data type,Require types: "${'' + types}"!`);
            }
        }
    };

    const renderTpl = (html, data) => {
        requireTypes(html, 'string');
        requireTypes(data, ['array', 'object']);
        if (!html || Object.keys(data).length === 0) {
            return '';
        }
        let regStart = '\\{\\{', regEnd = '\\}\\}', exeEnd = '/', tplReg = new RegExp(`${regStart}([\\s\\S]+?)?${regEnd}`, 'g'), code = '"use strict";let str=[];\n', cursor = 0, match, result = '', add = (fragment, isJs) => {
            isJs ? (code += (fragment.endsWith(exeEnd) ? fragment.replace('=&gt;', '=>').slice(0, -1) + '\n' : 'str.push(' + fragment + ');\n'))
                : (code += (fragment !== '' ? 'str.push("' + fragment.replace(/"/g, '\\"') + '");\n' : ''));
            return add;
        };
        while (match = tplReg.exec(html)) {
            add(html.slice(cursor, match.index))(match[1], true);
            cursor = match.index + match[0].length;
        }
        add(html.slice(cursor));
        code += `return str.join('');`;
        try {
            result = new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
        }
        catch (err) {
            console.error(`'${err.message}'`, ' in \n', code, '\n');
        }
        return result;
    };

    const getComputedVar = (name) => getComputedStyle(document.documentElement).getPropertyValue(name).trim();

    const getScreenSize = () => getComputedVar(`--${orca.prefix}screen`);

    const startUpper = (str) => {
        str = str.trim();
        return str.slice(0, 1).toUpperCase() + str.slice(1);
    };

    const sliceStrEnd = ({ str = '', key = '#', type = 'afterend', contain = true }) => {
        str = str.toString();
        key = key.toString();
        let result = '', indexKey = 0, lenKey = key.length, lenEnd = str.length, indexStart = 0;
        if (!str || !key) {
            return result;
        }
        str = str.trim();
        if (str.includes(key)) {
            if (type === 'beforebegin') {
                indexKey = str.indexOf(key);
                contain ? indexKey += lenKey : null;
                lenEnd = indexKey;
            }
            else if (type === 'afterbegin') {
                indexKey = str.indexOf(key);
                !contain ? indexKey += lenKey : null;
                indexStart = indexKey;
            }
            else if (type === 'beforeend') {
                indexKey = str.lastIndexOf(key);
                contain ? indexKey += lenKey : null;
                lenEnd = indexKey;
            }
            else if (type === 'afterend') {
                indexKey = str.lastIndexOf(key);
                !contain ? indexKey += lenKey : null;
                indexStart = indexKey;
            }
            result = str.substring(indexStart, lenEnd);
        }
        return result;
    };

    const delay = function ({ duration = 2000, todo, doing, done, frame = 0 }) {
        if (duration < 0)
            Promise.reject(new Error('Invalid duration'));
        todo && todo(frame);
        return new Promise((resolve, reject) => {
            try {
                if (!duration) {
                    done && done(frame);
                    resolve(frame);
                }
                let deadline = Date.now() + duration, listen = () => {
                    let newTime = Date.now();
                    if (newTime >= deadline) {
                        cancelAnimationFrame(frame);
                        done && done(frame);
                        resolve(frame);
                        frame = 0;
                    }
                    else {
                        frame = requestAnimationFrame(listen);
                        doing && doing(frame);
                    }
                };
                listen();
            }
            catch (e) {
                reject(e);
            }
        });
    };

    const getPlaces = (data) => data.toString().split(".")[1]?.length || 0;

    const toNumber = (data, opt) => {
        let result = 0, number = Number(data), options = Object.assign({ places: 10, mode: 'round', zero: false, epsilon: true }, opt);
        if (!data || !number) {
            return 0;
        }
        if (options.places < 0) {
            return number;
        }
        else {
            let precise = number + (options.epsilon ? Number.EPSILON : 0), tail = Number(`1${'0'.repeat(options.places)}`), tempPrecise = precise * tail;
            if (options.mode === 'floor') {
                result = Math.floor(tempPrecise) / tail;
            }
            else if (options.mode === 'ceil') {
                result = Math.ceil(tempPrecise) / tail;
            }
            else {
                result = Math.round(tempPrecise) / tail;
            }
            if (options.zero) {
                let decPlaces = getPlaces(result);
                options.places > decPlaces ? result = result + (!decPlaces ? '.' : '') + ('0'.repeat(options.places - decPlaces)) : null;
            }
            return result;
        }
    };

    const toPixel = (data, multiple) => {
        let result = 0;
        if (!data) {
            return result;
        }
        multiple = multiple || parseInt(orca.fsRoot) || 10;
        if (typeof data === 'string') {
            data = data.trim();
            if (data.endsWith('rem') || data.endsWith('REM')) {
                result = ~~(toNumber(data.replace('rem', '').replace('REM', '')) * multiple);
            }
            else if (data.endsWith('px') || data.endsWith('PX')) {
                result = ~~toNumber(data.replace('px', '').replace('PX', ''));
            }
            else if (data.startsWith('var(')) {
                let tmp = orca.getCssVar(data);
                result = toPixel(tmp);
            }
            else {
                result = ~~data;
            }
        }
        else if (typeof data === 'number') {
            result = ~~data;
        }
        return result;
    };

    const preventDft = (event, enhance = false) => {
        event.cancelable && event.preventDefault();
        enhance && event.stopPropagation();
    };

    const events = orca.isTouchScr ? ['touchstart', 'touchmove', 'touchend', 'touchcancel'] : ['mousedown', 'mousemove', 'mouseup', 'mouseleave'];

    const icons = {
        font: {
            succ: `<i class="${orca.prefix}icon-check-o"></i>`,
            error: `<i class="${orca.prefix}icon-close-o"></i>`,
            warn: `<i class="${orca.prefix}icon-warn-o"></i>`,
            info: `<i class="${orca.prefix}icon-info-o"></i>`,
            issue: `<i class="${orca.prefix}icon-issue-o"></i>`,
            'succ-t': `<i class="${orca.prefix}icon-check-o-t"></i>`,
            'error-t': `<i class="${orca.prefix}icon-close-o-t"></i>`,
            'warn-t': `<i class="${orca.prefix}icon-warn-o-t"></i>`,
            'info-t': `<i class="${orca.prefix}icon-info-o-t"></i>`,
            'issue-t': `<i class="${orca.prefix}icon-issue-o-t"></i>`,
            'succ-f': `<i class="${orca.prefix}icon-check-o-f"></i>`,
            'error-f': `<i class="${orca.prefix}icon-close-o-f"></i>`,
            'warn-f': `<i class="${orca.prefix}icon-warn-o-f"></i>`,
            'info-f': `<i class="${orca.prefix}icon-info-o-f"></i>`,
            'issue-f': `<i class="${orca.prefix}icon-issue-o-f"></i>`,
        },
        svg: {
            succ: `<svg class="${orca.prefix}svg-succ" xmlns="http://www.w3.org/2000/svg" width="86.6986mm" height="86.6986mm" viewBox="0 0 86.6986 86.6986"><path class="${orca.prefix}line ${orca.prefix}bg" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${orca.prefix}line ${orca.prefix}out" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${orca.prefix}line ${orca.prefix}in-1" d="M26.316,42.859L37.9984,54.5414L60.3826,32.1572"></path></svg>`,
            error: `<svg class="${orca.prefix}svg-error" xmlns="http://www.w3.org/2000/svg" width="86.6986mm" height="86.6986mm" viewBox="0 0 86.6986 86.6986"><path class="${orca.prefix}line ${orca.prefix}bg" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${orca.prefix}line ${orca.prefix}out" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${orca.prefix}line ${orca.prefix}in-1" d="M28.774,57.9246L57.9247,28.7739"></path><path class="${orca.prefix}line ${orca.prefix}in-2" d="M57.9246,57.9246L28.7739,28.7739"></path></svg>`,
            warn: `<svg class="${orca.prefix}svg-warn" xmlns="http://www.w3.org/2000/svg" width="86.6986mm" height="86.6986mm" viewBox="0 0 86.6986 86.6986"><path class="${orca.prefix}line ${orca.prefix}bg" d="M43.4611 7.24c2.8081,0.0924 4.39,1.7 5.3045,3.1159l17.4543 29.9414 17.3445 29.7538c0.5448,1.0193 1.596,4.0544 0.1109,6.4168 -1.4849,2.3626 -3.6815,2.9155 -5.3768,2.992l-34.9082 0.0002 -34.6892 -0.0002c-1.1636,-0.0421 -4.3433,-0.6583 -5.6666,-3.1131 -1.3232,-2.4549 -0.7085,-4.6157 0.0723,-6.1078l17.454 -29.9417 17.3449 -29.7537c0.6185,-0.977 2.7471,-3.396 5.5554,-3.3036z"></path><path class="${orca.prefix}line ${orca.prefix}out" d="M43.4611 7.24c2.8081,0.0924 4.39,1.7 5.3045,3.1159l17.4543 29.9414 17.3445 29.7538c0.5448,1.0193 1.596,4.0544 0.1109,6.4168 -1.4849,2.3626 -3.6815,2.9155 -5.3768,2.992l-34.9082 0.0002 -34.6892 -0.0002c-1.1636,-0.0421 -4.3433,-0.6583 -5.6666,-3.1131 -1.3232,-2.4549 -0.7085,-4.6157 0.0723,-6.1078l17.454 -29.9417 17.3449 -29.7537c0.6185,-0.977 2.7471,-3.396 5.5554,-3.3036z"></path><path class="${orca.prefix}line ${orca.prefix}in-1" d="M43.3493,27.8713L43.3493,57.2858"></path><circle class="${orca.prefix}circle ${orca.prefix}in-2" cx="43.3492" cy="64.3337" r="2.1166"></circle></svg>`,
            info: `<svg class="${orca.prefix}svg-info" xmlns="http://www.w3.org/2000/svg" width="86.6986mm" height="86.6986mm" viewBox="0 0 86.6986 86.6986"><path class="${orca.prefix}line ${orca.prefix}bg" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${orca.prefix}line ${orca.prefix}out" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${orca.prefix}line ${orca.prefix}in-1" d="M43.3493,65.0602L43.3493,30.9723"></path><circle class="${orca.prefix}circle ${orca.prefix}in-2" cx="43.3492" cy="23.5856" r="2.1166"></circle></svg>`,
            issue: `<svg class="${orca.prefix}svg-issue" xmlns="http://www.w3.org/2000/svg" width="86.6986mm" height="86.6986mm" viewBox="0 0 86.6986 86.6986"><path class="${orca.prefix}line ${orca.prefix}bg" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${orca.prefix}line ${orca.prefix}out" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${orca.prefix}line ${orca.prefix}in-1" d="M32.3757 35.7255c-0.2203,-11.823 12.5789,-14.1087 18.4056,-9.4189 5.4663,4.3995 4.7426,12.804 -3.1088,17.9938 -3.0015,1.9839 -3.0003,3.8403 -3.0003,10.1707"></path><circle class="${orca.prefix}circle ${orca.prefix}in-2" cx="44.6612" cy="60.5502" r="2.1166"></circle></svg>`,
        }
    };

    const propsMap = {
        x: { axis: 'x', position: 'left', start: 'insetInlineStart', startAlt: 'inset-inline-start', overflow: 'overflowX', inner: 'clientWidth', outer: 'offsetWidth', scroll: 'scrollLeft', client: 'clientX', size: 'width', index: 4, offset: 'offsetLeft', gap: 'marginInlineStart' },
        y: { axis: 'y', position: 'top', start: 'insetBlockStart', startAlt: 'inset-block-start', overflow: 'overflowY', inner: 'clientHeight', outer: 'offsetHeight', scroll: 'scrollTop', client: 'clientY', size: 'height', index: 5, offset: 'offsetTop', gap: 'marginBlockStart' }
    };

    const getEl = (obj, wrap) => {
        let objType = getDataType(obj), parType = getDataType(wrap), parent = parType.includes('HTML') ? wrap : document.querySelector(wrap), result = null;
        if (obj) {
            if (objType.includes('HTML')) {
                result = obj;
            }
            else if (objType === 'String') {
                try {
                    result = (parent || document).querySelector(obj.trim());
                }
                catch {
                    result = null;
                }
            }
        }
        return result;
    };

    const instance = {
        
        data: [],
        destroyFn: (item) => {
            if (!item) {
                return false;
            }
            if ((!item.ins.hasOwnProperty('destroyed') || !item.ins.destroyed) && item.ins.__proto__.destroy) {
                item.ins.destroy();
                item.destTime = Date.now();
            }
        },
        initFn: (item) => {
            if (!item) {
                return false;
            }
            if ((!item.ins.hasOwnProperty('destroyed') || item.ins.destroyed) && item.ins.__proto__.init) {
                item.ins.init();
                item.initTime = Date.now();
            }
        },
        
        push: function (ins, name = '', type = '') {
            if (!ins) {
                return false;
            }
            let obj = { name, ins, type, pushTime: Date.now() };
            if (!this.data.some((k) => k.ins === ins)) {
                this.data.push(obj);
            }
            return this;
        },
        
        find: function (name, type = '', destroyed = false) {
            if (!name) {
                return null;
            }
            let item;
            item = this.data.find((k) => {
                let flag = type ? k.type === type : true;
                return (k.ins.hasOwnProperty('destroyed')) ? (k.name === name && k.ins.destroyed === destroyed && flag) : (k.name === name && flag);
            });
            return item ? item.ins : null;
        },
        
        findAll: function (type = '', destroyed = false) {
            let items = [];
            if (!type) {
                items = this.data.filter((i) => i.ins.destroyed === destroyed);
            }
            else {
                items = this.data.filter((i) => {
                    return (i.ins.hasOwnProperty('destroyed')) ? (i.type === type && i.ins.destroyed === destroyed) : (i.type === type);
                });
            }
            return items.length > 0 ? items.map((i) => i.ins) : [];
        },
        
        destroy: function (name, type) {
            if (!name) {
                return false;
            }
            let item = type ? (this.data.find((i) => i.name === name && i.type === type)) : (this.data.find((i) => i.name === name));
            if (item) {
                this.destroyFn(item);
            }
            return this;
        },
        
        destroyAll: function (type) {
            let items = !type ? this.data : this.data.filter((i) => i.type === type);
            items.forEach((i) => {
                this.destroyFn(i);
            });
            return this;
        },
        
        clear: function () {
            this.data.forEach((i) => {
                this.destroyFn(i);
            });
            this.data.length = 0;
            return this;
        },
        
        init: function (name, type) {
            if (!name) {
                return false;
            }
            let item = type ? (this.data.find((i) => i.name === name && i.type === type)) : (this.data.find((i) => i.name === name));
            if (item) {
                this.initFn(item);
            }
            return this;
        },
        
        initAll: function (type) {
            let items = !type ? this.data : this.data.filter((i) => i.type === type);
            items.forEach((i) => {
                this.initFn(i);
            });
            return this;
        }
    };

    const getEls = (data, parent) => {
        let type = getDataType(data), parentEl = getEl(parent) || document, result = [];
        if (isEmpty(data)) {
            return result;
        }
        if (type.includes('HTML')) {
            result.push(data);
        }
        else if (type === 'String') {
            data = data.trim();
            result = data.split(',').map((k) => {
                return [...parentEl.querySelectorAll(k)];
            }).flat();
        }
        else if (type === 'Array') {
            result = data.map((k) => {
                return getEl(k, parentEl);
            });
        }
        return result.filter(Boolean);
    };

    const createEl = (name, attrs, content) => {
        name = name || 'div';
        let rootName = name.toUpperCase().trim(), rootEl = document.createElement(rootName), attrsType = getDataType(attrs), loop = (host, data) => {
            if (data === '' || data === null || data === undefined) {
                return false;
            }
            let dataType = getDataType(data);
            if (rootName === 'TEMPLATE') {
                host.innerHTML = data.toString();
            }
            else {
                if (dataType === 'Array' && data.length > 0) {
                    for (let k of data) {
                        let childType = getDataType(k);
                        if (childType.includes('HTML')) {
                            host.appendChild(k);
                        }
                        else {
                            let child = createEl(k.name, k.attrs, k.content);
                            child && host.appendChild(child);
                        }
                    }
                }
                else if (dataType.includes('HTML')) {
                    host.appendChild(data);
                }
                else if (dataType === 'String' && data.trim().startsWith('#') && data.trim().length > 1) {
                    let el = getEl(data);
                    if (!el)
                        return;
                    el.nodeName === 'TEMPLATE' ? host.appendChild(el.content.cloneNode(true)) : host.insertAdjacentHTML('beforeEnd', el.innerHTML);
                }
                else {
                    host.insertAdjacentHTML('beforeEnd', data);
                }
            }
        };
        if (attrs && attrsType === 'Object') {
            for (let k in attrs) {
                attrs.hasOwnProperty(k) && rootEl.setAttribute(k, typeof attrs[k] === 'string' ? attrs[k] : JSON.stringify(attrs[k]));
            }
        }
        loop(rootEl, content);
        return rootEl;
    };

    const parseStr = ({ content = '', type = 'object', method = config.parser, catchable = false, error }) => {
        
        let result = type === 'object' ? {} : type === 'array' ? [] : null;
        if (!content)
            return result;
        let trim = content.trim();
        
        try {
            let tmp = typeof method === 'function' ? method(trim) : method === 'JSON.parse' ? JSON.parse(trim) : new Function(`"use strict"; return ${trim}`)();
            result = tmp;
        }
        catch (err) {
            error && error(err);
            if (catchable)
                throw err;
        }
        return result;
    };

    const strToJson = (str, type = 'object') => {
        let dft = type === 'array' ? [] : {};
        if (typeof str !== 'string')
            return dft;
        str = str.trim();
        if (!str)
            return dft;
        str = (str.startsWith('[') && str.endsWith(']')) || (str.startsWith('{') && str.endsWith('}')) ? str : `{${str}}`;
        try {
            return parseStr({
                content: str,
                type,
                catchable: true,
            });
        }
        catch {
            return dft;
        }
    };

    const attrToJson = (elem, attr) => {
        requireTypes(attr, 'string');
        let el = getEl(elem), elAttr = el.getAttribute(attr), result = {};
        if (el && attr && elAttr) {
            result = strToJson(elAttr);
        }
        return result;
    };

    const extend = ({ target = {}, source = {}, host = null, attr = '' }) => {
        let targetType = getDataType(target), el = getEl(host);
        if (targetType !== 'Object') {
            return target;
        }
        else {
            source && deepMerge(target, source);
            el && attr && deepMerge(target, attrToJson(el, attr));
        }
        return target;
    };

    const trim = (str, placement) => {
        requireTypes(str, 'string');
        return placement === 'start' ? str.trimStart() :
            placement === 'end' ? str.trimEnd() :
                placement === 'both' ? str.trim() :
                    placement === 'global' ? str.replace(/[\s\r\n]+/g, '') : str.trim().replace(/[\s\r\n]+/g, ' ');
    };

    const allToEls = (data, parent) => {
        if (isEmpty(data))
            return [];
        let result = [], type = getDataType(data);
        if (type.includes('HTML')) {
            result.push(data);
        }
        else if (type === 'String') {
            let str = trim(data), separator = str.includes(config.splitHyphen) ? config.splitHyphen : config.wordHyphen;
            str.split(separator).forEach(k => {
                let el = getEl(k, parent);
                el && result.push(el);
            });
        }
        else if (type === 'Array') {
            data.forEach(k => {
                let el = getEl(k, parent);
                el && result.push(el);
            });
        }
        else if (type === 'NodeList') {
            result = [...data];
        }
        return result;
    };

    const ajax = (options) => {
        if (isEmpty(options)) {
            throw new Error(`There is no options!`);
        }
        let dft = {
            target: '',
            url: '',
            type: 'post',
            async: true,
            data: null,
            holdTime: 0,
            stopTime: 3600000,
            contType: '',
            headers: {},
            respType: '',
            catchable: false,
            spinStr: `<oc-spin></oc-spin>`,
            spinSel: '',
            xhrName: '',
            repeat: {
                index: 0,
                max: 0,
                keyword: '',
            },
            xhrFields: {},
            abort: (resp) => { },
            timeout: (resp) => { },
            opened: (resp) => { },
            before: (resp) => { },
            downloading: (resp) => { },
            uploading: (resp) => { },
            complete: (resp) => { },
            success: (resp) => { },
            error: (resp) => { },
            cb: (resp) => { },
        };
        extend({ target: dft, source: options });
        !dft.type && (dft.type = 'post');
        let label = createEl('span', { [orca.alias]: 'message' }), target = getEl(dft.target);
        target && (target.innerHTML = '', target.appendChild(label));
        let dftAbort = () => {
            target ? label.innerHTML = config.lang.ajax.abort : console.warn('The request has been suspended!');
        }, dftTimeout = () => {
            target ? label.innerHTML = config.lang.ajax.timeout : console.warn('The request is out of time!');
        }, dftBefore = (res) => {
            target && (label.innerHTML = res.content);
        }, dftSuccess = (res) => {
            target && (target.innerHTML = res.content);
        }, dftError = (res) => {
            target ? label.innerHTML = renderTpl(config.lang.ajax.error, { status: res.status }) : console.error(`The current error state is:${res.status}`);
        };
        let spinEls = allToEls(dft.spinSel), xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"), params;
        if (!isEmpty(dft.data)) {
            let dataType = getDataType(dft.data);
            if (dataType === 'FormData') {
                params = dft.data;
            }
            else if (dataType === 'Object') {
                if (dft.contType?.includes('json')) {
                    params = JSON.stringify(dft.data);
                }
                else {
                    
                    params = new URLSearchParams(dft.data).toString();
                    dft.contType = 'application/x-www-form-urlencoded';
                }
            }
            else {
                dft.data = dft.data.trim();
                params = dft.data.startsWith('&') || dft.data.startsWith('?') ? dft.data.slice(1) : dft.data;
                dft.contType = 'application/x-www-form-urlencoded';
            }
        }
        if (dft.contType) {
            dft.headers['Content-Type'] = dft.contType;
            if (!dft.contType.includes('urlencoded') && dft.type.toLowerCase() === 'get') {
                throw new Error(`Please request data with post!`);
            }
        }
        xhr.timeout = dft.stopTime;
        xhr.responseType = dft.respType;
        let dftResp = { target, label, xhr, spins: spinEls }, timeoutFun, errorFun, successFun, abortFun = () => {
            timeoutFun && xhr.removeEventListener('timeout', timeoutFun);
            xhr.abort();
            target && target.setAttribute(config.attrs.ajaxState, 'abort');
            !isEmpty(dft.abort) ? dft.abort(Object.assign({ status: xhr.status, content: xhr.response }, dftResp)) : dftAbort();
        };
        return new Promise((resolve, reject) => {
            let progress = (e, cb) => {
                let current = e.loaded, total = e.total, ratio = 0, percent = 0, result = '0%', time = (new Date(e.timeStamp)).getTime();
                if (e.lengthComputable) {
                    ratio = current / total;
                    percent = Math.round(ratio * 100);
                    result = percent + '%';
                    let data = Object.assign({ result, percent, current, total, ratio, time, status: xhr.status, abort: abortFun }, dftResp);
                    cb && cb(data);
                    percent >= 100 && dft.complete && dft.complete(data);
                }
            };
            xhr.upload.onprogress = (e) => {
                progress(e, (data) => {
                    !isEmpty(dft.uploading) && dft.uploading(data);
                });
            };
            xhr.onprogress = (e) => {
                progress(e, (data) => {
                    !isEmpty(dft.downloading) && dft.downloading(data);
                });
            };
            timeoutFun = () => {
                let resp = Object.assign({ status: xhr.status, content: xhr.response }, dftResp);
                target && target.setAttribute(config.attrs.ajaxState, 'timeout');
                !isEmpty(dft.timeout) ? dft.timeout(resp) : dftTimeout();
                dft.catchable && reject(resp);
                dft.cb && dft.cb(resp);
            };
            errorFun = (resp) => {
                target && target.setAttribute(config.attrs.ajaxState, 'error');
                !isEmpty(dft.error) ? dft.error(resp) : dftError(resp);
                dft.catchable && reject(resp);
                dft.cb && dft.cb(resp);
            };
            successFun = (resp) => {
                if (dft.repeat.max && dft.repeat.keyword && typeof resp.content === 'string') {
                    if (orca.ajaxStor[dft.repeat.index] < dft.repeat.max &&
                        resp.content.includes(dft.repeat.keyword)) {
                        if (isNull(orca.ajaxStor[dft.repeat.index])) {
                            orca.ajaxStor.push(0);
                            dft.repeat.index = orca.ajaxStor.length - 1;
                        }
                        else {
                            orca.ajaxStor[dft.repeat.index]++;
                        }
                        ajax(dft);
                        return;
                    }
                    else {
                        orca.ajaxStor[dft.repeat.index] = 0;
                    }
                }
                if (spinEls.length > 0) {
                    for (let k of spinEls)
                        k.removeAttribute(config.attrs.ajaxSpin);
                }
                target && target.setAttribute(config.attrs.ajaxState, 'success');
                !isEmpty(dft.success) ? dft.success(resp) : dftSuccess(resp);
                resolve(resp);
                dft.cb && dft.cb(resp);
            };
            xhr.addEventListener('timeout', timeoutFun);
            xhr.onreadystatechange = function () {
                if (xhr.readyState < 4) {
                    let resp = Object.assign({ status: xhr.status, content: dft.spinStr, abort: abortFun }, dftResp);
                    if (xhr.readyState === 1) {
                        dft.xhrName && (this[dft.xhrName] = xhr);
                        !isEmpty(dft.opened) && dft.opened(resp);
                    }
                    if (spinEls.length > 0) {
                        for (let k of spinEls)
                            k.toggleAttribute(config.attrs.ajaxSpin, true);
                    }
                    target && target.setAttribute(config.attrs.ajaxState, 'before');
                    !isEmpty(dft.before) ? dft.before(resp) : dftBefore(resp);
                }
                else {
                    let resp = Object.assign({ status: xhr.status }, dftResp);
                    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
                        if (!dft.respType || xhr.responseType === 'text') {
                            let div = createEl('div', '', xhr.responseText), content = '', reg = /(<head\b[^<]*(?:(?!<\/head>)<[^<]*)*<\/head>)|(<\/?html.*?>)|(<\!DOCTYPE.*?html.*?>)|(<\/?body.*?>)/gi, strEnd = sliceStrEnd({ str: dft.url }), childSel = (typeof dft.data === 'string' ? dft.data : strEnd), childDom = getEl(childSel, div);
                            if (childDom) {
                                content = childDom.innerHTML;
                            }
                            else if (!isEmpty(childSel) && !childDom) {
                                console.warn(`The node of "${childSel}" is not exist!`);
                                content = xhr.responseText.replace(reg, '').trim();
                            }
                            else {
                                if (xhr.responseText.trim().startsWith('{') || xhr.responseText.trim().startsWith('[')) {
                                    content = JSON.parse(xhr.responseText.trim());
                                }
                                else {
                                    content = xhr.responseText.replace(reg, '').trim();
                                }
                            }
                            resp.content = content;
                        }
                        else {
                            resp.content = xhr.response;
                        }
                        if (dft.holdTime) {
                            delay({
                                duration: dft.holdTime,
                                done: () => {
                                    successFun(resp);
                                }
                            });
                        }
                        else {
                            successFun(resp);
                        }
                    }
                    else {
                        resp.content = xhr.response;
                        if (dft.holdTime) {
                            delay({
                                duration: dft.holdTime,
                                done: () => {
                                    errorFun(resp);
                                }
                            });
                        }
                        else {
                            errorFun(resp);
                        }
                    }
                }
            };
            let openParams = [], sendParams = null;
            if (dft.type.toLowerCase() === 'get') {
                openParams = ['get', dft.url + '?now=' + Date.now() + '&' + params, dft.async];
            }
            else if (dft.type.toLowerCase() === 'post') {
                openParams = ['post', dft.url, dft.async];
                sendParams = params;
            }
            for (let k in dft.xhrFields) {
                dft.xhrFields.hasOwnProperty(k) && (xhr[k] = dft.xhrFields[k]);
            }
            xhr.open(...openParams);
            for (let k in dft.headers) {
                dft.headers.hasOwnProperty(k) && xhr.setRequestHeader(k, dft.headers[k]);
            }
            xhr.send(sendParams);
        });
    };

    const valToArr = (data, hyphen, toNum = true) => {
        let dataType = getDataType(data), arr = [];
        if ([undefined, null, 'undefined', 'null', ''].includes(data)) {
            return arr;
        }
        if (dataType === 'Array') {
            arr = data.filter((k) => !isNull(k));
        }
        else if (dataType === 'String') {
            arr = data.trim().split(hyphen || config.splitHyphen);
            arr = arr.filter((k) => {
                k = k.trim();
                return k !== '' && !isNull(k);
            });
            toNum && (arr = arr.map((k) => isNaN(+k) ? k : +k));
        }
        else {
            arr.push(data);
        }
        return [...new Set(arr)];
    };

    const getValsFromAttrs = (el) => {
        let elem = getEl(el), obj = {};
        if (elem) {
            obj.label = elem.textContent.trim();
            let attrs = [...elem.attributes];
            attrs.forEach(k => {
                obj[k.name] = (['selected', 'disabled', 'readonly', 'active', 'checked', 'expanded', 'draggable'].includes(k.name)) ? true : k.value.trim();
            });
            !obj.hasOwnProperty('value') && (obj.value = obj.label);
            obj.value && !obj.label && (obj.label = obj.value);
        }
        return obj;
    };

    const select2Tree = (el) => {
        let elem = getEl(el), result = [];
        if (!elem) {
            console.warn(`No node, no access to data!`);
            return result;
        }
        let getChild = () => {
            let data = [];
            [...elem.children].forEach(k => {
                data.push(getJson(k));
            });
            return data;
        }, getJson = (elem) => {
            let obj = { node: elem, ...getValsFromAttrs(elem) };
            if (elem.nodeName == 'OPTGROUP') {
                obj.children = [];
                [...elem.children].forEach(k => {
                    obj.children.push(getJson(k));
                });
            }
            return obj;
        };
        result = getChild();
        return result;
    };

    const ul2Tree = (el, type = 'tree') => {
        let elem = getEl(el), result = [];
        if (!elem) {
            console.warn(`No node, no access to data!`);
            return result;
        }
        let getChild = () => {
            let data = [];
            [...elem.children].forEach(k => {
                data.push(getJson(k));
            });
            return data;
        }, getJson = (elem) => {
            let obj = { node: elem.firstElementChild }, tmpLabel = obj.node.querySelector(`:scope> [${orca.alias}="label"]`), tmpBadge = obj.node.querySelector(`:scope> [${orca.alias}="badge"]`) || obj.node.querySelector(`:scope> OC-BADGE`), tmpTips = obj.node.querySelector(`:scope> [${orca.alias}="tips"]`), tmpIcon = obj.node.querySelector(`:scope> [${orca.alias}="icon"]`), tmpDisk = obj.node.querySelector(`:scope> [${orca.alias}="disk"]`), tmpCube = obj.node.querySelector(`:scope> [${orca.alias}="cube"]`), tmpCustom = obj.node.querySelector(`:scope> [${orca.alias}="custom"]`), tmpBrief = elem.querySelector(`:scope> .${orca.prefix}${type}-brief`), tmpCont = elem.querySelector(`:scope> .${orca.prefix}${type}-cont`), tmpExtra = elem.querySelector(`:scope> .${orca.prefix}${type}-extra`);
            obj.node.classList.contains(`${orca.prefix}${type}-head`) && (obj.headEl = obj.node);
            tmpLabel && (obj.labelEl = tmpLabel);
            tmpBadge && (obj.badgeEl = tmpBadge);
            tmpTips && (obj.tipsEl = tmpTips);
            tmpCustom && (obj.customEl = tmpCustom);
            tmpIcon && (obj.iconEl = tmpIcon);
            tmpDisk && (obj.diskEl = tmpDisk);
            tmpCube && (obj.cubeEl = tmpCube);
            tmpBrief && (obj.briefEl = tmpBrief);
            tmpCont && (obj.contEl = tmpCont);
            tmpExtra && (obj.extraEl = tmpExtra);
            Object.assign(obj, { ...getValsFromAttrs(obj.wrapEl), ...getValsFromAttrs(obj.node), ...getValsFromAttrs(obj.labelEl) });
            obj.headEl && !obj.labelEl && (obj.headEl.innerHTML = '');
            let parent = elem.querySelector(':scope> ul,:scope> ol');
            if (parent) {
                obj.children = [];
                [...parent.children].forEach(k => {
                    obj.children.push(getJson(k));
                });
            }
            return obj;
        };
        result = getChild();
        return result;
    };

    const getContent = async function (opts) {
        let dataType = getDataType(opts.content), getListArr = (data) => {
            let el = getEl(data, opts.parent) || createEl('div', {}, data), nodeName = el.nodeName, target, result;
            if (el) {
                if (['SELECT', 'DATALIST', 'UL', 'OL'].includes(nodeName)) {
                    target = el;
                }
                else if (nodeName === 'TEMPLATE') {
                    target = el.content.cloneNode(true).querySelector('ul,ol,select,datalist');
                }
                else {
                    target = el.querySelector('ul,ol,select,datalist');
                }
            }
            if (target) {
                let tgtName = target.nodeName;
                result = (['SELECT', 'DATALIST',].includes(tgtName)) ? select2Tree(target) :
                    (['UL', 'OL'].includes(tgtName)) ? ul2Tree(target) : [];
            }
            else {
                result = [];
            }
            return result;
        }, getIframe = (src) => {
            let dft = { src }, iframe = createEl('iframe', Object.assign(dft, opts.contData)), media = createEl('div', { [orca.alias]: 'media' }, iframe);
            return createEl('div', { class: `${orca.prefix}box-iframe` }, media);
        }, getImage = (src) => {
            let dft = { src }, image = createEl('img', Object.assign(dft, opts.contData)), media = createEl('div', { [orca.alias]: 'media' }, image);
            return createEl('div', { class: `${orca.prefix}box-image` }, media);
        }, getVideo = (src) => {
            let dft = { src, controls: 'controls' }, video = createEl('video', Object.assign(dft, opts.contData)), media = createEl('div', { [orca.alias]: 'media' }, video);
            return createEl('div', { class: `${orca.prefix}box-video` }, media);
        }, getAudio = (src) => {
            let dft = { src, controls: 'controls' }, audio = createEl('audio', Object.assign(dft, opts.contData)), media = createEl('div', { [orca.alias]: 'media' }, audio);
            return createEl('div', { class: `${orca.prefix}box-audio` }, media);
        }, getMedias = (type) => {
            let map = {
                iframe: getIframe,
                audio: getAudio,
                video: getVideo,
                image: getImage,
            }, vals = valToArr(opts.content, opts.hyphen || config.splitHyphen).map((k) => k.trim()), arr = [];
            for (let k of vals) {
                arr.push(map[type](k));
            }
            return arr;
        }, getAsync = async (url) => {
            let data, options = Object.assign({
                url,
                data: opts.contData,
                success: (resp) => {
                    data = resp.content;
                },
                cb: (resp) => {
                    opts.request && opts.request(resp);
                }
            }, opts.ajax);
            await ajax.call(this, options);
            return data;
        }, getAsyncs = async () => {
            let vals = valToArr(opts.content, opts.hyphen || config.splitHyphen), arr = [];
            for (let k of vals) {
                await getAsync(k).then((resp) => {
                    arr.push(resp);
                });
            }
            return arr;
        }, result;
        if (dataType === 'Number') {
            result = opts.content + '';
        }
        else if (dataType === 'String') {
            opts.content = opts.content.trim();
            if (opts.contType === 'text') {
                result = opts.content;
            }
            else if (opts.contType === 'html') {
                result = getEl(opts.content, opts.parent) ? getEl(opts.content, opts.parent).innerHTML : '';
            }
            else if (opts.contType === 'node') {
                result = getEl(opts.content, opts.parent);
            }
            else if (opts.contType === 'list') {
                result = getListArr(opts.content);
            }
            else if (opts.contType === 'form') {
                let tmp = getEl(opts.content, opts.parent), elem = tmp?.nodeName === 'TEMPLATE' ? tmp.content.cloneNode(true) : tmp;
                result = elem?.querySelector('form') || '';
            }
            else if (opts.contType === 'iframe') {
                result = getIframe(opts.content);
            }
            else if (opts.contType === 'iframes') {
                result = getMedias('iframe');
            }
            else if (opts.contType === 'image') {
                result = getImage(opts.content);
            }
            else if (opts.contType === 'images') {
                result = getMedias('image');
            }
            else if (opts.contType === 'video') {
                result = getVideo(opts.content);
            }
            else if (opts.contType === 'videos') {
                result = getMedias('video');
            }
            else if (opts.contType === 'audio') {
                result = getAudio(opts.content);
            }
            else if (opts.contType === 'audios') {
                result = getMedias('audio');
            }
            else if (opts.contType === 'async') {
                await getAsync(opts.content).then((resp) => {
                    result = resp;
                });
            }
            else if (opts.contType === 'asyncs') {
                await getAsyncs().then((resp) => {
                    result = resp;
                });
            }
            else if (fieldTypes.includes(opts.contType)) {
                let attrs = opts.contType === 'select' ? { popup: { multiple: true } } : opts.contType === 'datetime' ? { feature: 'flat', full: true } : opts.contType === 'upload' ? { 'feature': 'gallery' } : ['radios', 'checkboxes', 'checkbox'].includes(opts.contType) ? { type: 'text' } : { full: true }, valProp = ['checkboxes', 'radios', 'select'].includes(opts.contType) ? 'content' :
                    ['checkbox', 'radio'].includes(opts.contType) ? 'label' :
                        opts.contType === 'upload' ? 'url' :
                            opts.contType === 'file' ? 'placeholder' : 'value', dft = { [valProp]: opts.content, ...attrs, ...Object.assign({ name: orca.namePfx + Date.now() }, opts.contData) };
                result = createEl(`oc-${opts.contType}`, dft);
            }
            else {
                result = opts.content;
            }
        }
        else if (dataType === 'Promise') {
            await opts.content.then((resp) => {
                result = resp;
            });
        }
        else if (dataType === 'AsyncFunction') {
            await opts.content.call(this).then((resp) => {
                result = resp;
            });
        }
        else if (dataType === 'Function') {
            result = opts.content.call(this);
        }
        else if (dataType === 'Object' || dataType === 'Array') {
            if (dataType === 'Object' && opts.content[config.reqProp]) {
                await getContent(opts.content).then((resp) => {
                    result = resp;
                });
            }
            else {
                result = deepClone(opts.content);
            }
        }
        else if (dataType.includes('HTML') && opts.contType === 'list') {
            result = getListArr(opts.content);
        }
        else {
            result = opts.content;
        }
        opts.cb && opts.cb.call(this, result);
        return result;
    };

    const style = (elem, pseudo) => {
        let el = getEl(elem), result = el ? document.defaultView.getComputedStyle(el, pseudo) : {};
        return result;
    };

    const getClasses = (data) => {
        let dataType = getDataType(data), separator, result = [];
        if (dataType === 'Array') {
            result = data.filter((k) => k && typeof k === 'string');
        }
        else {
            data = trim(data);
            separator = data.includes(config.splitHyphen) ? config.splitHyphen : config.wordHyphen;
            result = data.split(separator);
        }
        return result.map((k) => trim(k, 'global')).filter(Boolean);
    };

    const classes = (target) => {
        let el = getEl(target);
        return {
            
            get: () => el ? getClasses(el.getAttrubute('class')) : [],
            
            add: function (classes, intercept) {
                let arr = getClasses(classes);
                if (!el || arr.length === 0) {
                    return this;
                }
                arr.forEach((k) => {
                    let tmp;
                    if (intercept) {
                        tmp = intercept(k);
                        tmp === true ? el.classList.add(k) :
                            (typeof tmp === 'string' && tmp) ? el.classList.add(tmp) : null;
                    }
                    else {
                        el.classList.add(k);
                    }
                });
                return this;
            },
            
            remove: function (classes, intercept) {
                let arr = getClasses(classes);
                if (!el || arr.length === 0)
                    return this;
                arr.forEach((k) => {
                    let tmp;
                    if (intercept) {
                        tmp = intercept(k);
                        tmp === true ? el.classList.remove(k) :
                            (typeof tmp === 'string' && tmp) ? el.classList.remove(tmp) : null;
                    }
                    else {
                        el.classList.remove(k);
                    }
                });
                return this;
            },
            
            replace: function (oldClass, newClass) {
                if (!el || !oldClass)
                    return this;
                if (el && newClass && oldClass) {
                    el.classList.remove(oldClass);
                    el.classList.add(newClass);
                }
                return this;
            },
            
            has: function (classes) {
                if (!el || isEmpty(classes))
                    return this;
                let arr = getClasses(classes);
                for (let k of arr) {
                    if (!el.classList.contains(k)) {
                        return false;
                    }
                }
                return true;
            }
        };
    };

    const elState = (elem) => {
        let dom = getEl(elem), isExist = dom ? true : false;
        if (!dom) {
            return { isExist, isCalc: false, isUncalc: true };
        }
        else {
            if (!dom.isConnected) {
                return { isExist, isVirtual: true, isHidden: true, isVisible: false, isCalc: false, isUncalc: true };
            }
            if (dom.style.display === 'none') {
                return { isExist, isVirtual: false, isHidden: true, isVisible: false, isCalc: false, isUncalc: true };
            }
            let style = getComputedStyle(dom), isVirtual = !style.display, isHidden = (style.display === 'none' || style.visibility === 'hidden'), isCalc = !!(style.display && style.display !== 'none'), isVisible = !!(isCalc && style.visibility === 'visible');
            return { isExist, isVirtual, isHidden, isVisible, isCalc, isUncalc: isVirtual || isHidden };
        }
    };

    const optBase = [
        {
            attr: 'ins-name',
            prop: 'insName',
            value: '',
        },
        {
            attr: 'stor-name',
            prop: 'storName',
            value: '',
        },
        {
            attr: 'stor-keys',
            prop: 'storKeys',
            value: [],
        },
        {
            attr: 'breakpoints',
            prop: 'breakpoints',
            value: {},
        },
        {
            attr: 'rtl',
            prop: 'rtl',
            value: false,
        },
        {
            attr: 'lang',
            prop: 'lang',
            value: {},
        },
        {
            attr: 'b4-init',
            prop: 'b4Init',
            value: null,
        },
        {
            attr: 'on-constructed',
            prop: 'onConstructed',
            value: null,
        },
        {
            attr: 'on-initiate',
            prop: 'onInitiate',
            value: null,
        },
        {
            attr: 'on-initiated',
            prop: 'onInitiated',
            value: null,
        },
        {
            attr: 'on-destroyed',
            prop: 'onDestroyed',
            value: null,
        },
        {
            attr: 'on-error',
            prop: 'onError',
            value: null,
        },
        {
            attr: 'on-reset',
            prop: 'onReset',
            value: null,
        },
        {
            attr: 'on-updated',
            prop: 'onUpdated',
            value: null,
        },
        {
            attr: 'on-saved',
            prop: 'onSaved',
            value: null,
        },
        {
            attr: 'on-clearedcache',
            prop: 'onClearedCache',
            value: null,
        },
        {
            attr: 'on-updatedcache',
            prop: 'onUpdatedCache',
            value: null,
        },
    ];

    let OCTMP_actClass = config.actClass;
    const optBubble = [
        {
            attr: 'heading',
            prop: 'heading',
            value: '',
        },
        {
            attr: 'divider',
            prop: 'divider',
            value: false,
        },
        {
            attr: 'duration',
            prop: 'duration',
            value: 0,
        },
        {
            attr: 'auto-dur',
            prop: 'autoDur',
            value: false,
        },
        {
            attr: 'asleep',
            prop: 'asleep',
            value: false,
        },
        {
            attr: 'dead-show',
            prop: 'deadShow',
            value: false,
        },
        {
            attr: 'keep-show',
            prop: 'keepShow',
            value: false,
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'padding',
            prop: 'padding',
            value: {
                enable: true,
                body: true,
                foot: true,
            }
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'act-class',
            prop: 'actClass',
            value: OCTMP_actClass,
        },
        {
            attr: 'tpl-str',
            prop: 'tplStr',
            value: '',
        },
        {
            attr: 'tpl-eng',
            prop: 'tplEng',
            value: null,
        },
        {
            attr: 'z-index',
            prop: 'zIndex',
            value: 0,
        },
        {
            attr: 'dedicated',
            prop: 'dedicated',
            value: false,
        },
        {
            attr: 'can-click',
            prop: 'canClick',
            value: null,
        },
        {
            attr: 'media',
            prop: 'media',
            value: {
                title: '',
                brief: '',
            },
        },
        {
            attr: 'auto-fill',
            prop: 'autoFill',
            value: {
                enable: false,
                inputSel: '',
                childSel: '',
                detectable: false,
                attr: '',
            },
        },
        {
            attr: 'bullet',
            prop: 'bullet',
            value: {
                enable: false,
                type: 'custom',
                parentNode: 'ul',
                childNode: 'li',
                unpadded: false,
                hoverable: false,
                divisible: false,
                multiline: false,
                cols: 0,
                lines: '',
                action: null,
            },
        },
        {
            attr: 'tools',
            prop: 'tools',
            value: {
                enable: true,
                placement: 'inside',
                children: ['close']
            },
            
        },
        {
            attr: 'footer',
            prop: 'footer',
            value: {
                enable: true,
                layout: 'plain',
                note: false,
                divider: false,
                padding: false,
                children: ['cancel', 'confirm']
            }
            
        },
        {
            attr: 'b4-show',
            prop: 'b4Show',
            value: null,
        },
        {
            attr: 'b4-hide',
            prop: 'b4Hide',
            value: null,
        },
        {
            attr: 'b4-fill',
            prop: 'b4Fill',
            value: null,
        },
        {
            attr: 'b4-confirm',
            prop: 'b4Confirm',
            value: null,
        },
        {
            attr: 'b4-cancel',
            prop: 'b4Cancel',
            value: null,
        },
        {
            attr: 'on-show',
            prop: 'onShow',
            value: null,
        },
        {
            attr: 'on-hide',
            prop: 'onHide',
            value: null,
        },
        {
            attr: 'on-shown',
            prop: 'onShown',
            value: null,
        },
        {
            attr: 'on-hidden',
            prop: 'onHidden',
            value: null,
        },
        {
            attr: 'on-invalidated',
            prop: 'onInvalidated',
            value: null,
        },
        {
            attr: 'on-validated',
            prop: 'onValidated',
            value: null,
        },
        {
            attr: 'on-sended',
            prop: 'onSended',
            value: null,
        },
        {
            attr: 'on-render',
            prop: 'onRender',
            value: null,
        },
        {
            attr: 'on-rendered',
            prop: 'onRendered',
            value: null,
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null,
        },
        {
            attr: 'on-transferred',
            prop: 'onTransferred',
            value: null,
        },
        {
            attr: 'on-confirmed',
            prop: 'onConfirmed',
            value: null,
        },
        {
            attr: 'on-canceled',
            prop: 'onCanceled',
            value: null,
        }, {
            attr: 'on-closed',
            prop: 'onClosed',
            value: null,
        }, {
            attr: 'on-cleared',
            prop: 'onCleared',
            value: null,
        },
        {
            attr: 'on-request',
            prop: 'onRequest',
            value: null
        },
        {
            attr: 'on-bulletschecked',
            prop: 'onBulletsChecked',
            value: null
        },
        {
            attr: 'on-bulletsselected',
            prop: 'onBulletsSelected',
            value: null
        },
        {
            attr: 'on-targetset',
            prop: 'onTargetSet',
            value: null
        },
        ...optBase
    ];

    const optDrawer = [
        {
            attr: 'placement',
            prop: 'placement',
            value: 'right',
        },
        {
            attr: 'trigger',
            prop: 'trigger',
            value: 'click',
        },
        {
            attr: 'offset',
            prop: 'offset',
            value: '100px',
        },
        {
            attr: 'size',
            prop: 'size',
            value: 'sm',
        },
        {
            attr: 'multiple',
            prop: 'multiple',
            value: true,
        },
        {
            attr: 'parent',
            prop: 'parent',
            value: '',
        },
        {
            attr: 'wing',
            prop: 'wing',
            value: {
                selector: '',
                actClass: '',
            },
        },
        {
            attr: 'mask',
            prop: 'mask',
            value: {
                enable: true,
                closable: true,
            },
        },
        ...optBubble
    ];

    const getEvtTarget = (evt) => {
        
        if (!evt.targetTouches) {
            return evt.target;
        }
        else {
            let tmp = evt.targetTouches[0] || evt.changedTouches[0];
            return document.elementFromPoint(tmp.clientX, tmp.clientY);
        }
    };

    const removeStyle = (el, prop) => {
        let target = getEl(el);
        if (!target || !prop)
            return;
        target.style.cssText = target.style.cssText.replace(`${prop}:`, '');
    };

    const addStyle = (el, key, value) => {
        let target = getEl(el);
        key = (key + '').toLowerCase();
        value = value + '';
        if (!target || !key || !value)
            return;
        let prop = key.replace(/-([a-z])/g, (match, k) => k.toUpperCase());
        target.style[prop] = value;
    };

    const isDateStr = (str) => (typeof str === 'string' && !isNaN(Date.parse(str)));

    const getUTCTimestamp = (value) => {
        let date, offset, dateTamp, valType = getDataType(value);
        if (valType === 'Date') {
            date = value;
        }
        else if (valType === 'String') {
            if (isDateStr(value)) {
                date = new Date(value);
            }
            else {
                date = new Date();
            }
        }
        else if (valType === 'Number') {
            date = new Date(value);
        }
        else {
            date = new Date();
        }
        dateTamp = date.getTime();
        offset = date.getTimezoneOffset() * 60000;
        return dateTamp + offset;
    };

    const getExpiration = (type = 'd', value = 365, output = 'locale') => {
        let dateExp;
        if (isDateStr(value)) {
            dateExp = new Date(value);
        }
        else {
            dateExp = new Date();
            switch (type) {
                case 's':
                    dateExp.setSeconds(dateExp.getSeconds() + ~~value);
                    break;
                case 'm':
                    dateExp.setMinutes(dateExp.getMinutes() + ~~value);
                    break;
                case 'h':
                    dateExp.setHours(dateExp.getHours() + ~~value);
                    break;
                default:
                    dateExp.setDate(dateExp.getDate() + ~~value);
            }
        }
        return output === 'utc' ? getUTCTimestamp(dateExp) : dateExp.getTime();
    };

    const storage = {
        
        set: function (key, value, opts) {
            if (isEmpty(key) && typeof key !== 'string')
                return;
            let options = Object.assign({ unit: 'd', expires: 0, override: true, type: 'local' }, opts), newValue = deepClone(value), valType = getDataType(value), stor = options.type === 'session' ? window.sessionStorage : window.localStorage, filterProps = (obj) => {
                Object.keys(obj).forEach(k => {
                    let val = obj[k], type = getDataType(val);
                    ['Array', 'Object'].includes(type) && filterProps(val);
                    (type.includes('HTML') || type.includes('Function') || ['Promise', 'Symbol', 'Instance'].includes(type)) && delete obj[k];
                });
                return obj;
            };
            if (['Array', 'Object'].includes(valType) && !isEmpty(newValue)) {
                filterProps(newValue);
            }
            let expires = options.expires !== 0 ? getExpiration(options.unit, options.expires) : 0, oldValue = this.get(key, options.type), valueExp = {
                data: (!options.override && this.get(key, options.type)) ? extend({ target: oldValue, source: newValue }) : newValue,
                expires,
            };
            if (((typeof options.expires === 'number' && options.expires < 0) || newValue === null) && this.get(key, options.type)) {
                this.remove(key, options.type);
            }
            else {
                stor.setItem(key, JSON.stringify(valueExp));
            }
            return this;
        },
        
        get: function (key, type = 'local') {
            if (isEmpty(key) || typeof key !== 'string') {
                return false;
            }
            let now = Date.now(), stor = type === 'session' ? window.sessionStorage : window.localStorage, valueStr = stor.getItem(key);
            if (valueStr) {
                let valueExp = (new Function('"use strict";return ' + valueStr))();
                if (valueExp.expires === 0 || now <= valueExp.expires) {
                    return valueExp.data;
                }
                else {
                    stor.removeItem(key);
                    return null;
                }
            }
            else {
                return null;
            }
        },
        
        remove: function (key, type = 'local') {
            if (isEmpty(key) || typeof key !== 'string') {
                return false;
            }
            let stor = type === 'session' ? window.sessionStorage : window.localStorage;
            stor.removeItem(key);
            return this;
        },
        
        clear: function (type = 'local') {
            let stor = type === 'session' ? window.sessionStorage : window.localStorage;
            stor.clear();
            return this;
        }
    };

    const optObserve = [
        {
            attr: 'deep',
            prop: 'deep',
            value: {
                enable: false,
                include: [],
                exclude: [],
            },
        },
        {
            attr: 'filter',
            prop: 'filter',
            value: null,
        },
        {
            attr: 'tpyes',
            prop: 'tpyes',
            value: ['Object', 'Array', 'Function'],
        },
        {
            attr: 'accept',
            prop: 'accept',
            value: true,
        },
        {
            attr: 'lenient',
            prop: 'lenient',
            value: true,
        },
        {
            attr: 'once',
            prop: 'once',
            value: false,
        },
        {
            attr: 'methods',
            prop: 'methods',
            value: ['set', 'delete'],
        },
        {
            attr: 'on-added',
            prop: 'onAdded',
            value: null,
        },
        {
            attr: 'on-edited',
            prop: 'onEdited',
            value: null,
        },
        {
            attr: 'on-set',
            prop: 'onSet',
            value: null,
        },
        {
            attr: 'on-deleted',
            prop: 'onDeleted',
            value: null,
        },
        {
            attr: 'on-crud',
            prop: 'onCrud',
            value: null,
        },
        {
            attr: 'on-new',
            prop: 'onNew',
            value: null,
        },
        {
            attr: 'on-applied',
            prop: 'onApplied',
            value: null,
        },
        {
            attr: 'on-trigger',
            prop: 'onTrigger',
            value: null,
        },
        {
            attr: 'on-completed',
            prop: 'onCompleted',
            value: null,
        },
        ...optBase
    ];

    const deepEqual = (a, b) => {
        if (a === b)
            return true;
        let typeA = getDataType(a), typeB = getDataType(b);
        if (typeA === typeB && typeA === 'Object') {
            let getStr = (data) => {
                let cache = new Set();
                return JSON.stringify(data, (key, val) => {
                    if (typeof val === 'object' && val !== null) {
                        if (cache.has(val))
                            return;
                        cache.add(val);
                    }
                    return val;
                });
            };
            return getStr(a) === getStr(b);
        }
        else {
            return false;
        }
    };

    const isProxy = (obj) => obj?._isProxy === true;

    const unique = (data, prop) => {
        let result;
        if (!isEmpty(data)) {
            result = [...new Set(data)];
            if (typeof result[0] === 'object' && prop) {
                let map = new Map();
                for (let k of result) {
                    !map.has(k[prop]) && map.set(k[prop], k);
                }
                result = [...map.values()];
            }
        }
        else {
            result = [...data];
        }
        return result;
    };

    const plan = {
        handle: (name, type, cb) => {
            let nameArr = [];
            if (type === 'String') {
                name = trim(name);
                nameArr = name.includes(',') ? name.split(',') : name.split(' ');
            }
            else if (type === 'Array') {
                nameArr = name.map((k) => trim(k));
            }
            if (nameArr.length > 0) {
                for (let k of nameArr) {
                    cb(k);
                }
            }
        },
        
        add: function (name, instance, content) {
            let nameType = getDataType(name), handle = (str) => {
                if (!instance.plans.hasOwnProperty(str)) {
                    instance.plans[str] = [];
                }
                let newValue = content.toString().replace(/\s/g, '').replace(/\;/g, '').match(/{(\S*)}/), oldValue = instance.plans[str].toString().replace(/\s/g, '').replace(/\;/g, '');
                newValue && !oldValue.includes(newValue[1]) ? instance.plans[str].push(content) : null;
            };
            this.handle(name, nameType, (item) => handle(item));
            return this;
        },
        
        remove: function (name, instance, content) {
            let nameType = getDataType(name), handle = (str) => {
                if (!instance.plans.hasOwnProperty(str)) {
                    return console.warn(`The ${str} event is invalid or unusable!`);
                }
                if (!content) {
                    delete instance.plans[str];
                }
                else {
                    let index = instance.plans[str].findIndex((k) => k === content);
                    if (index < 0) {
                        return console.warn(`The ${str} event is not bound!`);
                    }
                    instance.plans[str].splice(index, 1);
                    instance.plans[str].length === 0 ? delete instance.plans[str] : null;
                }
            };
            this.handle(name, nameType, (item) => handle(item));
            return this;
        },
        
        do: function (name, instance, ...params) {
            let nameType = getDataType(name), handle = (str) => {
                if (!instance.plans.hasOwnProperty(str)) {
                    return console.warn(`The ${str} event is unregistered or unusable!`);
                }
                instance.plans[str].forEach((k) => {
                    k.call(instance, ...params);
                });
            };
            this.handle(name, nameType, (item) => handle(item));
            return this;
        }
    };

    const attrJoinVal = (attr, value, map) => {
        let item = map ? map.find((k) => k.attr === attr) : null, isFn = () => {
            let tmp = attr.trim(), condition = item ? typeof item?.value === 'function' : false;
            return (tmp.startsWith('on-') || tmp.startsWith('b4-')) || condition;
        }, addFnShell = (str) => {
            let tmp = str.trim(), result = (!(tmp.startsWith('function') || tmp.startsWith('(')) && !tmp.endsWith('}')) ? `function(){${str}}` : str;
            return result;
        }, fnVal = isFn() ? addFnShell(value) : value;
        try {
            if (item) {
                if (value === null) {
                    return { [item.prop]: item.value };
                }
                else {
                    let valType = getDataType(item.value), trim = value.trim(), trueVals = ['', '1', 'true', true], falseVals = [null, 'null', 'undefined', '0', 'false', 'NaN'];
                    return item.type === 'ignore' ? { [item.prop]: value } :
                        (valType === 'String') ? { [item.prop]: value } :
                            (valType === 'Number') ? { [item.prop]: parseFloat(value) } :
                                (valType === 'Boolean' && trueVals.includes(trim)) ? { [item.prop]: true } :
                                    (valType === 'Boolean' && falseVals.includes(trim)) ? { [item.prop]: false } :
                                        (valType === 'Object' && item.value.hasOwnProperty('enable') && trueVals.includes(trim)) ? { [item.prop]: true } :
                                            (valType === 'Object' && item.value.hasOwnProperty('enable') && item.value.hasOwnProperty('children') && trim.startsWith('[') && trim.endsWith(']')) ? { [item.prop]: { enable: true, children: parseStr({ content: `${value}`, type: 'array', catchable: true }) } } :
                                                (valType === 'Object' && value.includes(':')) ? { [item.prop]: strToJson(value) } :
                                                    parseStr({ content: `{"${item.prop}":${fnVal}}`, type: 'object', catchable: true });
                }
            }
            else {
                return value === '' ? { [attr]: '' } : parseStr({ content: `{"${attr}":${fnVal}}`, type: 'object', catchable: true });
            }
        }
        catch (e) {
            return { [attr]: value };
        }
    };

    const breakpoints = (obj, points) => {
        if (isEmpty(obj) || isEmpty(points))
            return;
        let valids = [], assign = {}, width = document.body.clientWidth, validFun = (key, value) => {
            let _key = ~~key;
            if (_key === 0) {
                let tmp = key.split('-')[1];
                if (key.startsWith('screen')) {
                    let cond = (orca.screen === tmp) ||
                        (tmp === 'dt' && ['lg', 'xl', 'xxl', 'dt'].includes(orca.screen)) ||
                        (tmp === 'hh' && ['xxs', 'xs', 'sm', 'md', 'hh'].includes(orca.screen)) ||
                        (tmp === 'tb' && ['xs', 'sm', 'md', 'tb'].includes(orca.screen)) ? true : false;
                    cond && valids.push(value);
                }
                else if (key.startsWith('width')) {
                    ~~tmp <= width && valids.push(value);
                }
                else if (key.startsWith('destop')) {
                    JSON.parse(tmp) !== orca.isTouchScr && valids.push(value);
                }
            }
            else {
                _key <= width && valids.push(value);
            }
        };
        for (let k in points) {
            if (points.hasOwnProperty(k)) {
                Reflect.deleteProperty(points[k], 'breakpoints');
                validFun(k, points[k]);
            }
        }
        if (!valids.length)
            return;
        assign = Object.assign({}, ...valids);
        extend({ target: obj, source: assign });
    };

    const storeNode = (el) => {
        let target = getEl(el), result = null;
        if (target) {
            !target.hasOwnProperty('orca') && (target.orca = {});
            result = {
                addModule: (key) => {
                    if (!key)
                        return;
                    if (!target.orca.hasOwnProperty('modules')) {
                        target.orca.modules = {};
                    }
                    if (target.orca.modules[key])
                        return;
                    target.orca.modules[key] = true;
                    return target;
                },
                removeModule: (key) => {
                    if (!key)
                        return;
                    delete target.orca.modules[key];
                    return target;
                },
                addData: (key, value) => {
                    if (!key)
                        return;
                    target.orca[key] = value;
                    return target;
                },
                removeData: (key) => {
                    if (!key)
                        return;
                    delete target.orca[key];
                    return target;
                }
            };
        }
        return result;
    };

    const keyCond = (key) => {
        return !/^(stor-keys|ins-name|stor-name|storKeys|insName|storName|on-|b4-|on[A-Z]|b4[A-Z])/.test(key);
    };

    const spreadBool = (host, params) => {
        let result = host, hostType = getDataType(host), paramsType = getDataType(params);
        if (paramsType === 'Object') {
            if (hostType === 'Boolean') {
                Reflect.deleteProperty(params, 'enable');
                result = { enable: host, ...params };
            }
            else if (hostType === 'Object') {
                if (host.hasOwnProperty('enable')) {
                    host = Object.assign({}, params, host);
                }
                else {
                    for (let k in params) {
                        if (params.hasOwnProperty(k) && host.hasOwnProperty(k)) {
                            host[k] = spreadBool(host[k], params[k]);
                        }
                    }
                }
            }
        }
        return result;
    };

    const contains = (child, parent) => {
        let childEl = getEl(child), result = false;
        if (!childEl)
            return result;
        if (Array.isArray(parent)) {
            for (let k of parent) {
                let parentEl = getEl(k);
                if (!parentEl)
                    continue;
                if (parentEl.contains(childEl)) {
                    result = true;
                    break;
                }
            }
        }
        else {
            let parentEl = getEl(parent);
            result = parentEl && parentEl.contains(childEl) ? true : false;
        }
        return result;
    };

    const getRtl = () => {
        if (!orca.hasOwnProperty(orca.rtl)) {
            let tmp = getComputedVar(`--${orca.prefix}dir-coef`);
            orca.rtl = tmp == '-1' ? true : false;
        }
        return orca.rtl;
    };

    class ModBase {
        targetEl;
        targetData;
        options;
        destroyed;
        timestamp;
        renderCount;
        respSource;
        initialized;
        moduleName;
        dftOpts;
        rawOpts;
        rawHtml;
        rawEl;
        tplStr;
        tplEng;
        initCount;
        handleEls;
        isRtl;
        constructor() {
            this.timestamp = Date.now();
            this.respSource = null;
            this.initialized = false;
            this.initCount = 0;
            this.renderCount = 0;
            this.handleEls = [];
            
            this.targetEl = null;
            
            this.targetData = null;
            
            this.rawOpts = {};
            this.dftOpts = {};
            this.options = {};
            this.rawHtml = '';
            this.rawEl = null;
            
            this.destroyed = false;
            this.moduleName = this.constructor.name.toLowerCase();
            this.tplStr = '';
            this.tplEng = null;
        }
        
        getOptsFromMap(map) {
            let options = {};
            for (let k of map) {
                options[k.prop] = k.value;
            }
            return options;
        }
        
        isComp(elem) {
            return elem.getAttribute(orca.alias) === 'slot-host';
        }
        
        getElOptsMap(elem) {
            if (isEmpty(elem)) {
                return { el: null, attr: {} };
            }
            else {
                let isComp = this.isComp(elem), el = isComp ? elem.parentNode : elem, attr = isComp ? 'initiated' : `oc-${this.moduleName}`;
                return { el, attr };
            }
        }
        
        mergeOpts({ source = {}, map = [], el = null, component = false }) {
            let target = getEl(el), elMap = this.getElOptsMap(target), options = deepClone(this.getOptsFromMap(map));
            this.rawOpts = deepClone(options);
            !isEmpty(config.lang[this.moduleName]) && (options.lang = extend({ target: deepClone(config.lang[this.moduleName]), source: options.lang }));
            extend({ target: options, source: config[this.moduleName] || {} });
            extend({ target: options, source, host: elMap.el, attr: elMap.attr });
            component ? extend({ target: options, source: this.mergeCompAttrs(target, map) }) : null;
            this.dftOpts = deepClone(options);
            return options;
        }
        
        mergeCompAttrs(elem, map) {
            let options = {};
            if (this.isComp(elem)) {
                let target = elem.parentNode, attributes = target?.attributes;
                if (!target || target.nodeName.toLowerCase() !== `oc-${this.moduleName}` || !attributes)
                    return {};
                for (let k of attributes) {
                    let item = map.find((i) => i.attr === k.name);
                    if (item) {
                        
                        let keyVal = attrJoinVal(item.attr, k.value, [item]);
                        Object.assign(options, keyVal);
                    }
                }
            }
            return options;
        }
        
        getOptsAttr(elem) {
            return elem.nodeName === `OC-${this.moduleName.toUpperCase()}` ? 'options' : `oc-${this.moduleName}`;
        }
        
        getStrFromContent(str) {
            let el = getEl(str);
            return el ? el.innerHTML : str;
        }
        
        revertHtml(elem) {
            this.rawHtml ? elem.innerHTML = this.rawHtml : '';
            elem.children.length === 1 && (this.rawEl = elem.children[0]);
        }
        replaceMult(str = '', arr, opts = {}) {
            let options = Object.assign({ ignore: true, nodename: 'i' }, opts), regx = new RegExp(`(${arr.join('|')})`, `g${options.ignore ? 'i' : ''}`), tmp = `<${options.nodename} ${orca.alias}="mark"${options.classes ? ' class="' + options.classes + '"' : ''}>$1</${options.nodename}>`;
            return (str + '').replace(regx, tmp);
            
        }
        parseLayout(host = this.targetEl, template = '', map = {}) {
            let target = getEl(host), holder = createEl('i', { [orca.alias]: 'holder' }), gap = createEl('i', { [orca.alias]: 'gap' }), condition = (key) => key === 'holder' ? holder.cloneNode(true) : key === 'gap' ? gap.cloneNode(true) : map[key], getNodes = (str) => str.split('|').map(condition).filter(Boolean);
            if (!target || !template || isEmpty(map))
                return;
            if (template.includes('(') && template.includes(')')) {
                let startIdx = template.indexOf('('), endIdx = template.indexOf(')'), strL = template.slice(0, startIdx), strC = template.slice(startIdx + 1, endIdx), strR = template.slice(endIdx + 1), nodesL = getNodes(strL), nodesC = getNodes(strC), nodesR = getNodes(strR);
                nodesL.length && target.append(...nodesL);
                if (map.group) {
                    target.appendChild(map.group);
                    nodesC.length && map.group.append(...nodesC);
                }
                nodesR.length && target.append(...nodesR);
            }
            else {
                let nodes = getNodes(template);
                
                target.append(...nodes);
            }
        }
        
        updateOpts(spread) {
            this.optsMergeStorage && this.optsMergeStorage();
            !isEmpty(this.options.breakpoints) ? breakpoints(this.options, this.options.breakpoints) : null;
            if (Array.isArray(spread) && spread.length > 0) {
                let obj = {};
                for (let k of spread) {
                    obj[k] = this.rawOpts[k];
                }
                spreadBool(this.options, obj);
            }
        }
        
        getStorageKeys() {
            let result = [];
            if (Array.isArray(this.options.storKeys) && this.options.storKeys.length > 0) {
                result = this.options.storKeys;
            }
            else {
                result = Object.keys(this.options).filter((k) => keyCond(k));
            }
            return result;
        }
        
        single2Els(data, parent) {
            let result = [];
            if (data) {
                let dataType = getDataType(data);
                if (dataType === 'Array') {
                    result = data;
                }
                else if (dataType.includes('HTML')) {
                    result.push(data);
                }
                else {
                    result = getEls(data, parent);
                }
            }
            return result.filter(Boolean);
        }
        
        useTpl() {
            let tplEl = getEl(this.options.tplStr);
            this.tplEng = this.options.tplEng || renderTpl;
            this.tplStr = tplEl?.innerHTML || this.options.tplStr;
        }
        getTplcont(data, str = this.tplStr, eng = this.tplEng) {
            let tmp = eng || renderTpl;
            return tmp.name === 'template' ? tmp(this.tplStr)(data) : tmp(str, data);
        }
        
        
        useHandle(target) {
            return this.handleEls.length && contains(target, this.handleEls);
        }
        
        ready({ type = 'node', options = {}, maps = [], host, component = false, spread = [], }) {
            getDataType(host); let moreParams = {};
            this.propsMap = maps;
            if (type === 'node') {
                this.targetEl = getEl(host);
                if (this.targetEl) {
                    storeNode(this.targetEl)?.addModule(this.moduleName);
                    moreParams = {
                        el: this.targetEl,
                        component,
                    };
                    this.rawHtml = this.targetEl.innerHTML;
                    this.targetEl.children.length === 1 && (this.rawEl = this.targetEl.children[0]);
                    this.compAttrs = [];
                }
            }
            else {
                type === 'data' && (this.targetData = host);
            }
            this.options = this.mergeOpts({
                source: options,
                map: this.propsMap,
                ...moreParams,
            });
            this.storKeys = this.getStorageKeys();
            this.createProxy && this.createProxy();
            this.plans = {};
            instance.push(this, this.options.insName, this.moduleName);
            this.on('initiate', () => {
                this.destroyed = false;
                this.updateOpts(spread);
                this.targetEl && this.targetEl.classList.add(`${orca.prefix}initiated`);
                this.options.hasOwnProperty('tplStr') && this.useTpl();
            });
            this.on('initiated', () => {
                this.initialized = true;
                this.initCount++;
            });
            this.on('destroyed', () => {
                this.clearCache && this.clearCache();
                this.destroyed = true;
            });
        }
        moreExceed({ data, source, sliced = true, min = this.options.min, max = this.options.max }) {
            return new Promise((resolve, reject) => {
                let curLen = source.length, newLen = data.length, totalLen = curLen + newLen, param = { min, max, cur: curLen, val: newLen };
                if (max && totalLen > max) {
                    this.listen({ name: 'tooMany', params: [param] });
                    let tmp = max - curLen;
                    if (!tmp) {
                        reject();
                        console.warn(`The maximum quantity (${max}) has been reached, no more new data can be added!`);
                    }
                    else {
                        if (sliced) {
                            resolve(data.slice(0, tmp));
                            console.warn('The amount of newly added data is too much, only part of it has been added!');
                        }
                        else {
                            reject();
                            console.warn('The amount of newly added data is too much, further additions have been prevented!');
                        }
                    }
                }
                else if (totalLen < min) {
                    console.warn('The amount of newly added data is too little, please continue adding!');
                    this.listen({ name: 'tooFew', params: [param] });
                    resolve(null);
                }
                else {
                    resolve(null);
                }
            });
        }
        lessExceed({ data, source, sliced = true, min = this.options.min, max = this.options.max }) {
            return new Promise((resolve, reject) => {
                let curLen = source.length, newLen = data.length, totalLen = curLen - newLen, param = { min, max, cur: curLen, val: newLen };
                if (max && totalLen > max) {
                    console.warn('The current data is still too much, please continue deleting!');
                    this.listen({ name: 'tooMany', params: [param] });
                    resolve(null);
                }
                else if (totalLen < min) {
                    this.listen({ name: 'tooFew', params: [param] });
                    let tmp = curLen - min;
                    if (!tmp) {
                        reject();
                        console.warn(`The minimum quantity (${min}) has been reached, no more data can be deleted!`);
                    }
                    else {
                        if (sliced) {
                            resolve(data.slice(0, tmp));
                            console.warn('The amount of deleted data is too much, only part of it has been deleted!');
                        }
                        else {
                            reject();
                            console.warn('The amount of deleted data is too much, further deletion has been prevented!');
                        }
                    }
                }
                else {
                    resolve(null);
                }
            });
        }
        getDirRtl() {
            if (this.options.rtl) {
                this.isRtl = true;
                return;
            }
            if (!this.targetEl)
                return;
            let rtlAttr = this.targetEl.getAttribute('dir');
            if (rtlAttr === 'rtl') {
                this.isRtl = true;
                return;
            }
            this.isRtl = getRtl();
        }
        getRtlCoef() {
            return (this.options.axis === 'x' && this.isRtl ? -1 : 1);
        }
        lock(cb) {
            if (this.destroyed || !this.targetEl)
                return;
            this.targetEl.toggleAttribute('inert', true);
            this.destroyed = true;
            this.listen({ name: 'locked', cb });
            return this;
        }
        unlock(cb) {
            if (!this.targetEl)
                return;
            this.targetEl.toggleAttribute('inert', false);
            this.destroyed = false;
            this.listen({ name: 'unlocked', cb });
            return this;
        }
        
        async reset(cb) {
            this.options = deepClone(this.dftOpts);
            this.revertHtml && this.targetEl && this.revertHtml(this.targetEl);
            await this.init();
            this.clearCache && this.clearCache();
            this.listen && this.listen({ name: 'reset', cb });
            return this;
        }
        
        async update(settings, cb) {
            if (this.destroyed)
                return this;
            if (!isEmpty(settings)) {
                this.updateCache && this.updateCache(settings);
                extend({ target: this.options, source: settings });
                await this.init();
            }
            this.listen && this.listen({ name: 'updated', cb, params: [settings] });
            return this;
        }
        
        async updateCont(data, cb) {
            if (this.destroyed)
                return this;
            if (this.options.hasOwnProperty('content') && !isNull(data)) {
                this.options.content = data;
                await this.init();
                this.updateCache({ content: data });
                this.listen({ name: 'updatedCont', cb, params: [data] });
                return this;
            }
        }
        
        async init(cb) { }
        
        destroy(cb) { }
    }

    class ModBaseListen extends ModBase {
        
        plans = {};
        
        listen({ name, params = [], cb } = {}) {
            name && this.plans.hasOwnProperty(name) ? this.emit(name, ...params) : null;
            name && this.options[`on${startUpper(name)}`] && this.options[`on${startUpper(name)}`].call(this, ...params);
            cb && cb.call(this, ...params);
        }
        
        on(type, handler) {
            plan.add(type, this, handler);
            return this;
        }
        
        emit(type, ...params) {
            plan.do(type, this, ...params);
            return this;
        }
        
        off(type, handler) {
            plan.remove(type, this, handler);
            return this;
        }
    }

    class Observe extends ModBaseListen {
        options = {};
        dataType;
        completedCount;
        reactCount;
        proxys;
        fullMethods;
        methods;
        output;
        canProxy;
        hasProp;
        canDeep;
        canRun;
        keys;
        types;
        proxy;
        hostProxy;
        static hostType = 'data';
        static optMaps = optObserve;
        constructor(data, options = {}, initial = true) {
            super();
            super.ready({
                type: Observe.hostType,
                options,
                maps: Observe.optMaps,
                host: data,
                spread: ['deep'],
            });
            this.proxys = [];
            this.targetData && initial && this.init();
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            
            this.completedCount = 0;
            
            this.reactCount = 0;
            this.canProxy = (type, value) => (this.types.includes(type) && !isProxy(value));
            this.hasProp = (key) => (isEmpty(this.options.deep.include) || this.options.deep.include.includes(key)) && (isEmpty(this.options.deep.exclude) || !this.options.deep.exclude.includes(key));
            this.canDeep = (type, value) => this.canProxy(type, value) && this.options.deep.enable;
            this.canRun = (key) => this.options.filter ? this.options.filter(key) : true;
            
            this.keys = { got: [], set: [], deleted: [] };
            
            this.fullMethods = {
                get: (target, key, proxy) => {
                    if (!this.canRun(key))
                        return;
                    if (key === '_isProxy')
                        return true;
                    let value = target[key], baseProps = { target, key, value, raw: value, proxy };
                    !this.keys.got.includes(key) && this.keys.got.push(key);
                    super.listen({ name: 'got', params: [{ ...baseProps, type: 'got' }] });
                    super.listen({ name: 'crud', params: [{ ...baseProps, type: 'got' }] });
                    super.listen({ name: 'trigger', params: [{ ...baseProps, type: 'got' }] });
                    return Reflect.get(target, key, proxy);
                },
                set: (target, key, value, proxy) => {
                    if (!this.canRun(key))
                        return true;
                    if (deepEqual(target[key], value) || (this.options.lenient && target[key] === value) || (!this.options.lenient && target[key] == value))
                        return true;
                    let raw = target[key], baseProps = { target, key, value, raw, proxy }, handleType = target[key] === undefined ? 'added' : 'edited';
                    value = this.deepProxy(value);
                    if (this.options.accept) {
                        Reflect.set(target, key, value);
                    }
                    !this.keys.set.includes(key) && this.keys.set.push(key);
                    super.listen({ name: 'crud', params: [{ ...baseProps, type: 'set' }] });
                    super.listen({ name: 'set', params: [{ ...baseProps, type: 'set' }] });
                    super.listen({ name: handleType, params: [{ ...baseProps, type: handleType }] });
                    super.listen({ name: 'trigger', params: [{ ...baseProps, type: 'set' }] });
                    this.reactCount++;
                    this.complete(this.reactCount);
                    return true;
                },
                delete: (target, key) => {
                    if (!this.canRun(key))
                        return true;
                    let value = target[key], baseProps = { target, key, value, raw: value };
                    if (this.options.accept) {
                        Reflect.deleteProperty(target, key);
                    }
                    !this.keys.deleted.includes(key) && this.keys.deleted.push(key);
                    super.listen({ name: 'deleted', params: [{ ...baseProps, type: 'deleted' }] });
                    super.listen({ name: 'crud', params: [{ ...baseProps, type: 'deleted' }] });
                    super.listen({ name: 'trigger', params: [{ ...baseProps, type: 'deleted' }] });
                    this.reactCount++;
                    this.complete(this.reactCount);
                    return true;
                },
                construct: (target, args, proxy) => {
                    let baseProps = { target, args, proxy };
                    super.listen({ name: 'constructed', params: [{ ...baseProps, type: 'constructed' }] });
                    super.listen({ name: 'trigger', params: [{ ...baseProps, type: 'constructed' }] });
                    this.reactCount++;
                    this.complete(this.reactCount);
                    return Reflect.construct(target, args, proxy);
                },
                apply: (target, pointer, args) => {
                    let baseProps = { target, pointer, args };
                    super.listen({ name: 'applied', params: [{ ...baseProps, type: 'applied' }] });
                    super.listen({ name: 'trigger', params: [{ ...baseProps, type: 'applied' }] });
                    this.reactCount++;
                    this.complete(this.reactCount);
                    return Reflect.apply(target, pointer, args);
                }
            };
            
            this.methods = {};
            for (let k in this.fullMethods) {
                let key = k === 'delete' ? 'deleteProperty' : k;
                this.methods[key] = this.fullMethods[k];
            }
            this.types = isEmpty(this.options.types) ? ['Object', 'Array', 'Function', 'Class'] : this.options.types;
            this.dataType = getDataType(this.targetData);
            if (!this.types.includes(this.dataType)) {
                console.warn(`The target data type should be an ${this.types.join('/')}, but failed to proxy the data!`);
                this.proxy = this.targetData;
            }
            else {
                
                this.hostProxy = this.options.deep.enable ? this.deepProxy(this.targetData) : this.addProxy(this.targetData);
                this.proxy = this.hostProxy;
            }
            super.listen({ name: 'initiated', cb });
            return this;
        }
        deepProxy(data) {
            let dateType = getDataType(data);
            if (this.canDeep(dateType, data)) {
                for (let k in data) {
                    if (!this.hasProp(k))
                        continue;
                    let val = data[k], valType = getDataType(val);
                    if (data.hasOwnProperty(k) && this.canDeep(valType, val)) {
                        data[k] = this.deepProxy(val);
                    }
                }
                return this.addProxy(data);
            }
            return data;
        }
        addProxy(obj) {
            if (obj['_isProxy']) {
                this.proxys.push(obj);
                return obj;
            }
            else {
                let revProxy = Proxy.revocable(obj, this.methods);
                this.proxys.push(revProxy);
                return revProxy.proxy;
            }
        }
        complete(nowReact) {
            setTimeout(() => {
                if (nowReact === this.reactCount) {
                    if (this.options.once && this.completedCount !== 0)
                        return;
                    for (let i in this.keys) {
                        this.keys[i] = unique(this.keys[i].filter((k) => typeof k !== 'symbol'));
                    }
                    super.listen({ name: 'completed', params: [{ count: this.completedCount, target: this.targetData, proxy: this.hostProxy, keys: this.keys, type: 'completed' }] });
                    this.completedCount++;
                    this.keys = { got: [], set: [], deleted: [] };
                }
            }, 0);
        }
        destroy() {
            this.proxys.forEach((k) => {
                k.revoke();
            });
        }
    }

    class ModBaseListenCache extends ModBaseListen {
        storKeys = [];
        storObs;
        storTmp;
        
        createProxy() {
            
            this.storTmp = {};
            
            this.storObs = new Observe(this.storTmp);
        }
        
        clearCache(cb) {
            if (this.options.storName) {
                for (let k in this.storObs.proxy) {
                    Reflect.deleteProperty(this.storObs.proxy, k);
                }
                this.listen && this.listen({ name: 'clearedCache', cb });
                this.save();
            }
            return this;
        }
        
        updateCache(value, cb) {
            if (this.options.storName && !isEmpty(value)) {
                let temp = {};
                for (let k in value) {
                    value.hasOwnProperty(k) && this.storKeys.includes(k) && (temp[k] = value[k]);
                }
                deepMerge(this.storObs.proxy, temp, {});
                this.listen && this.listen({ name: 'updatedCache', cb });
                this.save();
            }
            return this;
        }
        
        optsMergeStorage() {
            if (this.options.storName) {
                let storageVal = storage.get(this.options.storName);
                if (!isEmpty(storageVal)) {
                    this.updateCache(storageVal);
                    extend({ target: this.options, source: storageVal });
                }
                else {
                    this.clearCache();
                }
            }
        }
        
        save(cb) {
            if (this.destroyed || !this.options.storName)
                return;
            let value = !isEmpty(this.storTmp) ? deepClone(this.storTmp) : {};
            storage.set(this.options.storName, value);
            this.listen && this.listen({ name: 'saved', cb, params: [value] });
            return this;
        }
    }

    const bulletTools = {
        
        getIBulletTpl: (global = {}) => {
            return `
        {{let   value = this.value?'value="'+ this.value +'"':this.label?'value="'+ this.label +'"':'',
                custom =this.custom?'<span ${orca.alias}="custom">'+this.custom+'</span>':'',
                badge = this.badge?'<oc-badge>'+this.badge+'</oc-badge>':'',
                tips =this.tips?'<i ${orca.alias}="tips">'+this.tips+'</i>':'',
                arrow=this.arrow?'<i class="'+this.arrow+'" ${orca.alias}="arrow"></i>':'',
                type = this.type || "${global.type}",
                check = this.checked && !['checkboxes','radios'].includes(type) ?'checked':'',
                name = this.name?'name="'+this.name+'"':'name="${orca.namePfx}${Date.now()}"',
                icon = this.icon?'<i ${orca.alias}="icon" class="'+this.icon+'"></i>':'',
                disk = this.disk?'<span ${orca.alias}="disk"><img src="'+this.disk+'"></span>':'',
                cube = this.cube?'<span ${orca.alias}="cube"><img src="'+this.cube+'"></span>':'',
                selected=this.selected?'selected':'',
                active=this.active?'active':'',
                disabled=this.disabled?'disabled':''; 
        /}}
        <${global.childNode}>
                    <div class="${orca.prefix}bullet" ${global.unpadded ? 'unpadded' : ''} ${global.hoverable ? 'hoverable' : ''}  ${global.multiline ? 'multiline' : ''} {{value}} {{selected}} {{active}} {{check}}  {{disabled}}>
                    {{icon}}
                    {{disk}}
                    {{cube}}
                    <div class="${orca.prefix}bullet-body">
                        {{if(type ==='checkboxes'){/}}
                            <oc-checkbox {{name}} {{this.checked?'check="ed"':''}} {{value}}>{{this.label}}</oc-checkbox>
                        {{}else if (type ==='radios'){/}}
                            <oc-radio {{name}} {{this.checked?'check="ed"':''}} {{value}}>{{this.label}}</oc-radio>
                        {{}else if(this.href){/}}
                            <a ${orca.alias}="label" href="{{this.href}}" {{this.target?'target="'+ this.target +'"':''}} {{this.rel?'rel="'+ this.rel +'"':''}}>{{this.label}}</a>
                        {{}else{/}}
                            <span ${orca.alias}="label">{{this.label}}</span>
                        {{}/}}
                    </div>
                    {{custom}}
                    {{badge}}
                    {{tips}}
                    {{arrow}}
                    </div>
                    ${global.divisible ? '<hr>' : ''}
                </${global.childNode}>
        `;
        },
        
        getBulletsTpl: function (global = {}) {
            let grid = '';
            if (global.cols > 0) {
                grid = `${orca.prefix}grid  ${orca.prefix}avg-${global.cols}`;
                grid += global.lines === 'fence' ? ` ${orca.prefix}fence` : global.lines === 'fluid' ? ` ${orca.prefix}fluid` : '';
            }
            return `
        <${global.parentNode} class="${orca.prefix}reset ${grid}">
            {{for(let k of this){/}}
                ${this.getIBulletTpl(global).replaceAll('this.', 'k.')}
            {{}/}}
        </${global.parentNode}>`;
        },
        getChildNodes: (parent) => {
            let target = getEl(parent);
            if (isEmpty(target)) {
                return [];
            }
            return getEls(`.${orca.prefix}bullet`, target);
        },
        getChecked: function (nodes) {
            let result = [];
            if (isEmpty(nodes))
                return '';
            if (nodes.length > 0) {
                if (nodes[0].querySelector('input')) {
                    for (let k of nodes) {
                        let input = k.querySelector('input');
                        input.checked && result.push(input.value);
                    }
                }
                else {
                    for (let k of nodes)
                        k.hasAttribute('checked') && result.push(k.getAttribute('value'));
                }
            }
            return result.filter(Boolean).join(',');
        },
        setChecked: function (vals, nodes) {
            let dataType = getDataType(vals), values = [];
            if (dataType === 'Array') {
                values = vals;
            }
            else if (dataType === 'String') {
                values = vals.split(',').filter(Boolean);
            }
            if (nodes.length === 0)
                return;
            if (values.length === 0) {
                for (let k of nodes) {
                    let input = k.querySelector('OC-CHECKBOX,OC-RADIO');
                    input ? input.removeAttribute('check') : k.removeAttribute('checked');
                }
            }
            else {
                let checkedItems = values.map((k) => nodes.find((i) => i?.querySelector('input')?.value == k || i.getAttribute('value') == k)).filter(Boolean);
                for (let k of nodes) {
                    let input = k.querySelector('OC-CHECKBOX,OC-RADIO');
                    if (checkedItems.includes(k)) {
                        input ? input.setAttribute('check', 'ed') : k.toggleAttribute('checked', true);
                    }
                    else {
                        input ? input.removeAttribute('check') : k.removeAttribute('checked');
                    }
                }
            }
        },
        toggleChecked: (item, els, type = 'select-single') => {
            if (!item || !type.includes('select') || isEmpty(els))
                return;
            let checked = item.hasAttribute('checked');
            type = type || 'select-single';
            if (type === 'select-single') {
                if (checked) {
                    return;
                }
                else {
                    item.toggleAttribute('checked', true);
                    els.filter((k) => k !== item && item.hasAttribute('checked')).forEach((k) => {
                        k.removeAttribute('checked');
                    });
                }
            }
            else {
                checked ? item.removeAttribute('checked') : item.toggleAttribute('checked', true);
            }
        },
        clearChecked: (els) => {
            if (isEmpty(els))
                return;
            for (let k of els) {
                let input = k.querySelector('OC-CHECKBOX,OC-RADIO');
                input ? input.removeAttribute('check') : k.removeAttribute('checked');
            }
        },
        toggleSelected(item, els) {
            if (!item || isEmpty(els))
                return;
            let selected = item.hasAttribute('selected');
            if (!selected) {
                item.toggleAttribute('selected', true);
                let other = els.find((k) => k !== item && k.hasAttribute('selected'));
                other && other.toggleAttribute('selected', false);
            }
        },
        setSelected(value, els) {
            if (!value || isEmpty(els))
                return;
            let item = els.find((k) => k.getAttribute('value') === value);
            item && this.toggleSelected(item, els);
        },
        getSelected(els) {
            if (isEmpty(els))
                return;
            let item = els.find((k) => k.hasAttribute('selected'));
            return item && item.getAttribute('value') || '';
        },
        clearSelected(els) {
            let item = els.find((k) => k.hasAttribute('selected'));
            item && item.removeAttribute('selected');
        }
    };

    const createBtns = (data, parent, settings = {}, refer) => {
        
        let target = getEl(parent), wrapEl = createEl('div', { class: `${orca.prefix}box-btns` }), map = {
            submit: {
                name: 'submit',
                label: config.lang.button.submit,
            },
            reset: {
                name: 'reset',
                label: config.lang.button.reset,
            },
            prev: {
                name: 'prev',
                label: config.lang.button.prev,
            },
            next: {
                name: 'next',
                label: config.lang.button.next,
            },
            now: {
                name: 'now',
                label: config.lang.button.now,
            },
            close: {
                name: 'close',
                label: config.lang.button.close,
            },
            cancel: {
                name: 'cancel',
                label: config.lang.button.cancel,
            },
            clear: {
                name: 'clear',
                label: config.lang.button.clear,
            },
            confirm: {
                name: 'confirm',
                label: config.lang.button.confirm,
            },
        }, keys = Object.keys(map), render = (props) => {
            let dft = {
                label: Object.keys(config.lang.button).includes(props.name) && !props.label ? config.lang.button[props.name] : (props.label || config.lang.button.default)
            }, setProp = (type) => { type && !isNull(props[type]) && (dft[type] = props[type]); }, propArr = ['type', 'theme', 'size', 'width', 'shape', 'check', 'icon', 'tail', 'disk', 'cube', 'tips', 'mean', 'disabled', 'shaded', 'grad'];
            for (let k of propArr)
                setProp(k);
            props.name && (dft[orca.alias] = props.name);
            props.hasOwnProperty('badge') && (dft.badge = props.badge);
            !isNull(props.href) && (dft.href = props.href);
            props.target && !isNull(props.href) && (dft.target = props.target);
            props.rel && !isNull(props.href) && (dft.rel = props.rel);
            
            props.el = createEl('oc-btn', Object.assign({ ...settings }, dft, props.attrs));
            !isEmpty(props.classes) && (classes(props.el).add(props.classes));
            !isEmpty(props.styles) && (props.el.style.cssText += props.styles);
        };
        data.forEach((k, i) => {
            let type = k?.name || k, result = keys.includes(type) ? extend({ target: { ...map[type] }, source: k.hasOwnProperty('name') ? k : {} }) : k;
            render(result);
            wrapEl.appendChild(result.el);
            result.action && (refer ? result.action.call(refer, result) : result.action(result));
            data[i] = result;
        });
        if (target) {
            let tmp = target.querySelector(`.${orca.prefix}box-btns`);
            tmp && tmp.remove();
            target.appendChild(wrapEl);
        }
        return wrapEl;
    };

    const createFooter = ({ nodeName = 'div', layout = 'center', attrs, tips = false, divider = false, padding = false, children = [] }, parent, refer) => {
        
        divider = spreadBool(divider, {});
        padding = spreadBool(padding, {});
        tips = spreadBool(tips, { html: config.lang.placehold.tips });
        let target = getEl(parent), outer, footerEl = createEl(nodeName, Object.assign({ class: `${orca.prefix}bubble-footer`, layout }, attrs)), dividerEl = divider.enable ? createEl(divider.nodeName || 'oc-line', Object.assign({ [orca.alias]: 'divider' }, divider.attrs)) : null, paddingEl = padding.enable ? createEl(padding.nodeName || 'div', Object.assign({ class: `${orca.prefix}p`, [orca.alias]: 'padding' }, padding.attrs)) : null, tipsEl = tips.enable ? createEl(tips.nodeName || 'div', Object.assign({ [orca.alias]: 'tips' }, tips.attrs), tips.html) : null, wrapEl = createEl('div', { class: `${orca.prefix}bubble-footer-wrap` });
        footerEl.setAttribute('layout', layout);
        dividerEl && footerEl.appendChild(dividerEl);
        paddingEl ? (footerEl.appendChild(paddingEl), outer = paddingEl) : (outer = footerEl);
        outer.appendChild(wrapEl);
        if (children.length > 0) {
            createBtns(children, wrapEl, layout === 'plain' ? { type: 'plain' } : {}, refer);
        }
        tipsEl && wrapEl.appendChild(tipsEl);
        if (target) {
            let tmp = target.querySelector(`.${orca.prefix}bubble-footer`);
            tmp && tmp.remove();
            target.appendChild(footerEl);
        }
        return footerEl;
    };

    const createTools = (data, parent, refer) => {
        
        let target = getEl(parent), toolsEl = createEl('span', { class: `${orca.prefix}box-tools` }), tipsIns, map = {
            add: {
                name: 'add',
                icon: `${orca.prefix}icon-plus`,
            },
            close: {
                name: 'close',
                icon: `${orca.prefix}icon-close`,
            },
            remove: {
                name: 'remove',
                icon: `${orca.prefix}icon-trash`,
            },
            edit: {
                name: 'edit',
                icon: `${orca.prefix}icon-edit`,
            },
            update: {
                name: 'update',
                icon: `${orca.prefix}icon-refresh`,
            },
            move: {
                name: 'move',
                icon: `${orca.prefix}icon-drag`,
            },
            file: {
                name: 'file',
                icon: `${orca.prefix}icon-file`,
            },
            folder: {
                name: 'folder',
                icon: `${orca.prefix}icon-folder`,
            },
            toggle: {
                name: 'toggle',
                icon: `${orca.prefix}icon-max`,
                swap: `${orca.prefix}icon-min`,
            },
            enlarge: {
                name: 'enlarge',
                icon: `${orca.prefix}icon-expand`,
                swap: `${orca.prefix}icon-collapse`,
            },
            widen: {
                name: 'widen',
                icon: `${orca.prefix}icon-expand-h`,
                swap: `${orca.prefix}icon-collapse-h`,
            },
            heighten: {
                name: 'heighten',
                icon: `${orca.prefix}icon-expand-v`,
                swap: `${orca.prefix}icon-collapse-v`,
            }
        }, keys = Object.keys(map), renderFn = (props) => {
            let dft = {}, arrow = props.extendable ? `<i ${orca.alias}="arrow"></i>` : '', iconStr = props.icon ? `<i class="${props.icon}" ${orca.alias}="icon"></i>` : '', diskStr = props.disk ? `<i ${orca.alias}="disk"><img src="${props.disk}"/></i>` : '', cubeStr = props.cube ? `<i ${orca.alias}="cube"><img src="${props.cube}"/></i>` : '', imageStr = props.image ? `<i ${orca.alias}="image"><img src="${props.image}"/></i>` : '', label = props.label ? `<i ${orca.alias}="label">${props.label}</i>` : '', html = iconStr + diskStr + cubeStr + imageStr + label + arrow;
            props.name && (dft[orca.alias] = props.name);
            props.title && (dft.title = props.title);
            props.focusable && (dft.tabindex = 1);
            props.wrapEl = createEl(props.nodeName || 'span', Object.assign(dft, props.attrs), html);
            props.iconEl = props.wrapEl.querySelector(`[${orca.alias}="icon"]`);
            props.cubeEl = props.wrapEl.querySelector(`[${orca.alias}="cube"]`);
            props.diskEl = props.wrapEl.querySelector(`[${orca.alias}="disk"]`);
            props.imageEl = props.wrapEl.querySelector(`[${orca.alias}="image"]`);
            props.labelEl = props.wrapEl.querySelector(`[${orca.alias}="label"]`);
            !isEmpty(props.classes) && classes(props.wrapEl).add(props.classes);
            !isEmpty(props.styles) && (props.wrapEl.style.cssText += props.styles);
        };
        data.forEach((k, i) => {
            let type = k?.name || k, result = keys.includes(type) ? Object.assign(map[type], k.name ? k : {}) : k;
            renderFn(result);
            toolsEl.appendChild(result.wrapEl);
            result.action && (refer ? result.action.call(refer, result) : result.action(result));
            data[i] = result;
        });
        if (target) {
            let tmp = target.querySelector(`.${orca.prefix}box-tools`);
            tmp && tmp.remove();
            target.appendChild(toolsEl);
        }
        let needTooltip = data.find((k) => k.tips);
        if (needTooltip) {
            toolsEl.tooltipTgr = 'pointermove';
            toolsEl.tooltipEvt = function () {
                let item = data.find((k) => k.wrapEl === this);
                if (item) {
                    tipsIns.replaceCont(item.tips);
                    tipsIns.transfer(this);
                }
            };
            let loadModule = async () => {
                let Mod = await Promise.resolve().then(function () { return Tooltip$1; });
                tipsIns = new Mod.default(needTooltip.wrapEl, {
                    content: '',
                    size: '',
                    placement: 'top',
                });
                for (let k of data) {
                    if (!k.tips)
                        continue;
                    k.wrapEl.addEventListener(toolsEl.tooltipTgr, toolsEl.tooltipEvt, false);
                }
            };
            loadModule();
        }
        return toolsEl;
    };

    const clampVal = ({ val = 0, min = 0, max = 100 }) => {
        let tmpVal = toNumber(val), tmpMin = toNumber(min), tmpMax = toNumber(max), result = (!['', null, undefined].includes(min) && tmpVal < tmpMin) ? tmpMin :
            (!['', null, undefined].includes(max) && tmpVal > tmpMax) ? tmpMax : tmpVal;
        return result;
    };

    const isCompField = (type) => !type || typeof type !== 'string' ? false : fieldTypes.includes(type.toLowerCase().replace('oc-', ''));

    const fieldTools = {
        getType: (target) => {
            let targetEl = getEl(target), result = '';
            if (!targetEl) {
                return result;
            }
            result = (['TEXTAREA', 'SELECT', 'INPUT'].includes(targetEl.nodeName)) ? 'native' :
                isCompField(targetEl.nodeName) && targetEl[orca.compSign] ? 'comp' : 'other';
            return result;
        },
        
        getVals: function ({ target, format = '', parent, separator = ',', child, key }) {
            let targetEl = getEl(target), targetType = this.getType(targetEl), values = [], none = format === 'array' ? [] : format === 'string' ? '' : null, result;
            try {
                if (targetEl) {
                    let nodeName = targetEl.nodeName, fieldType = targetEl.type, fields = [], parentEl = getEl(parent) || targetEl.closest('form') || document.body;
                    if (targetType === 'comp') {
                        if (['OC-CHECKBOX', 'OC-RADIO'].includes(nodeName)) {
                            fields = [...parentEl.querySelectorAll(`[name="${targetEl.name}"]`)].filter((k) => k[orca.compSign]);
                            for (let k of fields)
                                k.checked && k.value && values.push(k.value);
                            result = format === 'array' ? values : values.join(separator);
                        }
                        else {
                            let tmp = targetEl.value;
                            result = format === 'array' ? tmp.split(separator) : tmp;
                        }
                    }
                    else if (targetType === 'native') {
                        if (nodeName === 'SELECT') {
                            for (let k of [...targetEl.options]) {
                                k.selected && values.push(k.value || k.getAttribute('label') || '');
                            }
                        }
                        else if (fieldType === 'file') {
                            values = [...targetEl.files];
                        }
                        else if (['checkbox', 'radio'].includes(fieldType)) {
                            fields = [...parentEl.querySelectorAll(`[name="${targetEl.name}"]`)];
                            for (let k of fields)
                                k.checked && k.value && values.push(k.value);
                        }
                        else {
                            values = targetEl.value ? [targetEl.value] : [];
                        }
                        if (format === 'string') {
                            result = (fieldType === 'file') ? values.map((k) => k.name.trim()).join(separator) : values.join(separator);
                        }
                        else if (format === 'array') {
                            result = values;
                        }
                        else {
                            result = (nodeName === 'SELECT' && targetEl.multiple) || (fieldType === 'checkbox' && fields.length > 1) || (fieldType === 'file' && targetEl.multiple) ? values : (values[0] || '');
                        }
                    }
                    else {
                        let childEl = getEl(child, targetEl), hostEl = childEl || targetEl, tmp = key ? hostEl.getAttribute(key) : hostEl.textContent;
                        result = format === 'array' ? tmp.split(separator) : tmp;
                    }
                    return result;
                }
            }
            catch (err) {
                console.warn(err);
                return none;
            }
        },
        
        setVals: function ({ target, value, parent, separator = ',', child, key = '' }) {
            let targetEl = getEl(target), values = isEmpty(value) ? [] : valToArr(value, separator).map((k) => k + ''), parentEl = getEl(parent) || targetEl?.closest('form') || document.body, fields = [];
            if (targetEl) {
                let targetType = this.getType(targetEl);
                if (targetType === 'comp') {
                    let value = values.join(separator);
                    if (['OC-CHECKBOXES', 'OC-RADIOS'].includes(targetEl.nodeName)) {
                        targetEl.setAttribute('checked', value);
                    }
                    else if (['OC-CHECKBOX', 'OC-RADIO'].includes(targetEl.nodeName)) {
                        let fields = [...parentEl.querySelectorAll(`[name="${targetEl.name}"]`)].filter((k) => k[orca.compSign] && k.getAttribute('value'));
                        for (let k of fields) {
                            values.includes(k.value) ? k.setAttribute('check', 'ed') : k.removeAttribute('check');
                        }
                    }
                    else {
                        targetEl.setAttribute('value', value);
                    }
                }
                else if (targetType === 'native') {
                    let nodeName = targetEl.nodeName, fieldType = targetEl.type;
                    if (nodeName === 'SELECT') {
                        let options = [...targetEl.options], tmp = values.map((k) => k.toString());
                        options.forEach((k) => {
                            let value = k.value || k.getAttribute('label') || '';
                            k.selected = tmp.includes(value) ? true : false;
                        });
                        fields = [targetEl];
                    }
                    else if (['checkbox', 'radio'].includes(fieldType)) {
                        fields = [...parentEl.querySelectorAll(`[name="${targetEl.name}"]`)].filter((k) => k.getAttribute('value'));
                        let tmp = values.map((k) => k.toString());
                        fields.forEach((k) => {
                            k.checked = tmp.includes(k.value) ? true : false;
                        });
                    }
                    else if (fieldType === 'file') {
                        targetEl.value = '';
                        console.warn('The field.files property cannot be changed through scripts,this operation is performed by resetting!');
                    }
                    else if (fieldType === 'number') {
                        targetEl.value = clampVal({
                            val: values[0] || 0,
                            min: targetEl.min,
                            max: targetEl.max
                        });
                    }
                    else if (fieldType === 'range') {
                        targetEl.value = values[0] || targetEl.min || 0;
                    }
                    else {
                        targetEl.value = values.filter(Boolean).join();
                    }
                }
                else {
                    let childEl = getEl(child, targetEl), hostEl = childEl || targetEl;
                    key ? hostEl.setAttribute(key, value) : hostEl.innerHTML = value;
                }
            }
        },
        
        reset: function ({ target, parent, zero = false }) {
            let fieldEl = getEl(target);
            if (!fieldEl) {
                return;
            }
            let fielType = this.getType(fieldEl), type = fieldEl.type;
            if (fielType === 'native') {
                if (type?.includes('select')) {
                    [...fieldEl?.options].forEach((i) => i.selected = !zero ? i.defaultSelected : false);
                }
                else if (type === 'checkbox' || type === 'radio') {
                    let parentEl = getEl(parent) || fieldEl?.closest('form') || document.body, fields = [...parentEl.querySelectorAll(`[name="${fieldEl?.name}"]`)];
                    fields.forEach((k) => {
                        k.checked = !zero ? k.defaultChecked : false;
                    });
                }
                else if (['number', 'range'].includes(type)) {
                    fieldEl.value = !zero ? fieldEl?.defaultValue : (fieldEl?.min || 0);
                }
                else {
                    fieldEl.value = !zero ? fieldEl?.defaultValue : '';
                }
            }
            else if (fielType === 'comp') {
                zero ? fieldEl.clear() : fieldEl.reset();
            }
            else {
                if (zero && fieldEl.clear) {
                    fieldEl.clear();
                }
                else if (!zero && fieldEl.reset) {
                    fieldEl.reset();
                }
            }
        }
    };

    const tplToEl = (tpl) => {
        tpl = tpl.trim().replaceAll('&lt;', '<').replaceAll('&gt;', '>');
        if (!tpl)
            return null;
        let node = '';
        if (tpl.startsWith('<tr') || tpl.startsWith('<TR')) {
            node = 'tr';
            tpl = `<table><tbody>${tpl}</tbody></table>`;
        }
        else if (tpl.startsWith('<td') || tpl.startsWith('<TD')) {
            node = 'td';
            tpl = `<table><tbody><tr>${tpl}</tr></tbody></table>`;
        }
        let tplNode = createEl('TEMPLATE', '', tpl), clone = tplNode.content.cloneNode(true), elem = node ? clone.querySelector(node) : clone.firstElementChild;
        return elem || null;
    };

    const optMessage = [
        {
            attr: 'heading',
            prop: 'heading',
            value: '',
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'placement',
            prop: 'placement',
            value: 'center-top',
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'status',
            prop: 'status',
            value: 'info',
        },
        {
            attr: 'delay',
            prop: 'delay',
            value: 3000,
        },
        {
            attr: 'progress',
            prop: 'progress',
            value: true,
        },
        {
            attr: 'closable',
            prop: 'closable',
            value: true,
        },
        {
            attr: 'manual',
            prop: 'manual',
            value: false,
        },
        {
            attr: 'eager',
            prop: 'eager',
            value: false,
        },
        {
            attr: 'icon-show',
            prop: 'iconShow',
            value: false,
        },
        {
            attr: 'notable',
            prop: 'notable',
            value: false,
        },
        {
            attr: 'z-index',
            prop: 'zIndex',
            value: 0,
        },
        {
            attr: 'on-shown',
            prop: 'onShown',
            value: null,
        },
        {
            attr: 'on-hidden',
            prop: 'onHidden',
            value: null,
        },
        ...optBase
    ];

    class Message extends ModBaseListen {
        options = {};
        parentEl;
        template;
        shown;
        static hostType = 'none';
        static optMaps = optMessage;
        constructor(options, initial = true) {
            super();
            super.ready({
                options,
                type: Message.hostType,
                maps: Message.optMaps,
            });
            
            
            
            
            
            
            
            
            this.parentEl = null;
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.createParent(this.options.placement || 'center-top');
            this.createSection();
            this.shown = false;
            elState(this.parentEl).isVirtual && document.body.appendChild(this.parentEl);
            super.listen({ name: 'initiated', cb });
            this.options.eager && this.show();
            return this;
        }
        createParent = (placement) => {
            let parent = orca.messages.find((k) => k.placement === placement);
            if (!parent) {
                this.parentEl = createEl('div', { class: `${orca.prefix}message`, placement });
                this.options.classes && classes(this.parentEl).add(this.options.classes);
                orca.messages.push({ placement, el: this.parentEl });
            }
            else {
                this.parentEl = parent.el;
            }
            this.options.zIndex && (this.parentEl.style.zIndex = this.options.zIndex);
        };
        createSection() {
            this.template = `
        <oc-callout size="lg" opaque hidden content="${this.options.content === true || this.options.content === '' ? this.options.lang.content[this.options.status] : this.options.content}"
        ${this.options.notable ? 'notable' : ''}
        ${this.options.iconShow ? 'result' : ''}
        ${this.options.closable ? 'closable' : ''}
        ${this.options.status ? 'theme="' + (this.options.status || 'info') + '"' : ''}
        ${this.options.heading ? 'label="' + (this.options.heading === true ? this.options.lang.heading[this.options.status] : this.options.heading) + '"' : ''}
        ${!this.options.progress ? 'noprogress' : ''}
        >
        </oc-callout>
        `;
            this.targetEl = tplToEl(this.template);
        }
        getCloseBtns() {
            for (let k of getEls(`[${orca.alias}="closebubble"]`, this.targetEl))
                k.onclick = () => this.hide();
        }
        
        show(cb) {
            if (this.destroyed || this.shown)
                return this;
            this.parentEl.appendChild(this.targetEl);
            this.targetEl.toggleAttribute('hidden', false);
            this.getCloseBtns();
            this.targetEl.on('hidden', () => {
                this.targetEl.remove();
                this.shown = false;
                super.listen({ name: 'hidden' });
            });
            this.targetEl.on('shown', () => {
                this.shown = true;
                super.listen({ name: 'shown' });
            });
            !this.options.manual && this.targetEl.setAttribute('autoclose', this.options.delay);
            return this;
        }
        
        hide(cb) {
            if (this.destroyed || !this.shown)
                return this;
            this.targetEl.toggleAttribute('hidden', true);
            return this;
        }
        updateCont(content, cb) {
            if (this.destroyed)
                return this;
            this.targetEl.setAttribute('content', content);
            this.getCloseBtns();
            super.listen({ name: 'updatedCont', cb, params: [content] });
            return this;
        }
        
        async update(settings, cb) {
            if (this.destroyed)
                return this;
            this.targetEl.remove();
            this.options = extend({ target: this.options, source: settings });
            await this.init();
            super.listen({ name: 'updated', cb, params: [settings] });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.targetEl.remove();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const combineArr = ({ origin, length = 2, start = 0, splice = [], result = [] }) => {
        let arrayLen = origin.length;
        if (start + length > arrayLen) {
            return [];
        }
        for (let i = start; i < arrayLen; i++) {
            if (length === 1) {
                result.push([...splice, origin[i]]);
                i + 1 < arrayLen && combineArr({ origin, length, start: i + 1, splice, result });
                break;
            }
            combineArr({ origin, length: length - 1, start: i + 1, splice: [...splice, origin[i]], result });
        }
        return result || [];
    };

    const sliceFrags = ({ str = '', start = '{', end = '}', contain = true }) => {
        let reg = new RegExp(`\\${start}([^\\${end}]+)\\${end}`, 'g'), arr = str.match(reg) || [];
        return (!contain && arr.length > 0) ? arr.map((k) => k.replace(start, '').replace(end, '')) : arr;
    };

    const toLocalTime = (date) => {
        let dateStr, localDate, flag, loacalTime;
        if (date) {
            date = date.trim();
            localDate = new Date(date);
            flag = localDate instanceof Date && !isNaN(localDate.getTime());
            if (!flag) {
                throw new Error('Date format must be "YYYY-MM-DD" or "YYYY/MM/DD"!');
            }
            dateStr = date.replace(/-/g, "/");
            loacalTime = new Date(dateStr).getTime();
        }
        else {
            loacalTime = Date.now();
        }
        return loacalTime;
    };

    const validTools = {
        
        test: (value, pattern) => {
            if (isEmpty(value) || isEmpty(pattern)) {
                return false;
            }
            return (typeof pattern === 'string' ? new RegExp(pattern) : pattern).test(value);
        },
        
        expired: (value, data) => {
            let getTime = (v) => typeof v === 'string' ? toLocalTime(v) : v.getTime(), valueTime = getTime(value), dataType = getDataType(data), result = [-2, -2], compare = (a, b) => {
                return a < b ? -1 :
                    a === b ? 0 :
                        a > b ? 1 : -2;
            };
            if (isEmpty(value) || isEmpty(data)) {
                return result;
            }
            if (dataType === 'Array' && data.length === 2) {
                let dates = data.map((k) => getTime(k)).sort();
                result[0] = compare(valueTime, dates[0]);
                result[1] = compare(valueTime, dates[1]);
            }
            else {
                let dataTime = getTime(data);
                result[0] = compare(valueTime, dataTime);
            }
            return result;
        },
        
        than: (value, data) => {
            let result = [-2, -2], dataType = getDataType(data), valueParse = parseFloat(value), dataParse, compare = (a, b) => {
                return a < b ? -1 :
                    a === b ? 0 :
                        a > b ? 1 : -2;
            };
            if (dataType === 'Array') {
                if (data.length === 2) {
                    dataParse = data.map((k) => parseFloat(k)).sort();
                    result[0] = compare(valueParse, dataParse[0]);
                    result[1] = compare(valueParse, dataParse[1]);
                }
            }
            else {
                dataParse = parseFloat(data);
                result[0] = compare(valueParse, dataParse);
            }
            return result;
        },
        
        getStrength: (value, data) => {
            let datas = Object.assign({ lowerCase: '[a-z]', upperCase: '[A-Z]', digital: '[0-9]', chars: `[${config.valid.regChars}]`, local: `[${config.lang.valid.regLocal}]`, length: config.valid.lengthStr }, data), strength = 0;
            if (isEmpty(value) || typeof value !== 'string') {
                return strength;
            }
            for (let k in datas) {
                if (k === 'length') {
                    value.trim().length >= datas[k] ? strength++ : null;
                }
                else {
                    if (datas.hasOwnProperty(k) && datas[k]) {
                        value.match(new RegExp(datas[k])) ? strength++ : null;
                    }
                }
            }
            return strength;
        },
        
        parseLength: (value) => {
            let regex = '', text = '';
            if (value) {
                let arr = value.replace('{', '').replace('}', '').split(',').map((k) => ~~k);
                if (arr.length === 2) {
                    regex = (arr[1] && arr[1] > arr[0]) ? `{${arr[0]},${arr[1]}}` :
                        (arr[1] && arr[1] === arr[0]) ? `{${arr[0]}}` : `{${arr[0]},}`;
                    if (arr[1]) {
                        if (arr[0] === 0) {
                            text = renderTpl(config.lang.valid['length<='], { label: '', data: arr[1] });
                        }
                        else {
                            text = renderTpl(config.lang.valid['length>=<='], { label: '', data: arr });
                        }
                    }
                    else {
                        text = renderTpl(config.lang.valid['length>='], { label: '', data: arr[0] });
                    }
                }
                else {
                    regex = `{${arr[0]}}`;
                    text = renderTpl(config.lang.valid['length='], { label: '', data: arr[0] });
                }
            }
            return { regex, text };
        },
        
        parseSpecific: function (value, data) {
            value = trim(value, 'global');
            let regex = '', typeStr = value, rangeStr = '', text = '', strData = {}, regTypes = Object.assign({ ...config.lang.valid.types }, data?.types), tplStr = data?.tpl || config.lang.valid.specific, tplData = {};
            if (value) {
                let rangeTemp = sliceFrags({ str: value });
                if (rangeTemp.length > 0) {
                    rangeStr = rangeTemp[0];
                    typeStr = value.replace(rangeStr, '');
                }
                regex = '^';
                let arr = typeStr.split('&');
                arr.forEach((k) => {
                    let val = k.split('='), reg = '';
                    reg = (val[0] === 'a') ? `.*?[a-z]` :
                        (val[0] === 'A') ? `.*?[A-Z]` :
                            (val[0] === 'd') ? `.*?[0-9]` :
                                (val[0] === '~') ? `.*?[${data?.regChars || config.valid.regChars}]` :
                                    (val[0] === '@') ? `.*?[${data?.regLocal || config.lang.valid.regLocal}]` : '';
                    regex += (reg ? '(?=' + Array((val[1] ? ~~val[1] : 1) + 1).join(reg) + ')' : '');
                    strData[regTypes[val[0]]] = val[1] || 1;
                });
                tplData = { label: data?.label || '', name: data?.name || '', value: data?.value || '', data: strData };
                regex += `.${this.parseLength(rangeStr).regex || '{0,}'}$`;
                text = renderTpl(tplStr, tplData) + (rangeStr ? this.parseLength(rangeStr).text : '');
            }
            return { regex, text };
        },
        
        parseCombine: function (value, data) {
            value = trim(value, 'global');
            let regChars = data?.regChars || config.valid.regChars, regLocal = data?.regLocal || config.lang.valid.regLocal, regex = '', typeStr = value, rangeStr = '', text = '', strData = { types: [], total: 0 }, regTypes = Object.assign({ ...config.lang.valid.types }, data?.types), tplStr = data?.tpl || config.lang.valid.combine, tplData = {};
            if (value) {
                let rangeTemp = sliceFrags({ str: value });
                if (rangeTemp.length > 0) {
                    rangeStr = rangeTemp[0];
                    typeStr = value.replace(rangeStr, '');
                }
                let arr = typeStr.split(':'), types = ~~arr[1] ? ~~arr[1] : 2, regs = [];
                arr[0].includes('a') ? (regs.push('a-z'), strData.types.push(regTypes['a'])) : null;
                arr[0].includes('A') ? (regs.push('A-Z'), strData.types.push(regTypes['A'])) : null;
                arr[0].includes('d') ? (regs.push('0-9'), strData.types.push(regTypes['d'])) : null;
                arr[0].includes('~') ? (regs.push(regChars), strData.types.push(regTypes['~'])) : null;
                arr[0].includes('@') ? (regs.push(regLocal), strData.types.push(regTypes['@'])) : null;
                types = Math.min(types, regs.length);
                if (types === 1) {
                    regex = `^[${regs.join('')}]`;
                }
                else {
                    regex += '^';
                    combineArr({ origin: regs, length: types - 1 }).forEach((k) => {
                        regex += `(?![${k.join('')}]+$)`;
                    });
                    regex += `[${regs.join('')}]`;
                }
                strData.total = types;
                tplData = { label: data?.label || '', name: data?.name || '', value: data?.value || '', data: strData };
                regex += `${this.parseLength(rangeStr).regex || '{0,}'}$`;
                text = renderTpl(tplStr, tplData) + (rangeStr ? this.parseLength(rangeStr).text : '');
            }
            return { regex, text };
        },
        
        validForm: async ({ el, fail, succ, intvl = 100 }) => {
            let parentEl = getEl(el) || document.body, validItem = orca.valids.find((k) => k.parent === parentEl), children = validItem?.children || [], passed = true, fails = [], loopValid = async () => {
                for (let i = 0; i < children.length; i++) {
                    let v = children[i];
                    await delay({
                        duration: intvl * i
                    }).then(async () => {
                        await v.ins.do().then((res) => {
                            !res.passed ? (passed = res.passed, fails.push(v)) : null;
                        });
                    });
                }
            };
            if (orca.valids.length === 0 || !validItem) {
                new Message({
                    content: config.lang.valid.message.noValids,
                    iconShow: true,
                    status: 'info',
                }).show();
                return { passed: true, fails: [] };
            }
            await loopValid().then(() => {
                !passed ? (fail && fail(fails)) : (succ && succ());
            });
            return { passed, fails };
        },
        
        listenSubmit: async function ({ item, fail, succ, cb }) {
            let allItems = orca.valids, getItems = () => {
                let itemType = getDataType(item), result = [];
                if (isEmpty(item)) {
                    result = allItems;
                }
                else {
                    if (itemType === 'Array') {
                        result = item;
                    }
                    else {
                        if (itemType.includes('HTML')) {
                            result = [allItems.find((k) => k.parent === item)];
                        }
                        else if (itemType === 'String') {
                            let temp = getEl(item);
                            temp ? result = [allItems.find((k) => k.parent === temp)] : null;
                        }
                        else {
                            result = [item];
                        }
                    }
                }
                return result;
            }, usableItems = getItems().filter((k) => k?.parent?.nodeName === 'FORM'), result = { passed: true, fails: [] };
            if (usableItems.length > 0) {
                for (let k of usableItems) {
                    await this.validForm({
                        el: k.parent,
                        fail: (fails) => {
                            fail && fail(k, fails);
                        },
                        succ: (fails) => {
                            if (succ) {
                                succ(k, fails);
                            }
                            else {
                                k.parent.submit();
                            }
                        }
                    }).then((resp) => {
                        result = resp;
                        cb && cb(k, resp);
                    });
                }
            }
            return result;
        },
        
        factory: async (data) => {
            let textSucc = data?.text?.succ || config.lang.valid.succ, textFail = data?.text?.fail || config.lang.valid.fail, result = { passed: true, succ: renderTpl(textSucc, { label: data.label, name: data.name }), fail: renderTpl(textFail, { label: data.label, name: data.name }) };
            if (data.rules.length === 0) {
                return result;
            }
            try {
                for (let k in data.rules) {
                    if (data.rules.hasOwnProperty(k)) {
                        let item = data.rules[k], param = { value: data.value, name: data.name, label: data.label, type: k, ins: data.ins, data: data.ins.types[k] }, output = await item(param), dataType = getDataType(output);
                        if (dataType === 'Object') {
                            Object.assign(result, output?.content?.hasOwnProperty('passed') ? output.content : output);
                            if (!result.passed)
                                break;
                        }
                        else {
                            throw new Error('Return value is not a standard object : {passed,succ,fail}!');
                        }
                    }
                }
            }
            catch (err) {
                result.passed = false;
                new Message({
                    status: 'info',
                    content: config.lang.valid.message.wrongRule,
                }).show();
                console.error(err);
            }
            data.cb && data.cb(result);
            return result;
        }
    };

    const formTools = {
        
        getName: (item) => {
            let field = getEl(item), types = ['file', 'select-multiple', 'checkbox'];
            return (types.includes(field.type) && !field.name.endsWith('[]')) ? `${field.name}[]` : field.name;
        },
        
        getHosts: (el) => {
            let form = getEl(el), condition = (k) => k.name && !k.name.includes(orca.namePfx) && !k.hasAttribute(orca.embedSign);
            if (!form)
                return [];
            return unique([...form.querySelectorAll(`${fieldTypes.map((k) => 'oc-' + k).join()},input:not([type="submit"],[type="reset"]),select,textarea`)].filter(condition), 'name');
        },
        
        reset: function (el, zero = false) {
            let parentEl = getEl(el), fields = this.getHosts(parentEl);
            if (fields.length > 0) {
                for (let k of fields) {
                    fieldTools.reset({ target: k, parent: parentEl, zero });
                }
            }
        },
        
        setVals: function (el, data = {}) {
            let parentEl = getEl(el), fields = this.getHosts(parentEl);
            if (!parent || fields.length === 0) {
                return;
            }
            if (isEmpty(data))
                this.reset(parent, true);
            for (let [k, value] of Object.entries(data)) {
                let item = fields.find((i) => i.name === k);
                item && fieldTools.setVals({ target: item, value, parent });
            }
        },
        
        getVals: function (el, format = 'array') {
            let parentEl = getEl(el), none = format === 'string' ? '' : format === 'json' ? {} : format === 'formdata' ? new FormData() : [], fields = [], items = [], output;
            try {
                if (parentEl) {
                    fields = this.getHosts(parentEl);
                    items = fields.map((k) => {
                        let value = fieldTools.getVals({ target: k, parent: parentEl }), fullName = k.name + (Array.isArray(value) && !k.name.endsWith('[]') ? '[]' : '');
                        return { type: k.type, name: k.name, fullName, value };
                    });
                    if (format === 'string') {
                        output = '';
                        items.forEach((k, i) => {
                            let symbol = i === 0 ? '' : '&';
                            if (Array.isArray(k.value)) {
                                if (k.value.length > 0) {
                                    for (let x of k.value)
                                        output += symbol + k.fullName + '=' + (getDataType(k) === 'File' ? x.name : x);
                                }
                                else {
                                    output += symbol + k.fullName + '=';
                                }
                            }
                            else {
                                output += symbol + k.name + '=' + (getDataType(k.value) === 'File' ? k.value.name : k.value);
                            }
                        });
                    }
                    else if (format === 'formdata') {
                        output = new FormData();
                        for (let k of items) {
                            if (Array.isArray(k.value)) {
                                if (k.value.length > 0) {
                                    for (let x of k.value)
                                        output.append(k.fullName, x);
                                }
                            }
                            else {
                                output.append(k.name, k.value);
                            }
                        }
                        ;
                    }
                    else if (format === 'json') {
                        output = {};
                        for (let k of items)
                            output[k.name] = k.value;
                    }
                    else {
                        output = items;
                    }
                    return output;
                }
                else {
                    return none;
                }
            }
            catch {
                console.warn('Failed to retrieve data from the form, and empty content has been output!');
                return none;
            }
        },
        
        submit: async function (el, options) {
            let formEl = getEl(el);
            if (!formEl)
                throw new Error('The form node is required!');
            let opt = extend({
                target: {
                    type: 'post',
                    delay: 0,
                    
                },
                source: options
            }), ajaxSubmit = async () => {
                if (!opt.url)
                    throw new Error('The request url is required!');
                let btnEl = getEl(opt.button?.selector), btnText = btnEl ? btnEl.innerHTML : '', resume = () => {
                    formEl?.classList.remove(`${orca.prefix}ajoc-mask`);
                    if (btnEl) {
                        if (opt?.button?.replace) {
                            btnEl.removeAttribute('inert');
                            btnEl.innerHTML = btnText;
                        }
                        else {
                            opt?.button?.attr && btnEl.removeAttribute(opt.button.attr.key);
                        }
                    }
                };
                if (formEl?.classList.contains(`${orca.prefix}ajoc-mask`))
                    return;
                await ajax({
                    url: opt.url,
                    data: this.getVals(formEl, opt.type === 'get' ? 'string' : 'formdata'),
                    type: opt.type,
                    opened: (response) => {
                        opt.opened && opt.opened(response);
                    },
                    before: (response) => {
                        formEl?.classList.add(`${orca.prefix}ajoc-mask`);
                        if (btnEl) {
                            if (opt?.button?.replace === 'loading') {
                                btnEl.innerHTML = response.content;
                                btnEl.toggleAttribute('inert', true);
                            }
                            else if (opt.button?.replace === 'text') {
                                btnEl.innerHTML = config.lang.ajax.submit.btn;
                                btnEl.toggleAttribute('inert', true);
                            }
                            else {
                                opt?.button?.attr && btnEl.setAttribute(opt.button.attr.key, opt.button.attr.value);
                            }
                        }
                        opt.before && opt.before(response);
                    },
                    success: (response) => {
                        setTimeout(() => {
                            resume();
                            new Message({
                                content: config.lang.ajax.submit.succ,
                                status: 'succ',
                                iconShow: true,
                            }).show();
                            opt.success && opt.success(response);
                        }, opt.delay);
                    },
                    error: (response) => {
                        resume();
                        new Message({
                            content: config.lang.ajax.submit.fail,
                            status: 'error',
                            iconShow: true,
                        }).show();
                        opt.error && opt.error(response);
                    }
                });
            }, submitForm = async () => {
                if (opt.url) {
                    ajaxSubmit();
                }
                else {
                    formEl?.nodeName === 'FORM' && formEl.submit();
                }
            }, awaitValid = async () => {
                if (opt.valid) {
                    let resp = await opt.valid();
                    resp && submitForm();
                }
                else {
                    submitForm();
                }
            }, validItem = orca.valids.find((k) => k.parent === formEl);
            if (validItem) {
                await validTools.validForm({
                    el: formEl,
                    fail: () => {
                        opt.invalid && opt.invalid();
                    },
                    succ: async () => {
                        await awaitValid();
                    }
                });
            }
            else {
                await awaitValid();
            }
        }
    };

    const setContent = ({ content, target, position = 'override', engine, template, prevent }) => {
        let contType = getDataType(content), el = getEl(target), result = '';
        if (isNull(content))
            return;
        if (contType.includes('HTML') || contType === 'String' || contType === 'Number') {
            result = content;
        }
        else if (contType === 'Array' || contType === 'Object') {
            let tplDom = getEl(template), tplStr = tplDom?.innerHTML || template, tplEng = engine || renderTpl;
            if (tplStr && tplEng) {
                try {
                    result = tplEng.name === 'template' ? tplEng(tplStr)(content) : tplEng(tplStr, content);
                }
                catch (err) {
                    console.error(err);
                }
            }
            else {
                console.warn('Be sure to fill in the template content and template engine!');
            }
        }
        if (!isEmpty(prevent)) {
            prevent(result);
        }
        else {
            if (!el)
                return;
            let valType = getDataType(result);
            if (valType.includes('HTML')) {
                (position === 'override') ? (el.innerHTML = '', el.appendChild(content)) : el.insertAdjacentElement(position, content);
            }
            else {
                (position === 'override') ? el.innerHTML = result : el.insertAdjacentHTML(position, result);
            }
        }
    };

    const getAutoDur = (val) => isNull(val) ? 200 : ~~(parseFloat(val) / 3 + 250);

    class ModBaseListenCacheBubble extends ModBaseListenCache {
        bubbleType;
        positionIns;
        hoverIns;
        mainEl;
        state;
        footEl;
        data;
        submitXhr;
        contEl;
        template;
        wrapEl;
        bodyEl;
        headEl;
        maskEl;
        clickOutHideEvt;
        triggerClose;
        contXhr;
        triggerShow;
        wings;
        cssDur;
        duration;
        wrapHeight;
        leaveTrigger;
        static hostType = 'node';
        
        formEl = null;
        canTrigger = false;
        lastShowTime = 0;
        bullets = { nodes: [], value: '' };
        setEmpty() {
            if (this.bubbleType === 'popup') {
                this.positionIns && this.positionIns.destroy();
                this.hoverIns && this.hoverIns.destroy();
            }
            this.mainEl && this.mainEl.remove();
            
            this.state = 'hidden';
        }
        async hide(param) { }
        handleFooter() {
            if (this.footEl) {
                let isBullets = this.options.bullet.enable && ['checkboxes', 'radios', 'select-single', 'select-multi'].includes(this.options.bullet.type);
                this.options.footer.children.forEach((k) => {
                    if (k.name === 'confirm') {
                        if (k.action) {
                            k.action.call(this, k);
                        }
                        else {
                            if (!k?.attrs?.href) {
                                k.el.onclick = async (e) => {
                                    this.options.b4Confirm && await this.options.b4Confirm.call(this, k);
                                    let inputEl = getEl(this.options.autoFill.inputSel) || this.targetEl, childEl = getEl(this.options.autoFill.childSel, inputEl), vals;
                                    if (isCompField(this.options.contType)) {
                                        let value = ['checkbox', 'radio'].includes(this.options.contType) && !this.data.checked ? '' : this.data.value;
                                        this.options.autoFill.enable && inputEl && this.setTargetVals(value, inputEl, childEl);
                                        !this.options.keepShow && this.hide();
                                        vals = value;
                                    }
                                    else if (isBullets) {
                                        if (this.targetEl) {
                                            this.bullets.value = this.getBulletsChecked();
                                            this.setTargetVals(this.bullets.value, this.targetEl, childEl);
                                        }
                                        !this.options.keepShow && this.hide();
                                        vals = this.bullets.value;
                                    }
                                    else {
                                        if (k.event === 'submit') {
                                            if (this.formEl) {
                                                formTools.submit(this.formEl, {
                                                    url: k.url,
                                                    invalid: () => {
                                                        this.listen({ name: 'invalidated' });
                                                    },
                                                    valid: () => {
                                                        this.listen({ name: 'validated' });
                                                    }
                                                });
                                            }
                                            else {
                                                throw new Error('Form node is required!');
                                            }
                                        }
                                        else if (k.event === 'async') {
                                            if (this.formEl && k.url) {
                                                formTools.submit(this.formEl, {
                                                    url: k.url,
                                                    button: {
                                                        selector: k.el,
                                                        attr: { key: 'check', value: 'ing' },
                                                    },
                                                    opened: (resp) => {
                                                        this.submitXhr = resp.xhr;
                                                    },
                                                    invalid: () => {
                                                        this.listen({ name: 'invalidated' });
                                                    },
                                                    valid: () => {
                                                        this.listen({ name: 'validated' });
                                                    },
                                                    success: (resp) => {
                                                        this.listen({ name: 'sended', params: [resp.content] });
                                                    }
                                                });
                                            }
                                            else {
                                                throw new Error('The request url and form node are required!');
                                            }
                                        }
                                        else if (k.event === 'prevent') {
                                            preventDft(e);
                                        }
                                        else {
                                            !this.options.keepShow && this.hide();
                                        }
                                    }
                                    this.listen({ name: 'confirmed', cb: k.cb, params: [k, vals] });
                                };
                            }
                        }
                    }
                    else if (k.name === 'cancel') {
                        if (k.action) {
                            k.action.call(this, k);
                        }
                        else {
                            if (!k?.attrs?.href) {
                                k.el.onclick = async (e) => {
                                    this.options.b4Cancel && await this.options.b4Cancel.call(this, k);
                                    if (k.event === 'zero') {
                                        this.formEl && formTools.reset(this.formEl, true);
                                    }
                                    else if (k.event === 'reset') {
                                        this.formEl && formTools.reset(this.formEl, false);
                                    }
                                    else if (k.event === 'prevent') {
                                        preventDft(e);
                                    }
                                    else {
                                        !this.options.keepShow && this.hide();
                                    }
                                    this.listen({ name: 'canceled', cb: k.cb, params: [k] });
                                };
                            }
                        }
                    }
                    else if (k.name === 'close') {
                        if (k.action) {
                            k.action.call(this, k);
                        }
                        else {
                            k.el.onclick = () => {
                                this.hide();
                            };
                        }
                        this.listen({ name: 'closed', cb: k.cb, params: [k] });
                    }
                    else if (k.name === 'clear') {
                        if (k.action) {
                            k.action.call(this, k);
                        }
                        else {
                            k.el.onclick = () => {
                                if (isCompField(this.options.contType)) {
                                    fieldTools.reset({ target: this.data, zero: true });
                                }
                                else if (isBullets) {
                                    this.clearBulletsChecked();
                                }
                                this.listen({ name: 'cleared', cb: k.cb, params: [k] });
                            };
                        }
                    }
                    else {
                        k.action && k.action.call(this, k);
                    }
                });
            }
        }
        getBulletsTpl() {
            return !this.options.tplStr && this.options.bullet.enable ? bulletTools.getBulletsTpl(this.options.bullet) : '';
        }
        handleData(data) {
            let result = data;
            if (!this.options.bullet.enable)
                return result;
            if (Array.isArray(data) && typeof data[0] === 'string') {
                result = data.map((k) => { return { label: k }; });
            }
            else if (typeof data === 'string' && !data.includes(`${orca.prefix}bullet-body`)) {
                result = data.split(',').filter(Boolean).map((k) => { return { label: k }; });
            }
            return result;
        }
        async renderContent(data) {
            isEmpty(data) && console.info('No content to insert, proceeding without blocking.');
            this.data = this.handleData(data);
            if (this.options.b4Fill) {
                let resp = await this.options.b4Fill.call(this, this.data, this.contEl);
                resp && (this.data = resp);
            }
            this.listen({ name: 'render', params: [this.data] });
            let dataType = getDataType(this.data), tplEl = getEl(this.options.tplStr), template = tplEl?.innerHTML || this.options.tplStr || this.getBulletsTpl();
            if (dataType.includes('HTML') && ['image', 'iframe', 'audio', 'video'].includes(this.options.contType)) {
                this.options.media.title && this.data.insertAdjacentHTML('afterbegin', `<div ${orca.alias}="title">${this.options.media.title}</div>`);
                this.options.media.brief && this.data.insertAdjacentHTML('beforeend', `<div ${orca.alias}="brief">${this.options.media.brief}</div>`);
            }
            setContent({
                content: this.data,
                target: this.contEl,
                engine: this.options.tplEng,
                template,
            });
            this.formEl = this.contEl.querySelector('form');
            this.listen({ name: 'rendered', params: [this.data] });
        }
        renderBubble(name = 'popup') {
            
            this.template = renderTpl(this.getTpl(name), this.options);
            
            this.mainEl = tplToEl(this.template);
            
            this.wrapEl = this.mainEl.querySelector(`.${orca.prefix}${name}-wrap`);
            
            this.contEl = this.mainEl.querySelector(`.${orca.prefix}${name}-cont`);
            
            this.bodyEl = this.mainEl.querySelector(`.${orca.prefix}${name}-body`);
            
            this.headEl = this.mainEl.querySelector(`.${orca.prefix}${name}-head`);
            
            this.footEl = this.mainEl.querySelector(`.${orca.prefix}${name}-foot`);
            
            this.maskEl = this.mainEl.querySelector(`.${orca.prefix}${name}-mask`);
            if (this.options.tools.enable) {
                createTools(this.options.tools.children, this.wrapEl, this);
            }
            if (this.footEl) {
                if (this.options.footer.layout !== 'plain') {
                    this.options.footer.children = this.options.footer.children.map((k) => {
                        if (k === 'confirm') {
                            return { name: 'confirm', attrs: { theme: 'prim' } };
                        }
                        else if (k?.name === 'confirm') {
                            if (k.attrs) {
                                !k.attrs.theme && (k.attrs.theme = 'prim');
                            }
                            else {
                                k.attrs = { theme: 'prim' };
                            }
                            return k;
                        }
                        else {
                            return k;
                        }
                    });
                }
                createFooter(this.options.footer, this.footEl, this);
            }
        }
        getTpl(name = 'popup') {
            return `
                            {{let noPadding = (this.padding.enable  && !this.bullet.enable) || (this.padding.enable && this.bullet.enable && this.bullet.cols>0 && this.bullet.lines==='fluid');/}}
                            <div class="${orca.prefix}${name}">
                                {{ if(this?.mask?.enable){ /}}<div class="${orca.prefix}${name}-mask"></div>{{ } /}}
                                <div class="${orca.prefix}${name}-wrap">
                                    {{ if(this.heading){ /}}
                                        <div class="${orca.prefix}${name}-head">{{ this.heading }}</div>
                                        {{ } /}}
                                    {{ if(this.divider){ /}}
                                        <oc-line></oc-line>
                                        {{ } /}}
                                    <div class="${orca.prefix}${name}-body">
                                        {{ if(this.padding.enable){ /}}
                                            <div class="${orca.prefix}${name}-padding {{ this.padding.value || '${orca.prefix}p' }} "> 
                                        {{ }else if(noPadding){ /}}
                                            <div class="${orca.prefix}${name}-padding"> 
                                        {{ } /}}
                                                <div class="${orca.prefix}${name}-cont"></div>
                                        {{ if(noPadding || this.padding.enable){ /}}
                                            </div>
                                            {{ } /}}
                                    </div>
                                    {{ if((!this.bullet.enable && this.footer.enable) || (this.bullet.enable && ['custom','checkboxes','select-multi'].includes(this.bullet.type) && this.footer.enable)){ /}}
                                    <div class="${orca.prefix}${name}-foot {{ this.footer.layout !=='plain'? this.padding.value || '${orca.prefix}p':'' }} "></div>
                                    {{ } /}}
                                </div>
                            </div>
                            `;
        }
        
        initBullets() {
            this.on('show', () => {
                this.options.autoFill.enable && this.options.autoFill.detectable && this.presetFromTarget();
            });
            if (!this.options.bullet.enable)
                return;
            if (this.targetEl) {
                isNull(this.targetEl.readOnly) ? this.targetEl.toggleAttribute('readonly', true) : this.targetEl.readOnly = true;
            }
            this.bullets.nodes = bulletTools.getChildNodes(this.contEl);
            if (this.options.autoFill.enable) {
                let vals = this.getTargetVals();
                bulletTools.setChecked(vals, this.bullets.nodes);
            }
            let childEl = getEl(this.options.autoFill.childSel, this.targetEl), fill2Hide = () => {
                if (this.targetEl) {
                    this.bullets.value = this.getBulletsChecked();
                    this.setTargetVals(this.bullets.value, this.targetEl, childEl);
                }
                this.hide();
            };
            for (let [i, k] of this.bullets.nodes.entries()) {
                if (this.options.bullet.type.includes('select')) {
                    k.onclick = () => {
                        bulletTools.toggleChecked(k, this.bullets.nodes, this.options.bullet.type);
                        (this.options.bullet.type === 'select-single') && fill2Hide();
                    };
                }
                else if (this.options.bullet.type === 'radios') {
                    k.onclick = () => fill2Hide();
                }
                this.options.bullet.action && this.options.bullet.action.call(this, { el: k, data: Array.isArray(this.data) ? this.data[i] : null });
            }
        }
        presetFromTarget() {
            if (!this.options.autoFill.enable)
                return;
            let vals = this.getTargetVals();
            if (isCompField(this.options.contType)) {
                let isComp = this.data?.nodeName && this.data.nodeName.startsWith('OC-'), isEqual = vals === this.data.value;
                isComp && !isEqual && fieldTools.setVals({ target: this.data, value: vals, key: this.options.autoFill.key });
            }
            else {
                (vals !== this.bullets.value) && bulletTools.setChecked(vals, this.bullets.nodes);
            }
        }
        setBulletsChecked(vals) {
            if (!this.options.bullet.enable)
                return;
            bulletTools.setChecked(vals, this.bullets.nodes);
            if (this.options.autoFill.enable && ['radios', 'select-single'].includes(this.options.bullet.type)) {
                this.setTargetVals(this.getBulletsChecked());
            }
            this.listen({ name: 'bulletsChecked', params: [vals] });
        }
        getBulletsChecked() {
            if (!this.options.bullet.enable)
                return '';
            return bulletTools.getChecked(this.bullets.nodes);
        }
        toggleBulletsChecked(el, type = 'select-single') {
            let target = getEl(el);
            if (!target)
                return;
            bulletTools.toggleChecked(target, this.bullets.nodes, type);
        }
        clearBulletsChecked() {
            bulletTools.clearChecked(this.bullets.nodes);
        }
        checkedBulletsAll() {
            if (['radios', 'select-single'].includes(this.options.bullet.type))
                return;
            for (let k of this.bullets.nodes) {
                let input = k.querySelector('OC-CHECKBOX');
                if (input) {
                    (!k.hasAttribute('disabled') && !input.hasAttribute('disabled')) && input.setAttribute('check', 'ed');
                }
                else {
                    !k.hasAttribute('disabled') && k.setAttribute('checked', '');
                }
            }
        }
        setBulletsSelected(value) {
            bulletTools.setSelected(value, this.bullets.nodes);
            this.listen({ name: 'bulletsSelected', params: [value] });
        }
        getBulletsSelected() {
            return bulletTools.getSelected(this.bullets.nodes);
        }
        clearBulletsSelected() {
            bulletTools.clearSelected(this.bullets.nodes);
        }
        toggleBulletsSelected(el) {
            let target = getEl(el);
            target && bulletTools.toggleSelected(target, this.bullets.nodes);
        }
        getTargetVals() {
            if (!this.targetEl)
                return '';
            return fieldTools.getVals({ target: this.targetEl, child: getEl(this.options.autoFill.childSel, this.targetEl), key: this.options.autoFill.key });
        }
        setTargetVals(value = this.getBulletsChecked(), target = this.targetEl, child = getEl(this.options.autoFill.childSel, this.targetEl)) {
            if (!target)
                return;
            fieldTools.setVals({ target, value, child, key: this.options.autoFill.key });
            this.listen({ name: 'targetSet', params: [value] });
        }
        
        getDuration() {
            let tmp = parseFloat(style(this.bubbleType === 'popup' ? this.mainEl : this.wrapEl).animationDuration) * 1000 || 0;
            this.duration = this.options.duration || (this.options.autoDur ? getAutoDur(this.wrapHeight) : tmp);
        }
        
        async reset(cb) {
            this.options = deepClone(this.dftOpts);
            await this.init();
            this.clearCache();
            this.listen && this.listen({ name: 'reset', cb });
            return this;
        }
        
        async update(settings, cb) {
            if (this.destroyed || isEmpty(settings)) {
                return this;
            }
            if (!isEmpty(settings)) {
                this.updateCache(settings);
                extend({ target: this.options, source: settings });
                if (this.state !== 'ing') {
                    let tmp = this.state;
                    await this.init().then((res) => {
                        tmp === 'shown' && res.show();
                    });
                }
            }
            this.listen({ name: 'updated', cb, params: [settings] });
            return this;
        }
        
        async updateCont(content, cb) {
            if (this.destroyed || content === this.options.content)
                return this;
            await getContent.call(this, {
                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 = this.handleData(data);
                    this.renderContent(data);
                    this.updateCache({ content });
                    this.listen({ name: 'updatedCont', cb, params: [data] });
                }
            });
            return this;
        }
        replaceCont(content, cb) {
            if (this.destroyed)
                return this;
            let contType = getDataType(content);
            contType.includes('HTML') ? (this.contEl.innerHTML = '', this.contEl.appendChild(content)) : (this.contEl.innerHTML = content);
            this.listen({ name: 'replacedCont', cb, params: [content] });
        }
        unbindTrigger(str) {
        }
        bindTrigger(str) {
        }
        
        async transfer(el, cb) {
            if (this.destroyed)
                return this;
            let host = getEl(el);
            if (host && host !== this.targetEl) {
                let initialized = this.initialized;
                if (!initialized) {
                    this.targetEl = host;
                    await this.init();
                }
                else {
                    this.unbindTrigger('host');
                    this.targetEl = host;
                    this.bindTrigger();
                }
                if (this.bubbleType === 'popup' && initialized) {
                    this.positionIns.transfer(host, (target) => {
                        this.listen({ name: 'transferred', cb, params: [target] });
                    });
                }
                else {
                    this.listen({ name: 'transferred', cb, params: [host] });
                }
            }
            return this;
        }
        addPulseEvt() {
        }
        removePulseEvt() {
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.mainEl.remove();
            if (this.bubbleType === 'popup') {
                this.positionIns && this.positionIns.destroy();
                this.hoverIns && this.hoverIns.destroy();
                this.clickOutHideEvt && document.removeEventListener('click', this.clickOutHideEvt);
            }
            if (this.options.trigger === 'click' || this.options.trigger === 'input') {
                this.targetEl.removeEventListener(this.options.trigger, this.triggerShow);
                this.wings.forEach((i) => {
                    i.removeEventListener(this.options.wing.trigger || this.options.trigger, this.triggerShow);
                });
            }
            if (this.maskEl && this.options.mask.closable) {
                this.maskEl.removeEventListener('click', this.triggerShow);
            }
            this.contEl.querySelectorAll(`[${orca.alias}="closebubble"]`).forEach((k) => {
                k.removeEventListener('click', this.triggerClose);
            });
            if (this.bubbleType === 'dialog' && ['confirm', 'alert'].includes(this.options.feature)) {
                this.removePulseEvt();
                this.addPulseEvt();
            }
            this.canTrigger = false;
            this.contXhr && this.contXhr.abort();
            this.submitXhr && this.submitXhr.abort();
            this.leaveTrigger && this.leaveTrigger.cancel();
            this.destroyed = true;
            this.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    class Drawer extends ModBaseListenCacheBubble {
        options = {};
        parentEl;
        sizeProp;
        lastSize;
        lastPlace;
        bubbleType;
        timestamp;
        lastShowTime;
        confirmEl;
        cancelEl;
        closeEl;
        triggerShow;
        content;
        wrapSize;
        sequenceShow;
        sequenceHide;
        sequenceToggle;
        static optMaps = optDrawer;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Drawer.optMaps,
                component: true,
                spread: ['mask', 'tools', 'padding', 'footer', 'autoFill', 'bullet']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            this.bubbleType = 'drawer';
            this.timestamp = Date.now();
            this.lastShowTime = 0;
            let _this = this;
            this.triggerShow = function (evt) {
                if (this === _this.targetEl && _this.options.canClick) {
                    let target = getEvtTarget(evt), tmp = _this.options.canClick.call(_this, target, evt);
                    if (!tmp)
                        return;
                }
                if (_this.state === 'hidden') {
                    _this.show();
                    (_this.options.wing.actClass && _this.wings.includes(this)) && this.classList.add(_this.options.wing.actClass);
                }
                else if (_this.state === 'shown') {
                    !_this.options.keepShow && _this.hide();
                }
            };
            this.triggerClose = () => {
                !this.options.keepShow && this.hide();
            };
            this.sequenceToggle = () => {
                this.mainEl.toggleAttribute('show', true);
                for (let k of this.getToggleItems())
                    k.ins.hide();
            };
            this.sequenceShow = (el, placement) => {
                let size = (!el.style[placement]) ? this.options.offset : (parseInt(el.style[placement]) * 0.6 + parseInt(this.options.offset) + 'px');
                el.style[placement] = size;
            };
            this.sequenceHide = (el, placement) => {
                if (el.style[placement] == this.options.offset) {
                    el.style.cssText = el.style.cssText.replace(placement, '');
                }
                else {
                    el.style[placement] = (parseInt(el.style[placement]) - parseInt(this.options.offset)) / 0.6 + 'px';
                }
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setEmpty();
            this.options.placement = this.options.placement || 'right';
            this.parentEl = getEl(this.options.parent) || document.body;
            this.sizeProp = (this.options.placement === 'left' || this.options.placement === 'right') ? 'width' : 'height';
            
            this.wings = getEls(this.options.wing.selector);
            this.renderBubble('drawer');
            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.renderContent(data);
                }
            });
            this.lastPlace = '';
            this.handleFooter();
            this.handleTools();
            this.bindTrigger();
            this.contEl.querySelectorAll(`[${orca.alias}="closebubble"]`).forEach((k) => {
                k.removeEventListener('click', this.triggerClose);
                k.addEventListener('click', this.triggerClose, false);
            });
            this.initBullets();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        handleTools() {
            if (this.options.tools.enable) {
                this.options.tools.children.forEach((k) => {
                    if (k.name === 'close') {
                        k.wrapEl.onclick = () => this.hide();
                    }
                    else if (['widen', 'heighten', 'enlarge'].includes(k.name)) {
                        k.wrapEl.onclick = () => {
                            if (this.lastSize === 'max') {
                                classes(k.iconEl).replace(k.icon, k.swap);
                                this.mainEl.setAttribute('size', this.options.size);
                                this.lastSize = this.options.size;
                            }
                            else {
                                classes(k.iconEl).replace(k.swap, k.icon);
                                this.mainEl.setAttribute('size', 'max');
                                this.lastSize = 'max';
                            }
                        };
                    }
                    else {
                        k.action && k.action.call(this, k);
                    }
                });
            }
        }
        setAttrs() {
            this.options.classes && classes(this.mainEl).add(this.options.classes);
            this.options.size ? this.mainEl.setAttribute('size', this.options.size) : this.mainEl.removeAttribute('size');
            this.options.contType ? this.mainEl.setAttribute('conttype', this.options.contType) : this.mainEl.removeAttribute('conttype');
            this.contEl.toggleAttribute('dedicated', this.options.dedicated);
            this.options.placement ? this.mainEl.setAttribute('placement', this.options.placement) : this.mainEl.removeAttribute('placement', this.options.placement);
            this.options.zIndex ? addStyle(this.mainEl, 'z-index', this.options.zIndex) : removeStyle(this.mainEl, 'z-index');
            if (this.parentEl !== document.body) {
                let pStyle = style(this.parentEl);
                pStyle.position === 'static' && addStyle(this.parentEl, 'position', 'relative');
                pStyle.overflow !== 'hidden' && addStyle(this.parentEl, 'overflow', 'hidden');
                this.mainEl.toggleAttribute('restrict', true);
            }
            else {
                this.mainEl.removeAttribute('restrict');
            }
        }
        getBeforeItems() {
            return instance.data.filter((k) => k.ins !== this &&
                k.type === 'drawer' &&
                !k.ins.destroyed &&
                k.ins.state === 'shown' &&
                k.ins.parentEl === this.parentEl &&
                k.ins.options.placement === this.options.placement &&
                k.ins.lastShowTime < this.lastShowTime);
        }
        getToggleItems() {
            return instance.data.filter((k) => k.ins !== this &&
                k.type === 'drawer' &&
                !k.ins.destroyed &&
                k.ins.state === 'shown' &&
                k.ins.parentEl === this.parentEl);
        }
        getIngItems() {
            return instance.data.filter((k) => k.ins !== this &&
                k.type === 'drawer' &&
                !k.ins.destroyed &&
                k.ins.state === 'ing' &&
                k.ins.parentEl === this.parentEl &&
                k.ins.options.placement === this.options.placement);
        }
        bindTrigger() {
            if (this.options.trigger === 'click') {
                if (this.targetEl && !this.canTrigger) {
                    this.targetEl.removeEventListener('click', this.triggerShow);
                    this.targetEl.addEventListener('click', this.triggerShow, false);
                }
                if (this.wings.length > 0 && !this.canTrigger) {
                    this.wings.forEach((k) => {
                        k.removeEventListener('click', this.triggerShow);
                        k.addEventListener('click', this.triggerShow, false);
                    });
                }
            }
            else if (this.options.trigger === 'sticky') {
                this.show();
            }
            if (this.maskEl && this.options.mask.closable) {
                this.maskEl.removeEventListener('click', this.triggerShow);
                this.maskEl.addEventListener('click', this.triggerShow, false);
            }
            this.canTrigger = true;
        }
        unbindTrigger(mode = 'host') {
            this.canTrigger = false;
            if (this.options.trigger === 'click') {
                this.targetEl.removeEventListener('click', this.triggerShow);
                if (this.wings.length > 0 && mode === 'all') {
                    this.wings.forEach((item) => {
                        item.removeEventListener('click', this.triggerShow);
                    });
                }
            }
            if (this.maskEl && this.options.mask.closable && mode === 'all') {
                this.maskEl.removeEventListener('click', this.triggerShow);
            }
        }
        
        async show(cb) {
            if (this.destroyed || this.state !== 'hidden' || this.options.asleep)
                return;
            if (this.options.multiple && this.getIngItems().length)
                return this;
            this.state = 'ing';
            this.options.b4Show && await this.options.b4Show.call(this);
            elState(this.mainEl).isVirtual && this.parentEl.appendChild(this.mainEl);
            super.listen({ name: 'show', cb });
            this.wrapSize = parseInt(style(this.wrapEl)[this.sizeProp]);
            requestAnimationFrame(async () => {
                super.getDuration();
                this.wrapEl.style.transitionDuration = `${this.duration}ms`;
                this.targetEl && this.targetEl.classList.add(this.options.actClass);
                this.lastShowTime = Date.now();
                if (this.options.multiple) {
                    for (let k of this.getBeforeItems()) {
                        this.sequenceShow(k.ins.wrapEl, this.options.placement);
                    }
                }
                else {
                    this.sequenceToggle();
                }
                this.mainEl.toggleAttribute('show', true);
                await delay({
                    duration: this.duration,
                    done: () => {
                        this.state = 'shown';
                        super.listen({ name: 'shown', cb });
                    }
                });
            });
            return this;
        }
        
        async hide(cb) {
            if (this.destroyed || this.state !== 'shown')
                return this;
            if (this.options.multiple && this.getIngItems().length)
                return this;
            this.state = 'ing';
            if (!this.options.deadShow) {
                this.options.b4Hide && await this.options.b4Hide.call(this);
                super.listen({ name: 'hide', cb });
                this.targetEl && this.targetEl.classList.remove(this.options.actClass);
                this.options.wing.actClass && this.wings.map((k) => { k.classList.remove(this.options.wing.actClass); });
                this.maskEl && (this.maskEl.style.opacity = 0);
                this.wrapEl.style[this.options.placement] = '-' + style(this.wrapEl)[this.sizeProp];
                for (let k of this.getBeforeItems())
                    this.sequenceHide(k.ins.wrapEl, this.options.placement);
                for (let k of getEls('video,audio', this.mainEl))
                    k.pause();
                await delay({
                    duration: this.duration,
                    done: () => {
                        this.state = 'hidden';
                        this.mainEl.removeAttribute('show');
                        this.maskEl && this.maskEl.removeAttribute("style");
                        this.wrapEl.removeAttribute("style");
                        this.mainEl.remove();
                        super.listen({ name: 'hidden', cb });
                    }
                });
            }
            return this;
        }
    }

    const privacy = ({ content = config.lang.privacy.content, contType, contData, cb }) => {
        if (!storage.get('ORCAUI_GOT_PRIVACY')) {
            new Drawer(undefined, {
                content,
                contType,
                contData,
                footer: {
                    children: [
                        {
                            name: 'canceled',
                            label: config.lang.privacy.cancel,
                        },
                        {
                            name: 'confirmed',
                            label: config.lang.privacy.confirm,
                        },
                    ]
                },
                onConfirmed: () => {
                    storage.set('ORCAUI_GOT_PRIVACY', true);
                    cb && cb();
                }
            }).show();
        }
    };

    const support = (useCont = false, cb) => {
        try {
            createEl('div').querySelector(':has');
        }
        catch (e) {
            if (useCont && !storage.get('ORCAUI_GOT_SUPPORT')) {
                new Drawer(undefined, {
                    content: config.lang.support.content,
                    footer: {
                        children: [
                            {
                                name: 'canceled',
                                label: config.lang.support.cancel,
                            },
                            {
                                name: 'confirmed',
                                label: config.lang.support.confirm,
                            },
                        ]
                    },
                    onConfirmed: () => {
                        storage.set('ORCAUI_GOT_SUPPORT', true);
                        cb && cb();
                    }
                }).show();
            }
            return false;
        }
        return true;
    };

    const getSelectorType = (str) => {
        requireTypes(str, 'string');
        str = str.trim();
        let type = '', isUpperCase = (letter) => (letter >= 'A' && letter <= 'Z') ? true : false;
        if (str) {
            if (str.includes(' ')) {
                type = 'nesting';
            }
            else {
                type = (str.startsWith('#') ? 'id' :
                    str.startsWith('.') ? 'class' :
                        (str.startsWith('[') && str.endsWith(']')) ? 'attr' :
                            ([...str].every(i => isUpperCase(i))) ? 'node' : '');
            }
        }
        return type;
    };

    const purifyHtml = (str) => trim(str.replace(/<[^>]+>/g, ''));

    const offset = (elem) => {
        let totalLeft, totalTop, scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft, scrollTop = document.documentElement.scrollTop || document.body.scrollTop, targetEl = getEl(elem);
        if (!targetEl) {
            throw new Error(`The target node does not exist!`);
        }
        totalLeft = targetEl.getBoundingClientRect().left + scrollLeft;
        totalTop = targetEl.getBoundingClientRect().top + scrollTop;
        return {
            left: totalLeft,
            top: totalTop
        };
    };

    const tplToEls = (tpl) => {
        tpl = tpl.trim().replaceAll('&lt;', '<').replaceAll('&gt;', '>');
        if (!tpl)
            return [];
        let tplNode = createEl('TEMPLATE', '', tpl), clone = tplNode.content.cloneNode(true), firstEl = clone.firstElementChild, result;
        if (!firstEl)
            return [];
        if (firstEl.nodeName === 'TR') {
            let trs = [...clone.querySelectorAll('TR')], tmp = tplNode.innerHTML.split('</tr>').map(k => k.replace(/<\/?tr[^>]*>/g, ''));
            tmp.shift();
            trs.forEach((k, i) => {
                k.innerHTML = tmp[i];
            });
            result = trs;
        }
        else {
            result = [...clone.children];
        }
        return result;
    };

    const getHeights = (elem) => {
        let target = getEl(elem);
        if (!target) {
            throw new Error('The target node does not exist!');
        }
        let styles = style(target);
        return {
            height: parseInt(styles.height),
            paddingTop: parseInt(styles.paddingTop),
            paddingBottom: parseInt(styles.paddingBottom),
            marginTop: parseInt(styles.marginTop),
            marginBottom: parseInt(styles.marginBottom),
            borderTopWidth: parseInt(styles.borderTopWidth),
            borderBottomWidth: parseInt(styles.borderBottomWidth),
        };
    };

    const getWidths = (elem) => {
        let target = getEl(elem);
        if (!target) {
            throw new Error('The target node does not exist!');
        }
        let styles = style(target);
        return {
            width: parseInt(styles.width),
            paddingLeft: parseInt(styles.paddingLeft),
            paddingRight: parseInt(styles.paddingRight),
            marginLeft: parseInt(styles.marginLeft),
            marginRight: parseInt(styles.marginRight),
            borderLeftWidth: parseInt(styles.borderLeftWidth),
            borderRightWidth: parseInt(styles.borderRightWidth),
        };
    };

    const getElSpace = (target, axis = 'y') => {
        let el = getEl(target), tmp;
        if (!el)
            return 0;
        if (axis === 'x') {
            tmp = getWidths(el);
            return el.offsetWidth + tmp.marginLeft + tmp.marginRight;
        }
        else {
            tmp = getHeights(el);
            return el.offsetHeight + tmp.marginTop + tmp.marginBottom;
        }
    };

    const curveFns = {
        
        linear: (t) => t,
        
        ease: (t) => ((1 - t) ** 2) * t * 3 * 0.3 + (t ** 2) * (1 - t) * 3 * 1 + t ** 3,
        
        easeIn: (t) => (t ** 2) * (1 - t) * 3 * 0.2 + t ** 3,
        
        easeOut: (t) => ((1 - t) ** 2) * t * 3 * 0.8 + (t ** 2) * (1 - t) * 3 * 1 + t ** 3,
        
        easeInOut: (t) => t < 0.5 ? Math.sqrt(0.5 * t) : -Math.sqrt(0.5 * (-t + 1)) + 1,
        
        easeOutIn: (t) => t < 0.5 ? 2 * t ** 2 : -2 * (t - 1) ** 2 + 1,
    };

    let ease = ({ from, to, before, doing, done, progress, duration, curve }) => {
        
        if (!from || !to)
            throw new Error('from and to are required!');
        let initTime = Date.now(), result = { step: 0, value: { ...from }, frame: 0, remaining: 0 }, repeat = () => {
            let dftTime = duration || 500, newTime = Date.now() - initTime, ratio = newTime / dftTime, step = curveFns[curve || 'easeOut'](ratio), value = { ...from }, remaining = dftTime - newTime, frame = requestAnimationFrame(repeat);
            for (let k in from) {
                from.hasOwnProperty(k) && from[k] !== to[k] ? value[k] = from[k] + (to[k] - from[k]) * step : null;
            }
            result = { step, frame, value, remaining };
            orca.frame = frame;
            if (ratio < 1) {
                progress && progress(result);
                doing && doing(result);
            }
            else {
                cancelAnimationFrame(frame);
                result.step = 1;
                result.value = { ...to };
                result.remaining = 0;
                progress && progress(result);
                done && done(result);
            }
        };
        before && before(result);
        repeat();
        return result;
    };

    let slideDown = ({ el, display = 'block', before, doing, done, duration, curve = 'easeOut', cut = true }) => {
        
        let target = getEl(el);
        if (!target) {
            throw new Error('The target node does not exist!');
        }
        let state = elState(target);
        if (state.isHidden) {
            let rawStyle = target.style.cssText, dftCss = `${rawStyle}display: ${display};`, startCss = `${dftCss}${cut ? 'overflow:hidden;' : ''}`;
            target.style.cssText = startCss;
            let { height, paddingTop, paddingBottom, marginTop, marginBottom } = getHeights(target), time = ~~duration && duration !== 0 ? ~~duration : getAutoDur(height);
            target.style.cssText += `padding-top: 0; padding-bottom: 0;margin-top: 0; margin-bottom: 0;`;
            ease({
                from: { height: 0, paddingTop: 0, paddingBottom: 0, marginTop: 0, marginBottom: 0 },
                to: { height, paddingTop, paddingBottom, marginTop, marginBottom },
                duration: time,
                curve,
                before: (e) => {
                    before && before.call(target, { frame: e.frame, value: e.value.height, step: e.step, for: 'show' });
                },
                doing: (e) => {
                    target.style.cssText = `
                ${startCss}
                padding-top: ${e.value.paddingTop}px; 
                padding-bottom: ${e.value.paddingBottom}px;
                margin-top: ${e.value.marginTop}px; 
                margin-bottom: ${e.value.marginBottom}px; 
                height: ${e.value.height}px
                `;
                    doing && doing.call(target, { frame: e.frame, value: e.value.height, step: e.step, target, for: 'show' });
                }, done: (e) => {
                    target.style.cssText = dftCss;
                    done && done.call(target, { frame: e.frame, value: e.value.height, step: e.step, target, for: 'show' });
                }
            });
        }
        else if (state.isVirtual) {
            target.style.display = display;
            done && done.call(target);
        }
        return target;
    };

    let slideUp = ({ el, display = 'block', before, doing, done, duration, curve = 'easeOut', cut = true }) => {
        let target = getEl(el);
        if (!target) {
            throw new Error('The target node does not exist!');
        }
        let state = elState(target);
        if (state.isCalc) {
            let rawStyle = target.style.cssText, { height, paddingTop, paddingBottom, marginTop, marginBottom } = getHeights(target), time = ~~duration && duration !== 0 ? ~~duration : getAutoDur(height), dftCss = `${rawStyle}display: ${display};`, startCss = `${dftCss}${cut ? 'overflow:hidden;' : ''}`;
            target.style.cssText = `${startCss}padding-top: 0; padding-bottom: 0;margin-top: 0; margin-bottom: 0;`;
            ease({
                from: { height, paddingTop, paddingBottom, marginTop, marginBottom },
                to: { height: 0, paddingTop: 0, paddingBottom: 0, marginTop: 0, marginBottom: 0 },
                duration: time,
                curve,
                before: (e) => {
                    before && before.call(target, { frame: e.frame, value: e.value.height, step: e.step, for: 'hide' });
                },
                doing: (e) => {
                    target.style.cssText = `
                ${startCss}
                padding-top: ${e.value.paddingTop}px; 
                padding-bottom: ${e.value.paddingBottom}px;
                margin-top: ${e.value.marginTop}px; 
                margin-bottom: ${e.value.marginBottom}px; 
                height: ${e.value.height}px
                `;
                    doing && doing.call(target, { frame: e.frame, value: e.value.height, step: e.step, for: 'hide' });
                }, done: (e) => {
                    target.style.cssText = `${rawStyle}display: none`;
                    done && done.call(target, { frame: e.frame, value: e.value.height, step: e.step, for: 'hide' });
                }
            });
        }
        else if (state.isVirtual) {
            target.style.display = 'none';
            done && done.call(target);
        }
        return target;
    };

    let slideToggle = ({ el, display = 'block', before, doing, done, duration, curve = 'easeOut', cut = true }) => {
        let target = getEl(el);
        if (!target)
            throw new Error('The target node does not exist!');
        if (elState(target).isHidden) {
            slideDown({ el: target, display, duration, curve, cut, before, doing: doing?.down, done: done?.down });
        }
        else if (elState(target).isCalc) {
            slideUp({ el: target, display, duration, curve, cut, before, doing: doing?.up, done: done?.up });
        }
        return target;
    };

    let easeHeight = ({ el, height, type = 'down', doing, done, duration, curve = 'easeOut', cut = true, unaware = true }) => {
        let target = getEl(el);
        if (!target) {
            throw new Error('The target node does not exist!');
        }
        let canDo = !unaware || (unaware && elState(target).isCalc);
        if (canDo) {
            let origHeight = ~~height, styleHeight, _height = origHeight && height !== 0 ? origHeight : (styleHeight = getHeights(target).height), time = ~~duration && duration !== 0 ? ~~duration : getAutoDur(_height), dftCss = `${target.style.cssText} ${cut ? 'overflow:hidden;' : ''};`, from = {}, to = {};
            target.style.cssText = `${dftCss}`;
            if (type === 'to' && origHeight) {
                from = { height: isNull(styleHeight) ? styleHeight : getHeights(target).height };
                to = { height: origHeight };
            }
            else if (type === 'up') {
                from = { height: _height };
                to = { height: 0 };
            }
            else {
                from = { height: 0 };
                to = { height: _height };
            }
            ease({
                from,
                to,
                duration: time,
                curve,
                doing: (e) => {
                    target.style.cssText = `
                ${dftCss}
                height: ${e.value.height}px
                `;
                    doing && doing.call(target, { frame: e.frame, value: e.value.height, step: e.step });
                }, done: (e) => {
                    done && done.call(target, { frame: e.frame, value: e.value.height, step: e.step });
                }
            });
        }
        return target;
    };

    let fadeIn = ({ el, display = 'block', doing, done, duration = 200, curve = 'easeOut' }) => {
        let target = getEl(el);
        if (!target) {
            throw new Error('The target node does not exist!');
        }
        let state = elState(target), opacity = parseFloat(style(target).opacity), from = { opacity: 0 };
        if (opacity === 1) {
            return target;
        }
        if (state.isHidden) {
            from.opacity = 0;
            target.style.display = display;
            target.style.opacity = 0;
        }
        else if (state.isCalc && opacity !== 1) {
            from.opacity = opacity;
        }
        ease({
            from,
            to: { opacity: 1 },
            duration,
            curve,
            doing: (e) => {
                target.style.opacity = e.value.opacity;
                doing && doing.call(target, { frame: e.frame, value: e.value.opacity, step: e.step, target, for: 'show' });
            }, done: (e) => {
                target.style.opacity = 1;
                done && done.call(target, { frame: e.frame, value: e.value.opacity, step: e.step, target, for: 'show' });
            }
        });
        return target;
    };

    let fadeOut = ({ el, display, doing, done, duration = 200, curve = 'easeOut' }) => {
        let target = getEl(el);
        if (!target) {
            throw new Error('The target node does not exist!');
        }
        let opacity = parseFloat(style(target).opacity);
        if (opacity === 0) {
            return target;
        }
        display ? target.style.display = display : null;
        if (elState(target).isCalc) {
            ease({
                from: { opacity },
                to: { opacity: 0 },
                duration,
                curve,
                doing: (e) => {
                    target.style.opacity = e.value.opacity;
                    doing && doing.call(target, { frame: e.frame, value: e.value.opacity, step: e.step, target, for: 'hide' });
                }, done: (e) => {
                    target.style.opacity = 0;
                    done && done.call(target, { frame: e.frame, value: e.value.opacity, step: e.step, target, for: 'hide' });
                }
            });
        }
        return target;
    };

    let fadeToggle = ({ el, display = 'block', doing, done, duration = 200, curve = 'easeOut' }) => {
        let target = getEl(el);
        if (!target)
            throw new Error('The target node does not exist!');
        let state = elState(target), opacity = parseFloat(style(target).opacity);
        if (state.isHidden) {
            fadeIn({ el: target, display, duration, curve, doing: doing?.in, done: done?.in });
        }
        else if (state.isCalc) {
            if (opacity <= 0.5) {
                fadeIn({ el: target, display, duration, curve, doing: doing?.in, done: done?.in });
            }
            else {
                fadeOut({ el: target, display, duration, curve, doing: doing?.out, done: done?.out });
            }
        }
        return target;
    };

    let show = ({ el, display = 'block', done }) => {
        let target = getEl(el);
        if (!target) {
            throw new Error('The target node does not exist!');
        }
        if (display == 'visible') {
            target.style.visibility = 'visible';
        }
        else {
            target.style.display = display;
        }
        done && done.call(target, { target, for: 'show' });
        return target;
    };

    let hide = ({ el, display = 'none', done }) => {
        let target = getEl(el);
        if (!target) {
            throw new Error('The target node does not exist!');
        }
        if (display === 'hidden') {
            target.style.visibility = 'hidden';
        }
        else {
            target.style.display = 'none';
        }
        done && done.call(target, { target, for: 'hide' });
        return target;
    };

    let toggle = ({ el, display = { show: 'block', hide: 'none' }, done }) => {
        let target = getEl(el);
        if (!target)
            throw new Error('The target node does not exist!');
        elState(target).isVisible ? hide({ el: target, display: display.hide, done: done?.hide }) : show({ el: target, display: display.show, done: done?.show });
        return target;
    };

    const regExps = {
        
        email: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[-a-zA-Z0-9_-])+/,
        
        ip: /^\d+\.\d+\.\d+\.\d+$/,
        
        url: /^(?=^.{3,255}$)(http(s)?:\/\/)?(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+\.\w+)*$/,
        
        locale: /^[\u0391-\uFFE5]+$/,
        
        letter: /^[a-zA-Z]+$/,
        
        string: /^[a-zA-Z0-9]+$/,
        
        password: `^[a-zA-Z0-9${orca.config.valid.regChars}]+$`,
        
        ymdhms: /^(\d{4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/,
        
        ymd: /^(\d{4})(-|\/)(\d{1,2})\2(\d{1,2})$/,
        
        hms: /^((20|21|22|23|[0-1]\d)\:[0-5][0-9])(\:[0-5][0-9])?$/,
        
        ym: /^(\d{4})(-|\/)(\d{1,2})$/,
        
        y: /^(\d{4})$/,
        
        m: /^(0?[1-9]|1[0-2])$/,
        
        d: /^((0?[1-9])|((1|2)[0-9])|30|31)$/,
        
        integer: /^[1-9]\d*$/,
        
        number: /^(-?\d+)\.?(\d*)$/,
        
        cellphone: /^(\+1|1)?[\s.-]?\(?[2-9]\d{2}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/,
        
        landline: /^(\+1|1)?[\s.-]?\(?[2-9]\d{2}\)?[\s.-]?[2-9]\d{2}[\s.-]?\d{4}$/,
        
        plate: {
            
            nev: /^(?:[A-Z]{2,3}[- ]?)?(?:EV|EL|HY|ZEV)[- ]?[A-Z0-9]{2,6}$|^[A-Z0-9]{2,8}[- ]?(?:EV|EL|HY|ZEV)$/,
            
            oil: /^[A-Z0-9]{2,8}(?:[- ]?[A-Z0-9]{2,6})?$/,
        },
        
        id: /^(?!000|666)[0-8]\d{2}-(?!00)\d{2}-(?!0000)\d{4}$/,
        
        zip: /^(?:\d{5}(?:-\d{4})?|(?:APO|FPO|DPO) (?:AE|AP|AA) \d{4})$/,
    };

    const replaceFrag = ({ origin, text, start, stop, length }) => {
        typeof origin !== 'string' ? origin = JSON.stringify(origin) : null;
        typeof text !== 'string' ? text = JSON.stringify(text) : null;
        let result = '';
        if (start === undefined && stop === undefined) {
            result = text;
        }
        else if (start !== undefined && stop === undefined) {
            result = length !== undefined ? origin.substring(0, start) + text + origin.substring(start + length) : origin.substring(0, start) + text;
        }
        else if (start === undefined && stop !== undefined) {
            result = length !== undefined ? origin.substring(stop - length) + text + origin.substring(0, start) : text + origin.substring(stop);
        }
        else {
            result = origin.substring(0, start) + text + origin.substring(stop);
        }
        return result;
    };

    const paramToJson = (str) => {
        let result;
        if (str) {
            str = str.trim();
            let objStr = sliceFrags({ str }).join(''), arrStr = sliceFrags({ str, start: '[', end: ']' }).join(''), excludeStr = objStr + arrStr, std = str.split(',').filter(Boolean).map((k) => {
                return (!k.includes(':') && !excludeStr.includes(k)) ? `${k}:true` : k;
            }).join(',');
            try {
                result = parseStr({
                    content: `{${std}}`,
                    type: 'object',
                    catchable: true,
                });
            }
            catch {
                result = {};
                console.warn('Data parsing error, an empty object "{}" has been returned!');
            }
        }
        return result;
    };

    const getLast = (data) => {
        let dataType = getDataType(data), last = null;
        if (dataType === 'Array' && data.length > 0) {
            last = data.slice(-1)[0];
        }
        else if (dataType === 'Object' && Object.keys(data).length > 0) {
            last = Object.keys(data).slice(-1)[0];
        }
        return last;
    };

    const isSubset = (child, parent) => (Array.isArray(child)) ? child.length <= parent.length && child.every(k => parent.includes(k)) : parent.includes(child);

    const stdParam = (val, dft = {}, prop) => {
        let result = (getDataType(dft) === 'Object') ? { ...dft } : {};
        if (getDataType(val) === 'Object') {
            extend({
                target: result,
                source: val,
            });
        }
        else {
            if (prop && !isNull(val)) {
                Reflect.set(result, prop, val);
            }
        }
        return result;
    };

    const throttle = (fn, options) => {
        let dft = { intvl: config.throttle, prevent: false }, opts = stdParam(options, dft, 'intvl');
        let last = 0, timer = null, handler = function (e) {
            let now = Date.now();
            if (now - last > opts.intvl) {
                if (timer) {
                    clearTimeout(timer);
                    timer = null;
                }
                fn.apply(this, arguments);
                last = now;
            }
            else {
                opts.prevent ? (e.stopPropagation(), e.preventDefault()) : null;
            }
        };
        handler.cancel = () => {
            clearTimeout(timer);
            timer = null;
            return handler;
        };
        return handler;
    };

    const debounce = (fn, options) => {
        let dft = { delay: config.debounce, prevent: false, auto: false }, opts = stdParam(options, dft, 'delay');
        if (orca.isTouchScr && opts.auto) {
            return throttle(fn, { intvl: opts.delay, prevent: opts.prevent });
        }
        else {
            let timer = null, handler = function (e) {
                opts.prevent ? (e.stopPropagation(), e.preventDefault()) : null;
                timer ? clearTimeout(timer) : null;
                opts.instant && opts.instant();
                timer = setTimeout(() => {
                    fn.apply(this, arguments);
                }, opts.delay);
            };
            handler.cancel = () => {
                timer && clearTimeout(timer);
                return handler;
            };
            return handler;
        }
    };

    const convertByte = ({ val, to = '', places = 2, outer = 'span', inner = 'i', units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] }) => {
        val = clampVal({ val, min: 0, max: '' });
        let lvs = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'], unit = '', lv = 0, base = val / 1024, getVal = (i) => i === 0 ? val : toNumber(val / (1024 ** i), { places });
        if (lvs.includes(to)) {
            lv = lvs.findIndex(k => k === to);
        }
        else {
            lv = (base >= 1024 ** 4) ? 5 :
                (base >= 1024 ** 3) ? 4 :
                    (base >= 1024 ** 2) ? 3 :
                        (base >= 1024) ? 2 :
                            (base >= 1) ? 1 : 0;
        }
        val = getVal(lv);
        unit = units[lv];
        return { val, unit, str: `<${outer}><${inner}>${val}</${inner}>${unit}</${outer}>` };
    };

    const fileTools = {
        download: (url, name) => {
            let xhr = new XMLHttpRequest();
            xhr.open("GET", url, true);
            xhr.responseType = 'blob';
            xhr.onload = function () {
                let url = window.URL.createObjectURL(xhr.response), dom = createEl('a');
                dom.src = url || 'javascript:void(0);';
                dom.download = name || config.lang.placeholder.downloadName + Date.now();
                dom.click();
            };
            xhr.send();
        },
        getBase64: (file, cb) => {
            return new Promise((resolve, reject) => {
                try {
                    let reader = new FileReader();
                    reader.readAsDataURL(file);
                    reader.onload = (e) => {
                        cb && cb(e?.target?.result);
                        resolve(e?.target?.result);
                    };
                }
                catch (e) {
                    reject(e);
                }
            });
        },
        getSuffix: (file) => {
            if (file.name.includes('.')) {
                return file.name.split('.').pop();
            }
            else {
                return '';
            }
        },
        getFileName: (url) => {
            try {
                return url.split('/').pop()?.trim() || '';
            }
            catch {
                return '';
            }
        },
        urlToFile: function (url, name = '', cb) {
            name = name || this.getFileName(url) || config.lang.placeholder.fileName + Date.now();
            return new Promise((resolve, reject) => {
                ajax({
                    url,
                    respType: 'blob',
                    type: 'get',
                    error: (res) => {
                        reject(res.content);
                    },
                    success: (res) => {
                        let file = new File([res.content], name, { type: res.content.type });
                        cb && cb(file);
                        resolve(file);
                    }
                });
            });
        }
    };

    const increaseId = (data, hasId = true) => {
        let ids = new Set(), newId = 0;
        if (!data.length)
            return newId;
        if (hasId) {
            for (let k of data)
                ids.add(~~k.id);
            newId = Math.max(...ids) + 1;
        }
        else {
            newId = data.length;
        }
        return newId;
    };

    const findItem = (val, source, key, prio) => {
        let valType = getDataType(val);
        if (!source)
            return val;
        let result, first = source[0], firstId = first?.id, idType = getDataType(firstId);
        if (isNull(firstId) && valType === 'Number') {
            result = source[val];
        }
        else {
            if (key) {
                result = source.find((k) => k[key] === val);
            }
            else {
                if (valType.includes('HTML')) {
                    let hasPrio = (item) => prio?.node ? item[prio.node] === val : false, condition = (item) => hasPrio(item) || item.headEl === val || item.wrapEl === val;
                    result = source.find((k) => condition(k));
                }
                else {
                    let prop = (valType === 'Number') ? (prio?.number || 'id') :
                        (valType === 'String') ? prio?.string || (idType === 'String' ? 'id' : 'label') : '';
                    if (valType === 'Object') {
                        result = source.find((k) => k === val);
                    }
                    else {
                        result = prop ? source.find((k) => k[prop] === val || k[prio?.guard || 'value'] === val) : undefined;
                    }
                }
            }
        }
        return result;
    };

    const splice = ({ host = [], source, intent = 'end+', index = 0, cb }) => {
        if (isNull(host) || !Array.isArray(host))
            return [];
        let tmp = source !== undefined ? (Array.isArray(source) ? source : [source]) : null, data = Array.isArray(tmp) ? tmp : [tmp], idx = isNull(index) ? 0 : clampVal({ min: 0, max: host.length - 1, val: index }), items = [];
        if (intent === 'clear') {
            items = [...host];
            host.splice(0);
        }
        else if (intent === 'add') {
            if (!tmp)
                return host;
            let start = (idx >= host.length) ? (host.length - 1) : idx;
            host.splice(start, 0, ...data);
            items = host.slice(start, start + data.length);
        }
        else if (intent === 'remove') {
            let _tmp = source !== undefined ? host.indexOf(source) : idx;
            if (_tmp < 0) {
                return host;
            }
            else {
                items = host.slice(_tmp, _tmp + 1);
                host.splice(_tmp, 1);
            }
        }
        else if (intent === 'replace') {
            if (!tmp)
                return host;
            host.splice(idx, 1, ...data);
            items = host.slice(idx, idx + data.length);
        }
        else if (intent === 'start-') {
            items = host.slice(0, 1);
            host.shift();
        }
        else if (intent === 'end-') {
            items = host.slice(-1);
            host.pop();
        }
        else if (intent === 'start+') {
            if (!tmp)
                return host;
            host.unshift(...data);
            items = host.slice(0, data.length);
        }
        else {
            if (!tmp)
                return host;
            host.push(...data);
            items = host.slice(-data.length);
        }
        cb && cb(items);
        return host;
    };

    const dl2Tree = (el) => {
        let elem = getEl(el), result = [];
        if (!elem) {
            console.warn(`No node, no access to data!`);
            return result;
        }
        let heads = [...elem.querySelectorAll('dt')], bodys = [...elem.querySelectorAll('dd')];
        if (heads.length !== bodys.length) {
            console.warn('Inconsistent number of "dt" and "dd" tags!');
            return result;
        }
        if (heads.length === 0) {
            console.warn('No "dt" and "dd" tags!');
            return result;
        }
        result = heads.map((k, i) => {
            return { content: bodys[i].innerHTML, ...getValsFromAttrs(k) };
        });
        return result;
    };

    const treeTools = {
        
        find: function (arr, val, key) {
            let tmp = findItem(arr, val, key);
            if (tmp)
                return tmp;
            for (let k of arr) {
                k.children && this.find(k.children, val, key);
            }
            return null;
        },
        getBoolItems: (data, prop, negative = false) => {
            return data.filter((k) => negative ? !k[prop] : k[prop]);
        },
        
        toFlat: function (data) {
            let result = [];
            data.forEach(k => {
                if (k.children && !data.includes(k.children[0])) {
                    result = [...result, k, ...this.toFlat(k.children)];
                }
                else {
                    result.push(k);
                }
            });
            return result;
        },
        
        toTree: (data) => {
            if (!data || data.length === 0 || !data[0].hasOwnProperty('pId')) {
                return data;
            }
            let root = data[0].pId;
            data.forEach(k => {
                let children = data.filter(i => k.id == i.pId);
                if (children.length) {
                    k.children = children;
                }
            });
            return data.filter(k => k.pId == root);
        },
        
        addIdPath: ({ source, rootStart = config.rootStart, idStart = config.idStart, floorStart = config.floorStart, pathHyphen = config.pathHyphen, lbl2Val = true }) => {
            if (!Array.isArray(source) || source.length === 0 || source[0].hasOwnProperty('path')) {
                return source;
            }
            let hasId = source[0].hasOwnProperty('id') ? true : false, index = idStart, each = (data, floor, path = rootStart) => {
                data.forEach(item => {
                    if (!hasId) {
                        item.id = index;
                        index++;
                    }
                    item.floor = floor;
                    item.pId = item.pId || item.pId === 0 ? item.pId : rootStart;
                    item.path = path + pathHyphen + item.id;
                    (!item.hasOwnProperty('value') && item.hasOwnProperty('label') && lbl2Val) ? item.value = item.label : null;
                    if (item.children && item.children.length > 0) {
                        item.children.forEach((k) => {
                            k.pId = item.id;
                        });
                        each(item.children, floor + 1, item.path);
                    }
                    if (!item.path) {
                        item.path = item.pId + pathHyphen + item.id;
                    }
                });
            };
            each(source, floorStart);
            return source;
        },
        fromInput: (el, hyphen = config.splitHyphen) => {
            let elem = getEl(el), result = [];
            if (!elem) {
                console.warn(`No node, no access to data!`);
                return result;
            }
            let tmp = elem.value.trim();
            return !tmp ? [] : elem.value.trim().split(hyphen).map((k) => { return { label: k, value: k }; });
        },
        
        createBranchObj: function ({ source, flatData, target, isChild = true, isLeaf = true, rootStart = config.rootStart, idStart = config.idStart, floorStart = config.floorStart, pathHyphen = config.pathHyphen }) {
            let obj = {}, targetObj = findItem(target, flatData), emptyArr = flatData.length === 0, sourceType = getDataType(source), setIdLabelVal = (data, id) => {
                !data.hasOwnProperty('id') ? data.id = id : null;
                !data.hasOwnProperty('value') ? (data.hasOwnProperty('label') ? data.value = data.label : data.value = '') : null;
                !data.hasOwnProperty('label') ? data.label = config.lang.tree.label + id : null;
            }, setRootChild = (data, id) => {
                let base = {
                    pId: rootStart,
                    path: rootStart + pathHyphen + id,
                    floor: floorStart
                };
                setIdLabelVal(data, id);
                Object.assign(data, base);
            };
            if (isNull(flatData)) {
                return obj;
            }
            if (sourceType === 'String' || sourceType === 'Number') {
                obj.value = obj.label = source;
            }
            else if (sourceType === 'Object') {
                obj = { ...source };
            }
            if (emptyArr) {
                setRootChild(obj, idStart);
            }
            else {
                let newId = increaseId(flatData);
                if (!targetObj) {
                    obj.hasOwnProperty('id') ? newId = obj.id : null;
                    setRootChild(obj, newId);
                }
                else {
                    !targetObj.hasOwnProperty('children') && isChild && (targetObj.children = []);
                    let props = {};
                    setIdLabelVal(obj, newId);
                    props = isChild ? {
                        pId: targetObj.id,
                        path: targetObj.path + pathHyphen + obj.id,
                        floor: targetObj.floor + 1
                    } : {
                        pId: targetObj.pId,
                        path: targetObj.path.replace(new RegExp('(.*)' + targetObj.id), '$1' + obj.id),
                        floor: targetObj.floor
                    };
                    Object.assign(obj, props);
                }
            }
            !isLeaf && (obj.children = []);
            return obj;
        },
        
        childToParent: (source, arrowEnd = true) => {
            if (!source.children) {
                return;
            }
            if (!source.childrenEl) {
                source.childrenEl = createEl('ul');
                source.headEl.insertAdjacentElement('afterEnd', source.childrenEl);
            }
            if (!source.arrowEl) {
                source.arrowEl = createEl('i', { [orca.alias]: 'arrow' });
                source.headEl.insertAdjacentElement(arrowEnd ? 'beforeEnd' : 'afterBegin', source.arrowEl);
            }
        },
        parentToChild: (source) => {
            if (source.children) {
                return;
            }
            source.target.childrenEl.remove();
            source.target.childrenEl = null;
            source.target.arrowEl.remove();
            source.target.arrowEl = null;
            source.target.expanded = false;
        },
        
        addBranch: function ({ source, rootEl, flatData, treeData, brother, isFront = true, repeat = true, autoFill = true, cb }) {
            if (!flatData || !source) {
                return;
            }
            let existing = flatData.find((k) => k.pId === source.pId && k.label === source.label), brotherObj = findItem(brother, flatData), parentObj = findItem(source.pId, flatData), result;
            if (!repeat && existing) {
                console.warn(`A branch with the same label (${source.label}) and pId (${source.pId}) already exists. Duplicate addition is not allowed!`);
                return;
            }
            if (parentObj) {
                if (brotherObj && parentObj.children.includes(brotherObj)) {
                    let index = flatData.indexOf(brotherObj);
                    if (isFront) {
                        splice({ host: parentObj.children, source, index, intent: 'add', cb: (resp) => result = resp[0] });
                        autoFill && brotherObj.wrapEl.insertAdjacentElement('beforeBegin', source.wrapEl);
                    }
                    else {
                        splice({ host: parentObj.children, source, index: index + 1, intent: 'add', cb: (resp) => result = resp[0] });
                        autoFill && brotherObj.wrapEl.insertAdjacentElement('afterEnd', source.wrapEl);
                    }
                }
                else {
                    if (isFront) {
                        splice({ host: parentObj.children, source, intent: 'start+', cb: (resp) => result = resp[0] });
                        autoFill && parentObj.childrenEl.insertAdjacentElement('afterBegin', source.wrapEl);
                    }
                    else {
                        splice({ host: parentObj.children, source, intent: 'end+', cb: (resp) => result = resp[0] });
                        autoFill && parentObj.childrenEl.insertAdjacentElement('beforeEnd', source.wrapEl);
                    }
                }
            }
            else {
                if (brotherObj && brotherObj.pId === source.pId) {
                    let index = treeData.indexOf(brotherObj);
                    if (isFront) {
                        splice({ host: treeData, source, index, intent: 'add', cb: (resp) => result = resp[0] });
                        autoFill && brotherObj.wrapEl.insertAdjacentElement('beforeBegin', source.wrapEl);
                    }
                    else {
                        splice({ host: treeData, source, index: index + 1, intent: 'add', cb: (resp) => result = resp[0] });
                        autoFill && brotherObj.wrapEl.insertAdjacentElement('afterEnd', source.wrapEl);
                    }
                }
                else {
                    if (!rootEl) {
                        return;
                    }
                    if (isFront) {
                        splice({ host: treeData, source, intent: 'start+', cb: (resp) => result = resp[0] });
                        autoFill && rootEl.insertAdjacentElement('afterBegin', source.wrapEl);
                    }
                    else {
                        splice({ host: treeData, source, intent: 'end+', cb: (resp) => result = resp[0] });
                        autoFill && rootEl.insertAdjacentElement('beforeEnd', source.wrapEl);
                    }
                }
            }
            cb && cb(result, treeData);
        },
        
        removeBranch: function ({ source, flatData, treeData, cb, }) {
            if (isNull(source) || !flatData || flatData.length === 0) {
                return;
            }
            let obj = findItem(source, flatData), floorStart = treeData[0].floor;
            if (!obj) {
                return;
            }
            if (obj.floor === floorStart) {
                splice({ host: treeData, source: obj, intent: 'remove' });
            }
            else {
                let parent = findItem(obj.pId, flatData);
                if (!parent) {
                    return;
                }
                let children = parent.children;
                splice({ host: children, source: obj, intent: 'remove' });
                if (children.length === 0) {
                    this.parentToChild(parent);
                }
            }
            obj?.wrapEl && obj.wrapEl.remove();
            cb && cb(obj);
        },
        
        getParentsFromPath({ path, flatData, labelHyphen = config.labelHyphen, field = 'label', pathHyphen = config.pathHyphen, shift = false, pop = false }) {
            let paths = path.split(pathHyphen), parents = paths.map((k) => flatData.find((i) => i.id.toString() == k)).filter(Boolean), text = '';
            shift && parents.shift();
            pop && parents.pop();
            text = parents.map((k) => k[field]).join(labelHyphen);
            return { parents, text };
        },
        
        allToTree: async function ({ content, idStart = config.idStart, rootStart = config.rootStart, floorStart = config.rootStart, pathHyphen = config.pathHyphen, splitHyphen = config.splitHyphen, contType = '', contData = {}, ajax = {}, fill = true, ins, nodeType = 'tree', cb }) {
            if (isEmpty(content)) {
                return [];
            }
            let treeData = [], result = [], getFromNode = (node) => {
                let nodeName = node.nodeName, arr = [];
                if (nodeName === 'SELECT' || nodeName === 'DATALIST') {
                    arr = select2Tree(node);
                }
                else if (nodeName === 'UL' || nodeName === 'OL') {
                    arr = ul2Tree(node, nodeType);
                }
                else if (nodeName === 'DL') {
                    arr = dl2Tree(node);
                }
                else if (nodeName === 'SCRIPT' && node.getAttribute('type') === 'content') {
                    arr = this.toTree(parseStr({
                        content: node.textContent,
                        type: 'array',
                        error: (err) => {
                            console.error(config.error.parse, err);
                        }
                    }));
                }
                else if (nodeName === 'INPUT') {
                    arr = this.fromInput(node, splitHyphen);
                }
                return arr;
            }, getFromArray = (data) => {
                let copyData = deepClone(data);
                return this.toTree(copyData);
            }, strArr2ObjArr = (arr) => {
                let firstType = getDataType(arr[0]), tmp = (firstType === 'String' || firstType === 'Number') ? arr.map((k) => { return { label: k, value: k }; }) : arr;
                return tmp;
            };
            await getContent.call(ins, {
                content,
                contType,
                contData,
                ajax,
                cb: (resp) => {
                    let dataType = getDataType(resp);
                    if (dataType === 'Object' && resp.hasOwnProperty('data') && Array.isArray(resp.data)) {
                        treeData = getFromArray(resp.data);
                        resp.data = treeData;
                        result = resp;
                    }
                    else {
                        if (dataType === 'Array') {
                            treeData = getFromArray(strArr2ObjArr(resp));
                        }
                        else if (dataType.includes('HTML')) {
                            if (['UL', 'OL', 'DATALIST', 'DL', 'SELECT', 'SCRIPT'].includes(resp.nodeName)) {
                                treeData = strArr2ObjArr(getFromNode(resp));
                            }
                            else if (resp.nodeName.includes('INPUT')) {
                                treeData = this.fromInput(resp, splitHyphen);
                            }
                        }
                        else if (dataType === 'String') {
                            let tmp = createEl('div', '', resp), node = tmp.querySelector(':scope > ul,:scope > ol,:scope > datalist,:scope > dl,:scope > select,:scope > script,:scope > input');
                            if (node) {
                                treeData = strArr2ObjArr(getFromNode(node));
                                tmp.remove();
                            }
                            else {
                                let str = resp.trim(), type = (str.startsWith('{') && str.endsWith('}')) ? 'object' : (str.startsWith('[') && str.endsWith(']')) ? 'array' : '';
                                if (type) {
                                    treeData = this.toTree(strArr2ObjArr(parseStr({
                                        content: resp,
                                        type,
                                        error: (err) => {
                                            console.error(config.error.parse, err);
                                        }
                                    })));
                                }
                                else {
                                    treeData = strArr2ObjArr(resp.split(splitHyphen).filter(Boolean));
                                }
                            }
                        }
                        result = treeData;
                    }
                }
            });
            fill && this.addIdPath({ source: treeData, rootStart, idStart, floorStart, pathHyphen });
            cb && cb(result);
            return result;
        },
        getPathHyphen: (treeData) => {
            let item = treeData[0], id = item.id, floor = item.floor, pId = item.pId, path = item.path, hyphen = item.path.replace(pId, '').replace(id, '');
            return { id, floor, pId, path, hyphen };
        },
        graftBranch: function ({ source, target, flatData, treeData, rootEl, isFront = true, isChild = true, cb }) {
            if (isNull(source) || isEmpty(treeData)) {
                return;
            }
            let sourceObj = findItem(source, flatData), targetObj = findItem(target, flatData), firstData = this.getPathHyphen(treeData), floorStart = firstData.floor, rootStart = firstData.pId, pathHyphen = firstData.hyphen;
            if (!sourceObj) {
                return;
            }
            let sourceParent = findItem(sourceObj.pId, flatData);
            if (!sourceParent) {
                splice({ host: treeData, source: sourceObj, intent: 'remove' });
            }
            else {
                splice({ host: sourceParent.children, source: sourceObj, intent: 'remove' });
            }
            if (!targetObj) {
                if (isFront) {
                    rootEl?.insertAdjacentElement('afterBegin', sourceObj.wrapEl);
                    treeData.unshift(sourceObj);
                }
                else {
                    rootEl?.insertAdjacentElement('beforeEnd', sourceObj.wrapEl);
                    treeData.push(sourceObj);
                }
                sourceObj.pId = rootStart;
                sourceObj.floor = floorStart;
                sourceObj.path = rootStart + pathHyphen + sourceObj.id;
            }
            else {
                if (isChild) {
                    !targetObj.hasOwnProperty('children') && (targetObj.children = []);
                    if (isFront) {
                        targetObj.childrenEl.insertAdjacentElement('afterBegin', sourceObj.wrapEl);
                        targetObj.children.unshift(sourceObj);
                    }
                    else {
                        targetObj.childrenEl.insertAdjacentElement('beforeEnd', sourceObj.wrapEl);
                        targetObj.children.push(sourceObj);
                    }
                    sourceObj.pId = targetObj.id;
                    sourceObj.floor = targetObj.floor + 1;
                    sourceObj.path = targetObj.path + pathHyphen + sourceObj.id;
                }
                else {
                    if (targetObj.floor === floorStart) {
                        let index = treeData.indexOf(targetObj), id = isFront ? index : index + 1;
                        splice({ host: treeData, source: sourceObj, index: id, intent: 'add' });
                    }
                    else {
                        let targetParent = findItem(targetObj.pId, flatData), index = targetParent.children.indexOf(targetObj), id = isFront ? index : index + 1;
                        splice({ host: targetParent.children, source: sourceObj, index: id, intent: 'add' });
                    }
                    sourceObj.pId = targetObj.pId;
                    sourceObj.floor = targetObj.floor;
                    sourceObj.path = targetObj.path.replace(new RegExp('(.*)' + targetObj.id), '$1' + sourceObj.id);
                    let position = isFront ? 'beforeBegin' : 'afterEnd';
                    targetObj.wrapEl.insertAdjacentElement(position, sourceObj.wrapEl);
                }
            }
            cb && cb(sourceObj, targetObj);
        }
    };

    const moveItem = ({ source, target, data, isFront = true }) => {
        let sourceType = getDataType(source), targetType = getDataType(target), from = (sourceType === 'Number') ? source : data.indexOf(source), to = (targetType === 'Number') ? target : data.indexOf(target), sourceObj = sourceType === 'Number' ? data[source] : source, offset = isFront ? 0 : 1;
        if (isNull(from) || isEmpty(data)) {
            throw new Error('Cannot get the index of the moving item!');
        }
        if (from > data.length || from < 0) {
            throw new Error('Exceeded array length!');
        }
        if (to < 0 || to > data.length) {
            to = isFront ? 0 : data.length - 1;
        }
        if (from === to) {
            console.warn('Source and target are the same, not moved!');
            return;
        }
        data.splice(from, 1);
        from < to ? to-- : null;
        data.splice(to + offset, 0, sourceObj);
    };

    const findItems = (vals, source, key, pio) => {
        let valsType = getDataType(vals), result = [], tmp = (valsType === 'String') ? vals.split(pio?.separator || config.splitHyphen) :
            (valsType === 'Array') ? vals : [vals];
        result = tmp.map((k) => findItem(k, source, key, pio)).filter(Boolean);
        return result;
    };

    const getAttrBool = (val) => {
        return (val === 'true' || val === '') ? true : false;
    };

    const getAttrArr = (val, dft = '') => {
        let result = [];
        if (val !== null) {
            let tmp = val.trim();
            try {
                if (tmp === '' || tmp === 'true') {
                    dft && (result = dft.split(',').filter(Boolean));
                }
                else {
                    let val = parseStr({
                        content: tmp,
                        type: 'array',
                        catchable: true,
                    });
                    result = Array.isArray(val) ? val : [tmp];
                }
            }
            catch (err) {
                result = tmp.split(',');
            }
        }
        return result;
    };

    let theme = {
        
        set: function (value, name = '') {
            if (isEmpty(value)) {
                return;
            }
            let hexToRgbArr = (val) => {
                val = val.trim();
                let reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/, colorStr = val.toLowerCase(), result = [];
                if (reg.test(colorStr)) {
                    if (colorStr.length === 4) {
                        let temp = '#';
                        for (let k = 1; k < 4; k += 1) {
                            temp += colorStr.slice(k, k + 1).concat(colorStr.slice(k, k + 1));
                        }
                        colorStr = temp;
                    }
                    for (let k = 1; k < 7; k += 2) {
                        result.push(parseInt("0x" + colorStr.slice(k, k + 2)));
                    }
                }
                return result;
            }, rgbToHsl = (arr) => {
                let r = arr[0] / 255, g = arr[1] / 255, b = arr[2] / 255, min = Math.min(r, g, b), max = Math.max(r, g, b), h = 0, s, l = (min + max) / 2, diff = max - min;
                if (max === min) {
                    h = 0;
                    s = 0;
                }
                else {
                    s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min);
                    switch (max) {
                        case r:
                            h = (g - b) / diff + (g < b ? 6 : 0);
                            break;
                        case g:
                            h = 2 + (b - r) / diff;
                            break;
                        case b:
                            h = 4 + (r - g) / diff;
                            break;
                    }
                    h = Math.round(h * 60);
                }
                s = Math.round(s * 100);
                l = Math.round(l * 100);
                return arr.length === 4 ? [h, s, l, arr[3]] : [h, s, l, 1];
            }, getHslaArr = (val) => {
                let valType = getDataType(val), result = [];
                if (!isEmpty(val)) {
                    if (valType === 'String') {
                        val = val.trim().toLowerCase();
                        if (val.startsWith('hsl')) {
                            result = val.replace(/^(hsl|hsla)\(/, '').replace(/\)$/, '').replace(/\s/g, '').split(',');
                        }
                        else {
                            let temp = [];
                            if (val.startsWith('#')) {
                                temp = hexToRgbArr(val);
                            }
                            else if (val.startsWith('rgb')) {
                                temp = val.replace(/^(rgb|rgba)\(/, '').replace(/\)$/, '').replace(/\s/g, '').split(',').map(Number);
                            }
                            result = rgbToHsl(temp);
                        }
                    }
                    else if (valType === 'Array') {
                        result = val;
                    }
                }
                result.length === 3 ? result.push(1) : null;
                return result;
            }, valueType = getDataType(value);
            let hslaObj = { prim: [], text: [], error: [], succ: [], info: [], warn: [], issue: [] };
            if (valueType === 'Object') {
                for (let k in value) {
                    if (value.hasOwnProperty(k) && value[k].length > 2) {
                        hslaObj[k] = getHslaArr(value[k]);
                    }
                }
            }
            else {
                hslaObj.prim = getHslaArr(value);
            }
            if (isEmpty(storage.get('AxThemeRaw'))) {
                storage.set('AxThemeRaw', this.get());
            }
            let rootDom = document.querySelector(":root");
            for (let k in hslaObj) {
                if (hslaObj.hasOwnProperty(k) && hslaObj[k].length > 2) {
                    rootDom.style.setProperty(`--${orca.prefix}h-${k}`, hslaObj[k][0]);
                    rootDom.style.setProperty(`--${orca.prefix}s-${k}`, typeof hslaObj[k][1] === 'string' && hslaObj[k][1].includes('%') ? hslaObj[k][1] : hslaObj[k][1] + '%');
                    rootDom.style.setProperty(`--${orca.prefix}l-${k}`, typeof hslaObj[k][2] === 'string' && hslaObj[k][2].includes('%') ? hslaObj[k][2] : hslaObj[k][2] + '%');
                    rootDom.style.setProperty(`--${orca.prefix}a-${k}`, hslaObj[k][3]);
                }
            }
            name ? storage.set(name, hslaObj) : null;
        },
        get: function () {
            let getValue = (type) => {
                return [
                    getComputedVar(`--${orca.prefix}h-${type}`),
                    getComputedVar(`--${orca.prefix}s-${type}`),
                    getComputedVar(`--${orca.prefix}l-${type}`),
                    getComputedVar(`--${orca.prefix}a-${type}`),
                ].map(k => {
                    let val = k.trim();
                    return val.includes('%') ? val : Number(val);
                });
            };
            return {
                prim: getValue('prim'),
                text: getValue('text'),
                succ: getValue('succ'),
                error: getValue('error'),
                info: getValue('info'),
                warn: getValue('warn'),
                issue: getValue('issue'),
            };
        },
        reset: function () {
            let themeRaw = storage.get('AxThemeRaw');
            this.set(themeRaw);
        }
    };

    const attrValBool = (value) => ![null, 'false', '0', false, 0, undefined].includes(value);

    const getBetweenEls = ({ selector, start, end, root, exclude }) => {
        let rootEl = getEl(root) || document.body, startEl = getEl(start, rootEl), endEl = getEl(end, rootEl), excEls = getEls(exclude, rootEl), els = getEls(selector, rootEl), result = [];
        if (els.length === 0) {
            return result;
        }
        if (startEl && !endEl) {
            result = els.filter((k) => {
                return startEl.compareDocumentPosition(k) & Node.DOCUMENT_POSITION_FOLLOWING;
            });
        }
        else if (!startEl && endEl) {
            result = els.filter((k) => {
                return endEl.compareDocumentPosition(k) & Node.DOCUMENT_POSITION_PRECEDING;
            });
        }
        else if (startEl && endEl) {
            result = els.filter((k) => {
                return (startEl.compareDocumentPosition(k) & Node.DOCUMENT_POSITION_FOLLOWING) && endEl.compareDocumentPosition(k) & Node.DOCUMENT_POSITION_PRECEDING;
            });
        }
        if (excEls.length) {
            return result.filter((k) => {
                return !excEls.find((i) => i.contains(k));
            });
        }
        else {
            return result;
        }
    };

    const scrollTo = (elem, options) => {
        let opts = Object.assign({
            curve: 'easeOut',
            offset: 0,
            duration: 0,
        }, options), rootDom = getEl(options?.root), scrollParent = rootDom || window, scrollOffset = toPixel(opts.offset), anchorDom = getEl(elem), bodyScrollTop = document.documentElement.scrollTop || document.body.scrollTop, offsetScrolled = rootDom ? rootDom.scrollTop : bodyScrollTop, initTime = Date.now(), offsetClient = 0;
        if (rootDom && style(rootDom).position === 'static') {
            rootDom.style.position = 'relative';
        }
        if (anchorDom) {
            offsetClient = rootDom ? anchorDom.offsetTop - rootDom.scrollTop : anchorDom.getBoundingClientRect().top;
        }
        else {
            offsetClient = typeof elem === 'number' ? elem - offsetScrolled : -offsetScrolled;
        }
        let duration = !opts.duration || typeof opts.duration !== 'number' ? Math.abs(offsetClient) / 4 + 1000 : opts.duration, repeat = () => {
            let newTime = Date.now() - initTime, timestep = newTime / duration, step = offsetScrolled + (offsetClient - scrollOffset) * curveFns[opts.curve](timestep);
            scrollParent.scrollTo(0, step);
            repeat.timer = requestAnimationFrame(repeat);
            if (newTime >= duration) {
                scrollParent.scrollTo(0, step);
                cancelAnimationFrame(repeat.timer);
            }
        };
        repeat();
        return elem;
    };

    const setAttr = (el, key, value) => {
        let elem = getEl(el), valType = getDataType(value), result;
        if (!elem || !key)
            return;
        if (isNull(value) || value === false) {
            elem.removeAttribute(key);
            result = { key, value: isNull(value) ? null : false };
        }
        else {
            if (valType === 'Boolean' && value === true) {
                elem.toggleAttribute(key, true);
                result = { key, value: true };
            }
            else if (valType === 'String') {
                elem.setAttribute(key, value);
                result = { key, value };
            }
            else {
                elem.setAttribute(key, JSON.stringify(value));
                result = { key, value: elem.getAttribute(key) };
            }
        }
        return result;
    };

    const setAttrs = (el, data, cb) => {
        let elem = getEl(el), result = [];
        if (!elem || isEmpty(data))
            return;
        if (!Array.isArray(data) && !data.hasOwnProperty('key') && !data.hasOwnProperty('value')) {
            for (let k in data)
                result.push(setAttr(elem, k, data[k]));
        }
        else {
            let tmp = Array.isArray(data) ? data : [data];
            for (let k of tmp)
                result.push(setAttr(elem, k.key, k.value));
        }
        cb && cb(result.filter(Boolean));
    };

    const getScrollObj = () => navigator.userAgent.indexOf("Firefox") > 0 ? { event: 'DOMMouseScroll', detail: 'detail' } : { event: 'mousewheel', detail: 'wheelDelta' };

    const transformTools = {
        
        get: (elem, props, instead = false) => {
            let dom = getEl(elem), styles = style(dom), value = dom?.style?.transform, result = {
                rotate: 0,
                scale: { x: 1, y: 1 },
                translate: { x: 0, y: 0 },
                skew: { x: 0, y: 0 }
            };
            isEmpty(props) && (props = ['translate', 'scale', 'rotate', 'skew']);
            if (value) {
                let getReg = (type) => new RegExp(`${type}\\(([^\\)]+)\\)`), getText = (type) => value.match(getReg(type));
                if (props.includes('translate') && value.includes('translate') && getText('translate')) {
                    if (getText('translate')[1].includes(',')) {
                        let arr = getText('translate')[1].split(',').map((k) => parseInt(k));
                        result.translate = { x: arr[0], y: arr[1] };
                    }
                    else {
                        result.translate = { x: parseInt(getText('translate')[1]), y: 0 };
                    }
                }
                if (props.includes('scale') && value.includes('scale') && getText('scale')) {
                    if (getText('scale')[1].includes(',')) {
                        let arr = getText('scale')[1].split(',').map((k) => parseFloat(k));
                        result.scale = { x: arr[0], y: arr[1] };
                    }
                    else {
                        result.scale = { x: parseFloat(getText('scale')[1]), y: parseFloat(getText('scale')[1]) };
                    }
                }
                if (props.includes('rotate') && value.includes('rotate') && getText('rotate')) {
                    result.rotate = parseFloat(getText('rotate')[1]);
                }
                if (props.includes('skew') && value.includes('skew') && getText('skew')) {
                    if (getText('skew')[1].includes(',')) {
                        let arr = getText('skew')[1].split(',').map((k) => parseFloat(k));
                        result.skew = { x: arr[0], y: arr[1] };
                    }
                    else {
                        result.skew = { x: parseFloat(getText('skew')[1]), y: 0 };
                    }
                }
            }
            if (instead) {
                result.translate = { x: parseInt(styles.left), y: parseInt(styles.top) };
            }
            return result;
        },
        
        set: function ({ el, data, instead = false, cb }) {
            let dom = getEl(el), now = this.get(dom, ['translate', 'scale', 'rotate', 'skew'], instead), transformTxt = dom?.style.transform || '', getReg = (type) => { return new RegExp(`${type}\\(([^\\)]+)\\)`, 'gmi'); }, re = (val, label, prop) => isNull(val[prop]) ? now[label][prop] : val[prop];
            if (!dom && isEmpty(data))
                return;
            for (let k in data) {
                if (data.hasOwnProperty(k)) {
                    let value = '';
                    if (k === 'translate') {
                        if (instead) {
                            !isNaN(data[k]) ?
                                (dom.style.left = `${data[k]}px`) :
                                (dom.style.left = `${re(data[k], 'translate', 'x')}px`, dom.style.top = `${re(data[k], 'translate', 'y')}px`);
                        }
                        else {
                            value = !isNaN(data[k]) ? `${k}(${data[k]}px)` : `${k}(${re(data[k], 'translate', 'x')}px,${re(data[k], 'translate', 'y')}px)`;
                            if (transformTxt.includes(k)) {
                                if (transformTxt.startsWith('translate')) {
                                    transformTxt = transformTxt.replace(getReg(k), value);
                                }
                                else {
                                    transformTxt = transformTxt.replace(getReg(k), '');
                                    transformTxt = `${value} ${transformTxt}`;
                                }
                            }
                            else {
                                transformTxt = `${value} ${transformTxt}`;
                            }
                        }
                    }
                    else {
                        if (k === 'scale') {
                            value = !isNaN(data[k]) ? `${k}(${data[k]})` : `${k}(${re(data[k], 'scale', 'x')},${re(data[k], 'scale', 'y')})`;
                        }
                        else if (k === 'rotate') {
                            value = `${k}(${data[k]}deg)`;
                        }
                        else if (k === 'skew') {
                            value = !isNaN(data[k]) ? `${k}(${data[k]}deg)` : `${k}(${re(data[k], 'skew', 'x')}deg,${re(data[k], 'skew', 'y')}deg)`;
                        }
                        if (transformTxt.includes(k)) {
                            transformTxt = transformTxt.replace(getReg(k), value);
                        }
                        else {
                            transformTxt += ` ${value}`;
                        }
                    }
                }
            }
            dom.style.transform = transformTxt;
            cb && cb(transformTxt);
        },
        remove: ({ el, prop }) => {
            let dom = getEl(el), tmp = dom?.style?.transform;
            if (!dom || !tmp)
                return;
            dom.style.transform = prop ? tmp.replace(new RegExp(`${prop}\\([^)]+\\)\\s*`, 'g'), '') : 'none';
        },
        disable: (el) => {
            let dom = getEl(el);
            if (!dom)
                return;
            dom.style.transitionDuration = `0ms`;
        },
        enable: (el, duration = 200) => {
            let dom = getEl(el);
            if (!dom)
                return;
            dom.style.transitionDuration = `${duration}ms`;
        },
        clear: (el) => {
            let dom = getEl(el);
            if (!dom)
                return;
            dom.style.transition = `none`;
        },
        
        matrix: (elem) => {
            let el = getEl(elem);
            if (!el)
                return [];
            let value = style(el).transform;
            return (value === 'none') ? [1, 0, 0, 1, 0, 0] : value.replace(/[^0-9.\-,]/g, '').split(',').map(k => Number(k));
        },
    };

    const isScrollUp = (event, detailName = getScrollObj().detail) => {
        let mouseDetail = event[detailName], isUp;
        if (navigator.userAgent.indexOf("Firefox") > 0) {
            isUp = mouseDetail > 0 ? true : false;
        }
        else {
            isUp = mouseDetail < 0 ? true : false;
        }
        return isUp;
    };

    const eventMap = orca.isTouchScr ? ['touchstart', 'touchmove', 'touchend', 'touchcancel'] : ['mousedown', 'mousemove', 'mouseup', 'mouseleave'];

    const getClientObj = (event) => {
        let tmp = orca.isTouchScr ? event.targetTouches[0] : event;
        return tmp ? { x: tmp.clientX, y: tmp.clientY } : null;
    };

    const getNestProp = (data, path) => {
        if (!path)
            return data;
        return path.replace(/['"\s]/g, '').split('.').reduce((prev, cur) => {
            if (prev && prev[cur] !== undefined)
                return prev[cur];
            if (cur.endsWith(']')) {
                let tmp = [];
                if (cur.startsWith('[')) {
                    tmp = cur.split(']').map((k) => k.replace('[', '')).filter(Boolean);
                }
                else {
                    tmp = cur.split('[').map((k) => k.replace(']', ''));
                }
                return tmp.reduce((a, b) => a && a[b], prev);
            }
            return undefined;
        }, data);
    };

    const arrSort = (source, basis) => {
        if (isEmpty(source))
            return;
        let basisType = getDataType(basis), _basis = [], basisFn = (keys) => {
            if (keys.length === 0)
                return (a, b) => (a + '').localeCompare(b + '', config.lang.name);
            return (a, b) => {
                for (let k of keys) {
                    let key = '', dir = 0, result = 0;
                    if (k.hasOwnProperty('key')) {
                        key = k.key;
                    }
                    else {
                        key = 'label';
                    }
                    if (k.hasOwnProperty('dir')) {
                        dir = k.dir === 'asc' ? 1 : k.dir === 'desc' ? -1 : 0;
                    }
                    else {
                        dir = 1;
                    }
                    result = (getNestProp(a, key) + '').localeCompare(getNestProp(b, key) + '', k.locale || config.lang.name, k.opt || {});
                    if (result !== 0)
                        return result * dir;
                }
                return 0;
            };
        };
        if (basisType === 'Object') {
            _basis = [basis];
        }
        else if (basisType === 'Array') {
            _basis = basis;
        }
        source.sort(basisFn(_basis));
    };

    const clearRegx = (data) => (data + '').replace(/[.*+?^${}()|[\]\\]/g, '');

    const arrSearch = ({ keys, props = 'label', source = [], fuzzy = true, limit = 0, order = '', ignore = true, hyphen = config.splitHyphen }) => {
        if (isEmpty(keys) || isEmpty(props) || isEmpty(source)) {
            return [];
        }
        let keysArr = valToArr(keys, hyphen).map((k) => clearRegx(k)).filter(Boolean), propsArr = valToArr(props, hyphen), crudeArr = [], regStr = '(' + keysArr.join('|') + ')', regExp = new RegExp(regStr, `${ignore ? 'i' : ''}g`), lowerSet = (arr) => [...new Set(arr.map((k) => k.toLowerCase()))];
        for (let v of source) {
            let valueStr = propsArr.map(k => v[k]).join('■'), valueMatch = valueStr.match(regExp), valueObj = {}, keysMatch = [];
            if (valueMatch) {
                keysMatch = [...new Set(valueMatch)];
                valueObj = { source: v, weight: valueMatch.length, keys: keysMatch };
                if (!fuzzy) {
                    if (ignore) {
                        (lowerSet(keysArr).length === lowerSet(keysMatch).length) && crudeArr.push(valueObj);
                    }
                    else {
                        (keysArr.length === keysMatch.length) && crudeArr.push(valueObj);
                    }
                }
                else {
                    crudeArr.push(valueObj);
                }
            }
        }
        if (order) {
            let orderType = getDataType(order), basis;
            if (orderType === 'String') {
                basis = order === 'desc' ? { key: 'weight', dir: 'desc' } : order === 'asc' ? { key: 'weight', dir: 'asc' } : '';
            }
            else if (orderType === 'Boolean' && order === true) {
                basis = { key: 'weight', dir: 'desc' };
            }
            else {
                basis = order;
            }
            arrSort(crudeArr, basis);
        }
        (limit && crudeArr.length > limit) && crudeArr.splice(limit);
        return crudeArr;
    };

    const getIntArr = (data, hyphen = config.splitHyphen) => {
        let arrs = data.map((k) => {
            return typeof k === 'string' ? valToArr(k, hyphen) : k;
        });
        return arrs.reduce((prev, cur) => prev.filter((k) => cur.includes(k)));
    };

    const isOutside = (ev, elem) => {
        let el = getEl(elem);
        if (!el || !ev)
            return true;
        let point = orca.isTouchScr ? { x: ev.targetTouches[0].clientX, y: ev.targetTouches[0].clientY } : { x: ev.clientX, y: ev.clientY }, lt = { x: el.getBoundingClientRect().left, y: el.getBoundingClientRect().top }, rb = { x: lt.x + el.offsetWidth, y: lt.y + el.offsetHeight };
        return (point.x < lt.x || point.x > rb.x || point.y < lt.y || point.y > rb.y) ? true : false;
    };

    const getEvtClient = (evt, axis) => {
        let data = evt.targetTouches && evt.targetTouches[0] ? evt.targetTouches[0] : evt.changedTouches ? evt.changedTouches[0] : evt, prop = axis === 'x' ? 'clientX' : axis === 'y' ? 'clientY' : '';
        return prop ? data[prop] : { x: data.clientX, y: data.clientY };
    };

    const getRectPoints = (evt, elem) => {
        let el = getEl(elem), result = [];
        if (!el || !evt)
            return result;
        let point = getEvtClient(evt), x = point.x, y = point.y, size = { w: el.offsetWidth, h: el.offsetHeight }, lt = { x: el.getBoundingClientRect().left, y: el.getBoundingClientRect().top }, rb = { x: lt.x + size.w, y: lt.y + size.h }, range = { 'h1/3': lt.y + size.h / 3, 'h1/2': lt.y + size.h / 2, 'h2/3': lt.y + size.h * 2 / 3, 'w1/3': lt.x + size.w / 3, 'w1/2': lt.x + size.w / 2, 'w2/3': lt.x + size.w * 2 / 3 };
        if (x >= lt.x && x <= rb.x && y >= lt.y && y <= rb.y) {
            result.push('inside');
            if (y < range['h1/3']) {
                result.push('t/3');
            }
            else if (y >= range['h1/3'] && y < range['h1/2']) {
                result.push('t/2');
            }
            else if (y >= range['h2/3']) {
                result.push('b/3');
            }
            else if (y >= range['h1/2']) {
                result.push('b/2');
            }
            if (x < range['w1/3']) {
                result.push('l/3');
            }
            else if (x >= range['w1/3'] && x < range['w1/2']) {
                result.push('l/2');
            }
            else if (x >= range['w2/3']) {
                result.push('r/3');
            }
            else if (x >= range['w1/2']) {
                result.push('r/2');
            }
        }
        else {
            result = ['outside'];
        }
        return result;
    };

    const elsSort = (data, reverse = false) => {
        let tmp = data.map((k) => getEl(k)).filter(Boolean), els = unique(tmp);
        els.sort((a, b) => {
            if (a.contains(b))
                return 1;
            if (b.contains(a))
                return -1;
            return 0;
        });
        return reverse ? els.reverse() : els;
    };

    const getStrFromTpl = function (data, tplStr, tplEng) {
        let str = tplStr || this.tplStr, eng = tplEng || this.tplEng;
        return eng.name === 'template' ? eng(str)(data) : eng(str, data);
    };

    const setSingleSel = (target, sel) => {
        let arr = Array.isArray(target) ? target : [target], els = arr.map((k) => getEls(k)).flat().filter(Boolean), setFn = (el) => {
            if (sel.trim().startsWith('#')) {
                el.id = sel.slice(1);
            }
            else if (sel.trim().startsWith('.')) {
                el.classList.add(sel.slice(1));
            }
            else if (sel.trim().startsWith('[') && sel.trim().endsWith(']')) {
                let tmp = sel.slice(1, -1).replace('"', '').replace("'", '').split('=');
                el.setAttribute(tmp[0], tmp[1] || '');
            }
        };
        if (els.length === 0 || !sel || typeof sel !== 'string')
            return;
        for (let k of els) {
            setFn(k);
        }
    };

    const splitNum = (value) => {
        let num = value.toString().split('.'), str = `<s>${num[0]}</s>`;
        !isNull(num[1]) && (str += `<u>.${num[1]}</u>`);
        return `<span class="${orca.prefix}splitnum">${str}</span>`;
    };

    const parseUrlArr = (url, opts = {}) => {
        if (!url)
            return [];
        let options = Object.assign({ start: '{', end: '}', max: 20 }, opts), result = [], reg = new RegExp(`\\${options.start}(\\S*)\\${options.end}`), match = url.match(reg);
        if (!match)
            return [];
        let tmp = match[1], pageRange = tmp.split('-').map((k) => ~~k), pageCount = tmp.split(',').map((k) => ~~k), pageStart = pageRange[0], pageEnd = pageRange[1], pageMax = pageEnd || pageStart + options.max, holder = `${options.start}${tmp}${options.end}`;
        if (url.includes(',')) {
            result = pageCount.map((k) => url.replace(holder, k));
        }
        else {
            for (let i = pageStart; i <= pageMax; i++) {
                result.push(url.replace(holder, i));
            }
        }
        return result;
    };

    const dateTools = {
        toSlash: (data) => {
            return data.replaceAll('-', '/');
        },
        getTimeObj: function (str) {
            let tmp = str.replaceAll(' ', '').split(':'), result = { hh: 0, mm: 0, ss: 0 };
            if (str) {
                if (tmp.length < 2) {
                    result.hh = ~~str || 0;
                }
                else {
                    result.hh = ~~tmp[0] || 0;
                    result.mm = ~~tmp[1] || 0;
                    result.ss = ~~tmp[2] || 0;
                }
            }
            return result;
        },
        int2Date: (value, type = 'datetime') => {
            value = ~~value;
            let prop = (type === 'daytime') ? 'hh' : (type === 'month') ? 'MM' : 'YYYY';
            return { value, prop };
        },
        getDate: function (data, type = 'datetime', lang = config.lang.datetime) {
            let dateType = getDataType(data), result;
            if (isEmpty(data)) {
                result = new Date();
            }
            else {
                if (dateType === 'Date') {
                    result = new Date(data.valueOf());
                }
                else if (dateType === 'String') {
                    let isBc = data.includes(lang.bc);
                    data = this.toSlash(trim(data).replace(lang.bc, ''));
                    if (data.includes(' ')) {
                        result = new Date(data);
                        if (!data.includes('/')) {
                            console.warn('Invalid date format, current date used instead!');
                            result = new Date();
                        }
                        else {
                            let tmp = data.split(' '), tmpStart = tmp[0].split('/'), tmpEnd = tmp[1].split(':'), tmpFlat, tmpDate;
                            tmpStart[1] = tmpStart[1] ? tmpStart[1] - 1 : 0;
                            tmpStart[2] = tmpStart[2] || 0;
                            tmpEnd[1] = tmpEnd[1] || 0;
                            tmpEnd[2] = tmpEnd[2] || 0;
                            tmpFlat = [...tmpStart, ...tmpEnd].map((k) => ~~k);
                            isBc && (tmpFlat[0] = tmpFlat[0] * -1);
                            tmpDate = new Date(...tmpFlat);
                            tmpDate.setFullYear(tmpFlat[0]);
                            result = tmpDate;
                        }
                    }
                    else {
                        if (data.includes(':')) {
                            result = new Date('1970/1/1 ' + data);
                        }
                        else if (data.includes('/')) {
                            let tmp = data.split('/').map((k) => ~~k);
                            tmp[1] && tmp[1]--;
                            isBc && (tmp[0] = tmp[0] * -1);
                            result = new Date(...tmp);
                        }
                        else {
                            result = new Date('1970/1/1 00:00:00');
                            let tmp = this.int2Date(data, type);
                            tmp.prop === 'hh' ? result.setHours(tmp.value) : tmp.prop === 'MM' ? result.setMonth(tmp.value - 1) : result.setFullYear(isBc ? tmp.value * -1 : tmp.value);
                        }
                    }
                }
                else if (dateType === 'Object') {
                    result = new Date('1970/1/1 00:00:00');
                    data.hasOwnProperty('YYYY') && result.setFullYear(data.YYYY);
                    data.hasOwnProperty('MM') && result.setMonth(data.MM);
                    data.hasOwnProperty('DD') && result.setDate(data.DD);
                    data.hasOwnProperty('hh') && result.setHours(data.hh);
                    data.hasOwnProperty('mm') && result.setMinutes(data.mm);
                    data.hasOwnProperty('ss') && result.setSeconds(data.ss);
                }
                else {
                    result = new Date();
                }
            }
            if (['date', 'year', 'month'].includes(type)) {
                result.setHours(0);
                result.setMinutes(0);
                result.setSeconds(0);
                ['year', 'month'].includes(type) && result.setDate(1);
                type === 'year' && result.setMonth(0);
            }
            else if (type === 'daytime') {
                result.setFullYear(1970);
                result.setMonth(0);
                result.setDate(1);
            }
            return result;
        },
        getDateObj: function (data, type = 'datetime') {
            let dataType = getDataType(data), date, result;
            if (dataType === 'Object') {
                result = { ...data };
            }
            else {
                date = this.getDate(data, type);
                result = { YYYY: date.getFullYear(), MM: date.getMonth(), DD: date.getDate(), hh: date.getHours(), mm: date.getMinutes(), ss: date.getSeconds() };
            }
            if (['date', 'year', 'month'].includes(type)) {
                Reflect.deleteProperty(result, 'hh');
                Reflect.deleteProperty(result, 'mm');
                Reflect.deleteProperty(result, 'ss');
                ['year', 'month'].includes(type) && Reflect.deleteProperty(result, 'DD');
                type === 'year' && Reflect.deleteProperty(result, 'MM');
            }
            else if (type === 'daytime') {
                Reflect.deleteProperty(result, 'YYYY');
                Reflect.deleteProperty(result, 'MM');
                Reflect.deleteProperty(result, 'DD');
            }
            return result;
        },
        getCurDays: function (data) {
            let curDate = this.getDate(data), curYear = curDate.getFullYear(), curMonth = curDate.getMonth();
            return new Date(curYear, curMonth + 1, 0).getDate();
        },
        getOffsetDate: function (data, options = { YYYY: 0, MM: 0, DD: 0, hh: 0, mm: 0, ss: 0 }) {
            let curDate = this.getDate(data);
            options.hasOwnProperty('ss') && curDate.setDate(curDate.getSeconds() + options.ss);
            options.hasOwnProperty('mm') && curDate.setDate(curDate.getMinutes() + options.mm);
            options.hasOwnProperty('hh') && curDate.setDate(curDate.getHours() + options.hh);
            options.hasOwnProperty('DD') && curDate.setDate(curDate.getDate() + options.DD);
            options.hasOwnProperty('MM') && curDate.setMonth(curDate.getMonth() + options.MM);
            options.hasOwnProperty('YYYY') && curDate.setFullYear(curDate.getFullYear() + options.YYYY);
            return curDate;
        },
        fillZero: (data, places = 2) => data.toString().padStart(places, '0'),
        fillFormat: function (date, format, lang = config.lang.datetime) {
            let YYYY, MM, DD, hh, mm, ss, WW, weeks = lang.weeks, tmp = this.getDate(date);
            YYYY = tmp.getFullYear();
            MM = tmp.getMonth() + 1;
            DD = tmp.getDate();
            WW = tmp.getDay();
            hh = tmp.getHours();
            mm = tmp.getMinutes();
            ss = tmp.getSeconds();
            if (format.includes('YYYY')) {
                let tmp = Math.abs(YYYY) + '';
                if (YYYY < 0) {
                    if (format.includes('BC')) {
                        format = format.replace('BC', lang.bc);
                    }
                    else {
                        tmp = lang.bc + tmp;
                    }
                }
                else {
                    format.includes('BC') && (format = format.replace('BC', ''));
                }
                format = format.replace('YYYY', tmp);
            }
            format.includes('MM') && (format = format.replace('MM', this.fillZero(MM)));
            format.includes('DD') && (format = format.replace('DD', this.fillZero(DD)));
            format.includes('hh') && (format = format.replace('hh', this.fillZero(hh)));
            format.includes('mm') && (format = format.replace('mm', this.fillZero(mm)));
            format.includes('ss') && (format = format.replace('ss', this.fillZero(ss)));
            format.includes('WW') && (format = format.replace('WW', weeks[WW]));
            return format;
        },
        sort: function (data, order = 'asc') {
            return data.sort((a, b) => order === 'asc' ? this.getDate(a) - this.getDate(b) : this.getDate(b) - this.getDate(a));
        },
        getDateType: (format) => {
            return RegExp(/^(?=.*YYYY)(?=.*MM)(?=.*DD)(?=.*hh).*$/).test(format) ? 'datetime' :
                RegExp(/^(?=.*YYYY)(?=.*MM)(?=.*DD).*$/).test(format) ? 'date' :
                    RegExp(/^(?=.*YYYY)(?=.*MM).*$/).test(format) ? 'month' :
                        RegExp(/^(?=.*YYYY).*$/).test(format) ? 'year' :
                            RegExp(/^(?=.*hh).*$/).test(format) ? 'daytime' : '';
        },
        isSameDay: (a, b) => {
            
            return a.YYYY == b.YYYY && a.MM == b.MM && a.DD == b.DD;
            
        }
    };

    const repeatStr = (tpl, num = 1, data) => {
        let result = '';
        for (let i = 1; i <= num; i++) {
            result += renderTpl(tpl, { index: i, data });
        }
        return result;
    };

    const createModule = (options) => {
        let opts = Object.assign({ type: 'none', optMaps: [], component: false, spread: [], methods: {}, ready: null, init: null, augment: false, initial: true }, options), modName = opts.name || 'Module' + Date.now(), hasHost = ['node', 'data'].includes(opts.type), hostType = hasHost ? opts.type : 'none', str = `"use strict";
            return class ${modName} extends ModBaseListenCache {
                static hostType = "${hostType}";
                static optMaps =  optMaps;
                constructor(${hasHost ? 'host,' : ''}options, eager = initial) {
                    super();
                    super.ready({ type:"${hostType}",${hasHost ? 'host,' : ''} options, optMaps:${modName}.optMaps,  component, spread });
                    constructed && constructed.call(this);
                    super.listen({ name: 'constructed' });
                    eager && this.init();
                }
                async init(cb) {
                    super.listen({ name: 'initiate' });
                    try{
                        this.options.b4Init && await this.options.b4Init.call(this);
                    }catch{
                        console.warn(config.warn.init);
                        return this;
                    }
                    initiated && await initiated.call(this);
                    super.listen({ name: 'initiated', cb });
                    return this;
                }
            }
        `, module = new Function('optMaps', 'component', 'spread', 'constructed', 'initiated', 'initial', 'ModBaseListenCache', 'config', str)(opts.optMaps, opts.component, opts.spread, opts.constructed, opts.initiated, opts.initial, ModBaseListenCache, config);
        for (let k in opts.methods) {
            module.prototype[k] = opts.methods[k];
        }
        opts.augment && (orca[modName] = module);
        return module;
    };

    class CompBase extends HTMLElement {
        shadowEl;
        slotEl;
        propsRaw;
        properties;
        propsProxy;
        propsObs;
        custAttrs;
        boolAttrs;
        reset;
        clear;
        wrapEl;
        plans;
        connected;
        set;
        timestamp;
        connCount;
        rawHtml;
        canListen;
        sourceEl;
        ins;
        constructor() {
            super();
            this.properties = {};
            this.propsRaw = {};
            this[orca.compSign] = true;
            this.plans = {};
            this.timestamp = Date.now();
            this.connCount = 0;
            this.createPropsObs();
            this.canListen = true;
            this.getRawCont();
        }
        connectedCallback() {
            this.connectedRender();
        }
        disconnectedCallback() {
            this.listen({ name: 'disconnected' });
        }
        adoptedCallback() {
            this.listen({ name: 'adopted' });
        }
        static lazyAttrs = ['stor-name', 'class'];
        static baseAttrs = ['on-connected', 'on-disconnected', 'on-adopted', 'on-reset', 'on-set'];
        static jsonAttrs = ['lang'];
        static boolAttrs = [];
        createShadow() {
            this.shadowEl = this.attachShadow({ mode: "open" });
            this.slotEl = createEl('slot');
            this.shadowEl.appendChild(this.slotEl);
        }
        saveProps(name, newVal, comp) {
            this.propsProxy[name] = comp.boolAttrs.includes(name) ? getAttrBool(newVal) : comp.jsonAttrs.includes(name) ? strToJson(newVal) : newVal;
        }
        savePropsToListen(name, oldVal, newVal, comp, other) {
            if (other && Object.keys(other).includes(name)) {
                this.propsProxy[name] = other[name];
            }
            else {
                this.saveProps(name, newVal, comp);
            }
            this.changedMaps[name] && this.changedMaps[name].call(this, { name, newVal, oldVal, proxy: this.propsProxy });
        }
        getRawProps(comp, opts) {
            for (let k of [...comp.custAttrs, ...comp.lazyAttrs])
                this.propsRaw[k] = this.getAttribute(k);
            for (let k of comp.boolAttrs)
                this.propsRaw[k] = getAttrBool(this.getAttribute(k));
            for (let k of comp.jsonAttrs)
                this.propsRaw[k] = strToJson(this.getAttribute(k));
        }
        getProxyProps() {
            for (let k in this.propsRaw)
                this.propsProxy[k] = this.propsRaw[k];
        }
        restoreAttrs() {
            for (let k in this.propsProxy) {
                let valProxy = this.propsProxy[k], valRaw = this.propsRaw[k];
                if (valProxy !== valRaw) {
                    if (isNull(valRaw)) {
                        this.removeAttribute(k);
                    }
                    else if (valRaw === true) {
                        this.setAttribute(k, '');
                    }
                    else if (valRaw === false) {
                        this.removeAttribute(k);
                    }
                    else {
                        this.setAttribute(k, valRaw);
                    }
                }
            }
        }
        getHtmlVal(name = 'label', unformatted = true) {
            let val = unformatted ? this.textContent?.trim() : this.innerHTML;
            return val || this.getAttribute(name);
        }
        connectedRender(data) {
            this.render(data);
            this.connected = true;
            this.listen({ name: 'connected', params: [this.ins] });
            this.connCount++;
        }
        getConnCont(format = 'html') {
            let tmp = createEl('div', null, this.rawHtml);
            return format === 'text' ? tmp.textContent : this.rawHtml;
        }
        getRawCont() {
            if (!this.connCount) {
                let tmp = this.querySelector(`:scope>[${orca.alias}="source"]`);
                if (tmp) {
                    this.rawHtml = tmp.innerHTML;
                }
                else {
                    this.sourceEl = createEl('template', { [orca.alias]: 'source' });
                    this.sourceEl.innerHTML = this.rawHtml = this.innerHTML;
                }
            }
        }
        insertSource() {
            let tmpSourceEl = this.sourceEl || this.querySelector(`:scope>[${orca.alias}="source"]`);
            this.innerHTML = tmpSourceEl?.outerHTML || '';
        }
        createPropsObs() {
            this.propsObs = new Observe(this.properties, { deep: true });
            this.propsProxy = this.propsObs.proxy;
            this.propsObs.on('completed', (resp) => {
                this.ins && this.ins.initialized && resp.keys.set.length && this.completedEvt(resp);
            });
        }
        updateProxy(name, newVal, map) {
            let value;
            if (newVal === null) {
                this.propsProxy[name] = this.ins.rawOpts[name];
            }
            else {
                if (name === 'options') {
                    value = strToJson(newVal);
                }
                else if (name === 'async') {
                    value = getAttrBool(newVal);
                }
                else {
                    if (!map)
                        throw new Error(`Setting ${name} is invalid , Please use a module and set the map for options!`);
                    value = attrJoinVal(name, newVal, map);
                }
                deepMerge(this.propsProxy, value, {});
            }
        }
        getAttrHtmlData(data) {
            let arr, getStr = (str) => {
                let tmp = createEl('div', null, str), script = tmp.querySelector('script[type="content"]');
                return (script?.innerHTML || str).replace(/\n/g, '').trim();
            };
            if (isEmpty(data)) {
                let attrCont = this.getAttribute('content');
                arr = attrCont ? getAttrArr(attrCont) : getAttrArr(getStr(this.rawHtml));
            }
            else {
                arr = Array.isArray(data) ? data : getAttrArr(getStr(data));
            }
            return arr;
        }
        changedMaps = {};
    }

    class CompBaseComm extends CompBase {
        constructor() {
            super();
            this.reset = function () {
                this.innerHTML = '';
                this.fillWrap(this.propsRaw);
                this.restoreAttrs();
                this.render(this.propsRaw);
                this.listen({ name: 'reset' });
            };
            this.clear = (attr = 'value') => {
                this.removeAttribute(attr);
                this.listen({ name: 'cleared', params: [attr] });
            };
            this.set = (data) => {
                if (isEmpty(data))
                    return;
                let tmp = (typeof data === 'string') ? strToJson(data) : data;
                setAttrs(this, tmp, (resp) => {
                    this.listen({ name: 'set', params: [resp] });
                });
            };
            this.on('disconnected', () => {
                this.connCount = 0;
                this.innerHTML = this.rawHtml;
            });
            this.on('adopted', () => {
                this.connCount = 0;
                this.innerHTML = this.rawHtml;
            });
            this.on('connected', () => {
                this.setAttribute(orca.compSign, '');
                this.setCache();
            });
            this.on('reset', () => {
                this.clearCache();
            });
            this.propsObs.on('set', (data) => {
                this.connected && this.updateCache({ [data.key]: data.value });
            });
        }
        completedEvt(data) {
            this.ins.update(this.properties);
            this.listen({ name: 'updated', params: [this.properties] });
        }
        listen({ name, params = [], cb } = {}) {
            name && this.plans.hasOwnProperty(name) ? this.emit(name, ...params) : null;
            if (name && this.propsProxy[`on-${name.toLowerCase()}`]) {
                let value = this.propsProxy[`on-${name.toLowerCase()}`], addFnShell = (str) => {
                    let tmp = str.trim(), result = (!(tmp.startsWith('function') || tmp.startsWith('(')) && !tmp.endsWith('}')) ? `function(){${str}}` : str;
                    return result;
                }, fn = parseStr({
                    content: addFnShell(value),
                    type: 'other',
                    method: 'new Function'
                });
                fn && fn.call(this, ...params);
            }
            cb && cb.call(this, ...params);
        }
        on(type, handler) {
            plan.add(type, this, handler);
            return this;
        }
        emit(type, ...params) {
            plan.do(type, this, ...params);
            return this;
        }
        off(type, handler) {
            plan.remove(type, this, handler);
            return this;
        }
        setCache() {
            let storName = this.propsProxy['stor-name'], cache = storage.get(storName);
            if (!storName || !cache)
                return;
            let copyCache = deepClone(cache), dataCache = copyCache['data'], hasData = copyCache.hasOwnProperty('data');
            if (hasData) {
                dataCache ? setAttr(this, 'data', dataCache) : this.removeAttribute('data');
                Reflect.deleteProperty(copyCache, 'data');
            }
            for (let k in copyCache) {
                setAttr(this, k, copyCache[k]);
            }
        }
        updateCache(data) {
            let storName = this.propsProxy['stor-name'];
            if (!storName)
                return;
            let cache = storage.get(storName) || {};
            Object.assign(cache, data);
            storage.set(storName, cache);
        }
        clearCache() {
            let storName = this.propsProxy['stor-name'];
            if (!storName)
                return;
            storage.clear(storName);
        }
    }

    const createComp = (options) => {
        let opts = Object.assign({ attrs: [], methods: {}, excludeAttrs: [], modOpts: {}, augment: false, autoUpdate: true, autoIns: true, register: true }, options), elem = window.customElements.get(opts.tagName);
        if (elem) {
            console.warn(`${opts.tagName} is already defined!`);
            return elem;
        }
        let compName = opts.compName || 'Comp' + Date.now(), hostName = opts.hostName || 'div', optMaps = opts.module ? opts.module.optMaps : [], attrs = opts.module ? [...optMaps.map((k) => k.attr), ...opts.attrs] : opts.attrs, str = `"use strict";
            return class ${compName} extends CompBaseComm {
                constructor() {
                    super();
                    this.createShadow();
                    this.createPropsObs();
                    this.optMaps = optMaps;
                    this.canUpdate = true;
                    for (let k of [...attrs, 'options']) this.propsRaw[k] = this.getAttribute(k);
                    this.on('connected',()=>{
                        connected && connected.call(this);
                    });
                    this.reset = () => {
                        this.restoreAttrs();
                        this.listen({ name: 'reset' });
                    }
                    for (let k in methods) this[k] = methods[k].bind(this);
                    constructed && constructed.call(this);
                    this.listen({ name: 'constructed'});
                }
                static get observedAttributes() {
                    return [...attrs, 'options'];
                }
                attributeChangedCallback(name, oldVal, newVal) {
                    if (!this.canListen) return;
                    !excludeAttrs.includes(name) && this.updateProxy(name, newVal,this.optMaps);
                    changed && changed.call(this,{name, oldVal, newVal});
                    this.listen({ name: 'changed', params: [{name, oldVal, newVal}] });
                }
                render() {
                    this.insertSource();
                    this.wrapEl = createEl('${hostName}',{${orca.alias}:'slot-host'}, this.rawHtml);
                    this.appendChild(this.wrapEl);
                    autoIns && module && (this.ins = new module(this.wrapEl,modOpts));
                    this.propsObs.on('completed', (data) => {
                        if(this.connCount > 1){
                            autoUpdate && this?.ins?.update && this.ins.update(this.properties);
                            updated && updated.call(this,data);
                            this.listen({ name: 'updated',params:[data]});
                        }
                        this.listen({ name: 'completed',params:[data]});
                    });
                }
            }
        `, component = new Function('constructed', 'connected', 'changed', 'updated', 'autoUpdate', 'autoIns', 'excludeAttrs', 'module', 'modOpts', 'CompBaseComm', 'createEl', 'attrs', 'optMaps', 'methods', str)(opts.constructed, opts.connected, opts.changed, opts.updated, opts.autoUpdate, opts.autoIns, opts.excludeAttrs, opts.module, opts.modOpts, CompBaseComm, createEl, attrs, optMaps, opts.methods);
        opts.register && window.customElements.define(opts.tagName, component);
        opts.augment && (orca[compName] = component);
        return component;
    };

    const getArrMap = (data, key) => {
        if (!Array.isArray(data) || !data.length)
            return null;
        let map = new Map();
        for (let k of data) {
            let prop = key ? k[key] : k;
            !map.has(k[prop]) && map.set(prop, k);
        }
        return map;
    };

    const includes = (data, value) => {
        if (!Array.isArray(data) || !data.length)
            return false;
        let set = new Set(data), result = set.has(value);
        set.clear();
        return result;
    };

    const capStart = (str) => {
        let idx = str.search(/[a-zA-Z]/);
        if (idx > -1) {
            let char = str.charAt(idx);
            return str.replace(char, char.toUpperCase());
        }
        else {
            return str;
        }
    };

    const removeItem = (data, item) => {
        if (!Array.isArray(data) || !data.length || !item)
            return;
        for (let i = 0; i < data.length; i++) {
            if (data[i] === item) {
                data.splice(i, 1);
                break;
            }
        }
    };

    const appendEls = ({ parent, nodes, reverse = false, target, prepend = false }) => {
        let fragment = document.createDocumentFragment(), tmp = Array.isArray(nodes) ? nodes : [nodes], data = tmp.filter((k) => k && k.nodeType && (k.nodeType === k.ELEMENT_NODE)), host = getEl(parent), targetEl = getEl(target, host), refer;
        if (!host || !data.length)
            return;
        for (let k of data)
            reverse ? fragment.prepend(k) : fragment.appendChild(k);
        if (targetEl) {
            refer = prepend ? targetEl : targetEl.nextElementSibling;
        }
        else {
            refer = prepend ? host.firstElementChild : null;
        }
        host.insertBefore(fragment, refer);
    };

    const decompTask = ({ tasks: initTasks, run, count = 4, doing, done, type = 'idle', delay = 0 }) => {
        if (!Array.isArray(initTasks) || !initTasks.length)
            return;
        if (typeof run !== 'function')
            throw new Error('run must be a function!');
        let tasks = [...initTasks], idx = 0, isAborted = false, next = () => {
            if (isAborted)
                return;
            if (type === 'timeout')
                setTimeout(handler, delay);
            else if (type === 'idle')
                requestIdleCallback(handler);
            else
                requestAnimationFrame(handler);
        }, handler = () => {
            if (isAborted)
                return;
            let end = Math.min(idx + count, tasks.length);
            for (; idx < end; idx++) {
                let task = tasks[idx], progress = tasks.length <= 1 ? 1 : idx / (tasks.length - 1);
                try {
                    run && run(task);
                }
                catch (err) {
                    console.error('Task error:', err);
                }
                doing?.(task, progress);
            }
            idx >= (tasks.length) ? done?.() : next();
        };
        next();
        return {
            abort: () => { isAborted = true; },
            add: (newTasks) => {
                if (!newTasks)
                    return;
                let tmp = Array.isArray(newTasks) ? newTasks : [newTasks];
                tasks.push(...tmp);
                (idx >= tasks.length - tmp.length && !isAborted) && next();
            }
        };
    };

    const filterPrims = (data) => {
        let filter = (obj) => {
            return Object.entries(obj).reduce((start, [key, value]) => {
                if (['number', 'string', 'boolean', 'undefined', 'bigint', 'symbol'].includes(typeof value)) {
                    start[key] = value;
                }
                return start;
            }, {});
        };
        if (Array.isArray(data)) {
            return data.map((k) => {
                let dataType = getDataType(k);
                return dataType === 'Object' ? filter(k) : k;
            });
        }
        else {
            let dataType = getDataType(data);
            return dataType === 'Object' ? filter(data) : data;
        }
    };

    const createEvt = ({ target, name, cb, options }) => {
        let el = getEl(target);
        if (!el || !name)
            return;
        let dft = { cancelable: true, composed: false, bubbles: false }, evt = new CustomEvent(name, Object.assign(dft, options)), fn = function (e) {
            cb.call(this, e);
        };
        cb && el.addEventListener(name, fn);
        return {
            event: evt,
            remove: () => {
                cb && el.removeEventListener(name, fn);
            }
        };
    };

    const optPopup$1 = [
        {
            attr: 'placement',
            prop: 'placement',
            value: 'center',
        },
        {
            attr: 'trigger',
            prop: 'trigger',
            value: 'click',
        },
        {
            attr: 'size',
            prop: 'size',
            value: 'md',
        },
        {
            attr: 'in',
            prop: 'in',
            value: 'fadeIn',
        },
        {
            attr: 'out',
            prop: 'out',
            value: 'fadeOut',
        },
        {
            attr: 'multiple',
            prop: 'multiple',
            value: true,
        },
        {
            attr: 'draggable',
            prop: 'draggable',
            value: true,
        },
        {
            attr: 'feature',
            prop: 'feature',
            value: '',
        },
        {
            attr: 'height',
            prop: 'height',
            value: '',
        },
        {
            attr: 'adaptive',
            prop: 'adaptive',
            value: true,
        },
        {
            attr: 'draggable',
            prop: 'draggable',
            value: true,
        },
        {
            attr: 'gesture',
            prop: 'gesture',
            value: {},
        },
        {
            attr: 'parent',
            prop: 'parent',
            value: '',
        },
        {
            attr: 'wing',
            prop: 'wing',
            value: {
                selector: '',
                actClass: '',
            },
        },
        {
            attr: 'mask',
            prop: 'mask',
            value: {
                enable: true,
                closable: true,
            },
        },
        ...optBubble
    ];

    const optGesture = [
        {
            attr: 'parent',
            prop: 'parent',
            value: ''
        },
        {
            attr: 'viewport',
            prop: 'viewport',
            value: {
                enable: false,
                selector: '',
                dmpRatio: 0.8,
                bouncy: true,
                duration: 0,
            },
        },
        {
            attr: 'jitter-click',
            prop: 'jitterClick',
            value: 10,
        },
        {
            attr: 'jitter-trans',
            prop: 'jitterTrans',
            value: 1,
        },
        {
            attr: 'origin',
            prop: 'origin',
            value: null,
        },
        {
            attr: 'unbound',
            prop: 'unbound',
            value: '[unbound]',
        },
        {
            attr: 'spy',
            prop: 'spy',
            value: {
                enable: false,
            },
        },
        {
            attr: 'click',
            prop: 'click',
            value: {
                timeThr: 200,
                delay: 200,
                dblclickable: true,
                holdDelay: 1000,
                hold2Menu: false,
            },
        },
        {
            attr: 'step',
            prop: 'step',
            value: {
                mode: 'translate',
                axis: 'y',
                value: 0,
                duration: 500,
                intvl: 200,
                linkage: true,
                reverse: false,
                curve: 'easeOut',
            },
        },
        {
            attr: 'wheel',
            prop: 'wheel',
            value: false,
        },
        {
            attr: 'keyboard',
            prop: 'keyboard',
            value: {
                enable: false,
                prev: 'ArrowUp',
                next: 'ArrowDown',
                intvl: 200,
                target: null,
            },
        },
        {
            attr: 'translate',
            prop: 'translate',
            value: {
                enable: true,
                max: 10000000,
                min: -10000000,
                instead: false,
                target: '',
            },
        },
        {
            attr: 'drift',
            prop: 'drift',
            value: {
                enable: false,
                timeThr: 300,
                distThr: 20,
                coef: 0.5,
                duration: 500,
                curve: 'easeOut',
                auto: true,
            },
        },
        {
            attr: 'swipe',
            prop: 'swipe',
            value: {
                enable: false,
                timeThr: 100,
                distThr: 20,
                coef: 0.5,
                duration: 500,
                curve: 'easeOut',
                auto: true,
            },
        },
        {
            attr: 'scale',
            prop: 'scale',
            value: {
                enable: false,
                centered: true,
                max: 100,
                min: 0,
            },
        },
        {
            attr: 'rotate',
            prop: 'rotate',
            value: {
                enable: false,
                max: 3600,
                min: -3600,
            },
        },
        {
            attr: 'initial-val',
            prop: 'initialVal',
            value: null,
            
        },
        {
            attr: 'b4-trigger',
            prop: 'b4Trigger',
            value: null,
        },
        {
            attr: 'on-start',
            prop: 'onStart',
            value: null,
        },
        {
            attr: 'on-move',
            prop: 'onMove',
            value: null,
        },
        {
            attr: 'on-enter',
            prop: 'onEnter',
            value: null,
        },
        {
            attr: 'on-leave',
            prop: 'onLeave',
            value: null,
        },
        {
            attr: 'on-end',
            prop: 'onEnd',
            value: null,
        },
        {
            attr: 'on-click',
            prop: 'onClick',
            value: null,
        },
        {
            attr: 'on-dblclick',
            prop: 'onDblclick',
            value: null,
        },
        {
            attr: 'on-hold',
            prop: 'onHold',
            value: null,
        },
        {
            attr: 'on-scale',
            prop: 'onScale',
            value: null,
        },
        {
            attr: 'on-scaling',
            prop: 'onScaling',
            value: null,
        },
        {
            attr: 'on-scaled',
            prop: 'onScaled',
            value: null,
        },
        {
            attr: 'on-rotate',
            prop: 'onRotate',
            value: null,
        },
        {
            attr: 'on-rotating',
            prop: 'onRotating',
            value: null,
        },
        {
            attr: 'on-rotated',
            prop: 'onRotated',
            value: null,
        },
        {
            attr: 'on-translate',
            prop: 'onTranslate',
            value: null,
        },
        {
            attr: 'on-translating',
            prop: 'onTranslating',
            value: null,
        },
        {
            attr: 'on-translated',
            prop: 'onTranslated',
            value: null,
        },
        {
            attr: 'on-drift',
            prop: 'onDrift',
            value: null,
        },
        {
            attr: 'on-drifting',
            prop: 'onDrifting',
            value: null,
        },
        {
            attr: 'on-drifted',
            prop: 'onDrifted',
            value: null,
        },
        {
            attr: 'on-canceled',
            prop: 'onCanceled',
            value: null,
        },
        {
            attr: 'on-trigger',
            prop: 'onTrigger',
            value: null,
        },
        {
            attr: 'on-finished',
            prop: 'onFinished',
            value: null,
        },
        ...optBase
    ];

    const optSpy = [
        {
            attr: 'margin',
            prop: 'margin',
            value: '0px',
        },
        {
            attr: 'threshold',
            prop: 'threshold',
            value: [0, 1]
        },
        {
            attr: 'root',
            prop: 'root',
            value: null
        },
        {
            attr: 'spy-sel',
            prop: 'spySel',
            value: '',
        },
        {
            attr: 'nav-sel',
            prop: 'navSel',
            value: '',
        },
        {
            attr: 'sub-sel',
            prop: 'subSel',
            value: '',
        },
        {
            attr: 'intvl',
            prop: 'intvl',
            value: 500,
        },
        {
            attr: 'repeat',
            prop: 'repeat',
            value: true,
        },
        {
            attr: 'active',
            prop: 'active',
            value: '',
        },
        {
            attr: 'in',
            prop: 'in',
            value: '',
        },
        {
            attr: 'out',
            prop: 'out',
            value: '',
        },
        {
            attr: 'visible',
            prop: 'visible',
            value: true,
        },
        {
            attr: 'manual',
            prop: 'manual',
            value: false,
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'wing',
            prop: 'wing',
            value: {
                selector: '',
                offset: 0,
                duration: 0,
            },
        },
        {
            attr: 'b4-add',
            prop: 'b4Add',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'on-show',
            prop: 'onShow',
            value: null,
        },
        {
            attr: 'on-showing',
            prop: 'onShowing',
            value: null,
        },
        {
            attr: 'on-shown',
            prop: 'onShown',
            value: null,
        },
        {
            attr: 'on-in',
            prop: 'onIn',
            value: null,
        },
        {
            attr: 'on-out',
            prop: 'onOut',
            value: null,
        },
        {
            attr: 'on-added',
            prop: 'onAdded',
            value: null,
        },
        {
            attr: 'on-removed',
            prop: 'onRemoved',
            value: null,
        },
        ...optBase
    ];

    class Spy extends ModBaseListen {
        options = {};
        storObs;
        storTmp;
        navEl;
        subEls;
        items;
        interactIns;
        rootEl;
        actIsAttr;
        active;
        hide2Debounce;
        static hostType = 'node';
        static optMaps = optSpy;
        constructor(elem, options = {}) {
            super();
            super.ready({
                options,
                maps: Spy.optMaps,
                host: elem,
                component: false,
            });
            
            
            
            
            
            
            
            this.navEl = this.options.navSel ? getEl(this.options.navSel) : null;
            this.subEls = this.navEl && this.options.subSel ? this.navEl.querySelectorAll(this.options.subSel) : [];
            this.hide2Debounce = debounce((el) => {
                if (el.orca.spy.state === 'hidden') {
                    if (el.orca.spy?.out) {
                        classes(el).add(el.orca.spy?.out);
                    }
                    if (el.orca.spy?.in) {
                        classes(el).remove(el.orca.spy?.in);
                        !this.options.visible && classes(el).add(`${orca.prefix}o`);
                    }
                    if (this.active) {
                        el.orca.spy.wing.forEach((k) => {
                            this.actIsAttr ? k.removeAttribute(this.active[0]) : classes(k).remove(this.active);
                        });
                    }
                }
            }, this.options.intvl);
            this.rootEl = getEl(this.options.root);
            this.getActive();
            super.listen({ name: 'constructed' });
            this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.items = [];
            this.interactIns && this.interactIns.disconnect();
            this.interactIns = new IntersectionObserver(entries => {
                entries.forEach(i => {
                    let args = { target: i.target, ratio: i.intersectionRatio, ins: this.interactIns, entry: i };
                    if (i.isIntersecting) {
                        args.intersecting = true;
                        if (i.intersectionRatio === 0) {
                            i.target.orca.spy.state = 'show';
                            super.listen({ name: 'shown', params: [args] });
                        }
                        else if (i.intersectionRatio === 1) {
                            i.target.orca.spy.state = 'shown';
                            super.listen({ name: 'shown', params: [args] });
                            this.setActiveOnly(i.target);
                        }
                        else {
                            i.target.orca.spy.state = 'showing';
                            super.listen({ name: 'showing', params: [args] });
                        }
                        if (i.target.orca.spy.ratio < i.intersectionRatio) {
                            super.listen({ name: 'in', params: [args] });
                            !this.options.visible && classes(i.target).remove(`${orca.prefix}o`);
                            if (i.target.orca.spy.state = 'showing') {
                                if (i.target.orca.spy?.in) {
                                    classes(i.target).add(i.target.orca.spy?.in, (name) => i.target.classList.contains(name) ? false : true);
                                }
                            }
                            !this.options.repeat && this.interactIns.unobserve(i.target);
                        }
                        i.target.orca.spy.ratio = i.intersectionRatio;
                    }
                    else {
                        args.intersecting = false;
                        i.target.orca.spy.state = 'hidden';
                        if (this.options.repeat) {
                            this.hide2Debounce.cancel()(i.target);
                        }
                        super.listen({ name: 'out', params: [args] });
                        i.target.orca.spy.ratio = 0;
                    }
                });
            }, {
                root: this.rootEl,
                rootMargin: this.options.margin,
                threshold: this.options.threshold,
            });
            if (this.options.spySel) {
                this.items = [...this.targetEl.querySelectorAll(this.options.spySel)];
            }
            else {
                this.targetEl && this.items.push(this.targetEl);
            }
            if (this.options.b4Add) {
                let resp = await this.options.b4Add.call(this, this.items);
                resp && (this.items = resp);
            }
            if (!this.options.manual && this.items.length) {
                this.items.forEach((k) => {
                    this.setSpyAttr(k);
                    this.interactIns.observe(k);
                });
            }
            super.listen({ name: 'initiated', cb });
            return this;
        }
        getActive() {
            let activeTrim = this.options.active.trim();
            if (activeTrim.startsWith('[') && activeTrim.endsWith(']')) {
                this.actIsAttr = true;
                this.active = activeTrim.replace('[', '').replace(']', '').replace(' ', '').split('=');
            }
            else {
                this.actIsAttr = false;
                this.active = this.options.active;
            }
        }
        setActiveOnly(el) {
            if (!isEmpty(this.active)) {
                el.orca.spy.wing.forEach((k) => {
                    if (this.actIsAttr) {
                        if (this.active.length > 0) {
                            k.setAttribute(this.active[0], this.active[1] || '');
                        }
                    }
                    else {
                        classes(k).add(this.active, (name) => {
                            return k.classList.contains(name) ? false : true;
                        });
                    }
                });
                let other = this.items.filter((k) => k !== el && k.orca.spy), otherWings = other.map((k) => k.orca.spy.wing).flat(Infinity);
                otherWings.forEach((k) => {
                    this.actIsAttr ? k.removeAttribute(this.active[0]) : classes(k).remove(this.active);
                });
            }
        }
        setSpyAttr(el) {
            if (!getDataType(el).includes('HTML'))
                return;
            let attrs = attrToJson(el, 'spy'), props = {
                observed: true,
                wing: this.getWings(el),
                in: attrs.in || this.options.in,
                out: attrs.out || this.options.out,
                ratio: 0,
            };
            if (!el.orca) {
                el.orca = { spy: props };
            }
            else {
                el.orca.spy = props;
            }
            this.options.classes && classes(el).add(this.options.classes);
            !this.options.visible && classes(el).add(`${orca.prefix}o`);
        }
        getWings(el) {
            let arrFromId = [], arrFromSpy = [], arrFromOpt = [], wingArr = [];
            if (el.id) {
                if (this.subEls.length > 0 && this.subEls[0].hasAttribute('href')) {
                    let navWing = this.subEls.find((k) => k.getAttribute('href') === `#${k.id}`);
                    navWing && arrFromId.push(navWing);
                }
                else {
                    arrFromId = [...document.querySelectorAll(`[href='#${el.id}']`)];
                }
            }
            else {
                let index = this.items.findIndex((k) => k == el);
                index !== -1 && this.subEls[index] ? arrFromId.push(this.subEls[index]) : null;
            }
            if (el.hasAttribute('spy')) {
                let attrs = attrToJson(el, 'spy');
                if (attrs.wing) {
                    arrFromSpy = allToEls(attrs.wing);
                }
            }
            if (this.options.wing.selector) {
                arrFromOpt = allToEls(this.options.wing.selector);
            }
            wingArr = [...arrFromId, ...arrFromSpy, ...arrFromOpt].filter(Boolean);
            wingArr.forEach(k => {
                k.onclick = (e) => {
                    preventDft(e);
                    scrollTo(el, { root: this.rootEl, duration: this.options.wing.duration, offset: this.options.wing.offset });
                };
            });
            return wingArr;
        }
        getEls(data) {
            let dataType = getDataType(data), els = [];
            if (dataType === 'Array') {
                els = data.map((k) => getEl(k)).filter(Boolean);
            }
            else if (dataType === 'String') {
                els = allToEls(data).filter(Boolean);
            }
            return els;
        }
        async add(data, cb) {
            if (this.destroyed)
                return;
            let els = this.getEls(data);
            if (!els.length)
                return this;
            if (this.options.b4Add) {
                let resp = await this.options.b4Add.call(this, els);
                resp && (els = resp);
            }
            els.forEach((i) => {
                if (!i?.orca?.spy) {
                    this.setSpyAttr(i);
                    this.interactIns.observe(i);
                    !this.items.includes(i) && this.items.push(i);
                }
                else {
                    new Message({
                        content: renderTpl(this.options.lang.isObserved, { src: i.dataset.src || i.src }),
                        iconShow: true,
                        status: 'info',
                    }).show();
                }
            });
            super.listen({ name: 'add', cb, params: [els] });
            return this;
        }
        async remove(data, cb) {
            if (this.destroyed)
                return;
            let els = this.getEls(data);
            this.options.b4Remove && await this.options.b4Remove.call(this, els);
            els.forEach((i) => {
                if (this.items.includes(i)) {
                    if (i.orca.spy) {
                        Reflect.deleteProperty(i, 'spy');
                        this.interactIns.unobserve(i);
                    }
                    else {
                        new Message({
                            content: renderTpl(this.options.lang.isUnobserved, { src: i.dataset.src || i.src }),
                            iconShow: true,
                            status: 'info',
                        }).show();
                    }
                }
            });
            super.listen({ name: 'remove', cb, params: [els] });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return;
            this.interactIns.disconnect();
            this.items.forEach((k) => {
                k.orca.spy.wing.forEach((i) => {
                    i.onclick = null;
                });
            });
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const getHypotenuse = (x = 0, y = 0) => Math.sqrt(x * x + y * y);

    class Gesture extends ModBaseListen {
        options = {};
        started;
        eventState;
        scrollObj;
        evtTarget;
        startTime;
        diffTime;
        jitterClick;
        jitterTrans;
        clickCount;
        preventEase;
        holdHandler;
        canTrans;
        transType;
        stepVal;
        moveVals;
        diffVals;
        startCoord;
        triangleVals;
        moveCount;
        touchesMoveCount;
        paramsFormat;
        params;
        endParams;
        driftListen;
        sizes;
        viewRange;
        viewportEl;
        parentEl;
        initialVals;
        spyIns;
        lastVals;
        nowVals;
        startVals;
        totalTrans;
        startFn;
        moveFn;
        endFn;
        stepFn;
        wheelFn;
        keyboardFn;
        cancelFn;
        menuFn;
        triggerFn;
        transitionendFn;
        preventDft;
        lastTarget;
        finishFn;
        static hostType = 'node';
        static optMaps = optGesture;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Gesture.optMaps,
                spread: ['translate', 'drift', 'scale', 'swipe', 'rotate', 'viewport', 'keyboard', 'spy']
            });
            
            
            
            
            
            
            
            
            
            
            
            let _this = this;
            this.started = false;
            this.eventState = 'end';
            this.scrollObj = getScrollObj();
            this.evtTarget = null;
            this.startTime = 0;
            this.diffTime = 0;
            this.jitterClick = _this.options.jitterClick + (orca.isTouchScr ? 10 : 0);
            this.jitterTrans = _this.options.jitterTrans + (orca.isTouchScr ? 4 : 0);
            this.clickCount = 0;
            this.preventEase = false;
            this.holdHandler = null;
            this.handleEls = getEls(this.options.translate.target);
            for (let k of this.handleEls)
                k.setAttribute('handle', '');
            this.canTrans = true;
            this.transType = 'translate';
            this.getStepVal();
            this.moveVals = {
                h: 0,
                x: 0,
                y: 0,
                c: { id: 0, x: 0, y: 0 },
                d: { x: '', y: '' }
            };
            this.diffVals = { scale: 0, rotate: 0, translate: { x: 0, y: 0, h: 0 } };
            this.startCoord = { x: 0, y: 0 };
            this.triangleVals = { start: { x: 0, y: 0, h: 0 }, last: { x: 0, y: 0, h: 0 }, now: { x: 0, y: 0, h: 0 } };
            this.moveCount = 0;
            this.touchesMoveCount = 0;
            this.paramsFormat = {
                orgEvt: null,
                pointer: orca.isTouchScr ? 'finger' : 'mouse',
                scale: {
                    direction: 0,
                    diff: 0,
                    value: { x: 1, y: 1 },
                    translate: { x: 0, y: 0 }
                },
                rotate: {
                    direction: 0,
                    diff: 0,
                    value: 0
                },
                translate: {
                    direction: { x: 0, y: 0 },
                    diff: { x: 0, y: 0, h: 0 },
                    value: { x: 0, y: 0 },
                    canDrift: false,
                    canSwipe: false,
                },
                drift: {
                    duration: 0,
                    direction: { x: 0, y: 0 },
                    diff: { x: 0, y: 0, h: 0 },
                    value: { x: 0, y: 0 }
                },
                swipe: {
                    duration: 0,
                    direction: { x: 0, y: 0 },
                    diff: { x: 0, y: 0, h: 0 },
                    value: { x: 0, y: 0 }
                },
                step: {
                    direction: { x: 0, y: 0 },
                },
                coord: { x: 0, y: 0 },
                target: this.targetEl,
                name: '',
                moveStart: false,
                touchesStart: false,
                moveEnd: false,
                moveTime: 0,
            };
            this.params = null;
            this.endParams = {
                moveStart: false,
                touchesStart: false,
                moveEnd: true,
            };
            this.startFn = function (e) {
                _this.evtTarget = getEvtTarget(e);
                _this.prevEvtDft(e);
                _this.params = { ...deepClone(_this.paramsFormat), evtTarget: _this.evtTarget, relatedTarget: null };
                _this.params.orgEvt = e;
                if ((orca.isTouchScr && e.targetTouches.length > 2 && e.changedTouches.length === 0) || !contains(_this.evtTarget, _this.targetEl)) {
                    _this.started = false;
                    return;
                }
                _this.lastTarget = null;
                _this.getStartVals();
                _this.targetEl.setAttribute('gesture', 'start');
                let changedVals = _this.getTouchCoords(e, 'targetTouches'), targetVals = _this.getTouchCoords(e, 'targetTouches'), paramsHold = { ..._this.params }, paramsTranslate = { ..._this.params }, paramsScale = { ..._this.params }, paramsRotate = { ..._this.params }, paramsStart = { ..._this.params };
                _this.startCoord = _this.getCenterCoord(changedVals);
                _this.startTime = Date.now();
                if (!orca.isTouchScr || e.targetTouches.length === 1) {
                    _this.holdHandler = setTimeout(() => {
                        paramsHold.coord = { ..._this.startCoord };
                        paramsHold.name = 'hold';
                        _this.listen({ name: 'hold', params: [paramsHold] });
                        clearTimeout(_this.holdHandler);
                    }, _this.options.click.holdDelay);
                }
                else {
                    _this.holdHandler && clearTimeout(_this.holdHandler);
                }
                if (orca.isTouchScr && e.targetTouches.length > 1) {
                    if (_this.options.scale.enable) {
                        _this.startCoord = _this.getCenterCoord(targetVals);
                        paramsScale.coord = { ..._this.startCoord };
                        paramsScale.scale.value = _this.lastVals.scale;
                        paramsScale.name = 'scale';
                        _this.listen({ name: 'scale', params: [paramsScale] });
                    }
                    if (_this.options.rotate.enable) {
                        paramsRotate.coord = { ..._this.startCoord };
                        paramsRotate.rotate.value = _this.lastVals.rotate;
                        paramsRotate.name = 'rotate';
                        _this.listen({ name: 'rotate', params: [paramsRotate] });
                    }
                }
                if (_this.options.translate.enable) {
                    paramsTranslate.coord = { ..._this.startCoord };
                    paramsTranslate.translate.value = { ..._this.lastVals.translate };
                    paramsTranslate.name = 'translate';
                    if (_this.handleEls.length === 0 || _this.useHandle(_this.evtTarget)) {
                        _this.listen({ name: 'translate', params: [paramsTranslate] });
                    }
                    else {
                        _this.canTrans = false;
                    }
                }
                paramsStart.coord = { ..._this.startCoord };
                paramsStart.scale.value = _this.lastVals.scale;
                paramsStart.rotate.value = _this.lastVals.rotate;
                paramsStart.translate.value = { ..._this.lastVals.translate };
                paramsStart.totalTrans = _this.totalTrans;
                paramsStart.name = 'start';
                _this.listen({ name: 'start', params: [paramsStart] });
                _this.options.viewport.enable && _this.getSizeDiff(_this.lastVals.translate);
                _this.started = true;
                _this.eventState = 'start';
            };
            this.moveFn = function (e) {
                _this.evtTarget = getEvtTarget(e);
                if (!_this.started)
                    return;
                _this.prevEvtDft(e);
                
                _this.driftListen && cancelAnimationFrame(_this.driftListen.frame);
                _this.diffTime = Date.now() - _this.startTime;
                _this.moveCount++;
                _this.params.orgEvt = e;
                let targetVals = _this.getTouchCoords(e, 'targetTouches'), moveStart = _this.moveCount === 1 ? true : false;
                _this.moveVals = _this.getMoveVals(targetVals, _this.startCoord);
                if (_this.moveVals.h <= _this.jitterTrans) {
                    return;
                }
                else {
                    _this.targetEl.style.transitionDuration = `0ms`;
                }
                let paramsTouches = { ..._this.params, coord: _this.moveVals.c, moveStart, evtTarget: _this.evtTarget, relatedTarget: null }, paramsTranslate = { ...paramsTouches }, paramsScale = { ...paramsTouches }, paramsRotate = { ...paramsTouches }, paramsMove = { ...paramsTouches };
                if (_this.options.translate.enable) {
                    _this.diffVals.translate = { x: ~~_this.moveVals.x, y: ~~_this.moveVals.y, h: ~~_this.moveVals.h };
                    _this.updateNowTrans();
                    _this.options.viewport.enable && (_this.nowVals.translate = _this.getBounceVals(_this.nowVals.translate));
                    _this.moveVals.h > _this.jitterClick && _this.holdHandler && clearTimeout(_this.holdHandler);
                    paramsTranslate = extend({
                        target: paramsTouches,
                        source: {
                            translate: {
                                diff: { ..._this.diffVals.translate },
                                value: { ..._this.nowVals.translate },
                                direction: _this.moveVals.d
                            },
                            name: 'translating'
                        }
                    });
                    _this.totalTrans = _this.nowVals.translate;
                    if (_this.parentEl && isOutside(e, _this.parentEl))
                        _this.canTrans = false;
                    if (_this.canTrans) {
                        if (_this.options.swipe.enable && _this.diffTime < _this.options.swipe.timeThr && _this.diffVals.translate.h > _this.options.swipe.distThr) {
                            _this.transType = 'swipe';
                        }
                        else {
                            _this.transType = 'translate';
                            _this.targetEl.setAttribute('gesture', 'move');
                            _this.listen({ name: 'translating', params: [paramsTranslate] });
                        }
                    }
                }
                if (orca.isTouchScr && e.targetTouches.length > 1) {
                    _this.touchesMoveCount++;
                    _this.triangleVals.now = _this.getTriangleVals(targetVals[0], targetVals[1]);
                    if (_this.touchesMoveCount === 1) {
                        _this.triangleVals.start = { ..._this.triangleVals.now };
                        _this.diffVals.scale = 0;
                        _this.diffVals.rotate = 0;
                        paramsTouches.touchesStart = true;
                    }
                    else {
                        _this.diffVals.scale = (_this.triangleVals.now.h / _this.triangleVals.last.h) - 1;
                        _this.diffVals.rotate = _this.triangleVals.now.a - _this.triangleVals.last.a;
                        _this.correctDiffRotate();
                    }
                    _this.correctRangeScale();
                    _this.correctRangeRotate();
                    if (_this.options.scale.enable) {
                        paramsScale = extend({
                            target: paramsTouches,
                            source: {
                                scale: {
                                    diff: toNumber(_this.diffVals.scale),
                                    value: { x: toNumber(_this.nowVals.scale.x), y: toNumber(_this.nowVals.scale.y) },
                                    direction: _this.diffVals.scale > 0 ? 1 : _this.diffVals.scale < 0 ? -1 : 0
                                },
                                name: 'scaling'
                            }
                        });
                        if (!_this.options.scale.centered) {
                            paramsScale.scale.translate = _this.getScaleTrans({
                                coord: paramsScale.coord,
                                diff: paramsScale.scale.diff,
                            });
                            _this.totalTrans = _this.getScaleTrans({
                                initVal: _this.totalTrans,
                                coord: paramsScale.coord,
                                diff: paramsScale.scale.diff,
                            });
                        }
                        _this.listen({ name: 'scaling', params: [paramsScale] });
                    }
                    if (_this.options.rotate.enable) {
                        paramsRotate = extend({
                            target: paramsTouches,
                            source: {
                                rotate: {
                                    diff: toNumber(_this.diffVals.rotate),
                                    value: toNumber(_this.nowVals.rotate),
                                    direction: _this.diffVals.rotate > 0 ? 1 : _this.diffVals.rotate < 0 ? -1 : 0
                                },
                                name: 'rotating'
                            }
                        });
                        _this.listen({ name: 'rotating', params: [paramsRotate] });
                    }
                }
                paramsMove = extend({
                    target: paramsTouches,
                    source: {
                        rotate: paramsRotate.rotate,
                        scale: paramsScale.scale,
                        translate: paramsTranslate.translate,
                        totalTrans: _this.totalTrans,
                        name: 'move'
                    }
                });
                _this.listen({ name: 'move', params: [paramsMove] });
                _this.triangleVals.last = { ..._this.triangleVals.now };
                _this.eventState = 'move';
                if (_this.lastTarget !== _this.evtTarget) {
                    if (_this.lastTarget) {
                        _this.listen({ name: 'leave', params: [{ ...paramsMove, evtTarget: _this.lastTarget, relatedTarget: _this.evtTarget }] });
                    }
                    if (_this.evtTarget) {
                        _this.listen({ name: 'enter', params: [paramsMove] });
                    }
                    _this.lastTarget = _this.evtTarget;
                }
            };
            this.endFn = function (e) {
                if (!_this.started)
                    return;
                _this.prevEvtDft(e);
                _this.moveCount = _this.touchesMoveCount = 0;
                _this.params.orgEvt = e;
                _this.params.evtTarget = _this.evtTarget;
                _this.params.relatedTarget = null;
                _this.params.moveTime = _this.diffTime = Date.now() - _this.startTime;
                _this.holdHandler && clearTimeout(_this.holdHandler);
                let paramsTranslate = {
                    ..._this.params,
                    coord: { ..._this.moveVals.c },
                    translate: {
                        diff: { ..._this.diffVals.translate },
                        value: { ..._this.nowVals.translate },
                        direction: { ..._this.moveVals.d },
                    },
                    ..._this.endParams,
                }, paramsClick = { ..._this.params, ..._this.endParams }, paramsScale = { ...paramsClick }, paramsRotate = { ...paramsClick }, paramsEnd = { ...paramsClick };
                if (_this.diffVals.translate.h < _this.jitterClick) {
                    if (_this.diffTime < _this.options.click.timeThr && (!orca.isTouchScr && e.button === 0 || orca.isTouchScr)) {
                        let coords = _this.getTouchCoords(e, 'changedTouches'), endCoord = _this.getCenterCoord(coords);
                        paramsClick.coord = endCoord;
                        paramsClick.name = 'click';
                        if (_this.options.click.dblclickable) {
                            _this.clickCount++;
                            if (_this.clickCount === 1) {
                                setTimeout(() => {
                                    if (_this.clickCount === 1) {
                                        _this.listen({ name: 'click', params: [paramsClick] });
                                    }
                                    else if (_this.clickCount > 1) {
                                        paramsClick.name = 'dblclick';
                                        _this.listen({ name: 'dblclick', params: [paramsClick] });
                                    }
                                    _this.clickCount = 0;
                                }, _this.options.click.delay);
                            }
                        }
                        else {
                            _this.listen({ name: 'click', params: [paramsClick] });
                        }
                    }
                }
                if (_this.canTrans && _this.options.translate.enable) {
                    let canDrift = _this.diffVals.translate.h > (_this.options.drift.distThr * (orca.isTouchScr ? 2 : 1)) && _this.diffTime < (_this.options.drift.timeThr / (orca.isTouchScr ? 2 : 1));
                    paramsTranslate.translate.canSwipe = _this.transType === 'swipe' ? true : false;
                    paramsTranslate.translate.canDrift = paramsTranslate.translate.canSwipe ? false : canDrift;
                    paramsTranslate.name = 'translated';
                    _this.listen({ name: 'translated', params: [paramsTranslate] });
                    if (!_this.preventEase) {
                        if (_this.transType === 'swipe') {
                            _this.updateEaseParamsListen(paramsTranslate, 'swipe');
                        }
                        else {
                            (_this.options.drift.enable && canDrift) && _this.updateEaseParamsListen(paramsTranslate);
                        }
                    }
                    _this.options.viewport.enable && _this.moveVals.h > 1 && _this.rebound();
                }
                if (orca.isTouchScr) {
                    if (_this.options.scale.enable) {
                        paramsScale.scale.diff = toNumber(_this.diffVals.scale);
                        paramsScale.scale.value = { x: toNumber(_this.nowVals.scale.x), y: toNumber(_this.nowVals.scale.y) };
                        paramsScale.name = 'scaled';
                        _this.listen({ name: 'scaled', params: [paramsScale] });
                    }
                    if (_this.options.rotate.enable) {
                        paramsRotate.rotate.diff = toNumber(_this.diffVals.rotate);
                        paramsRotate.rotate.value = toNumber(_this.nowVals.rotate);
                        paramsRotate.name = 'rotated';
                        _this.listen({ name: 'rotated', params: [paramsRotate] });
                    }
                    _this.options.viewport.enable && _this.moveVals.h > 1 && _this.getSizeDiff();
                    _this.lastVals.rotate = _this.nowVals.rotate;
                    _this.lastVals.scale = { ..._this.nowVals.scale };
                }
                paramsEnd.translate = paramsTranslate.translate;
                paramsEnd.drift = paramsTranslate.drift;
                paramsEnd.scale = paramsScale.scale;
                paramsEnd.rotate = paramsRotate.rotate;
                paramsEnd.totalTrans = _this.totalTrans;
                paramsEnd.name = 'end';
                _this.listen({ name: 'end', params: [paramsEnd] });
                _this.lastVals.translate = { ..._this.nowVals.translate };
                _this.setCompleted();
                _this.removeSecondEvents();
            };
            this.stepFn = (e, dirValue, type = 'wheel') => {
                if (!_this.options.scale.enable && !_this.options.rotate.enable && !_this.options.translate.enable)
                    return;
                _this.options.viewport.enable && _this.getSizeDiff();
                _this.getStartVals();
                _this.options.step.duration ? _this.targetEl.style.transitionDuration = `${_this.options.step.duration}ms` : null;
                _this.targetEl.style.transitionTimingFunction = orca.curves[_this.options.step.curve];
                _this.params = {
                    ...deepClone(_this.paramsFormat),
                    relatedTarget: null,
                    evtTarget: (type === 'keyboard' ? this.targetEl : getEvtTarget(e))
                };
                _this.params = extend({
                    target: _this.params,
                    source: {
                        pointer: type,
                        orgEvt: e,
                        coord: type === 'keyboard' ? { x: 0, y: 0 } : { x: e.clientX, y: e.clientY },
                        step: {
                            direction: { x: dirValue, y: dirValue }
                        },
                        translate: { value: { ..._this.nowVals.translate } },
                        scale: {
                            value: { ..._this.nowVals.scale },
                            direction: dirValue
                        },
                        rotate: {
                            value: _this.nowVals.rotate,
                            direction: dirValue
                        },
                        moveTime: parseFloat(style(_this.targetEl).transitionDuration) * 1000
                    }
                });
                _this.listen({ name: 'step', params: [{ ..._this.params, name: 'step' }] });
                let paramsAction = { ..._this.params };
                if (_this.options.step.mode === 'scale') {
                    if (!_this.options.scale.enable)
                        return;
                    _this.diffVals.scale = (dirValue === 1 ? _this.stepVal : -_this.stepVal);
                    _this.correctRangeScale();
                    paramsAction.scale.diff = toNumber(_this.diffVals.scale);
                    paramsAction.scale.value = { x: toNumber(_this.nowVals.scale.x), y: toNumber(_this.nowVals.scale.y) };
                    if (!_this.options.scale.centered) {
                        paramsAction.scale.translate = _this.getScaleTrans({
                            coord: paramsAction.coord,
                            diff: paramsAction.scale.diff,
                        });
                        _this.totalTrans = _this.getScaleTrans({
                            initVal: _this.totalTrans,
                            coord: paramsAction.coord,
                            diff: paramsAction.scale.diff,
                        });
                    }
                    _this.options.step.linkage && _this.listen({ name: 'scaling', params: [{ ...paramsAction, name: 'scaling' }] });
                }
                else if (_this.options.step.mode === 'rotate') {
                    if (!_this.options.rotate.enable)
                        return;
                    _this.diffVals.rotate = (dirValue === 1 ? _this.stepVal : -_this.stepVal);
                    _this.correctRangeRotate();
                    paramsAction.rotate.diff = toNumber(_this.diffVals.rotate);
                    paramsAction.rotate.value = toNumber(_this.nowVals.rotate);
                    _this.options.step.linkage && _this.listen({ name: 'rotating', params: [{ ...paramsAction, name: 'rotating' }] });
                }
                else if (_this.options.step.mode === 'translate') {
                    if (!_this.options.translate.enable)
                        return;
                    let direction = _this.options.step.axis === 'y' ? { x: 0, y: -dirValue, } : { x: -dirValue, y: 0 }, axisDist = -dirValue * _this.stepVal, x = _this.options.step.axis === 'y' ? 0 : axisDist, y = _this.options.step.axis === 'x' ? 0 : axisDist;
                    _this.diffVals.translate = { x, y, h: _this.stepVal };
                    _this.updateNowTrans();
                    _this.options.viewport.enable && (_this.nowVals.translate = _this.getViewLimitVals(_this.nowVals.translate));
                    paramsAction.translate.diff = _this.diffVals.translate;
                    paramsAction.translate.value = _this.nowVals.translate;
                    paramsAction.translate.direction = direction;
                    _this.options.step.linkage && _this.listen({ name: 'translating', params: [{ ...paramsAction, name: 'translating' }] });
                }
                _this.listen({ name: 'stepped', params: [{ ...paramsAction, name: 'stepped' }] });
                _this.listen({ name: 'move', params: [{ ...paramsAction, totalTrans: _this.totalTrans, name: 'move' }] });
                _this.lastVals[_this.options.step.mode] = { ..._this.nowVals[_this.options.step.mode] };
            };
            this.wheelFn = throttle(function (e) {
                e.stopPropagation();
                e.preventDefault();
                let isUp = _this.correctWheelDirection(isScrollUp(e, _this.scrollObj.detail)), dirValue = isUp ? 1 : -1;
                _this.stepFn(e, dirValue, 'wheel');
            }, { intvl: _this.options.step.intvl, prevent: true });
            this.keyboardFn = throttle((e) => {
                e.stopPropagation();
                e.preventDefault();
                let dirValue = (e.code === this.options.keyboard.prev) ? -1 : (e.code === this.options.keyboard.next) ? 1 : 0;
                if (!dirValue)
                    return;
                _this.stepFn(e, dirValue, 'keyboard');
            }, { intvl: _this.options.step.intvl, prevent: true });
            this.cancelFn = function (e) {
                _this.setCompleted();
                _this.removeSecondEvents();
                let paramsCancel = Object.assign(deepClone(_this.paramsFormat), {
                    orgEvt: e,
                    relatedTarget: null,
                    evtTarget: getEvtTarget(e),
                    coord: { x: e.clientX, y: e.clientY },
                    ..._this.endParams,
                    name: 'canceled'
                });
                _this.listen({ name: 'canceled', params: [paramsCancel] });
            };
            this.menuFn = function (e) {
                if (_this.isUnbound(e.target))
                    return;
                e.stopPropagation();
                e.preventDefault();
                let paramsClick = Object.assign(deepClone(_this.paramsFormat), {
                    orgEvt: e,
                    relatedTarget: null,
                    evtTarget: getEvtTarget(e),
                    coord: { x: e.clientX, y: e.clientY },
                    ..._this.endParams,
                    name: 'hold'
                });
                _this.listen({ name: 'hold', params: [paramsClick] });
            };
            this.triggerFn = async (e) => {
                if (this.isUnbound(getEvtTarget(e)))
                    return;
                e.stopPropagation();
                try {
                    this.options.b4Trigger && await this.options.b4Trigger.call(this, e);
                }
                catch {
                    return;
                }
                this.addSecondEvents();
                super.listen({ name: 'trigger', params: [e] });
            };
            this.finishFn = (e) => {
                this.removeSecondEvents();
                super.listen({ name: 'finished', params: [e] });
            };
            this.transitionendFn = (e) => {
                if (e.propertyName !== 'transform')
                    return;
                e.stopPropagation();
                if (this.options.viewport.enable) {
                    this.getSizeDiff(this.nowVals.translate);
                    this.rebound(this.nowVals.translate);
                }
            };
            this.preventDft = (e) => {
                e?.preventDefault();
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        getStartVals() {
            this.startVals = transformTools.get(this.targetEl, ['translate', 'scale', 'rotate'], this.options.translate.instead);
            this.totalTrans = { ...this.startVals.translate };
            this.nowVals = {
                translate: {
                    ...this.startVals.translate,
                    h: ~~getHypotenuse(this.startVals.translate.x, this.startVals.translate.y)
                },
                scale: { ...this.startVals.scale },
                rotate: this.startVals.rotate,
            };
            this.lastVals = deepClone(this.nowVals);
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch (err) {
                err ? console.error(err) : console.warn(config.warn.init);
                return this;
            }
            this.setEmpty();
            this.parentEl = getEl(this.options.parent);
            this.viewportEl = getEl(this.options.viewport.selector);
            this.options.initialVal ? transformTools.set({ el: this.targetEl, data: this.options.initialVal, instead: this.options.translate.instead }) : null;
            this.initialVals = this.options.translate.instead ?
                transformTools.get(this.targetEl, ['translate', 'scale', 'rotate', 'skew'], this.options.translate.instead) :
                this.targetEl.style.transform;
            this.addPrimEvents();
            if (orca.isTouchScr) {
                if (this.handleEls.length) {
                    for (let k of this.handleEls)
                        k.addEventListener('touchstart', this.preventDft, { passive: false });
                }
                else {
                    this.targetEl.addEventListener('touchstart', this.preventDft, { passive: false });
                }
            }
            this.targetEl.addEventListener("transitionend", this.transitionendFn, { passive: false });
            if (!orca.isTouchScr) {
                if (this.options.wheel) {
                    this.targetEl.removeEventListener(this.scrollObj.event, this.wheelFn);
                    this.targetEl.addEventListener(this.scrollObj.event, this.wheelFn, { passive: false });
                }
                if (this.options.click.hold2Menu) {
                    this.targetEl.removeEventListener('contextmenu', this.menuFn);
                    this.targetEl.addEventListener('contextmenu', this.menuFn);
                }
            }
            this.setSpy();
            this.setCompleted();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setEmpty() {
        }
        prevEvtDft(evt, target = this.evtTarget) {
            if (orca.isTouchScr) {
                if (!this.options.scale.enable && !this.options.rotate.enable) {
                    if (this.useHandle(target) || (!this.handleEls.length && contains(target, this.targetEl))) {
                        preventDft(evt, true);
                    }
                }
                else {
                    contains(target, this.targetEl) && preventDft(evt, true);
                }
            }
            else {
                if (this.useHandle(target) || (!this.handleEls.length && contains(target, this.targetEl))) {
                    preventDft(evt, true);
                }
            }
        }
        setSpy() {
            if (!this.options.spy.enable)
                return;
            let opts = extend({
                target: {
                    onIn: () => {
                        super.listen({ name: 'showing' });
                    },
                    onOut: () => {
                        this.options.keyboard.enable && !orca.isTouchScr && window.removeEventListener('keydown', this.keyboardFn);
                        super.listen({ name: 'hidden' });
                    },
                    onShown: () => {
                        this.options.keyboard.enable && !orca.isTouchScr && window.addEventListener('keydown', this.keyboardFn, { passive: false });
                        super.listen({ name: 'shown' });
                    }
                },
                source: this.options.spy,
            });
            this.spyIns = new Spy(getEl(this.options.keyboard.target) || this.targetEl, opts);
        }
        isUnbound(target) {
            let unbounds = getEls(this.options.unbound, this.targetEl);
            return unbounds.find((k) => contains(target, k));
        }
        updateEaseParamsListen(params, type = 'drift') {
            let distH = ~~((this.options[type].timeThr - this.diffTime) * this.options[type].coef) * (type === 'swipe' ? (orca.isTouchScr ? 8 : 12) : 1), distX = ~~(distH * (this.diffVals.translate.x / this.diffVals.translate.h)), distY = ~~(distH * (this.diffVals.translate.y / this.diffVals.translate.h)), driftX = this.clampVals('translate', params.translate.value.x + distX), driftY = this.clampVals('translate', params.translate.value.y + distY);
            params[type].direction = params.translate.direction;
            params[type].diff = { x: distX, y: distY, h: distH };
            params[type].duration = this.options[type].duration;
            params[type].value = this.options.viewport.enable ? this.getViewLimitVals({ x: driftX, y: driftY }) : { x: driftX, y: driftY };
            params.name = type;
            this.listen({ name: type, params: [params] });
            if (this.options[type].auto) {
                this.targetEl.style.transitionDuration = `0ms`;
                this.driftListen = ease({
                    from: params.translate.value,
                    to: params[type].value,
                    curve: this.options[type].curve,
                    duration: this.options[type].duration,
                    doing: (e) => {
                        params.translate.value = { x: Math.floor(e.value.x), y: Math.floor(e.value.y) };
                        this.listen({ name: (type === 'swipe' ? 'swiping' : 'drifting'), params: [params] });
                    }, done: () => {
                        let translateVals = transformTools.get(this.targetEl, ['translate'], this.options.translate.instead).translate;
                        if ((params[type].value.x === translateVals.x) && (params[type].value.y === translateVals.y)) {
                            this.listen({ name: (type === 'swipe' ? 'swiped' : 'drifted'), params: [params] });
                        }
                    }
                });
            }
        }
        updateNowTrans() {
            let x = this.lastVals.translate.x + this.diffVals.translate.x, y = this.lastVals.translate.y + this.diffVals.translate.y;
            this.nowVals.translate = { x: ~~x, y: ~~y };
            this.correctRangeTrans();
        }
        getMoveVals(vals, startCoord) {
            let c = this.getCenterCoord(vals), diff = this.getTriangleVals(c, startCoord), h = ~~diff.h, x = ~~diff.x, y = ~~diff.y, d = { x: x > 0 ? 1 : x < 0 ? -1 : 0, y: y > 0 ? 1 : y < 0 ? -1 : 0 };
            return { c, h, x, y, d };
        }
        addPrimEvents() {
            this.targetEl.addEventListener('pointerdown', this.triggerFn, { passive: false });
            this.targetEl.removeEventListener('pointerup', this.triggerFn, { passive: false });
        }
        removePrimEvents() {
            this.targetEl.removeEventListener('pointerdown', this.triggerFn);
            this.targetEl.removeEventListener('pointerup', this.finishFn);
        }
        removeSecondEvents() {
            document.removeEventListener(eventMap[0], this.startFn);
            document.removeEventListener(eventMap[1], this.moveFn);
            document.removeEventListener(eventMap[2], this.endFn);
            document.removeEventListener(eventMap[3], this.cancelFn);
        }
        addSecondEvents() {
            document.addEventListener(eventMap[0], this.startFn, { passive: false });
            document.addEventListener(eventMap[1], this.moveFn, { passive: false });
            document.addEventListener(eventMap[2], this.endFn, { passive: false });
            document.addEventListener(eventMap[3], this.cancelFn, { passive: false });
        }
        setCompleted() {
            this.started = false;
            this.moveCount = this.touchesMoveCount = 0;
            this.diffVals = { scale: 0, rotate: 0, translate: { x: 0, y: 0, h: 0 } };
            this.holdHandler && clearTimeout(this.holdHandler);
            this.canTrans = true;
            this.preventEase = false;
            this.targetEl.style.cssText = this.targetEl.style.cssText.replace('transition-duration: 0ms', '');
            this.targetEl.removeAttribute('gesture');
        }
        getOrign(coord, rect) {
            let x = coord.x - rect.left, y = coord.y - rect.top;
            x < 0 ? x = 0 : x > rect.width ? x = rect.width : null;
            y < 0 ? y = 0 : y > rect.height ? y = rect.height : null;
            return { x, y };
        }
        getScaleTrans(options) {
            let styles = style(this.targetEl), width = parseInt(styles.width), height = parseInt(styles.height), origin = this.options.origin || { x: width / 2, y: height / 2 }, rect = this.targetEl.getBoundingClientRect(), newOrigin = this.getOrign(options.coord, rect), transform = transformTools.get(this.targetEl, ['translate'], this.options.translate.instead), percent = (attr) => {
                let value = newOrigin[attr] / rect[attr === 'x' ? 'width' : 'height'];
                value < 0 ? value = 0 : value > 1 ? value = 1 : null;
                return value;
            }, orginDiff = (attr) => {
                return (origin[attr] - (attr === 'x' ? width : height) * percent(attr)) * options.diff;
            }, initVal = options.initVal || { x: transform.translate.x, y: transform.translate.y }, x = initVal.x + orginDiff('x'), y = initVal.y + orginDiff('y');
            return { x: ~~x, y: ~~y };
        }
        getTouchCoords(event, target = 'targetTouches') {
            let touches = [];
            if (orca.isTouchScr) {
                for (let k of event[target]) {
                    touches.push({
                        x: ~~k.clientX,
                        y: ~~k.clientY
                    });
                }
            }
            else {
                touches.push({
                    x: ~~event.clientX,
                    y: ~~event.clientY
                });
            }
            return touches;
        }
        getCenterCoord(data) {
            let result, avg = (n, axis) => {
                let value = 0;
                for (let k = 0; k < n; k++) {
                    value += data[k][axis];
                }
                return value / n;
            };
            if (data.length > 1) {
                result = { x: ~~avg(2, 'x'), y: ~~avg(2, 'y') };
            }
            else if (data.length === 1) {
                result = data[0];
            }
            else {
                result = { x: 0, y: 0 };
            }
            return result;
        }
        getTriangleVals(now, last) {
            let x = now.x - last.x, y = now.y - last.y, h = getHypotenuse(x, y), a = Math.atan2(y, x) * 180 / Math.PI;
            return { x, y, h, a };
        }
        correctRangeTrans() {
            let x = this.clampVals('translate', this.nowVals.translate.x), y = this.clampVals('translate', this.nowVals.translate.y), tmpX, tmpY, diffX, diffY, diffH;
            if (x !== this.nowVals.translate.x) {
                tmpX = x;
                diffX = x - this.lastVals.translate.x;
            }
            else {
                tmpX = this.nowVals.translate.x;
                diffX = this.diffVals.translate.x;
            }
            if (y !== this.nowVals.translate.y) {
                tmpY = y;
                diffY = y - this.lastVals.translate.y;
            }
            else {
                tmpY = this.nowVals.translate.y;
                diffY = this.diffVals.translate.y;
            }
            diffH = getHypotenuse(diffX, diffY);
            this.diffVals.translate = { x: diffX, y: diffY, h: diffH };
            this.nowVals.translate = { x: tmpX, y: tmpY };
        }
        correctRangeRotate() {
            this.nowVals.rotate = this.clampVals('rotate', this.nowVals.rotate);
            let tmp = this.nowVals.rotate + this.diffVals.rotate;
            if (tmp >= this.options.rotate.max) {
                this.diffVals.rotate = this.options.rotate.max - this.nowVals.rotate;
            }
            else if (tmp <= this.options.rotate.min) {
                this.diffVals.rotate = this.options.rotate.min - this.nowVals.rotate;
            }
            this.nowVals.rotate += this.diffVals.rotate;
        }
        correctDiffRotate() {
            if (this.triangleVals.now.a > 0 && this.triangleVals.last.a < 0) {
                if (this.triangleVals.now.a > 90 && this.triangleVals.last.a < -90) {
                    this.diffVals.rotate = 360 - this.diffVals.rotate;
                }
                else if (this.triangleVals.now.a < 90 && this.triangleVals.last.a > -90) {
                    this.diffVals.rotate = -this.diffVals.rotate;
                }
            }
            else if (this.triangleVals.now.a < 0 && this.triangleVals.last.a > 0) {
                if (this.triangleVals.now.a > -90 && this.triangleVals.last.a < 90) {
                    this.diffVals.rotate = -this.diffVals.rotate;
                }
                else if (this.triangleVals.now.a < -90 && this.triangleVals.last.a > 90) {
                    this.diffVals.rotate = -(360 + this.diffVals.rotate);
                }
            }
        }
        correctRangeScale() {
            this.nowVals.scale.x = this.clampVals('scale', this.nowVals.scale.x);
            this.nowVals.scale.y = this.clampVals('scale', this.nowVals.scale.y);
            let tmpX = this.nowVals.scale.x + this.diffVals.scale, tmpY = this.nowVals.scale.y + this.diffVals.scale;
            if (tmpX >= this.options.scale.max || tmpY >= this.options.scale.max) {
                this.diffVals.scale = Math.min((this.options.scale.max - this.nowVals.scale.x), (this.options.scale.max - this.nowVals.scale.y));
            }
            else if (tmpX <= this.options.scale.min || tmpY <= this.options.scale.min) {
                this.diffVals.scale = Math.min((this.options.scale.min - this.nowVals.scale.x), (this.options.scale.min - this.nowVals.scale.y));
            }
            this.nowVals.scale.x += this.diffVals.scale;
            this.nowVals.scale.y += this.diffVals.scale;
        }
        clampVals(prop, value) {
            return clampVal({ val: value, min: this.options[prop].min, max: this.options[prop].max });
        }
        correctWheelDirection(value) {
            return this.options.step.reverse ? !value : value;
        }
        getStepVal() {
            if (!this.options.step.value) {
                this.stepVal = this.options.step.mode === 'translate' ? 60 : this.options.step.mode === 'scale' ? 0.5 : this.options.step.mode === 'rotate' ? 10 : 0;
            }
            else {
                this.stepVal = this.options.step.value = 0;
            }
        }
        getSizeDiff(val) {
            this.sizes = {
                viewport: { width: 0, height: 0, left: 0, right: 0, top: 0, bottom: 0 },
                target: { width: 0, height: 0, left: 0, right: 0, top: 0, bottom: 0 },
                diff: { x: 0, y: 0 },
                offset: { left: 0, right: 0, top: 0, bottom: 0 }
            };
            if (!this.viewportEl || this.viewportEl === document.body || this.viewportEl === document.documentElement) {
                this.sizes.viewport = {
                    width: document.documentElement.clientWidth,
                    height: document.documentElement.clientHeight,
                    left: 0,
                    top: 0,
                    right: document.documentElement.clientWidth,
                    bottom: document.documentElement.clientHeight
                };
            }
            else {
                let tmp = this.viewportEl.getBoundingClientRect();
                this.sizes.viewport = {
                    width: tmp.width,
                    height: tmp.height,
                    left: tmp.left,
                    top: tmp.top,
                    right: tmp.right,
                    bottom: tmp.bottom,
                };
            }
            let rect = this.targetEl.getBoundingClientRect();
            this.sizes.target = {
                width: rect.width,
                height: rect.height,
                left: rect.left,
                top: rect.top,
                right: rect.right,
                bottom: rect.bottom,
            };
            this.sizes.diff = { x: this.sizes.viewport.width - this.sizes.target.width, y: this.sizes.viewport.height - this.sizes.target.height };
            this.sizes.offset = {
                left: this.sizes.viewport.left - this.sizes.target.left,
                right: this.sizes.viewport.right - this.sizes.target.right,
                top: this.sizes.viewport.top - this.sizes.target.top,
                bottom: this.sizes.viewport.bottom - this.sizes.target.bottom,
            };
            
            this.getViewRange(val);
        }
        getViewRange(val) {
            let value = val || transformTools.get(this.targetEl, ['translate'])['translate'];
            this.viewRange = {
                x: [value.x + this.sizes.offset.left, value.x + this.sizes.offset.right].sort(),
                y: [value.y + this.sizes.offset.top, value.y + this.sizes.offset.bottom].sort(),
            };
        }
        getDmpVals(value) {
            let dmp = this.options.viewport.dmpRatio ** 2;
            return this.options.viewport.bouncy ? value * dmp : value;
        }
        getBounceVals(data) {
            let x = data.x, y = data.y;
            if (x < this.viewRange.x[0]) {
                x += this.getDmpVals(this.viewRange.x[0] - x);
            }
            else if (x > this.viewRange.x[1]) {
                x += this.getDmpVals(this.viewRange.x[1] - x);
            }
            if (y < this.viewRange.y[0]) {
                y += this.getDmpVals(this.viewRange.y[0] - y);
            }
            else if (y > this.viewRange.y[1]) {
                y += this.getDmpVals(this.viewRange.y[1] - y);
            }
            return { x: ~~x, y: ~~y };
        }
        getViewLimitVals(data) {
            let x = clampVal({ val: data.x, min: this.viewRange.x[0], max: this.viewRange.x[1] }), y = clampVal({ val: data.y, min: this.viewRange.y[0], max: this.viewRange.y[1] });
            return { x, y };
        }
        getAutoDur(val1, val2) {
            return Math.abs(val1 - val2) / 3 + 200;
        }
        rebound(val) {
            let tmp = val || this.nowVals.translate, dur, condition = false;
            if (tmp.x < this.viewRange.x[0]) {
                dur = this.getAutoDur(this.viewRange.x[0], tmp.x);
                tmp.x = this.viewRange.x[0];
                condition = true;
            }
            else if (tmp.x > this.viewRange.x[1]) {
                dur = this.getAutoDur(this.viewRange.x[1], tmp.x);
                tmp.x = this.viewRange.x[1];
                condition = true;
            }
            if (tmp.y < this.viewRange.y[0]) {
                dur = this.getAutoDur(this.viewRange.y[0], tmp.y);
                tmp.y = this.viewRange.y[0];
                condition = true;
            }
            else if (tmp.y > this.viewRange.y[1]) {
                dur = this.getAutoDur(this.viewRange.y[1], tmp.y);
                tmp.y = this.viewRange.y[1];
                condition = true;
            }
            if (!condition)
                return;
            this.targetEl.style.transitionDuration = `${this.options.viewport.duration || dur}ms`;
            transformTools.set({
                el: this.targetEl,
                data: { translate: { x: tmp.x, y: tmp.y } }
            });
        }
        reset(cb) {
            this.targetEl.style.transform = this.initialVals;
            super.listen({ name: 'reset', cb });
            return this;
        }
        destroy(cb) {
            if (this.destroyed) {
                return this;
            }
            this.setCompleted();
            this.targetEl.removeEventListener('pointerdown', this.triggerFn);
            this.targetEl.removeEventListener("transitionend", this.transitionendFn);
            if (orca.isTouchScr) {
                if (this.handleEls.length) {
                    for (let k of this.handleEls)
                        k.removeEventListener('touchstart', this.preventDft);
                }
                else {
                    this.targetEl.removeEventListener('touchstart', this.preventDft);
                }
            }
            this.removeSecondEvents();
            if (!orca.isTouchScr) {
                this.options.wheel && this.targetEl.removeEventListener(this.scrollObj.event, this.wheelFn);
                this.options.keyboard.enable && window.removeEventListener('keydown', this.keyboardFn);
                this.options.click.hold2Menu && this.targetEl.removeEventListener('contextmenu', this.menuFn);
                this.spyIns && this.spyIns.destroy();
            }
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    class Dialog extends ModBaseListenCacheBubble {
        options = {};
        timestamp;
        bubbleType;
        parentEl;
        lastPlace;
        lastSize;
        lastPlacement;
        gestureIns;
        wrapSize;
        confirmEl;
        cancelEl;
        closeEl;
        triggerShow;
        content;
        aniIn;
        aniOut;
        addPulseAnim;
        removePulseAnim;
        static optMaps = optPopup$1;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Dialog.optMaps,
                component: true,
                spread: ['mask', 'tools', 'padding', 'footer', 'autoFill', 'bullet']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            this.bubbleType = 'dialog';
            this.timestamp = Date.now();
            let _this = this;
            this.triggerShow = function (evt) {
                if (this === _this.targetEl && _this.options.canClick) {
                    let target = getEvtTarget(evt), tmp = _this.options.canClick.call(_this, target, evt);
                    if (!tmp)
                        return;
                }
                if (_this.state === 'hidden') {
                    _this.show();
                    (_this.options.wing.actClass && _this.wings.includes(this)) && this.classList.add(_this.options.wing.actClass);
                }
                else if (_this.state === 'shown') {
                    !_this.options.keepShow && _this.hide();
                }
            };
            this.triggerClose = () => {
                !this.options.keepShow && this.hide();
            };
            this.addPulseAnim = () => {
                this.mainEl.classList.add(`${orca.prefix}pulseShow`);
            };
            this.removePulseAnim = () => {
                this.mainEl.classList.remove(`${orca.prefix}pulseShow`);
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setEmpty();
            this.parentEl = getEl(this.options.parent) || document.body;
            this.options.placement = this.options.placement || 'center';
            this.setFeature();
            
            this.wings = getEls(this.options.wing.selector);
            this.renderBubble('dialog');
            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.renderContent(data);
                }
            });
            this.fixAni(this.options.placement);
            this.lastPlace = '';
            this.handleFooter();
            this.handleTools();
            this.bindTrigger();
            this.setDraggable();
            this.contEl.querySelectorAll(`[${orca.alias}="closebubble"]`).forEach((k) => {
                k.removeEventListener('click', this.triggerClose);
                k.addEventListener('click', this.triggerClose, false);
            });
            if (['confirm', 'alert'].includes(this.options.feature)) {
                this.removePulseEvt();
                this.addPulseEvt();
            }
            this.initBullets();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setFeature() {
            if (!this.options.feature)
                return;
            if (['alert', 'prompt', 'notice'].includes(this.options.feature)) {
                this.options.footer.layout = 'right';
            }
            if (['prompt', 'notice'].includes(this.options.feature)) {
                this.options.mask.enable = false;
            }
            if (['confirm', 'alert', 'prompt'].includes(this.options.feature)) {
                this.options.mask.closable = false;
                this.options.placement = 'center-top';
                this.options.padding.value = `${orca.prefix}p-md`;
                this.options.in = 'fadeInDown';
                this.options.out = 'fadeOutDown';
                this.options.tools.enable = false;
                let footer = Dialog.optMaps.find((k) => k.prop === 'footer'), isSame = footer.value.children.toString() == this.options.footer.children.toString();
                if (this.options.feature === 'alert') {
                    isSame && (this.options.footer.children = ['confirm']);
                }
                else if (this.options.feature === 'prompt') {
                    isSame && (this.options.footer.children = ['close', 'clear', 'confirm']);
                }
            }
            if (this.options.feature === 'notice') {
                this.options.placement = 'left-bottom';
            }
        }
        addPulseEvt() {
            this.maskEl.addEventListener('click', this.addPulseAnim, false);
            this.mainEl.addEventListener('animationend', this.removePulseAnim, false);
        }
        removePulseEvt() {
            this.maskEl.removeEventListener('click', this.addPulseAnim);
            this.mainEl.removeEventListener('animationend', this.removePulseAnim);
        }
        fixAni(placement) {
            this.aniIn = placement === 'max' && this.options.in === 'slideDown' ? 'fadeIn' : this.options.in;
            this.aniOut = placement === 'max' && this.options.out === 'slideUp' ? 'fadeOut' : this.options.out;
        }
        handleTools() {
            if (this.options.tools.enable) {
                this.options.tools.children.forEach((k) => {
                    k.wrapEl.querySelector(`[${orca.alias}="icon"]`);
                    if (k.name === 'close') {
                        k.wrapEl.onclick = () => {
                            this.hide();
                        };
                    }
                    else if (k.name === 'widen') {
                        k.wrapEl.onclick = () => {
                            if (this.lastSize === 'max') {
                                classes(k.iconEl).replace(k.icon, k.swap);
                                this.mainEl.setAttribute('size', this.options.size);
                                this.lastSize = this.options.size;
                            }
                            else {
                                classes(k.iconEl).replace(k.swap, k.icon);
                                this.mainEl.setAttribute('size', 'max');
                                this.lastSize = 'max';
                            }
                        };
                    }
                    else if (k.name === 'enlarge') {
                        k.wrapEl.onclick = () => {
                            if (this.lastPlacement === 'center-max') {
                                classes(k.iconEl).replace(k.icon, k.swap);
                                this.mainEl.setAttribute('placement', this.options.placement);
                                this.lastPlacement = this.options.placement;
                            }
                            else {
                                classes(k.iconEl).replace(k.swap, k.icon);
                                this.mainEl.setAttribute('placement', 'center-max');
                                this.lastPlacement = 'center-max';
                            }
                        };
                    }
                    else {
                        k.action && k.action.call(this, k);
                    }
                });
            }
        }
        setAttrs() {
            this.options.classes && classes(this.mainEl).add(this.options.classes);
            this.options.size ? this.mainEl.setAttribute('size', this.options.size) : this.mainEl.removeAttribute('size');
            this.options.contType ? this.mainEl.setAttribute('conttype', this.options.contType) : this.mainEl.removeAttribute('conttype');
            this.contEl.toggleAttribute('dedicated', this.options.dedicated);
            this.options.placement ? this.mainEl.setAttribute('placement', this.options.placement) : this.mainEl.removeAttribute('placement', this.options.placement);
            this.options.zIndex ? addStyle(this.mainEl, 'z-index', this.options.zIndex) : removeStyle(this.mainEl, 'z-index');
            this.options.tools.enable ? this.mainEl.setAttribute('toolsplace', this.options.tools.placement) : this.mainEl.removeAttribute('toolsplace');
            this.options.feature ? this.mainEl.setAttribute('feature', this.options.feature) : this.mainEl.removeAttribute('feature');
            if (this.parentEl !== document.body) {
                let pStyle = style(this.parentEl);
                pStyle.position === 'static' && addStyle(this.parentEl, 'position', 'relative');
                pStyle.overflow !== 'hidden' && addStyle(this.parentEl, 'overflow', 'hidden');
                this.mainEl.toggleAttribute('restrict', true);
            }
            else {
                this.mainEl.removeAttribute('restrict');
            }
        }
        setDraggable() {
            if (!this.headEl || !this.options.draggable)
                return;
            this.gestureIns = new Gesture(this.wrapEl, extend({
                target: {
                    viewport: {
                        enable: true,
                        selector: this.parentEl,
                    },
                    translate: {
                        target: this.headEl,
                    },
                    onTranslate: () => {
                        this.wrapEl.style.animationName = 'none';
                    },
                    onTranslating: (data) => {
                        transformTools.set({
                            el: this.wrapEl,
                            data: { translate: data.translate.value }
                        });
                    },
                },
                source: this.options.gesture,
            }));
        }
        bindTrigger() {
            if (this.options.trigger === 'click') {
                if (this.targetEl && !this.canTrigger) {
                    this.targetEl.removeEventListener('click', this.triggerShow);
                    this.targetEl.addEventListener('click', this.triggerShow, false);
                }
                if (this.wings.length > 0 && !this.canTrigger) {
                    this.wings.forEach((k) => {
                        k.removeEventListener('click', this.triggerShow);
                        k.addEventListener('click', this.triggerShow, false);
                    });
                }
            }
            else if (this.options.trigger === 'sticky') {
                this.show();
            }
            if (this.maskEl && this.options.mask.closable) {
                this.maskEl.removeEventListener('click', this.triggerShow);
                this.maskEl.addEventListener('click', this.triggerShow, false);
            }
            this.canTrigger = true;
        }
        unbindTrigger(mode = 'host') {
            this.canTrigger = false;
            if (this.options.trigger === 'click') {
                this.targetEl.removeEventListener('click', this.triggerShow);
                if (this.wings.length > 0 && mode === 'all') {
                    this.wings.forEach((item) => {
                        item.removeEventListener('click', this.triggerShow);
                    });
                }
            }
            if (this.maskEl && this.options.mask.closable && mode === 'all') {
                this.maskEl.removeEventListener('click', this.triggerShow);
            }
        }
        toggleHide() {
            let other = instance.data.filter((k) => k.ins !== this &&
                k.type === 'dialog' &&
                !k.ins.destroyed &&
                k.ins.state === 'shown' &&
                k.ins.parentEl === this.parentEl);
            for (let k of other)
                k.ins.hide();
        }
        
        async show(cb) {
            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 && this.parentEl.appendChild(this.mainEl);
            super.listen({ name: 'show', cb });
            this.wrapHeight = parseInt(style(this.wrapEl).height);
            requestAnimationFrame(async () => {
                super.getDuration();
                this.wrapEl.style.transitionDuration = `${this.duration}ms`;
                this.targetEl && this.targetEl.classList.add(this.options.actClass);
                if (this.aniIn === 'slideDown') {
                    easeHeight({ el: this.wrapEl, height: this.wrapHeight, type: 'down', duration: this.duration, unaware: false });
                }
                else {
                    this.options.duration && (this.wrapEl.style.animationDuration = `${this.options.duration}ms`);
                    this.aniIn && (this.wrapEl.style.animationName = orca.prefix + this.aniIn);
                }
                !this.options.multiple && this.toggleHide();
                this.lastShowTime = Date.now();
                this.mainEl.toggleAttribute('show', true);
                await delay({
                    duration: this.duration,
                    done: () => {
                        this.state = 'shown';
                        super.listen({ name: 'shown', cb });
                    }
                });
            });
            return this;
        }
        
        async hide(cb) {
            if (this.destroyed || this.state !== 'shown') {
                return this;
            }
            this.state = 'ing';
            if (!this.options.deadShow) {
                this.options.b4Hide && await this.options.b4Hide.call(this);
                super.listen({ name: 'hide', cb });
                this.targetEl ? this.targetEl.classList.remove(this.options.actClass) : null;
                this.options.wing.actClass && this.wings.map((k) => { k.classList.remove(this.options.wing.actClass); });
                this.maskEl && (this.maskEl.style.opacity = 0);
                if (this.aniOut === 'slideUp') {
                    easeHeight({ el: this.wrapEl, height: this.wrapHeight, type: 'up', duration: this.duration, unaware: false });
                }
                else {
                    this.aniOut && (this.wrapEl.style.animationName = orca.prefix + this.aniOut);
                }
                for (let k of getEls('video,audio', this.mainEl))
                    k.pause();
                await delay({
                    duration: this.duration,
                    done: () => {
                        this.state = 'hidden';
                        this.mainEl.removeAttribute('show');
                        this.maskEl && this.maskEl.removeAttribute("style");
                        this.wrapEl.style.height = null;
                        this.wrapEl.style.animationName = null;
                        this.mainEl.remove();
                        super.listen({ name: 'hidden', cb });
                        if (this.options.heading && !['fadeIn', 'slideDown'].includes(this.aniIn)) {
                            this.options.heading && (transformTools.remove({ el: this.wrapEl, prop: 'translate' }));
                        }
                    }
                });
            }
            return this;
        }
    }

    const confirm = ({ content, contType, contData, tplStr, tplEng, heading, yes, no }) => {
        if (isEmpty(content))
            return;
        return new Promise((resolve) => {
            new Dialog(null, {
                content,
                contType,
                contData,
                heading,
                tplStr,
                tplEng,
                feature: 'confirm',
                onConfirmed: () => {
                    yes && yes();
                    resolve(true);
                },
                onCanceled: () => {
                    no && no();
                    resolve(false);
                }
            }).show();
        });
    };

    const alert = ({ content, contType, contData, heading, tplStr, tplEng, yes, dialog = {} }) => {
        if (isEmpty(content))
            return;
        return new Promise((resolve) => {
            new Dialog(null, deepMerge({
                content,
                contType,
                contData,
                heading,
                tplStr,
                tplEng,
                feature: 'alert',
                onConfirmed: () => {
                    yes && yes();
                    resolve(true);
                },
            }, dialog)).show();
        });
    };

    const notice = ({ content, contType = '', contData = {}, heading = '', label = '', tplStr, tplEng, yes, dialog = {} }) => {
        if (isEmpty(content))
            return;
        return new Promise((resolve) => {
            new Dialog(null, deepMerge({
                content,
                contType,
                contData,
                heading,
                tplStr,
                tplEng,
                feature: 'notice',
                footer: {
                    children: [{
                            name: 'confirm',
                            label,
                        }]
                },
                onConfirmed: () => {
                    yes && yes();
                    resolve(true);
                },
            }, dialog)).show();
        });
    };

    const prompt = (options) => {
        let opts = Object.assign({ fields: [{ type: 'input' }] }, options), data = Array.isArray(opts.fields) ? opts.fields : [opts.fields], frags = document.createDocumentFragment(), ins = !opts.insName ? null : instance.find(opts.insName, 'dialog'), getParams = (data) => {
            let maps = data.map((k) => { return { type: k.type, label: k.label, value: k.field.value }; }), vals = maps.map((k) => k.value), params = { value: vals, fields: maps };
            return params;
        };
        if (ins) {
            return new Promise((resolve) => {
                ins.off('confirmed');
                ins.on('confirmed', () => {
                    let params = getParams(ins.promptData);
                    resolve(params);
                });
                ins.show();
            });
        }
        for (let k of data) {
            let label = k.label ? `<div class="${orca.prefix}field-label">${k.label}</div>` : '', note = k.note ? `<div  class="${orca.prefix}field-note">${k.note}</div>` : '', attrs = Object.assign(k.type === 'upload' ? { feature: 'gallery' } : k.type === 'datetime' ? { display: 'inline', footer: false, 'auto-fill': true, } : {}, k.attrs), input = createEl(`oc-${k.type || 'input'}`, { ...attrs }), tpl = `
            <section class="${orca.prefix}field ${orca.prefix}field-apart">
                ${label}
                <div class="${orca.prefix}field-cont">
                    <div class="${orca.prefix}field-input"></div>
                    ${note}
                </div>
            </section>
        `, dom = tplToEl(tpl);
            dom.querySelector(`.${orca.prefix}field-input`).appendChild(input);
            frags.appendChild(dom);
            k.field = input;
        }
        return new Promise((resolve) => {
            ins = new Dialog(null, deepMerge({
                insName: opts.insName,
                heading: opts.heading,
                size: 'lg',
                feature: 'prompt',
                onInitiated: function () {
                    this.contEl.appendChild(frags);
                    this.promptData = data;
                },
                onConfirmed: function () {
                    let params = getParams(this.promptData);
                    opts.yes && opts.yes(params);
                    resolve(params);
                    !opts.insName && (ins = null);
                },
                onCleared: () => {
                    for (let k of data)
                        k.field.clear();
                },
                onClosed: () => {
                    !opts.insName && (ins = null);
                }
            }, opts.dialog)).show();
        });
    };

    const removeStyles = (el, props) => {
        let target = getEl(el);
        if (!target || isEmpty(props))
            return;
        for (let k of props)
            removeStyle(target, k);
    };

    const addStyles = (el, data) => {
        let target = getEl(el);
        if (!target || isEmpty(data))
            return;
        for (let k of Array.isArray(data) ? data : [data]) {
            addStyle(target, k.key, k.value);
        }
    };

    const regComp = (comp) => {
        if (!comp || getDataType(comp) !== 'Class')
            return;
        let reg = (comp) => window.customElements.define(`oc-${comp.name.replace('Elem', '').toLowerCase()}`, comp);
        if (comp.dependencies && comp.dependencies?.length) {
            for (let i of comp.dependencies) {
                try {
                    reg(i.comp);
                }
                catch { }
            }
        }
        try {
            reg(comp);
        }
        catch {
        }
    };

    const promiseRaf = (cb) => {
        if (isEmpty(cb))
            return Promise.resolve();
        return new Promise(resolve => {
            requestAnimationFrame(() => {
                cb();
                resolve();
            });
        });
    };

    const setRtl = (value = true) => {
        let dom = document.documentElement;
        if (value) {
            dom.setAttribute('dir', 'rtl');
            orca.rtl = true;
        }
        else {
            dom.removeAttribute('dir');
            Reflect.deleteProperty(orca, 'rtl');
        }
    };

    class ModBaseListenCacheNest extends ModBaseListenCache {
        flatData;
        treeData;
        treeInputEl;
        check(param, bool) {
        }
        updateArrowEl(param) {
        }
        eachCollapse(param) {
        }
        eachExpand(param) {
        }
        initCheckeds() {
            if (!this.options.check.enable)
                return;
            let vals = valToArr(this.options.check.value).map((k) => findItem(k, this.flatData)).filter(Boolean), items = this.flatData.filter((k) => k.checked);
            for (let k of items)
                k.checked = false;
            this.check([...items, ...vals]);
        }
        initReadonlys() {
            this.readonly(valToArr(this.options.readonly));
        }
        initDisableds() {
            this.disable(valToArr(this.options.disable));
        }
        getReadonlys() {
            return (this.flatData || this.treeData).filter((k) => k.readonly);
        }
        getDisableds() {
            return (this.flatData || this.treeData).filter((k) => k.disabled);
        }
        getExpandeds() {
            return (this.flatData || this.treeData).filter((k) => k.expanded);
        }
        getCheckeds() {
            return (this.flatData || this.treeData).filter((k) => k.checked);
        }
        getUncheckeds() {
            return (this.flatData || this.treeData).filter((k) => !k.checked);
        }
        getArrowEl(item) {
            if (!this.options.arrow.enable)
                return;
            item.arrowEl = createEl('i', { [orca.alias]: 'arrow' });
            this.updateArrowEl(item);
        }
        toggleArrow(val, item) {
            let map = val ? { new: 'show', old: 'hide', action: 'add' } : { new: 'hide', old: 'show', action: 'remove' };
            item.headEl.toggleAttribute('expanded', val);
            if (this.options.arrow.type === 'image') {
                item.arrowEl.style.backgroundImage = `url("${this.options.arrow[map.new]}")`;
            }
            else {
                if (this.options.arrow.show === this.options.arrow.hide) {
                    item.arrowEl.classList[map.action](this.options.arrow.anim);
                }
                else {
                    classes(item.arrowEl).replace(this.options.arrow[map.old], this.options.arrow[map.new]);
                }
            }
        }
        async collapse(data, cb) {
            if (this.destroyed)
                return;
            let tmp = Array.isArray(data) ? data : [data];
            for (let k of tmp) {
                await this.eachCollapse(k);
            }
            cb && cb.call(this, this.getExpandeds());
            return this;
        }
        async expand(data, cb) {
            if (this.destroyed)
                return;
            let tmp = Array.isArray(data) ? data : [data];
            for (let k of tmp) {
                await this.eachExpand(k);
            }
            cb && cb.call(this, this.getExpandeds());
            return this;
        }
        collapseAll(cb) {
            if (this.destroyed)
                return;
            for (let k of this.getExpandeds())
                this.eachCollapse(k);
            this.listen({ name: 'collapsedAll', cb });
            return this;
        }
        expandAll(cb) {
            if (this.destroyed)
                return;
            for (let k of this.flatData) {
                k.children && !k.expanded && this.eachExpand(k);
            }
            this.listen({ name: 'expandedAll', cb });
            return this;
        }
        lock(cb) {
            if (this.destroyed || !this.targetEl)
                return;
            this.targetEl.toggleAttribute('inert', true);
            this.destroyed = true;
            this.treeInputEl.disabled = true;
            this.listen({ name: 'locked', cb });
            return this;
        }
        unlock(cb) {
            if (!this.targetEl)
                return;
            this.targetEl.toggleAttribute('inert', false);
            this.destroyed = false;
            this.treeInputEl.disabled = false;
            this.listen({ name: 'unlocked', cb });
            return this;
        }
        readonly(data, cb) {
            if (this.destroyed)
                return;
            let tmp = isNull(data) ? this.flatData : (Array.isArray(data) ? data : [data]), items = tmp.map((k) => findItem(k, this.flatData)).filter(Boolean);
            for (let k of items)
                k.readonly = true;
            this.listen({ name: 'readonly', cb, params: [items] });
            return this;
        }
        readonlyAll(cb) {
            if (this.destroyed)
                return;
            for (let k of this.flatData)
                k.readonly = true;
            this.listen({ name: 'readonlyAll', cb });
            return this;
        }
        disable(data, cb) {
            if (this.destroyed)
                return;
            let tmp = isNull(data) ? this.flatData : (Array.isArray(data) ? data : [data]), items = tmp.map((k) => findItem(k, this.flatData)).filter(Boolean);
            for (let k of items)
                k.disabled = true;
            this.listen({ name: 'disabled', cb, params: [items] });
            return this;
        }
        disableAll(cb) {
            if (this.destroyed)
                return;
            for (let k of this.flatData)
                k.disabled = true;
            this.listen({ name: 'disabledAll', cb });
            return this;
        }
        enable(data, cb) {
            if (this.destroyed)
                return;
            let tmp = isNull(data) ? this.flatData : (Array.isArray(data) ? data : [data]), items = tmp.map((k) => findItem(k, this.flatData)).filter((k) => k && (k.disabled || k.readonly));
            for (let k of items) {
                k.hasOwnProperty('disabled') && (k.disabled = false);
                k.hasOwnProperty('readonly') && (k.readonly = false);
            }
            this.listen({ name: 'enabled', cb, params: [items] });
            return this;
        }
        enableAll(cb) {
            if (this.destroyed)
                return;
            this.enable(this.flatData);
            this.listen({ name: 'enabledAll', cb });
            return this;
        }
        toggleCheck(item) {
            item.checked ? this.check(item, false) : this.check(item, true);
        }
        uncheckAll(cb) {
            if (this.destroyed || !this.options.check.enable)
                return;
            for (let k of this.flatData) {
                k.checked = false;
            }
            this.listen({ name: 'uncheckedAll', cb });
            return this;
        }
        getSiblings(item) {
            return this.flatData.filter((k) => k.pId == item.pId && k !== item);
        }
        updateElCont(item, value, type = 'brief') {
            let prop = type === 'content' ? 'cont' : type, val = isNull(value) ? item[type] : value, valType = getDataType(val);
            valType.includes('HTML') ? (item[prop + 'El'].innerHTML = '', item[prop + 'El'].appendChild(val)) : (item[prop + 'El'].innerHTML = val);
        }
        async getElCont({ target, data = {}, prop = 'brief', cb }) {
            let elProp = prop === 'content' ? 'contEl' : `${prop}El`;
            await getContent.call(this, {
                content: data?.content || target[prop],
                contType: data?.contType || 'text',
                contData: data?.contData || { ...target },
                ajax: {
                    xhrName: 'contXhr',
                    target: target[elProp],
                    ...(data?.ajax || {})
                },
                request: (data) => {
                    this.listen({ name: 'request', params: [data] });
                },
                cb: async (resp) => {
                    let content = ['Array', 'Object'].includes(getDataType(resp)) ? { ...target, [prop]: resp } : resp;
                    setContent({
                        content,
                        template: data?.tplStr || this.tplStr,
                        engine: data?.tplEng || this.tplEng,
                        prevent: (cont) => {
                            cb && cb(cont, target);
                        }
                    });
                }
            });
        }
        async setElCont({ item, data = {}, prop = 'brief', cb }) {
            let target = findItem(item, this.flatData);
            if (!target)
                return;
            elState(target.bodyEl).isVirtual && target.headEl.insertAdjacentElement('afterend', target.bodyEl);
            await this.getElCont({
                target,
                data,
                cb: (cont) => {
                    if (target[prop] === cont) {
                        this.updateElCont(target, cont, prop);
                    }
                    else {
                        target[prop] = cont;
                        !isProxy(target) && this.updateElCont(target, cont, prop);
                    }
                    cb && cb(cont, target);
                }
            });
        }
    }

    let OCTMP_textFold = config.lang.more.fold, OCTMP_textUnfold = config.lang.more.unfold;
    const optMore = [
        {
            attr: 'stor-keys',
            prop: 'storKeys',
            value: ['content', 'length', 'folded'],
        },
        {
            attr: 'content',
            prop: 'content',
            value: ''
        },
        {
            attr: 'length',
            prop: 'length',
            value: 60,
        },
        {
            attr: 'folded',
            prop: 'folded',
            value: true,
        },
        {
            attr: 'text-fold',
            prop: 'textFold',
            value: OCTMP_textFold,
        },
        {
            attr: 'text-unfold',
            prop: 'textUnfold',
            value: OCTMP_textUnfold,
        },
        {
            attr: 'class-fold',
            prop: 'classFold',
            value: `${orca.prefix}c-prim`,
        },
        {
            attr: 'class-unfold',
            prop: 'classUnfold',
            value: `${orca.prefix}c-prim`,
        },
        {
            attr: 'on-fold',
            prop: 'onFold',
            value: null,
        },
        {
            attr: 'on-unfold',
            prop: 'onUnfold',
            value: null,
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null,
        },
        ...optBase
    ];

    class More extends ModBaseListenCache {
        options = {};
        intercepted;
        button;
        content;
        folded;
        handlers;
        html;
        pureHtml;
        event;
        text;
        ell;
        static hostType = 'node';
        static optMaps = optMore;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: More.optMaps,
                host: elem,
                component: true,
            });
            
            this.content = '';
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            
            this.folded = this.options.folded;
            this.getPureContent();
            this.targetEl.innerHTML = this.content;
            this.setAttrs();
            if (this.content.length > this.options.length) {
                this.intercepted = this.content.substring(0, this.options.length) + '...';
                this.button = createEl('i');
                this.targetEl.appendChild(this.button);
                this.toggle(this.folded ? 'fold' : 'unfold');
                this.button.onclick = () => {
                    this.folded ? this.toggle('unfold') : this.toggle('fold');
                };
            }
            super.listen({ name: 'initiated', cb });
            return this;
        }
        
        
        setAttrs() {
            
        }
        
        toggle(type) {
            if (type === 'unfold') {
                this.targetEl.removeChild(this.button.previousSibling);
                this.button.innerHTML = this.options.textUnfold;
                this.button.setAttribute('class', this.options.classUnfold);
                this.button.insertAdjacentHTML('beforeBegin', this.content);
                super.listen({ name: 'unfold' });
                this.folded = false;
            }
            else if (type === 'fold') {
                this.targetEl.removeChild(this.button.previousSibling);
                this.button.innerHTML = this.options.textFold;
                this.button.setAttribute('class', this.options.classFold);
                this.button.insertAdjacentHTML('beforeBegin', this.intercepted);
                super.listen({ name: 'fold' });
                this.folded = true;
            }
            super.updateCache({ folded: this.folded });
        }
        
        getPureContent() {
            if (this.options.content && typeof this.options.content === 'string') {
                this.content = super.getStrFromContent(this.options.content);
            }
            else {
                this.content = this.rawHtml ? this.rawHtml : this.targetEl.innerHTML;
            }
            this.content = purifyHtml(this.content);
        }
        
        destroy(cb) {
            if (this.destroyed) {
                return this;
            }
            this.button.onclick = null;
            this.clearCache();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
        
        
        async updateCont(text, cb) {
            if (this.destroyed) {
                return this;
            }
            this.options.content = text;
            await this.init();
            super.updateCache({ content: this.content });
            super.listen({ name: 'updatedCont', cb, params: [this.content] });
            return this;
        }
    }

    const optPosition = [
        {
            attr: 'enable',
            prop: 'enable',
            value: true,
        },
        {
            attr: 'placement',
            prop: 'placement',
            value: 'top-center',
        },
        {
            attr: 'arrow',
            prop: 'arrow',
            value: {
                enable: true,
                size: '0.5rem',
                offset: '2.8rem',
                gap: '.8rem',
            }
        },
        {
            attr: 'parent-mutation',
            prop: 'parentMutation',
            value: {
                enable: true,
                selector: '',
                options: {
                    attributes: true,
                    characterData: true,
                    childList: true,
                    subtree: true,
                }
            }
        },
        {
            attr: 'target-obs',
            prop: 'targetObs',
            value: {
                enable: true,
                attrs: ['class'],
                size: true,
            }
        },
        {
            attr: 'bubble-obs',
            prop: 'bubbleObs',
            value: {
                enable: true,
                attrs: ['class'],
                size: true,
            }
        },
        {
            attr: 'delay',
            prop: 'delay',
            value: 20,
        },
        {
            attr: 'on-transferred',
            prop: 'onTransferred',
            value: null,
        },
        {
            attr: 'on-reposition',
            prop: 'onReposition',
            value: null,
        },
        ...optBase
    ];

    class Position extends ModBaseListen {
        options = {};
        bubbleEl;
        arrowEl;
        gap;
        parent;
        placement;
        observerCount;
        completeCount;
        trigger;
        targetAttrsObs;
        targetSizeObs;
        bubbleAttrsObs;
        bubbleSizeObs;
        parentObs;
        bubbleData;
        browserData;
        bodyData;
        regularPlaces;
        specialPlaces;
        places;
        timer;
        fullGap;
        static hostType = 'none';
        static optMaps = optPosition;
        constructor(target, bubble, options = {}, initial = config.initial) {
            super();
            super.ready({
                type: Position.hostType,
                options,
                host: target,
                maps: Position.optMaps,
                spread: ['arrow', 'parentMutation', 'targetObs', 'bubbleObs']
            });
            
            this.targetEl = getEl(target);
            this.bubbleEl = getEl(bubble);
            if (!this.targetEl || !this.bubbleEl) {
                throw new Error(`The host element and guest element must be exist!`);
            }
            
            this.gap = toPixel(this.options.arrow.gap);
            
            let tmp = getEl(this.options.parentMutation.selector);
            this.parent = this.options.parentMutation.enable && tmp ? tmp : null;
            this.regularPlaces = [
                'left-start', 'left-center', 'left-end',
                'right-start', 'right-center', 'right-end',
                'top-start', 'top-center', 'top-end',
                'bottom-start', 'bottom-center', 'bottom-end',
            ];
            this.specialPlaces = ['left-max', 'right-max', 'top-max', 'bottom-max', 'center', 'center-max',];
            this.places = [...this.regularPlaces, ...this.specialPlaces];
            this.trigger = debounce(() => {
                let bubbleState = elState(this.bubbleEl);
                if (bubbleState.isVirtual || !bubbleState.isVisible || bubbleState.isUncalc)
                    return;
                let targetState = elState(this.targetEl);
                if (targetState.isVirtual || !targetState.isVisible || targetState.isUncalc)
                    return;
                this.resetPlacement();
            }, this.options.delay);
            this.targetAttrsObs = new MutationObserver((mutations) => {
                for (let mutation of mutations) {
                    if (this.options.targetObs.attrs.includes(mutation.attributeName)) {
                        this.trigger();
                    }
                }
            });
            this.targetSizeObs = new ResizeObserver(() => {
                this.trigger();
            });
            this.bubbleAttrsObs = new MutationObserver((mutations) => {
                for (let mutation of mutations) {
                    if (this.options.bubbleObs.attrs.includes(mutation.attributeName)) {
                        this.trigger();
                    }
                }
            });
            this.bubbleSizeObs = new ResizeObserver(() => {
                this.trigger();
            });
            this.parentObs = new MutationObserver(() => {
                if (!this.unsettable('target') && this.targetData) {
                    if (offset(this.targetEl).left !== this.targetData.left || offset(this.targetEl).top !== this.targetData.top) {
                        this.trigger();
                    }
                }
            });
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            
            this.placement = this.correctPlace(this.options.placement);
            if (!this.places.includes(this.placement))
                return this;
            this.options.placement = this.placement;
            !['center', 'center-max'].includes(this.placement) && this.createArrow();
            this.setAttrs();
            this.resetPlacement();
            this.options.enable && this.setObs();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setObs() {
            window.addEventListener('resize', this.trigger);
            window.addEventListener('scroll', this.trigger);
            if (this.options.targetObs.enable) {
                if (this.options.targetObs.attrs.length > 0) {
                    this.targetAttrsObs.observe(this.targetEl, {
                        attributes: true,
                    });
                }
                this.options.targetObs.size ? this.targetSizeObs.observe(this.targetEl) : null;
            }
            if (this.options.bubbleObs.enable) {
                if (this.options.bubbleObs.attrs.length > 0) {
                    this.bubbleAttrsObs.observe(this.bubbleEl, {
                        attributes: true,
                    });
                }
                this.options.bubbleObs.size ? this.bubbleSizeObs.observe(this.bubbleEl) : null;
            }
            if (this.parent) {
                this.parentObs.observe(this.parent, this.options.parentMutation.options);
            }
        }
        removeObs() {
            if (this.options.targetObs.enable) {
                this.options.targetObs.attrs.length > 0 ? this.targetAttrsObs.disconnect() : null;
                this.options.targetObs.size ? this.targetSizeObs.disconnect() : null;
            }
            if (this.options.bubbleObs.enable) {
                this.options.bubbleObs.attrs.length > 0 ? this.bubbleAttrsObs.disconnect() : null;
                this.options.bubbleObs.size ? this.bubbleSizeObs.disconnect() : null;
            }
            this.parent ? this.parentObs.disconnect() : null;
            window.removeEventListener('resize', this.trigger);
            window.removeEventListener('scorll', this.trigger);
        }
        correctPlace(value) {
            return (value === 'left') ? 'left-center' :
                (value === 'right') ? 'right-center' :
                    (value === 'top') ? 'top-center' :
                        (value === 'bottom') ? 'bottom-center' :
                            (value === 'max') ? 'center-max' : value;
        }
        
        setAttrs() {
            this.bubbleEl.style.position = (['center', 'center-max'].includes(this.placement)) ? 'fixed' : 'absolute';
            this.setPlacementAttr();
        }
        setPlacementAttr() {
            this.bubbleEl.setAttribute('placement', this.placement);
        }
        createArrow() {
            if (this.options.arrow.enable) {
                this.arrowEl = createEl('i', { style: 'position:absolute', [orca.alias]: 'arrow' });
                this.bubbleEl.appendChild(this.arrowEl);
            }
        }
        setArrow(placement) {
            let [left, right, top, bottom] = ['auto', 'auto', 'auto', 'auto'], exceedWidth = this.targetData.width > this.bubbleData.width / 2, exceedHeight = this.targetData.height > this.bubbleData.height / 2, arrowHalf = toPixel(getComputedStyle(this.arrowEl).width) / 2, arrowOffset = toPixel(this.options.arrow.offset), arrowRotate = '';
            if (placement.includes('top') || placement.includes('bottom')) {
                if (placement.includes('max')) {
                    let targetLeft = this.targetData.offsetLeft + this.targetData.width / 2, exceedStart = targetLeft < this.bubbleData.offsetLeft + arrowOffset - arrowHalf, exceedEnd = targetLeft > this.bubbleData.offsetRight - arrowOffset + arrowHalf;
                    left = (exceedEnd || exceedStart) ? '-10000px' : (this.targetData.offsetLeft - this.bubbleData.offsetLeft) + this.targetData.width / 2 - arrowHalf + 'px';
                }
                else if (placement.includes('start')) {
                    left = !exceedWidth ? Math.floor(this.targetData.width / 2 - arrowHalf) + 'px' : this.options.arrow.offset;
                }
                else if (placement.includes('end')) {
                    right = !exceedWidth ? Math.floor(this.targetData.width / 2 - arrowHalf) + 'px' : this.options.arrow.offset;
                }
                else {
                    left = this.bubbleData.width / 2 - 1 - arrowHalf + 'px';
                }
            }
            else if (placement.includes('left') || placement.includes('right')) {
                if (placement.includes('max')) {
                    let targetTop = this.targetData.offsetTop + this.targetData.height / 2, exceedStart = targetTop < this.bubbleData.offsetTop + arrowOffset - arrowHalf, exceedEnd = targetTop > this.bubbleData.offsetBottom - arrowOffset + arrowHalf;
                    top = (exceedEnd || exceedStart) ? '-10000px' : (this.targetData.offsetTop - this.bubbleData.offsetTop) + this.targetData.height / 2 - arrowHalf + 'px';
                }
                else if (placement.includes('start')) {
                    top = !exceedHeight ? Math.floor(this.targetData.height / 2 - arrowHalf) + 'px' : this.options.arrow.offset;
                }
                else if (placement.includes('end')) {
                    bottom = !exceedHeight ? Math.floor(this.targetData.height / 2 - arrowHalf) + 'px' : this.options.arrow.offset;
                }
                else {
                    top = this.bubbleData.height / 2 - 1 - arrowHalf + 'px';
                }
            }
            else {
                left = '-10000px';
                top = '-10000px';
            }
            if (placement.includes('top')) {
                bottom = '-' + this.options.arrow.size;
                arrowRotate = '45';
            }
            else if (placement.includes('bottom')) {
                top = '-' + this.options.arrow.size;
                arrowRotate = '-135';
            }
            else if (placement.includes('left')) {
                right = '-' + this.options.arrow.size;
                arrowRotate = '-45';
            }
            else if (placement.includes('right')) {
                left = '-' + this.options.arrow.size;
                arrowRotate = '135';
            }
            let tmp = `left:${left};right:${right};top:${top};bottom:${bottom};transform:rotate(${arrowRotate}deg);`;
            this.arrowEl.style.cssText += tmp;
            
        }
        getRectsData() {
            this.bodyData = {
                width: document.body.offsetWidth,
                height: document.body.offsetHeight,
            };
            this.browserData = {
                width: document.documentElement.clientWidth,
                height: document.documentElement.clientHeight,
                scrollTop: document.documentElement.scrollTop || document.body.scrollTop,
                scrollLeft: document.documentElement.scrollLeft || document.body.scrollLeft
            };
            let targetRect = this.targetEl.getBoundingClientRect();
            this.targetData = {
                width: targetRect.width,
                height: targetRect.height,
                offsetLeft: targetRect.left,
                offsetRight: targetRect.right,
                offsetTop: targetRect.top,
                offsetBottom: targetRect.bottom,
                gapRight: this.browserData.width - targetRect.right,
                gapBottom: this.browserData.height - targetRect.bottom,
                ...offset(this.targetEl)
            };
            this.getBubbleData();
        }
        getBubbleData() {
            let bubbleRect = this.bubbleEl.getBoundingClientRect();
            this.bubbleData = {
                width: bubbleRect.width,
                height: bubbleRect.height,
                offsetLeft: bubbleRect.left,
                offsetRight: bubbleRect.right,
                offsetTop: bubbleRect.top,
                offsetBottom: bubbleRect.bottom,
                gapRight: this.browserData.width - bubbleRect.right,
                gapBottom: this.browserData.height - bubbleRect.bottom
            };
        }
        
        setPlacement(placement) {
            let [left, right, top, bottom] = ['auto', 'auto', 'auto', 'auto'], cssText = '';
            if (placement.includes('bottom') || placement.includes('top')) {
                if (placement.includes('bottom')) {
                    left = placement === 'bottom' || placement === 'bottom-center' ? (this.targetData.left - (this.bubbleData.width - this.targetData.width) / 2) :
                        placement === 'bottom-start' ? this.targetData.left :
                            placement === 'bottom-end' ? this.targetData.left + this.targetData.width - this.bubbleData.width : 0;
                    top = `${toNumber(this.targetData.top + this.targetData.height + this.gap, { mode: 'ceil' })}px`;
                    left = `${toNumber(left, { mode: 'ceil' })}px`;
                }
                else if (placement.includes('top')) {
                    left = placement === 'top' || placement === 'top-center' ? (this.targetData.left - (this.bubbleData.width - this.targetData.width) / 2) :
                        placement === 'top-start' ? this.targetData.left :
                            placement === 'top-end' ? (this.targetData.left + this.targetData.width - this.bubbleData.width) : 0;
                    bottom = `${toNumber((this.bodyData.height - this.targetData.top + this.gap), { mode: 'ceil' })}px`;
                    left = `${toNumber(left, { mode: 'ceil' })}px`;
                }
            }
            else if (placement.includes('left') || placement.includes('right')) {
                if (placement.includes('left')) {
                    if (placement === 'left' || placement === 'left-center') {
                        top = `${toNumber(this.targetData.top - (this.bubbleData.height - this.targetData.height) / 2, { mode: 'ceil' })}px`;
                    }
                    else if (placement === 'left-start') {
                        top = `${toNumber(this.targetData.top, { mode: 'ceil' })}px`;
                    }
                    else if (placement === 'left-end') {
                        bottom = `${toNumber(this.bodyData.height - this.targetData.top - this.targetData.height, { mode: 'ceil' })}px`;
                    }
                    right = `${toNumber(this.browserData.width - this.targetData.left + this.gap, { mode: 'ceil' })}px`;
                }
                else if (placement.includes('right')) {
                    if (placement === 'right' || placement === 'right-center') {
                        top = `${toNumber(this.targetData.top - (this.bubbleData.height - this.targetData.height) / 2, { mode: 'ceil' })}px`;
                    }
                    else if (placement === 'right-start') {
                        top = `${toNumber(this.targetData.top, { mode: 'ceil' })}px`;
                    }
                    else if (placement === 'right-end') {
                        bottom = `${toNumber(this.bodyData.height - this.targetData.top - this.targetData.height, { mode: 'ceil' })}px`;
                    }
                    left = `${toNumber(this.targetData.left + this.targetData.width + this.gap, { mode: 'ceil' })}px`;
                }
            }
            if (this.placement === 'center-max') {
                cssText = `width:calc(100vw - ${orca.fullGap}*2);height:calc(100vh - ${orca.fullGap}*2);`;
                left = orca.fullGap;
                top = orca.fullGap;
            }
            else if (this.placement === 'center') {
                cssText = `margin-left:-${toNumber(this.bubbleEl.getBoundingClientRect().width / 2, { mode: 'ceil' })}px;margin-top:-${toNumber(this.bubbleEl.getBoundingClientRect().height / 2, { mode: 'ceil' })}px;`;
                left = '50%';
                top = '50%';
            }
            else if (this.placement === 'top-max' || this.placement === 'bottom-max') {
                left = `${toNumber(this.browserData.scrollLeft + toPixel(orca.fullGap), { mode: 'ceil' })}px`;
                cssText = `width:calc(100vw - ${orca.fullGap}*2);`;
            }
            else if (this.placement === 'left-max' || this.placement === 'right-max') {
                top = `${toNumber(this.browserData.scrollTop + toPixel(orca.fullGap), { mode: 'ceil' })}px`;
                cssText = `height:calc(100vh - ${orca.fullGap}*2);`;
            }
            this.bubbleEl.style.cssText += (cssText + `left:${left};right:${right};top:${top};bottom:${bottom};`);
            
            this.getBubbleData();
            this.arrowEl ? this.setArrow(placement) : null;
        }
        resetBubbleAttrs() {
            let tmp = this.bubbleEl.style.cssText.replace('margin-left:', '').replace('margin-top:', '').replace('width:', '').replace('height:', '') + `;left:auto;right:auto;top:auto;bottom:auto;`;
            this.bubbleEl.style.cssText = tmp;
            
            this.getBubbleData();
        }
        getSurroundGap() {
            let left = this.targetData.offsetLeft - this.bubbleData.width - this.gap, top = this.targetData.offsetTop - this.bubbleData.height - this.gap, right = this.browserData.width - this.targetData.offsetRight - this.bubbleData.width - this.gap, bottom = this.browserData.height - this.targetData.offsetBottom - this.bubbleData.height - this.gap, startTop = this.targetData.offsetTop, startBottom = this.browserData.height - (startTop + this.bubbleData.height), centerTop = this.targetData.offsetTop - (this.bubbleData.height - this.targetData.height) / 2, centerBottom = this.browserData.height - (centerTop + this.bubbleData.height), endTop = this.targetData.offsetBottom - this.bubbleData.height, endBottom = this.browserData.height - this.targetData.offsetBottom, startLeft = this.targetData.offsetLeft, startRight = this.browserData.width - (startLeft + this.bubbleData.width), centerLeft = this.targetData.offsetLeft - (this.bubbleData.width - this.targetData.width) / 2, centerRight = this.browserData.width - (centerLeft + this.bubbleData.width), endLeft = this.targetData.offsetRight - this.bubbleData.width, endRight = this.browserData.width - this.targetData.offsetRight;
            return {
                left, right, top, bottom,
                start: { left: startLeft, right: startRight, top: startTop, bottom: startBottom },
                center: { left: centerLeft, right: centerRight, top: centerTop, bottom: centerBottom },
                end: { left: endLeft, right: endRight, top: endTop, bottom: endBottom }
            };
        }
        fixPlacement() {
            if (this.targetData.gapRight > this.browserData.width || this.targetData.offsetLeft > this.browserData.width || ['center', 'center-max'].includes(this.placement))
                return;
            let gaps = this.getSurroundGap();
            if (this.placement.includes('top') && (gaps.top < 0 && gaps.bottom >= 0)) {
                this.placement = this.placement.replace('top', 'bottom');
            }
            else if (this.placement.includes('bottom') && (gaps.bottom < 0 && gaps.top >= 0)) {
                this.placement = this.placement.replace('bottom', 'top');
            }
            else if (this.placement.includes('left') && (gaps.left < 0 && gaps.right >= 0)) {
                this.placement = this.placement.replace('left', 'right');
            }
            else if (this.placement.includes('right') && (gaps.right < 0 && gaps.left >= 0)) {
                this.placement = this.placement.replace('right', 'left');
            }
            if (!['left-max', 'right-max', 'top-max', 'bottom-max'].includes(this.placement)) {
                if ((this.placement.includes('top') || this.placement.includes('bottom')) && this.bubbleData.width < this.browserData.width) {
                    if (this.bubbleData.width > this.targetData.width) {
                        if (this.targetData.offsetLeft < 0 && this.targetData.gapRight < this.browserData.width) {
                            this.placement = this.placement.replace('end', 'start').replace('center', 'start');
                        }
                        else if (this.targetData.gapRight < 0 && this.targetData.offsetLeft < this.browserData.width) {
                            this.placement = this.placement.replace('start', 'end').replace('center', 'end');
                        }
                        else {
                            if (gaps.end.left < 0 && gaps.center.left < 0) {
                                this.placement = this.placement.replace('end', 'start').replace('center', 'start');
                            }
                            else if (gaps.end.left < 0 && this.placement.includes('end')) {
                                this.placement = this.placement.replace('end', 'center');
                            }
                            else if (gaps.end.left < 0 && gaps.center.left > 0 && this.placement.includes('start') && (this.options.placement.includes('end') || this.options.placement.includes('center'))) {
                                this.placement = this.placement.replace('start', 'center');
                            }
                            else if (gaps.end.left > 0 && this.placement.includes('center') && (this.options.placement.includes('end'))) {
                                this.placement = this.placement.replace('center', 'end');
                            }
                            if (gaps.start.right < 0 && gaps.center.right < 0) {
                                this.placement = this.placement.replace('start', 'end').replace('center', 'end');
                            }
                            else if (gaps.start.right < 0 && this.placement.includes('start')) {
                                this.placement = this.placement.replace('start', 'center');
                            }
                            else if (gaps.start.right < 0 && gaps.center.right > 0 && this.placement.includes('end') && (this.options.placement.includes('start') || this.options.placement.includes('center'))) {
                                this.placement = this.placement.replace('end', 'center');
                            }
                            else if (gaps.start.right > 0 && this.placement.includes('center') && (this.options.placement.includes('start'))) {
                                this.placement = this.placement.replace('center', 'start');
                            }
                        }
                    }
                    else {
                        if (gaps.start.left < 0 && gaps.center.left < 0) {
                            this.placement = this.placement.replace('start', 'end').replace('center', 'end');
                        }
                        else if (gaps.start.left < 0 && this.placement.includes('start')) {
                            this.placement = this.placement.replace('start', 'center');
                        }
                        else if (gaps.start.left < 0 && gaps.center.left > 0 && this.placement.includes('end') && (this.options.placement.includes('start') || this.options.placement.includes('center'))) {
                            this.placement = this.placement.replace('end', 'center');
                        }
                        else if (gaps.start.left > 0 && this.placement.includes('center') && (this.options.placement.includes('start'))) {
                            this.placement = this.placement.replace('center', 'start');
                        }
                        if (gaps.end.right < 0 && gaps.center.right < 0) {
                            this.placement = this.placement.replace('end', 'start').replace('center', 'start');
                        }
                        else if (gaps.end.right < 0 && this.placement.includes('end')) {
                            this.placement = this.placement.replace('end', 'center');
                        }
                        else if (gaps.end.right < 0 && gaps.center.right > 0 && this.placement.includes('start') && (this.options.placement.includes('end') || this.options.placement.includes('center'))) {
                            this.placement = this.placement.replace('start', 'center');
                        }
                        else if (gaps.end.right > 0 && this.placement.includes('center') && (this.options.placement.includes('end'))) {
                            this.placement = this.placement.replace('center', 'end');
                        }
                    }
                }
                if ((this.placement.includes('left') || this.placement.includes('right')) && this.bubbleData.height < this.browserData.height) {
                    if (this.bubbleData.height > this.targetData.height) {
                        if (this.targetData.offsetTop < 0 && this.targetData.gapBottom < this.browserData.height) {
                            this.placement = this.placement.replace('end', 'start').replace('center', 'start');
                        }
                        else if (this.targetData.gapBottom < 0 && this.targetData.offsetTop < this.browserData.height) {
                            this.placement = this.placement.replace('start', 'end').replace('center', 'end');
                        }
                        else {
                            if (gaps.end.top < 0 && gaps.center.top < 0) {
                                this.placement = this.placement.replace('end', 'start').replace('center', 'start');
                            }
                            else if (gaps.end.top < 0 && this.placement.includes('end')) {
                                this.placement = this.placement.replace('end', 'center');
                            }
                            else if (gaps.end.top < 0 && gaps.center.top > 0 && this.placement.includes('start') && (this.options.placement.includes('end') || this.options.placement.includes('center'))) {
                                this.placement = this.placement.replace('start', 'center');
                            }
                            else if (gaps.end.top > 0 && this.placement.includes('center') && (this.options.placement.includes('end'))) {
                                this.placement = this.placement.replace('center', 'end');
                            }
                            if (gaps.start.bottom < 0 && gaps.center.bottom < 0) {
                                this.placement = this.placement.replace('start', 'end').replace('center', 'end');
                            }
                            else if (gaps.start.bottom < 0 && this.placement.includes('start')) {
                                this.placement = this.placement.replace('start', 'center');
                            }
                            else if (gaps.start.bottom < 0 && gaps.center.bottom > 0 && this.placement.includes('end') && (this.options.placement.includes('start') || this.options.placement.includes('center'))) {
                                this.placement = this.placement.replace('end', 'center');
                            }
                            else if (gaps.start.bottom > 0 && this.placement.includes('center') && (this.options.placement.includes('start'))) {
                                this.placement = this.placement.replace('center', 'start');
                            }
                        }
                    }
                    else {
                        if (gaps.start.top < 0 && gaps.center.top < 0) {
                            this.placement = this.placement.replace('start', 'end').replace('center', 'end');
                        }
                        else if (gaps.start.top < 0 && this.placement.includes('start')) {
                            this.placement = this.placement.replace('start', 'center');
                        }
                        else if (gaps.start.top < 0 && gaps.center.top > 0 && this.placement.includes('end') && (this.options.placement.includes('start') || this.options.placement.includes('center'))) {
                            this.placement = this.placement.replace('end', 'center');
                        }
                        else if (gaps.start.top > 0 && this.placement.includes('center') && (this.options.placement.includes('start'))) {
                            this.placement = this.placement.replace('center', 'start');
                        }
                        if (gaps.end.bottom < 0 && gaps.center.bottom < 0) {
                            this.placement = this.placement.replace('end', 'start').replace('center', 'start');
                        }
                        else if (gaps.end.bottom < 0 && this.placement.includes('end')) {
                            this.placement = this.placement.replace('end', 'center');
                        }
                        else if (gaps.end.bottom < 0 && gaps.center.bottom > 0 && this.placement.includes('start') && (this.options.placement.includes('end') || this.options.placement.includes('center'))) {
                            this.placement = this.placement.replace('start', 'center');
                        }
                        else if (gaps.end.bottom > 0 && this.placement.includes('center') && (this.options.placement.includes('end'))) {
                            this.placement = this.placement.replace('center', 'end');
                        }
                    }
                }
            }
            this.fullyExpose(gaps);
            this.setPlacementAttr();
        }
        fullyExpose(gaps) {
            if (this.options.placement === this.placement || this.placement.includes('max'))
                return;
            let placeArr = this.placement.split('-'), parentStr = placeArr[0], childStr = placeArr[1];
            parentStr = (this.options.placement.includes('top') && gaps.top >= 0) ? 'top' :
                (this.options.placement.includes('bottom') && gaps.bottom >= 0) ? 'bottom' :
                    (this.options.placement.includes('left') && gaps.left >= 0) ? 'left' :
                        (this.options.placement.includes('right') && gaps.right >= 0) ? 'right' : placeArr[0];
            if (this.options.placement.includes('top') || this.options.placement.includes('bottom')) {
                if (this.options.placement.includes('start') && gaps.start[(this.bubbleData.width > this.targetData.width) ? 'right' : 'left'] >= 0) {
                    childStr = 'start';
                }
                else if (this.options.placement.includes('end') && gaps.end[(this.bubbleData.width > this.targetData.width) ? 'left' : 'right'] >= 0) {
                    childStr = 'end';
                }
                else if (this.options.placement.includes('center') && gaps.center.left >= 0 && gaps.center.right >= 0) {
                    childStr = 'center';
                }
            }
            else if (this.options.placement.includes('left') || this.options.placement.includes('right')) {
                if (this.options.placement.includes('start') && gaps.start[(this.bubbleData.height > this.targetData.height) ? 'bottom' : 'top'] >= 0) {
                    childStr = 'start';
                }
                else if (this.options.placement.includes('end') && gaps.end[(this.bubbleData.height > this.targetData.height) ? 'top' : 'bottom'] >= 0) {
                    childStr = 'end';
                }
                else if (this.options.placement.includes('center') && gaps.center.top >= 0 && gaps.center.bottom >= 0) {
                    childStr = 'center';
                }
            }
            this.placement = `${parentStr}-${childStr}`;
        }
        unsettable(type) {
            let el = type === 'target' ? this.targetEl : this.bubbleEl;
            return elState(el).isUncalc;
        }
        
        resetPlacement(cb) {
            if (this.destroyed || !this.places.includes(this.placement) || this.unsettable()) {
                return this;
            }
            this.getRectsData();
            this.resetBubbleAttrs();
            this.fixPlacement();
            this.setPlacement(this.placement);
            super.listen({ name: 'changed', cb, params: [this.placement] });
        }
        
        change(placement, cb) {
            if (this.destroyed) {
                return this;
            }
            placement && (this.placement = this.correctPlace(placement));
            if (!this.places.includes(this.placement))
                return this;
            this.options.placement = this.placement;
            this.setAttrs();
            this.getRectsData();
            this.resetBubbleAttrs();
            this.setPlacement(this.placement);
            super.listen({ name: 'changed', cb, params: [this.placement] });
            return this;
        }
        
        transfer(elem, cb) {
            if (this.destroyed || !elem)
                return;
            this.targetEl = getEl(elem);
            if (this.targetEl) {
                this.resetPlacement(cb);
                super.listen({ name: 'transferred', cb, params: [this.targetEl] });
            }
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return;
            this.removeObs();
            this.trigger.cancel();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb, params: [this.placement] });
            return this;
        }
    }

    const optHover = [
        {
            attr: 'timeout',
            prop: 'timeout',
            value: 50,
        },
        {
            attr: 'intvl',
            prop: 'intvl',
            value: 50,
        },
        {
            attr: 'throttle',
            prop: 'throttle',
            value: 200,
        },
        {
            attr: 'threshold',
            prop: 'threshold',
            value: 7,
        },
        {
            attr: 'hold',
            prop: 'hold',
            value: '',
        },
        {
            attr: 'on-move',
            prop: 'onMove',
            value: null,
        },
        {
            attr: 'on-enter',
            prop: 'onEnter',
            value: null,
        },
        {
            attr: 'on-leave',
            prop: 'onLeave',
            value: null,
        },
        ...optBase
    ];

    class Hover extends ModBaseListen {
        options = {};
        curX;
        curY;
        preX;
        preY;
        isActive;
        enterTimer;
        leaveTimer;
        eventToggle;
        holdEl;
        enterCompare;
        globalEvent;
        moveEvent;
        enterEvent;
        leaveEvent;
        enterHold;
        leaveHold;
        static hostType = 'node';
        static optMaps = optHover;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: Hover.optMaps,
                host: elem,
            });
            
            
            
            
            
            
            
            
            
            this.curX;
            this.curY;
            
            
            this.preX;
            this.preY;
            this.enterTimer;
            this.leaveTimer;
            
            this.isActive = false;
            
            this.holdEl = getEl(this.options.hold);
            this.eventToggle = (type, elem, event) => {
                let obj = { event, target: elem };
                if (type === 'enter') {
                    this.isActive = true;
                    super.listen({ name: 'enter', params: [{ ...obj, inside: true, name: 'enter' }] });
                }
                else if (type === 'leave') {
                    this.isActive = false;
                    super.listen({ name: 'leave', params: [{ ...obj, inside: false, name: 'leave' }] });
                }
            };
            this.enterCompare = (elem, event) => {
                let distX = this.preX - this.curX, distY = this.preY - this.curY, distance = Math.sqrt(distX ** 2 + distY ** 2);
                if (distance < this.options.threshold) {
                    if (!this.isActive) {
                        this.eventToggle('enter', elem, event);
                    }
                }
                else {
                    this.preX = this.curX;
                    this.preY = this.curY;
                    this.enterTimer = setTimeout(() => {
                        this.enterCompare(elem, event);
                    }, this.options.intvl);
                }
            };
            this.globalEvent = throttle((event) => {
                let inTarget = contains(event.target, this.targetEl), inHold = this.holdEl ? contains(event.target, this.holdEl) : true, inside = inTarget && inHold;
                super.listen({ name: 'move', params: [{ inside, event, name: 'move', target: event.target }] });
            }, this.options.throttle);
            this.moveEvent = (event) => {
                this.curX = event.pageX;
                this.curY = event.pageY;
            };
            this.enterEvent = (event) => {
                clearTimeout(this.leaveTimer);
                this.preX = event.pageX;
                this.preY = event.pageY;
                this.enterTimer = setTimeout(() => {
                    this.enterCompare(event.target, event);
                }, this.options.intvl);
            };
            this.leaveEvent = (event) => {
                clearTimeout(this.enterTimer);
                this.leaveTimer = setTimeout(() => {
                    this.eventToggle('leave', event.target, event);
                }, this.options.timeout);
            };
            this.enterHold = () => {
                clearTimeout(this.leaveTimer);
            };
            this.leaveHold = (event) => {
                clearTimeout(this.enterTimer);
                this.leaveTimer = setTimeout(() => {
                    this.eventToggle('leave', this.targetEl, event);
                }, this.options.timeout);
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            document.body.removeEventListener('mousemove', this.globalEvent);
            this.targetEl.removeEventListener('mousemove', this.moveEvent);
            this.targetEl.removeEventListener('mouseenter', this.enterEvent);
            this.targetEl.removeEventListener('mouseleave', this.leaveEvent);
            document.body.addEventListener('mousemove', this.globalEvent);
            this.targetEl.addEventListener('mousemove', this.moveEvent);
            this.targetEl.addEventListener('mouseenter', this.enterEvent);
            this.targetEl.addEventListener('mouseleave', this.leaveEvent);
            if (this.holdEl) {
                this.holdEl.removeEventListener('mouseenter', this.enterHold);
                this.holdEl.removeEventListener('mouseleave', this.leaveHold);
                this.holdEl.addEventListener('mouseenter', this.enterHold);
                this.holdEl.addEventListener('mouseleave', this.leaveHold);
            }
            super.listen({ name: 'initiated', cb });
        }
        
        destroy(cb) {
            if (this.destroyed) {
                return this;
            }
            document.body.removeEventListener('mousemove', this.globalEvent);
            this.targetEl.removeEventListener('mousemove', this.moveEvent);
            this.targetEl.removeEventListener('mouseenter', this.enterEvent);
            this.targetEl.removeEventListener('mouseleave', this.leaveEvent);
            if (this.holdEl) {
                this.holdEl.removeEventListener('mouseenter', this.enterHold);
                this.holdEl.removeEventListener('mouseleave', this.leaveHold);
            }
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optPopup = [
        {
            attr: 'theme',
            prop: 'theme',
            value: '',
        },
        {
            attr: 'placement',
            prop: 'placement',
            value: 'top',
        },
        {
            attr: 'trigger',
            prop: 'trigger',
            value: 'hover',
        },
        {
            attr: 'page-close',
            prop: 'pageClose',
            value: true,
        },
        {
            attr: 'size',
            prop: 'size',
            value: 'md',
        },
        {
            attr: 'in',
            prop: 'in',
            value: 'fadeIn',
        },
        {
            attr: 'out',
            prop: 'out',
            value: 'fadeOut',
        },
        {
            attr: 'multiple',
            prop: 'multiple',
            value: false,
        },
        {
            attr: 'height',
            prop: 'height',
            value: '',
        },
        {
            attr: 'adaptive',
            prop: 'adaptive',
            value: true,
        },
        {
            attr: 'position',
            prop: 'position',
            value: {},
        },
        {
            attr: 'arrow',
            prop: 'arrow',
            value: {
                enable: true,
                size: '0.5rem',
                offset: '2.8rem',
                gap: '.8rem',
            }
        },
        {
            attr: 'wing',
            prop: 'wing',
            value: {
                selector: '',
                trigger: 'click',
                actClass: '',
            },
        },
        {
            attr: 'on-reposition',
            prop: 'onReposition',
            value: null,
        },
        ...optBubble
    ];

    class Popup extends ModBaseListenCacheBubble {
        options = {};
        confirmEl;
        cancelEl;
        closeEl;
        triggerShow;
        clickOutHideEvt;
        content;
        bubbleType;
        aniIn;
        aniOut;
        initialPlace;
        isCompField;
        static optMaps = optPopup;
        constructor(elem, options = {}, initial = config.initial) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Popup.optMaps,
                component: false,
                spread: ['arrow', 'tools', 'padding', 'footer', 'autoFill', 'bullet']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            this.bubbleType = 'popup';
            let _this = this;
            this.triggerShow = function (evt) {
                evt.preventDefault();
                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 === _this.targetEl && _this.options.canClick) {
                        let target = getEvtTarget(evt), tmp = _this.options.canClick.call(_this, target, evt);
                        if (!tmp)
                            return;
                    }
                    if (_this.state === 'hidden') {
                        _this.show();
                        if (!_this.options.multiple) {
                            let items = instance.data.filter((i) => i.type === _this.constructor.name.toLowerCase() && i.ins !== _this && i.ins.state === 'shown');
                            for (let k of items)
                                k.ins.hide();
                        }
                        else {
                            _this.options.wing.actClass && _this.wings.includes(this) && this.classList.add(_this.options.wing.actClass);
                        }
                    }
                    else if (_this.state === 'shown') {
                        !_this.options.keepShow && _this.hide();
                    }
                }
                else if (_this.options.trigger === 'input') {
                    if (!_this.targetEl?.value) {
                        !_this.options.keepShow && _this.hide();
                    }
                    else {
                        _this.show();
                        _this.options.wing.actClass && _this.wings.includes(this) && this.classList.add(_this.options.wing.actClass);
                    }
                }
            };
            this.clickOutHideEvt = (e) => {
                !contains(e.target, [this.mainEl, this.targetEl, ...this.wings]) &&
                    this.state === 'shown' &&
                    !this.options.keepShow &&
                    elState(e.target).isVisible &&
                    this.hide();
            };
            this.triggerClose = () => {
                !this.options.keepShow && this.hide();
            };
            this.leaveTrigger = debounce(() => {
                !this.options.keepShow && this.hide();
            });
            super.listen({ name: 'constructed' });
            initial && this.targetEl && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setEmpty();
            this.options.placement = this.options.placement || 'top';
            this.options.trigger = this.options.trigger === 'hover' && orca.isTouchScr ? 'click' : this.options.trigger;
            this.isCompField = fieldTypes.includes(this.options.contType.toLowerCase());
            if (this.isCompField) {
                this.options.tools.placement = 'outside';
            }
            
            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.renderContent(data);
                }
            });
            this.fixAni(this.options.placement);
            this.createPosition();
            this.handleFooter();
            this.handleTools();
            this.bindTrigger();
            this.contEl.querySelectorAll(`[${orca.alias}="closebubble"]`).forEach((k) => {
                k.removeEventListener('click', this.triggerClose);
                k.addEventListener('click', this.triggerClose, false);
            });
            this.initBullets();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        fixAni(placement) {
            this.aniIn = placement.includes('max') && this.options.in === 'slideDown' ? 'fadeIn' : this.options.in;
            this.aniOut = placement.includes('max') && this.options.out === 'slideUp' ? 'fadeOut' : this.options.out;
        }
        handleTools() {
            if (this.options.tools.enable) {
                this.options.tools.children.forEach((k) => {
                    if (k.name === 'close') {
                        k.wrapEl.onclick = () => this.hide();
                    }
                    else if (k.name === 'enlarge') {
                        if (this.positionIns.placement === 'center-max') {
                            classes(k.iconEl).replace(k.icon, k.swap);
                            this.initialPlace = this.rawOpts.placement;
                        }
                        else {
                            this.initialPlace = this.positionIns.placement;
                        }
                        k.wrapEl.onclick = () => {
                            if (this.positionIns.placement === 'center-max') {
                                classes(k.iconEl).replace(k.swap, k.icon);
                                this.reposition(this.initialPlace);
                            }
                            else {
                                classes(k.iconEl).replace(k.icon, k.swap);
                                this.reposition('center-max');
                            }
                        };
                    }
                    else if (k.name === 'widen') {
                        if (this.positionIns.placement === 'top-max' || this.positionIns.placement === 'bottom-max') {
                            classes(k.iconEl).replace(k.icon, k.swap);
                            this.initialPlace = this.positionIns.placement.split('-')[0];
                        }
                        else {
                            this.initialPlace = 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 (['left-max', 'right-max', 'top-max', 'bottom-max'].includes(this.positionIns.placement)) {
                                classes(k.iconEl).replace(k.swap, k.icon);
                                this.reposition(this.initialPlace);
                            }
                            else {
                                let position = this.positionIns.placement.split('-')[0];
                                classes(k.iconEl).replace(k.icon, k.swap);
                                this.reposition(position + '-max');
                            }
                        };
                    }
                    else if (k.name === 'heighten') {
                        if (this.positionIns.placement === 'left-max' || this.positionIns.placement === 'right-max') {
                            classes(k.iconEl).replace(k.icon, k.swap);
                            this.initialPlace = this.positionIns.placement.split('-')[0];
                        }
                        else {
                            this.initialPlace = 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 (['left-max', 'right-max', 'top-max', 'bottom-max'].includes(this.positionIns.placement)) {
                                classes(k.iconEl).replace(k.swap, k.icon);
                                this.reposition(this.initialPlace);
                            }
                            else {
                                let position = this.positionIns.placement.split('-')[0];
                                classes(k.iconEl).replace(k.icon, k.swap);
                                this.reposition(position + '-max');
                            }
                        };
                    }
                    else {
                        k.action && k.action.call(this, k);
                    }
                });
            }
        }
        setAttrs() {
            this.options.classes && classes(this.mainEl).add(this.options.classes);
            this.options.size ? this.mainEl.setAttribute('size', this.options.size) : this.mainEl.removeAttribute('size');
            this.options.contType ? this.mainEl.setAttribute('conttype', this.options.contType) : this.mainEl.removeAttribute('conttype');
            this.options.placement ? this.mainEl.setAttribute('placement', this.options.placement) : this.mainEl.removeAttribute('placement', this.options.placement);
            this.contEl.toggleAttribute('dedicated', this.options.dedicated);
            this.options.height ? addStyle(this.contEl, 'height', this.options.height) : removeStyle(this.contEl, 'height');
            this.options.zIndex ? addStyle(this.mainEl, 'z-index', this.options.zIndex) : removeStyle(this.mainEl, 'z-index');
            this.options.tools.enable ? this.mainEl.setAttribute('toolsplace', this.options.tools.placement) : this.mainEl.removeAttribute('toolsplace');
            this.options.theme ? this.mainEl.setAttribute('theme', this.options.theme) : this.mainEl.removeAttribute('theme');
        }
        createPosition() {
            let tmpArr = this.options.placement.split('-'), placement = this.options.placement;
            if (this.options.adaptive && orca.screen === 'xxs') {
                if (tmpArr[0] === 'left') {
                    placement = 'top-max';
                }
                else if (tmpArr[0] === 'right') {
                    placement = 'bottom-max';
                }
                else if (!tmpArr.includes('max') && ['top', 'bottom'].includes(tmpArr[0])) {
                    placement = tmpArr[0] + '-max';
                }
            }
            
            this.positionIns = new Position(this.targetEl, this.mainEl, extend({
                target: {
                    placement,
                    arrow: this.options.arrow,
                    targetObs: {
                        attrs: [],
                    },
                    bubbleObs: {
                        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) => {
                        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') {
                
                this.hoverIns = new Hover(this.targetEl, {
                    onEnter: () => {
                        this.show();
                    },
                    onLeave: this.leaveTrigger,
                    hold: this.mainEl,
                });
            }
            else if (this.options.trigger === 'sticky') {
                this.options.multiple = true;
                this.show();
            }
            if (this.options.pageClose && !this.options.multiple) {
                !this.canTrigger && document.addEventListener('click', this.clickOutHideEvt, false);
            }
            this.canTrigger = true;
        }
        unbindTrigger(mode = '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) => {
                        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.clickOutHideEvt, false);
            }
        }
        
        reposition(placement, cb) {
            if (this.destroyed || !placement) {
                return this;
            }
            this.positionIns.change(placement, (placement) => {
                this.fixAni(placement);
                this.updateCache({ placement });
                super.listen({ name: 'reposition', cb, params: [placement] });
            });
            return this;
        }
        
        async show(cb) {
            if (this.destroyed || this.options.asleep) {
                return this;
            }
            if (this.state !== 'hidden') {
                if (this.state === 'shown')
                    this.leaveTrigger.cancel();
                return this;
            }
            this.state = 'ing';
            this.options.b4Show && await this.options.b4Show.call(this);
            elState(this.mainEl).isVirtual && document.body.appendChild(this.mainEl);
            super.listen({ name: 'show', cb });
            this.targetEl && this.targetEl.classList.add(this.options.actClass);
            this.lastShowTime = Date.now();
            this.hoverIns && (this.hoverIns.isActive = true);
            requestAnimationFrame(async () => {
                this.positionIns.change();
                this.wrapHeight = this.positionIns.bubbleData.height;
                super.getDuration();
                this.mainEl.style.visibility = 'visible';
                if (this.aniIn === 'slideDown') {
                    easeHeight({ el: this.wrapEl, height: this.wrapHeight, type: 'down', duration: this.duration, unaware: false });
                }
                else {
                    this.options.duration && (this.mainEl.style.animationDuration = `${this.options.duration}ms`);
                    this.aniIn && (this.mainEl.style.animationName = orca.prefix + this.aniIn);
                }
                await delay({
                    duration: this.duration,
                    done: () => {
                        this.state = 'shown';
                        super.listen({ name: 'shown', cb });
                    }
                });
            });
            return this;
        }
        
        async hide(cb) {
            if (this.destroyed) {
                return this;
            }
            if (this.state !== 'shown') {
                if (this.state === 'ing')
                    this.mainEl.style.visibility = null;
                return this;
            }
            this.state = 'ing';
            if (!this.options.deadShow) {
                this.options.b4Hide && await this.options.b4Hide.call(this);
                super.listen({ name: 'hide', cb });
                this.targetEl && this.targetEl.classList.remove(this.options.actClass);
                this.options.wing.actClass && this.wings.map((k) => { k.classList.remove(this.options.wing.actClass); });
                if (this.aniOut === 'slideUp') {
                    easeHeight({ el: this.wrapEl, height: this.wrapHeight, type: 'up', duration: this.duration, unaware: false });
                }
                else {
                    this.aniOut && (this.mainEl.style.animationName = orca.prefix + this.aniOut);
                }
                this.mainEl.querySelectorAll('video,audio').forEach((k) => {
                    k.pause();
                });
                this.hoverIns && (this.hoverIns.isActive = false);
                await delay({
                    duration: this.duration,
                    done: () => {
                        this.state = 'hidden';
                        this.mainEl.style.visibility = null;
                        this.mainEl.remove();
                        super.listen({ name: 'hidden', cb });
                        this.aniOut === 'slideUp' && (this.wrapEl.style.height = 'auto');
                    }
                });
            }
            return this;
        }
    }

    const optDodge = [
        {
            attr: 'placeholder',
            prop: 'placeholder',
            value: '',
        },
        {
            attr: 'on-set',
            prop: 'onSet',
            value: null,
        },
        {
            attr: 'on-canceled',
            prop: 'onCanceled',
            value: null,
        },
        ...optBase
    ];

    class Dodge extends ModBaseListenCache {
        options = {};
        inputEl;
        labelEl;
        isFocus;
        toggle;
        timestamp;
        placeholder;
        static hostType = 'node';
        static optMaps = optDodge;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Dodge.optMaps,
            });
            
            
            
            
            
            
            
            
            
            
            
            
            this.timestamp = Date.now();
            
            this.inputEl = this.targetEl.querySelector("input,textarea");
            if (!this.inputEl) {
                throw new Error('Form field node not found!');
            }
            
            this.labelEl = null;
            
            this.isFocus = false;
            this.toggle = {
                focus: () => {
                    this.inputEl.focus();
                    this.inputEl.removeAttribute('readonly');
                    this.targetEl.setAttribute('dodged', '');
                    this.isFocus = true;
                },
                blur: (e) => {
                    this.inputEl.blur();
                    this.inputEl.setAttribute('readonly', '');
                    !this.inputEl.value ? this.targetEl.removeAttribute('dodged') : this.targetEl.setAttribute('dodged', '');
                    this.isFocus = false;
                }
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            
            this.placeholder = this.getPlaceholder();
            this.setAttrs();
            this.render();
            this.inputEl.addEventListener('focus', this.toggle.focus, false);
            this.inputEl.addEventListener('blur', this.toggle.blur, false);
            this.labelEl.onclick = () => {
                this.toggle.focus();
            };
            this.inputEl.value ? this.toggle.focus() : null;
            super.listen({ name: 'initiated', cb });
            return this;
        }
        getPlaceholder() {
            let inputHolder = this.inputEl.getAttribute('placeholder');
            return this.options.placeholder ? this.options.placeholder :
                inputHolder ? inputHolder : config.lang.form.placeholder;
        }
        render() {
            if (!this.labelEl) {
                this.labelEl = createEl('label', '', this.placeholder);
                this.inputEl.removeAttribute("placeholder");
                this.inputEl.insertAdjacentElement('afterend', this.labelEl);
            }
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}dodge`);
            this.inputEl.toggleAttribute('readonly', true);
            this.inputEl.classList.contains("oc-lg") ? this.targetEl.classList.add("oc-lg") : null;
        }
        
        set(value, cb) {
            if (this.destroyed) {
                return this;
            }
            if (value) {
                this.inputEl.value = value;
                this.toggle.focus();
            }
            else {
                this.inputEl.focus();
            }
            super.listen({ name: 'set', cb, params: [value] });
            return this;
        }
        
        cancel(cb) {
            if (this.destroyed) {
                return this;
            }
            this.inputEl.value = '';
            this.inputEl.blur();
            this.toggle.blur();
            super.listen({ name: 'canceled', cb });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed) {
                return this;
            }
            this.labelEl.onclick = null;
            this.inputEl.removeEventListener('focus', this.toggle.focus);
            this.inputEl.removeEventListener('blur', this.toggle.blur);
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optValid = [
        {
            attr: 'label',
            prop: 'label',
            value: '',
        },
        {
            attr: 'placement',
            prop: 'placement',
            value: '',
        },
        {
            attr: 'icon-show',
            prop: 'iconShow',
            value: true,
        },
        {
            attr: 'type',
            prop: 'type',
            value: 'required',
        },
        {
            attr: 'extend',
            prop: 'extend',
            value: {},
        },
        {
            attr: 'parent',
            prop: 'parent',
            value: '',
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'fail',
            prop: 'fail',
            value: '',
        },
        {
            attr: 'succ',
            prop: 'succ',
            value: '',
        },
        {
            attr: 'separator',
            prop: 'separator',
            value: ',',
        },
        {
            attr: 'style-host',
            prop: 'styleHost',
            value: false,
        },
        {
            attr: 'succ-show',
            prop: 'succShow',
            value: true,
        },
        {
            attr: 'node-name',
            prop: 'nodeName',
            value: 'div',
        },
        {
            attr: 'message',
            prop: 'message',
            value: {},
        },
        {
            attr: 'popup',
            prop: 'popup',
            value: {},
        },
        {
            attr: 'reg-local',
            prop: 'regLocal',
            value: '',
        },
        {
            attr: 'reg-chars',
            prop: 'regChars',
            value: '',
        },
        {
            attr: 'length-str',
            prop: 'lengthStr',
            value: 6,
        },
        {
            attr: 'trigger',
            prop: 'trigger',
            value: 'blur',
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'on-trigger',
            prop: 'onTrigger',
            value: null,
        },
        {
            attr: 'on-changed',
            prop: 'onChanged',
            value: null,
        },
        {
            attr: 'on-shown',
            prop: 'onShown',
            value: null
        },
        {
            attr: 'on-hidden',
            prop: 'onHidden',
            value: null
        },
        ...optBase
    ];

    class Valid extends ModBaseListenCache {
        options = {};
        useRules;
        dftRules;
        inputEl;
        timestamp;
        name;
        label;
        parentEl;
        valid;
        hostValid;
        msgEl;
        otherBox;
        checkFun;
        types;
        userRules;
        result;
        output;
        msgIcon;
        msgText;
        popupIns;
        msgIns;
        obsProps;
        observer;
        static hostType = 'node';
        static optMaps = optValid;
        constructor(elem, options = {}, initial = config.initial) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Valid.optMaps,
            });
            this.timestamp = Date.now();
            if (!this.targetEl.getAttribute('name')) {
                throw new Error('The element to be verified must have name attribute!');
            }
            
            this.name = this.targetEl.getAttribute('name');
            
            this.label = this.options.label || this.name;
            
            this.parentEl = getEl(this.options.parent) || this.targetEl.closest('form') || document.body;
            
            this.valid = { target: this.targetEl, name: this.name, ins: this };
            this.hostValid = null;
            this.pushValids();
            
            this.createMsgEl();
            this.otherBox = getEl(this.options.placement);
            this.createObs();
            this.checkFun = () => {
                this.do();
            };
            this.dftRules = {
                
                'required': (data) => {
                    let fail = renderTpl(this.options.lang.required, { label: data.label });
                    return !isEmpty(data.value) ? { passed: true } : { passed: false, fail, type: 'required' };
                },
                
                ...this.loopTestRules(['email', 'cellphone', 'landline', 'ip', 'id', 'zip', 'url', 'locale', 'password', 'letter', 'string', 'ymdhms', 'ymd', 'hms', 'ym', 'y', 'm', 'd', 'integer', 'number']),
                'plate': (data) => {
                    let regex = data.value.length === 8 ? regExps.plate.nev : regExps.plate.oil;
                    return this.testRegex({ regex, value: data.value, name: 'plate' });
                },
                'date': (data) => {
                    let flag = isDateStr(data.value), fail = renderTpl(this.options.lang['date'], { label: data.label, value: data.value });
                    return flag ? { passed: true } : { passed: false, fail, type: 'date' };
                },
                
                ...this.loopDateRules(['date=', 'date<', 'date<=', 'date>', 'date>=', 'date><', 'date><=', 'date>=<', 'date>=<=']),
                
                ...this.loopThanRules(['than=', 'than>', 'than>=', 'than<', 'than<=', 'than><', 'than><=', 'than>=<', 'than>=<=',]),
                
                ...this.loopLengthRules(['length=', 'length>', 'length>=', 'length<', 'length<=', 'length><', 'length><=', 'length>=<', 'length>=<=']),
                
                ...this.loopIncludeRules(['include', 'exclude']),
                
                ...this.loopValuesRules(['count=', 'count>', 'count>=', 'count<', 'count<=', 'count><', 'count><=', 'count>=<', 'count>=<=']),
                
                ...this.loopSameRules(['same', 'different']),
                
                'strength': (data) => {
                    if (typeof data.value !== 'string') {
                        return { passed: false, fail: this.options.lang.strFormat };
                    }
                    let strength = this.getStrength(data.value), fail = renderTpl(this.options.lang['strength'], { label: data.label, name: data.name, value: strength, data: this.types['strength'] });
                    return strength >= this.types['strength'] ? { passed: true } : { passed: false, fail, type: 'strength' };
                },
                
                'specific': (data) => {
                    if (typeof data.value !== 'string') {
                        return { passed: false, fail: this.options.lang.strFormat };
                    }
                    let parse = validTools.parseSpecific(this.types['specific'], { label: data.label, name: data.name, value: data.value, tpl: this.options.lang['specific'] }), regExp = parse.regex, regText = parse.text;
                    return validTools.test(data.value, regExp) ? { passed: true } : { passed: false, fail: regText, type: 'specific' };
                },
                
                'combine': (data) => {
                    if (typeof data.value !== 'string') {
                        return { passed: false, fail: this.options.lang.strFormat };
                    }
                    let parse = validTools.parseCombine(this.types['combine'], { label: data.label, name: data.name, ins: this, value: data.value, tpl: this.options.lang['combine'] }), regExp = parse.regex, regText = parse.text;
                    return validTools.test(data.value, regExp) ? { passed: true } : { passed: false, fail: regText, type: 'combine' };
                },
                
                'async': (data) => {
                    return ajax.call(this, Object.assign({
                        url: this.types['async'],
                        data: {
                            label: data.label,
                            name: data.name,
                            value: data.value,
                            strength: this.getStrength(data.value),
                        },
                    }, this.options.ajax));
                },
                ...this.options.extend
            };
            validTools.listenSubmit({ item: this.parentEl });
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setEmpty();
            
            this.types = typeof this.options.type === 'string' ? paramToJson(this.options.type) : this.options.type;
            this.getUserRules();
            if (['change', 'blur', 'input'].includes(this.options.trigger)) {
                this.targetEl.removeEventListener(this.options.trigger, this.checkFun);
                this.targetEl.addEventListener(this.options.trigger, this.checkFun, false);
            }
            else if (this.options.trigger === 'load') {
                this.do();
            }
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setEmpty() {
            this.msgEl ? this.msgEl.innerHTML = '' : null;
            this.popupIns ? this.popupIns.destroy : null;
            this.msgIns ? this.msgIns.destroy : null;
        }
        loopTestRules(types) {
            let result = {};
            types.forEach((k) => {
                if (regExps.hasOwnProperty(k)) {
                    result[k] = (data) => {
                        if (Array.isArray(data.value)) {
                            return { passed: false, fail: this.options.lang.strFormat, id: 'strFormat' };
                        }
                        return this.testRegex({ regex: regExps[k], value: data.value, name: k });
                    };
                }
            });
            return result;
        }
        loopIncludeRules(types) {
            let result = {};
            types.forEach((k) => {
                result[k] = (data) => {
                    if (!Array.isArray(data.data)) {
                        return { passed: false, fail: this.options.lang.arrFormat };
                    }
                    let value = Array.isArray(data.value) ? data.value : data.value.split(this.options.separator), flag = isSubset(value, data.data), fail = renderTpl(this.options.lang[k], { label: data.label, name: data.name, value: data.value, data: data.data });
                    k === 'exclude' && (flag = !flag);
                    return flag ? { passed: true } : { passed: false, fail, type: k };
                };
            });
            return result;
        }
        loopSameRules(types) {
            let result = {};
            types.forEach((k) => {
                result[k] = (data) => {
                    if (!Array.isArray(data.data)) {
                        return { passed: false, fail: this.options.lang.arrFormat };
                    }
                    let referField = this.parentEl.querySelector(`[name="${this.types[k][0]}"]`), referValue = this.getVals(referField, 'string'), targetValue = this.getVals(this.targetEl, 'string'), fail = renderTpl(this.options.lang[k], { label: data.label, name: data.name, value: targetValue, data: data.data }), condition = k === 'same' ? (referValue === targetValue) : (referValue !== targetValue);
                    return condition ? { passed: true } : { passed: false, fail, type: k };
                };
            });
            return result;
        }
        loopDateRules(types) {
            let result = {};
            types.forEach((k) => {
                result[k] = (data) => {
                    if (Array.isArray(data.value)) {
                        return { passed: false, fail: this.options.lang.strFormat };
                    }
                    let flag = validTools.expired(data.value, data.data).join(''), fail = renderTpl(this.options.lang[k], { label: data.label, value: data.value, data: data.data }), condition = k === 'date=' ? (flag === '0-2') :
                        k === 'date<' ? (flag === '-1-2') :
                            k === 'date<=' ? (flag === '0-2' || flag === '-1-2') :
                                k === 'date>' ? (flag === '1-2') :
                                    k === 'date>=' ? (flag === '1-2' || flag === '0-2') :
                                        k === 'date><' ? (flag === '1-1') :
                                            k === 'date><=' ? (flag === '1-1' || flag === '10') :
                                                k === 'date>=<' ? (flag === '1-1' || flag === '0-1') :
                                                    k === 'date>=<=' ? (['1-1', '10', '0-1', '00'].includes(flag)) : true;
                    return condition ? { passed: true } : { passed: false, fail, type: k };
                };
            });
            return result;
        }
        loopThanRules(types) {
            let result = {};
            types.forEach((k) => {
                result[k] = (data) => {
                    if (Array.isArray(data.value)) {
                        return { passed: false, fail: this.options.lang.strFormat };
                    }
                    let flag = validTools.than(data.value, data.data).join(''), fail = renderTpl(this.options.lang[k], { label: data.label, value: data.value, data: data.data }), condition = k === 'than>' ? (flag === '1-2') :
                        k === 'than>=' ? (flag === '1-2' || flag === '0-2') :
                            k === 'than<' ? (flag === '-1-2') :
                                k === 'than<=' ? (flag === '0-2' || flag === '-1-2') :
                                    k === 'than=' ? (flag === '0-2') :
                                        k === 'than><' ? (flag === '1-1') :
                                            k === 'than><=' ? (flag === '1-1' || flag === '10') :
                                                k === 'than>=<' ? (flag === '1-1' || flag === '0-1') :
                                                    k === 'than>=<=' ? (['1-1', '10', '0-1', '00'].includes(flag)) : true;
                    return condition ? { passed: true } : { passed: false, fail, type: k };
                };
            });
            return result;
        }
        loopLengthRules(types) {
            let result = {};
            types.forEach((k) => {
                result[k] = (data) => {
                    if (Array.isArray(data.value)) {
                        return { passed: false, fail: this.options.lang.strFormat, id: 'strFormat' };
                    }
                    let pattern = k === 'length=' ? this.types[k] :
                        k === 'length>' ? `${this.types[k] + 1},` :
                            k === 'length>=' ? `${this.types[k]},` :
                                k === 'length<' ? `0,${this.types[k] - 1}` :
                                    k === 'length<=' ? `0,${this.types[k]}` :
                                        k === 'length><' ? `${this.types[k][0] + 1},${this.types[k][1] - 1}` :
                                            k === 'length><=' ? `${this.types[k][0] + 1},${this.types[k][1]}` :
                                                k === 'length>=<' ? `${this.types[k][0]},${this.types[k][1] - 1}` :
                                                    k === 'length>=<=' ? `${this.types[k][0]},${this.types[k][1]}` : '', regex = new RegExp(`^.{${pattern}}$`);
                    return this.testRegex({ regex, value: data.value, name: k });
                };
            });
            return result;
        }
        loopValuesRules(types) {
            let result = {};
            for (let k of types) {
                result[k] = (data) => {
                    let value = (Array.isArray(data.value)) ? data.value : data.value.split(this.options.separator).filter(Boolean), fail = renderTpl(this.options.lang[k], { label: data.label, name: data.name, value: value.length, data: data.data }), condition = k === 'count>=<=' ? (value.length >= this.types[k][0] && value.length <= this.types[k][1]) :
                        k === 'count><=' ? (value.length > this.types[k][0] && value.length <= this.types[k][1]) :
                            k === 'count>=<' ? (value.length >= this.types[k][0] && value.length < this.types[k][1]) :
                                k === 'count><' ? (value.length > this.types[k][0] && value.length < this.types[k][1]) :
                                    k === 'count=' ? `${value.length} === ${this.types[k]}` : `${value.length} ${k.replace('count', '')} ${this.types[k]}`;
                    return new Function(`"use strict";return ${condition}`)() ? { passed: true } : { passed: false, fail, type: k };
                };
            }
            return result;
        }
        testRegex({ regex, value, name }) {
            let flag = validTools.test(value, regex), fail = renderTpl(this.options.lang[name], { label: this.label, value, data: this.types[name] });
            ((name === 'length<' || name === 'length<=') && !value) && (flag = true);
            return flag ? { passed: true } : { passed: false, fail, type: name };
        }
        extendRules(rules) {
            Object.assign(this.dftRules, rules);
        }
        getUserRules() {
            this.userRules = {};
            for (let k in this.types) {
                if (this.types.hasOwnProperty(k) && this.dftRules.hasOwnProperty(k)) {
                    this.userRules[k] = this.dftRules[k];
                    this.userRules[k].data = this.types[k];
                }
            }
        }
        
        getVals(field = this.targetEl, format = '') {
            return fieldTools.getVals({ target: field, parent: this.parentEl, format });
        }
        
        getStrength(value = this.getVals(this.targetEl)) {
            return validTools.getStrength(value, {
                chars: `[${this.options.regChars}]`,
                local: `[${this.options.regLocal}]`,
                length: this.options.lengthStr
            });
        }
        
        do() {
            if (this.destroyed)
                return this;
            let value = this.getVals(this.targetEl) || '';
            
            return validTools.factory({
                value,
                name: this.name,
                label: this.label,
                ins: this,
                rules: this.userRules,
                text: {
                    succ: this.options.succ,
                    fail: this.options.fail,
                },
                cb: (resp) => {
                    
                    this.result = resp;
                    
                    this.output = { ...resp, name: this.name, label: this.label, value, ins: this, strength: this.getStrength(value) };
                    super.listen({ name: 'trigger', params: [this.output] });
                    Object.assign(this.observer.proxy, resp);
                }
            });
        }
        toggleStyle(passed) {
            if (passed) {
                this.msgEl.classList.remove(`${orca.prefix}c-error`);
                this.msgEl.classList.add(`${orca.prefix}c-succ`);
                this.targetEl.setAttribute('validate', 'passed');
                if (this.options.styleHost) {
                    this.targetEl.classList.remove(`${orca.prefix}c-error`);
                    this.targetEl.classList.add(`${orca.prefix}c-succ`);
                }
            }
            else {
                this.msgEl.classList.remove(`${orca.prefix}c-succ`);
                this.msgEl.classList.add(`${orca.prefix}c-error`);
                this.targetEl.setAttribute('validate', 'failed');
                if (this.options.styleHost) {
                    this.targetEl.classList.remove(`${orca.prefix}c-succ`);
                    this.targetEl.classList.add(`${orca.prefix}c-error`);
                }
            }
        }
        render(msg) {
            this.toggleStyle(msg.passed);
            if (msg.passed) {
                this.msgIcon = this.options.iconShow ? icons.font["succ-f"] : '';
                this.msgText = msg.succ;
            }
            else {
                this.msgIcon = this.options.iconShow ? icons.font["error-f"] : '';
                this.msgText = msg.fail;
            }
            this.msgEl.innerHTML = this.msgIcon + this.msgText;
            if (this.otherBox) {
                elState(this.msgEl).isVirtual && this.otherBox.appendChild(this.msgEl);
            }
            else {
                if (typeof this.options.placement !== 'string') {
                    return this;
                }
                this.options.placement = this.options.placement.trim();
                if (this.options.placement === 'down') {
                    let box = this.targetEl.closest(`.${orca.prefix}box-input`)?.querySelector(`[${orca.alias}="input"]`);
                    box ? box.insertAdjacentElement('afterEnd', this.msgEl) : null;
                }
                else if (this.options.placement === 'right') {
                    let box = this.targetEl.closest(`.${orca.prefix}box-input`)?.querySelector(`[${orca.alias}="help"]`);
                    box ? box.appendChild(this.msgEl) : null;
                }
                else if (this.options.placement === 'popup') {
                    if (!this.popupIns) {
                        this.popupIns = new Popup(this.targetEl, {
                            content: this.msgEl,
                            placement: 'bottom-start',
                            keepShow: true,
                            footer: false,
                            tools: false,
                            arrow: {
                                enable: false,
                                gap: 0,
                            },
                            classes: `${orca.prefix}plain`,
                            trigger: 'sticky'
                        });
                    }
                }
                else if (this.options.placement === 'message') {
                    if (!this.msgIns) {
                        this.msgIns = new Message({
                            content: this.msgText,
                            iconShow: true,
                            status: msg.passed ? 'succ' : 'error',
                        }).show();
                    }
                    else {
                        this.msgIns.update({
                            content: this.msgText,
                            status: msg.passed ? 'succ' : 'error',
                        }).show();
                    }
                }
                else {
                    elState(this.msgEl).isVirtual ? this.targetEl.insertAdjacentElement('afterend', this.msgEl) : null;
                }
            }
        }
        createMsgEl() {
            
            this.msgEl = this.hostValid ? this.hostValid.ins.msgEl : createEl(this.options.nodeName, { class: `${orca.prefix}valid` });
        }
        createObs() {
            
            this.obsProps = this.hostValid ? this.hostValid.ins.obsProps : {};
            this.observer = new Observe(this.obsProps);
            this.observer.on('completed', () => {
                this.render(this.result);
                super.listen({ name: 'changed', params: [this.output] });
            });
        }
        pushValids() {
            if (orca.valids.length === 0) {
                orca.valids.push({ parent: this.parentEl, children: [this.valid] });
            }
            else {
                let index = orca.valids.findIndex(k => (k.parent === this.parentEl));
                if (index > -1) {
                    let valids = orca.valids[index].children, temp = valids.find((k) => k.name === this.name);
                    !temp ? valids.push(this.valid) : (this.hostValid = temp);
                }
                else {
                    orca.valids.push({ parent: this.parentEl, children: [this.valid] });
                }
            }
        }
        
        hide(cb) {
            if (this.destroyed) {
                return this;
            }
            if (this.options.placement === 'message') ;
            else if (this.options.placement === 'popup') {
                this.popupIns.hide();
            }
            else {
                this.msgEl.remove();
            }
            super.listen({ name: 'hidden', cb });
            return this;
        }
        show(cb) {
            if (this.destroyed) {
                return this;
            }
            if (this.otherBox) {
                elState(this.msgEl).isVirtual ? this.otherBox.appendChild(this.msgEl) : null;
            }
            else {
                if (this.options.placement === 'message') {
                    this.msgIns.show();
                }
                else if (this.options.placement === 'popup') {
                    this.popupIns.show();
                }
                else {
                    elState(this.msgEl).isVirtual ? this.targetEl.insertAdjacentElement('afterend', this.msgEl) : null;
                }
            }
            super.listen({ name: 'shown', cb });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed) {
                return this;
            }
            if (['change', 'blur', 'input'].includes(this.options.trigger)) {
                this.targetEl.removeEventListener(this.options.trigger, this.checkFun);
            }
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    let OCTMP_rootStart$1 = config.rootStart, OCTMP_idStart$1 = config.idStart, OCTMP_floorStart$1 = config.floorStart, OCTMP_pathHyphen$1 = config.pathHyphen;
    const optMenu$1 = [
        {
            attr: 'theme',
            prop: 'theme',
            value: 'light',
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'passive',
            prop: 'passive',
            value: false,
        },
        {
            attr: 'expose',
            prop: 'expose',
            value: false,
        },
        {
            attr: 'active',
            prop: 'active',
            value: '',
        },
        {
            attr: 'disable',
            prop: 'disable',
            value: '',
        },
        {
            attr: 'multiple',
            prop: 'multiple',
            value: false,
        },
        {
            attr: 'expand-all',
            prop: 'expandAll',
            value: false,
        },
        {
            attr: 'z-index',
            prop: 'zIndex',
            value: 0,
        },
        {
            attr: 'trigger',
            prop: 'trigger',
            value: 'click',
        },
        {
            attr: 'root-start',
            prop: 'rootStart',
            value: OCTMP_rootStart$1,
        },
        {
            attr: 'id-start',
            prop: 'idStart',
            value: OCTMP_idStart$1,
        },
        {
            attr: 'floor-start',
            prop: 'floorStart',
            value: OCTMP_floorStart$1,
        },
        {
            attr: 'path-hyphen',
            prop: 'pathHyphen',
            value: OCTMP_pathHyphen$1,
        },
        {
            attr: 'duration',
            prop: 'duration',
            value: 0,
        },
        {
            attr: 'page-close',
            prop: 'pageClose',
            value: false,
        },
        {
            attr: 'arrow',
            prop: 'arrow',
            value: {
                enable: true,
                icon: '',
            },
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'linkage',
            prop: 'linkage',
            value: true,
        },
        {
            attr: 'unpadded',
            prop: 'unpadded',
            value: false,
        },
        {
            attr: 'lamp',
            prop: 'lamp',
            value: '',
        },
        {
            attr: 'full',
            prop: 'full',
            value: false,
        },
        {
            attr: 'spill',
            prop: 'spill',
            value: false,
        },
        {
            attr: 'layout',
            prop: 'layout',
            value: 'indent|legend|icon|disk|cube|image|label|custom|tips||badge|arrow',
        },
        {
            attr: 'tree',
            prop: 'tree',
            value: {},
        },
        {
            attr: 'drawer',
            prop: 'drawer',
            value: {
                host: '',
                placement: 'left',
                footer: false,
            },
        },
        {
            attr: 'nav',
            prop: 'nav',
            value: {
                enable: false,
                headWidth: '',
                bodyWidth: '',
                marginLeft: '',
                marginRight: '',
                align: 'left',
            },
        },
        {
            attr: 'on-activated',
            prop: 'onActivated',
            value: null
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null
        },
        ...optBase
    ];

    let OCTMP_connector = config.labelHyphen, OCTMP_separator$4 = config.splitHyphen, OCTMP_rootStart = config.rootStart, OCTMP_idStart = config.idStart, OCTMP_floorStart = config.floorStart, OCTMP_pathHyphen = config.pathHyphen;
    const optTree = [
        {
            attr: 'name',
            prop: 'name',
            value: '',
        },
        {
            attr: 'value',
            prop: 'value',
            value: '',
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'passive',
            prop: 'passive',
            value: false,
        },
        {
            attr: 'disable',
            prop: 'disable',
            value: '',
        },
        {
            attr: 'readonly',
            prop: 'readonly',
            value: '',
        },
        {
            attr: 'min',
            prop: 'min',
            value: 0,
        },
        {
            attr: 'max',
            prop: 'max',
            value: 0,
        },
        {
            attr: 'sliced',
            prop: 'sliced',
            value: true,
        },
        {
            attr: 'expand',
            prop: 'expand',
            value: {
                value: '',
                all: false,
                only: true,
                linkage: false,
            },
        },
        {
            attr: 'select',
            prop: 'select',
            value: {
                enable: true,
                only: true,
                value: '',
                linkage: false,
                span: 'tree',
                addSelected: false,
            },
        },
        {
            attr: 'arrow',
            prop: 'arrow',
            value: {
                enable: true,
                show: `${orca.prefix}icon-right`,
                hide: `${orca.prefix}icon-right`,
                anim: `${orca.prefix}rotate90`,
                type: 'icon',
                trigger: 'click',
            },
        },
        {
            attr: 'legend',
            prop: 'legend',
            value: {
                enable: false,
                parent: [`${orca.prefix}icon-folder`, `${orca.prefix}icon-folder-open`],
                child: `${orca.prefix}icon-file-text`,
                type: 'icon',
            },
        },
        {
            attr: 'check',
            prop: 'check',
            value: {
                enable: false,
                type: 'checkbox',
                value: '',
                min: 0,
                max: 0,
                sliced: true,
                linkage: true,
                only: false,
                span: 'tree',
            },
        },
        {
            attr: 'tools',
            prop: 'tools',
            value: {
                enable: false,
                trigger: 'hover',
                children: ['folder', 'file', 'edit', 'remove'],
            },
        },
        {
            attr: 'output',
            prop: 'output',
            value: {
                enable: true,
                target: '',
                connector: OCTMP_connector,
                separator: OCTMP_separator$4,
                type: '',
                from: 'selected',
                field: 'label',
                instant: true,
                autosort: false,
            },
        },
        {
            attr: 'sql-data',
            prop: 'sqlData',
            value: {
                deep: 0,
                start: 0,
                count: 0,
                order: 'id asc',
                where: '',
            },
        },
        {
            attr: 'paginated',
            prop: 'paginated',
            value: {
                enable: false,
                count: 10,
                override: false,
                exception: false,
            },
        },
        {
            attr: 'delay',
            prop: 'delay',
            value: 100,
        },
        {
            attr: 'deferred',
            prop: 'deferred',
            value: false,
        },
        {
            attr: 'shortcut',
            prop: 'shortcut',
            value: {
                enable: false,
                span: 'blank',
                mean: 'selected',
            },
        },
        {
            attr: 'search',
            prop: 'search',
            value: {
                target: '',
                trigger: 'input',
                delay: 500,
                value: '',
                limit: 0,
                fuzzy: true,
                ignore: true,
            },
        },
        {
            attr: 'drag',
            prop: 'drag',
            value: {
                enable: false,
                exclude: '',
            },
        },
        {
            attr: 'drop',
            prop: 'drop',
            value: {
                attr: 'dropnode',
                global: false,
            },
        },
        {
            attr: 'chain',
            prop: 'chain',
            value: false,
        },
        {
            attr: 'auto-fill',
            prop: 'autoFill',
            value: true,
        },
        {
            attr: 'root-start',
            prop: 'rootStart',
            value: OCTMP_rootStart,
        },
        {
            attr: 'id-start',
            prop: 'idStart',
            value: OCTMP_idStart,
        },
        {
            attr: 'floor-start',
            prop: 'floorStart',
            value: OCTMP_floorStart,
        },
        {
            attr: 'path-hyphen',
            prop: 'pathHyphen',
            value: OCTMP_pathHyphen,
        },
        {
            attr: 'duration',
            prop: 'duration',
            value: 0,
        },
        {
            attr: 'bubble',
            prop: 'bubble',
            value: {
                enable: false,
                type: 'popup',
            },
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'display',
            prop: 'display',
            value: 'inline',
        },
        {
            attr: 'layout',
            prop: 'layout',
            value: 'indent|arrow|check|legend|icon|disk|cube|image|label|badge|tips|custom|tools',
        },
        {
            attr: 'feature',
            prop: 'feature',
            value: {
                type: '',
                expand: {
                    all: true,
                    only: false,
                },
                check: {
                    linkage: true,
                    only: false,
                    span: 'tree',
                },
                layout: {
                    dropdown: 'indent|arrow|icon|disk|cube|image|label|holder|tips|badge',
                    select: 'indent|arrow|icon|disk|cube|image|label|holder|tips|badge',
                    check: 'indent|arrow|check|icon|disk|cube|image|label|holder|tips|badge',
                    button: 'icon|arrow|disk|cube|image|label|tips|badge',
                    list: 'indent|arrow|icon|disk|cube|image(label|badge|tips|custom)'
                }
            },
        },
        {
            attr: 'b4-expand',
            prop: 'b4Expand',
            value: null,
        },
        {
            attr: 'b4-collapse',
            prop: 'b4Collapse',
            value: null,
        },
        {
            attr: 'b4-add',
            prop: 'b4Add',
            value: null,
        },
        {
            attr: 'b4-edit',
            prop: 'b4Edit',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'b4-graft',
            prop: 'b4Graft',
            value: null,
        },
        {
            attr: 'on-rendered',
            prop: 'onRendered',
            value: null,
        },
        {
            attr: 'on-insertitem',
            prop: 'onInsertItem',
            value: null,
        },
        {
            attr: 'on-insertitems',
            prop: 'onInsertItems',
            value: null,
        },
        {
            attr: 'on-trigger',
            prop: 'onTrigger',
            value: null
        },
        {
            attr: 'on-added',
            prop: 'onAdded',
            value: null
        },
        {
            attr: 'on-edited',
            prop: 'onEdited',
            value: null
        },
        {
            attr: 'on-removed',
            prop: 'onRemoved',
            value: null
        },
        {
            attr: 'on-disabled',
            prop: 'onDisabled',
            value: null
        },
        {
            attr: 'on-enabled',
            prop: 'onEnabled',
            value: null
        },
        {
            attr: 'on-disabledall',
            prop: 'onDisabledAll',
            value: null
        },
        {
            attr: 'on-enabledall',
            prop: 'onEnabledAll',
            value: null
        },
        {
            attr: 'on-readonly',
            prop: 'onReadonly',
            value: null
        },
        {
            attr: 'on-readonlyall',
            prop: 'onReadonlyAll',
            value: null
        },
        {
            attr: 'on-expand',
            prop: 'onExpand',
            value: null
        },
        {
            attr: 'on-expanded',
            prop: 'onExpanded',
            value: null
        },
        {
            attr: 'on-collapse',
            prop: 'onCollapse',
            value: null
        },
        {
            attr: 'on-collapsed',
            prop: 'onCollapsed',
            value: null
        },
        {
            attr: 'on-expandall',
            prop: 'onExpandAll',
            value: null
        },
        {
            attr: 'on-expandedAll',
            prop: 'onExpandedAll',
            value: null
        },
        {
            attr: 'on-collapsedall',
            prop: 'onCollapsedAll',
            value: null
        },
        {
            attr: 'on-selected',
            prop: 'onSelected',
            value: null
        },
        {
            attr: 'on-deselected',
            prop: 'onDeselected',
            value: null
        },
        {
            attr: 'on-selectedall',
            prop: 'onSelectedAll',
            value: null
        },
        {
            attr: 'on-checked',
            prop: 'onChecked',
            value: null
        },
        {
            attr: 'on-unchecked',
            prop: 'onUnchecked',
            value: null
        },
        {
            attr: 'on-checkedall',
            prop: 'onCheckedAll',
            value: null
        },
        {
            attr: 'on-filled',
            prop: 'onFilled',
            value: null
        },
        {
            attr: 'on-turned',
            prop: 'onTurned',
            value: null
        },
        {
            attr: 'on-got',
            prop: 'onGot',
            value: null
        },
        {
            attr: 'on-set',
            prop: 'onSet',
            value: null
        },
        {
            attr: 'on-cleared',
            prop: 'onCleared',
            value: null
        },
        {
            attr: 'on-grafted',
            prop: 'onGrafted',
            value: null
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null
        },
        {
            attr: 'on-request',
            prop: 'onRequest',
            value: null
        },
        {
            attr: 'on-toofew',
            prop: 'onTooFew',
            value: null
        },
        {
            attr: 'on-toomany',
            prop: 'onTooMany',
            value: null
        },
        {
            attr: 'on-locked',
            prop: 'onLocked',
            value: null
        },
        {
            attr: 'on-unlocked',
            prop: 'onUnlocked',
            value: null
        },
        {
            attr: 'on-output',
            prop: 'onOutput',
            value: null
        },
        ...optBase
    ];

    const optDrag = [
        {
            attr: 'original',
            prop: 'original',
            value: true,
        },
        {
            attr: 'group',
            prop: 'group',
            value: '',
        },
        {
            attr: 'drags',
            prop: 'drags',
            value: '',
        },
        {
            attr: 'drops',
            prop: 'drops',
            value: '',
        },
        {
            attr: 'parent',
            prop: 'parent',
            value: '',
        },
        {
            attr: 'wraps',
            prop: 'wraps',
            value: '',
        },
        {
            attr: 'showEmpty',
            prop: 'showEmpty',
            value: true,
        },
        {
            attr: 'handle',
            prop: 'handle',
            value: '',
        },
        
        
        {
            attr: 'method',
            prop: 'method',
            value: 'hover',
        },
        {
            attr: 'purpose',
            prop: 'purpose',
            value: 'auto',
        },
        {
            attr: 'embed',
            prop: 'embed',
            value: {
                position: 'after',
                selector: '',
            }
        },
        {
            attr: 'pushable',
            prop: 'pushable',
            value: {
                enable: true,
                intent: 'cut',
            }
        },
        {
            attr: 'pullable',
            prop: 'pullable',
            value: true,
        },
        {
            attr: 'point',
            prop: 'point',
            value: {
                before: ['t/3', 't/2'],
                after: ['b/3', 'b/2'],
            },
        },
        {
            attr: 'holder',
            prop: 'holder',
            value: {
                enable: false,
                style: [],
            },
        },
        {
            attr: 'arrow',
            prop: 'arrow',
            value: {
                enable: false,
                icon: `._icon-right`,
                placement: 'left',
                selector: '',
            },
        },
        {
            attr: 'gesture',
            prop: 'gesture',
            value: {},
        },
        {
            attr: 'flip',
            prop: 'flip',
            value: {
                enable: true,
                fluct: -100,
            },
        },
        {
            attr: 'throttle',
            prop: 'throttle',
            value: 100,
        },
        {
            attr: 'duration',
            prop: 'duration',
            value: 200,
        },
        {
            attr: 'ignore',
            prop: 'ignore',
            value: '',
        },
        {
            attr: 'b4-drop',
            prop: 'b4Drop',
            value: null,
        },
        {
            attr: 'b4-trigger',
            prop: 'b4Trigger',
            value: null,
        },
        {
            attr: 'on-dragstart',
            prop: 'onDragStart',
            value: null,
        },
        {
            attr: 'on-dragenter',
            prop: 'onDragEnter',
            value: null,
        },
        {
            attr: 'on-dragleave',
            prop: 'onDragLeave',
            value: null,
        },
        {
            attr: 'on-dragmove',
            prop: 'onDragMove',
            value: null,
        },
        {
            attr: 'on-dropped',
            prop: 'onDropped',
            value: null,
        },
        {
            attr: 'on-dragend',
            prop: 'onDragEnd',
            value: null,
        },
        {
            attr: 'on-dragcancel',
            prop: 'onDragCancel',
            value: null,
        },
        {
            attr: 'on-transferred',
            prop: 'onTransferred',
            value: null,
        },
        {
            attr: 'on-swapped',
            prop: 'onSwapped',
            value: null,
        },
        {
            attr: 'on-embeded',
            prop: 'onEmbeded',
            value: null,
        },
        {
            attr: 'on-sorted',
            prop: 'onSorted',
            value: null,
        },
        {
            attr: 'on-cloned',
            prop: 'onCloned',
            value: null,
        },
        {
            attr: 'on-trigger',
            prop: 'onTrigger',
            value: null,
        },
        {
            attr: 'on-finished',
            prop: 'onFinished',
            value: null,
        },
        {
            attr: 'on-dragout',
            prop: 'onDragOut',
            value: null,
        },
        {
            attr: 'on-dropout',
            prop: 'onDropOut',
            value: null,
        },
        ...optBase
    ];

    const optFlip = [
        {
            attr: 'parent',
            prop: 'parent',
            value: ''
        },
        {
            attr: 'children',
            prop: 'children',
            value: '',
        },
        {
            attr: 'other',
            prop: 'other',
            value: '',
        },
        {
            attr: 'fluct',
            prop: 'fluct',
            value: 0,
        },
        {
            attr: 'easing',
            prop: 'easing',
            value: 'ease-out',
        },
        {
            attr: 'prevent',
            prop: 'prevent',
            value: false,
        },
        {
            attr: 'b4-add',
            prop: 'b4Add',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'b4-play',
            prop: 'b4Play',
            value: null,
        },
        {
            attr: 'b4-play',
            prop: 'b4Play',
            value: null,
        },
        {
            attr: 'b4-playall',
            prop: 'b4PlayAll',
            value: null,
        },
        {
            attr: 'on-played',
            prop: 'onPlayed',
            value: null,
        },
        {
            attr: 'on-playedall',
            prop: 'onPlayedAll',
            value: null,
        },
        ...optBase
    ];

    class Flip extends ModBaseListen {
        options = {};
        parentEl;
        flipEls;
        flipData;
        childrenObs;
        canPlay;
        playedEls;
        srcNode;
        allPlayed;
        parentH;
        static hostType = 'none';
        static optMaps = optFlip;
        constructor(options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: Flip.optMaps,
            });
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch (err) {
                err ? console.error(err) : console.warn(config.warn.init);
                return this;
            }
            this.parentEl = getEl(this.options.parent);
            this.allPlayed = true;
            this.playedEls = [];
            this.canPlay = !this.options.prevent;
            this.updateFlipEls();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        async play(target) {
            if (this.destroyed || !target?.orca?.flip || elState(target).isUncalc)
                return;
            if (this.options.b4Play) {
                let resp = await this.options.b4Play.call(this, target);
                resp && (target = resp);
            }
            let restDur = target.orca.flip.anim ? (target.orca.flip.anim.effect.getTiming().duration - target.orca.flip.anim.currentTime) : 0;
            target.orca.flip.anim?.cancel();
            let nowTranslate = this.getTranslate(target), nowRect = this.getRect(target), dist = {
                x: target.orca.flip.now.x - nowRect.x,
                y: target.orca.flip.now.y - nowRect.y,
            };
            let isSamePos = target.orca.flip.last.x === nowRect.x && target.orca.flip.last.y === nowRect.y;
            if (!dist.x && !dist.y)
                return new Promise(resolve => { resolve(null); });
            target.orca.flip.last = nowRect;
            let anim = target.animate([
                {
                    transform: `translate(${dist.x + nowTranslate.x}px,${dist.y + nowTranslate.y}px)`,
                },
                {
                    transform: `translate(${nowTranslate.x}px,${nowTranslate.y}px)`,
                }
            ], {
                duration: isSamePos ? restDur : this.getDuration(dist),
                easing: this.options.easing,
                fill: 'forwards'
            });
            target.orca.flip.anim = anim;
            await new Promise(resolve => requestAnimationFrame(resolve));
            return new Promise(resolve => {
                anim.onfinish = () => {
                    anim.cancel();
                    this.setFirstRect(target);
                    this.playedEls.push(target);
                    super.listen({ name: 'played', params: [target] });
                    resolve(null);
                };
            });
        }
        getDuration(dist) {
            return Math.max(0, getAutoDur(getHypotenuse(dist.x, dist.y)) + this.options.fluct);
        }
        getTranslate(target) {
            let m = new DOMMatrix(style(target).transform);
            return { x: m.m41, y: m.m42 };
        }
        getRect(target) {
            let tmp = target.getBoundingClientRect();
            return {
                x: tmp.left,
                y: tmp.top,
            };
        }
        setFirstRect(target) {
            if (!target.orca) {
                target.orca = { flip: {} };
            }
            else {
                target.orca.flip = {};
            }
            target.orca.flip.last = this.getRect(target);
            target.orca.flip.now = { ...target.orca.flip.last };
        }
        setNowRects() {
            for (let k of this.flipEls) {
                k.orca.flip.now = this.getRect(k);
            }
        }
        updateFlipEls() {
            if (!this.options.children) {
                this.flipEls = this.parentEl ? [...this.parentEl.children] : [];
            }
            else {
                this.flipEls = getEls(this.options.children, this.parentEl);
            }
            if (this.options.other) {
                let tmp = getEls(this.options.other);
                tmp.length && (this.flipEls = unique([...this.flipEls, ...tmp]));
            }
            for (let k of this.flipEls)
                this.setFirstRect(k);
        }
        async add(target, cb) {
            let els = getEls(target);
            if (!els.length)
                return this;
            if (this.options.b4Add) {
                let resp = await this.options.b4Add.call(this, els);
                resp && (els = resp);
            }
            for (let k of els) {
                this.flipEls.push(k);
                this.setFirstRect(k);
            }
            super.listen({ name: 'added', cb, params: [els] });
            return this;
        }
        async remove(target, cb) {
            let els = getEls(target);
            if (!els.length)
                return this;
            if (this.options.b4Remove) {
                let resp = await this.options.b4Remove.call(this, els);
                resp && (els = resp);
            }
            this.flipEls = this.flipEls.filter((k) => !els.includes(k));
            for (let el of els)
                Reflect.deleteProperty(el, 'flip');
            super.listen({ name: 'removed', cb, params: [els] });
            return this;
        }
        async playAll(cb) {
            if (this.flipEls.length < 2 || !this.canPlay || this.destroyed)
                return this;
            if (this.options.b4PlayAll) {
                let resp = await this.options.b4PlayAll.call(this, this.flipEls);
                resp && (this.flipEls = resp);
            }
            let promises = [...this.flipEls].map(k => this.play(k));
            this.allPlayed = false;
            await Promise.all(promises);
            this.allPlayed = true;
            super.listen({ name: 'playedAll', cb, params: [unique(this.playedEls)] });
            this.playedEls = [];
            return this;
        }
        destroy(cb) {
            if (this.destroyed)
                return this;
            for (let k of this.flipEls) {
                k.orca.flip?.anim?.cancel();
                Reflect.deleteProperty(k.orca, 'flip');
            }
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    class Drag extends ModBaseListen {
        targetEl;
        options = {};
        curX;
        curY;
        preX;
        preY;
        isActive;
        enterTimer;
        leaveTimer;
        eventToggle;
        holdEl;
        enterCompare;
        globalEvent;
        moveEvent;
        enterEvent;
        leaveEvent;
        enterHold;
        leaveHold;
        holderDrag;
        holderDrop;
        holderEmpty;
        dropArrow;
        orgHolder;
        selfEls;
        dragEls;
        dropEls;
        lastDrop;
        lastPoint;
        dftParams;
        dropOver;
        dropEnd;
        dragstartEvt;
        dragendEvt;
        dragenterEvt;
        dragoverEvt;
        dragdropEvt;
        dragleaveEvt;
        mousedownEvt;
        mouseupEvt;
        targetPoints;
        targetTag;
        holderAttr;
        orgVal;
        nowVal;
        orgStyle;
        parentEl;
        wrapEls;
        ignoreEls;
        sourceNode;
        flipIns;
        gestureIns;
        hoverCount;
        cloned;
        ghostEl;
        otherGroupIns;
        triggered;
        lastTarget;
        isTransferred;
        childObs;
        childObsOpts;
        commTrigger;
        commDragStart;
        commDragEnter;
        commDragLeave;
        commDragOver;
        commDragDrop;
        commDragEnd;
        commDragThrot;
        commFinished;
        static hostType = 'node';
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: optDrag,
                host: elem,
                component: false,
                spread: ['arrow', 'pushable', 'holder', 'flip']
            });
            if (!this.targetEl)
                throw new Error('The target node for drag start is missing!');
            this.holderEmpty = createEl('div', { class: `${orca.prefix}holder-empty` }, this.options.lang.holderEmpty);
            this.holderDrop = createEl('div', { class: `${orca.prefix}holder-drop ${orca.prefix}d-none` }, this.options.lang.holderDrop);
            this.dropArrow = createEl('i', { class: `${orca.prefix}drop-arrow ${this.options.arrow.icon}`, placement: this.options.arrow.placement, point: 'inside' });
            this.lastPoint = '';
            this.targetPoints = [];
            this.dragstartEvt = (evt) => {
                evt.dataTransfer.effectAllowed = 'copyMove';
                this.commDragStart(evt);
            };
            this.dragenterEvt = (evt) => {
                evt.preventDefault();
                this.commDragEnter(evt.target, evt);
            };
            this.dragleaveEvt = (evt) => {
                this.commDragLeave(evt.target, evt.relatedTarget, evt);
            };
            this.dragoverEvt = (evt) => {
                evt.preventDefault();
                evt.dataTransfer.dropEffect = evt.ctrlKey ? 'copy' : 'move';
                let resp = this.commDragOver(evt.target, evt);
                resp === false && super.listen({ name: 'dragOut', params: [evt] });
            };
            this.dragdropEvt = async (evt) => {
                evt.preventDefault();
                let resp = await this.commDragDrop(evt.target, evt);
                resp === false && super.listen({ name: 'dropOut', params: [evt] });
                return;
            };
            this.dragendEvt = (evt) => {
                this.commDragEnd(evt.target, evt);
            };
            this.commTrigger = async (evt) => {
                try {
                    this.options.b4Trigger && await this.options.b4Trigger.call(this, evt);
                }
                catch {
                    return false;
                }
                this.updateDragsDrops();
                this.removeDroppeds();
                if (this.flipIns) {
                    this.flipIns.options.children = this.getFlipChldren();
                    this.flipIns.updateFlipEls();
                }
                let dragEl = this.dragEls.find((k) => k.contains(evt.target));
                if (!dragEl)
                    return false;
                if (this.handleEls.length === 0 || this.useHandle(evt.target)) {
                    evt.stopPropagation();
                    dragEl.setAttribute('draggable', 'true');
                    this.sourceNode = dragEl;
                    orca.dragNode = this.sourceNode;
                    this.addDestopEvents();
                    super.listen({ name: 'trigger', params: [{ target: dragEl, event: evt }] });
                    this.triggered = true;
                }
            };
            this.commDragStart = (evt) => {
                document.body.toggleAttribute('dragbody', true);
                this.isTransferred = false;
                this.cloned = false;
                if (this.otherGroupIns.length) {
                    for (let k of this.otherGroupIns) {
                        k.isTransferred = false;
                        k.cloned = false;
                    }
                }
                this.setHolderAttrs();
                requestAnimationFrame(() => {
                    this.sourceNode.classList.add(`${orca.prefix}drag-wait`);
                });
                super.listen({ name: 'dragStart', params: [{ target: null, source: this.sourceNode, point: 'outside', event: evt, type: '' }] });
            };
            this.commDragEnter = (evtTarget, evt) => {
                let target = this.dropEls.find((k) => k === evtTarget) || this.wrapEls.find((k) => k === evtTarget);
                if (!target)
                    return false;
                this.toggleDropping(evtTarget, true);
                this.hoverCount = 0;
                super.listen({ name: 'dragEnter', params: [{ target, source: this.sourceNode, point: this.lastPoint, event: evt, type: this.getTransferType() }] });
            };
            this.commDragLeave = (evtTarget, relatedTarget, evt) => {
                let target = this.dropEls.find((k) => k === evtTarget) || this.wrapEls.find((k) => k === evtTarget), related = this.dropEls.includes(relatedTarget);
                if (!target || target === relatedTarget || (!related && target.contains(relatedTarget)))
                    return false;
                this.toggleDropping(target, false);
                
                this.removeArrow();
                super.listen({ name: 'dragLeave', params: [{ target, source: this.sourceNode, relatedTarget, point: this.lastPoint, event: evt, type: this.getTransferType() }] });
                return true;
            };
            this.commDragOver = (evtTarget, evt) => {
                if (!this.options.pushable.enable)
                    return false;
                if (!this.options.pullable && !contains(this.sourceNode, this.selfEls))
                    return false;
                if (evtTarget === this.sourceNode)
                    return false;
                if (evtTarget === this.holderDrop) {
                    return false;
                }
                this.commDragThrot(evtTarget, evt);
            };
            this.commDragDrop = async (evtTarget, evt) => {
                this.removeDroppings();
                this.removeArrow();
                if (!this.options.pushable.enable || this.options.method !== 'drop')
                    return false;
                if (!this.options.pullable && !contains(this.sourceNode, this.selfEls))
                    return false;
                let target = evtTarget, param = { target, source: this.sourceNode, point: this.lastPoint, event: evt, type: this.getTransferType() };
                if (this.wrapEls.includes(evtTarget)) {
                    try {
                        this.options.b4Drop && await this.options.b4Drop.call(this, param);
                    }
                    catch {
                        console.info('The event of releasing the mouse or finger has been blocked!');
                        return false;
                    }
                    this.flipIns && this.flipIns.setNowRects();
                    this.insertEl(target, this.sourceNode, evt, 'beforeend');
                    this.options.holder.enable && this.hideHolder();
                    this.flipIns && this.flipIns.playAll();
                    param.target = target;
                    super.listen({ name: 'transferred', params: [param] });
                    this.isTransferred = true;
                }
                else {
                    let toClone = this.canClone(evtTarget), drops = this.dropEls;
                    target = drops.find((k) => k.contains(evtTarget));
                    if (!target)
                        return false;
                    if (!this.insertable(target, this.sourceNode))
                        return false;
                    try {
                        this.options.b4Drop && await this.options.b4Drop.call(this, param);
                    }
                    catch {
                        console.info('The event of releasing the mouse or finger has been blocked!');
                        return false;
                    }
                    if (this.flipIns) {
                        if (target?.flip?.anim?.playState === 'running' || target === this.sourceNode)
                            return false;
                        let copyNode = this.cloneStart(toClone);
                        this.flipIns.setNowRects();
                        copyNode && this.cloneEnd({ target, source: this.sourceNode, relatedTarget: copyNode, event: evt });
                        this.options.purpose === 'swap' ? this.swapNodes(target, this.sourceNode) : this.insertEl(target, this.sourceNode, evt);
                        this.options.holder.enable && this.hideHolder();
                        this.flipIns.playAll();
                    }
                    else {
                        let copyNode = this.cloneStart(toClone);
                        copyNode && this.cloneEnd({ target, source: this.sourceNode, relatedTarget: copyNode, event: evt });
                        this.options.purpose === 'swap' ? this.swapNodes(target, this.sourceNode) : this.insertEl(target, this.sourceNode, evt);
                        this.options.holder.enable && this.hideHolder();
                    }
                    param.target = target;
                    super.listen({ name: 'transferred', params: [param] });
                    this.isTransferred = true;
                }
                this.toggleDropped(this.sourceNode, true);
                super.listen({ name: 'dropped', params: [param] });
                return;
            };
            this.commDragEnd = (evtTarget, evt) => {
                let param = { target: evtTarget, source: this.sourceNode, point: this.lastPoint, event: evt };
                this.revert();
                super.listen({ name: 'dragEnd', params: [param] });
            };
            this.commFinished = (evt) => {
                this.revert();
                super.listen({ name: 'finished', params: [evt] });
            };
            this.commDragThrot = throttle((evtTarget, evt) => {
                this.hoverCount++;
                let param = { source: this.sourceNode, event: evt }, target;
                if (this.wrapEls.includes(evtTarget)) {
                    target = evtTarget;
                    let isEmpty = !target.children.length || getEl(`:scope > .${orca.prefix}holder-empty`, target);
                    if (!isEmpty)
                        return;
                    this.flipIns && this.flipIns.setNowRects();
                    if (this.options.method === 'hover') {
                        this.insertEl(target, this.sourceNode, evt, 'beforeend');
                    }
                    else {
                        this.options.holder.enable && this.insertEl(target, this.holderDrop, evt, 'beforeend');
                        param.source = this.holderDrop;
                    }
                    this.flipIns && this.flipIns.playAll();
                    param.target = target;
                    param.point = 'inside';
                    param.type = 'embed';
                    super.listen({ name: 'transferred', params: [param] });
                    this.isTransferred = true;
                    super.listen({ name: 'dragMove', params: [param] });
                }
                else {
                    let toClone = this.options.method === 'hover' && this.canClone(evtTarget), drops = this.dropEls, copyNode, condition = this.options.method === 'hover' || (this.options.method === 'drop' && this.options.holder.enable), insertNode = this.options.method === 'drop' && this.options.holder.enable ? this.holderDrop : this.sourceNode;
                    target = drops.find((k) => k.contains(evtTarget));
                    if (!target)
                        return;
                    param.target = target;
                    if (this.flipIns) {
                        if (target?.flip?.anim?.playState === 'running')
                            return;
                        this.updatePoints(evt, target);
                        this.insertUpdateArrow(target);
                        super.listen({ name: 'dragMove', params: [param] });
                        if (!condition || !this.insertable(target, this.sourceNode))
                            return;
                        copyNode = this.cloneStart(toClone);
                        this.flipIns.setNowRects();
                        copyNode && this.cloneEnd({ target, source: this.sourceNode, relatedTarget: copyNode, event: evt }, (node) => {
                            insertNode = node;
                            this.sourceNode = node;
                        });
                        this.options.purpose === 'swap' ? this.swapNodes(target, this.sourceNode) : this.insertEl(target, insertNode, evt);
                        this.flipIns.playAll();
                        param.point = this.lastPoint;
                        param.type = this.getTransferType();
                        super.listen({ name: 'transferred', params: [param] });
                        this.isTransferred = true;
                    }
                    else {
                        this.updatePoints(evt, target);
                        this.insertUpdateArrow(target);
                        super.listen({ name: 'dragMove', params: [param] });
                        if (this.options.method === 'drop' || !this.insertable(target, this.sourceNode))
                            return;
                        copyNode = this.cloneStart(toClone);
                        copyNode && this.cloneEnd({ target, source: this.sourceNode, relatedTarget: copyNode, event: evt }, (node) => {
                            insertNode = node;
                            this.sourceNode = node;
                        });
                        this.insertEl(target, insertNode, evt);
                        param.point = this.lastPoint;
                        param.type = this.getTransferType();
                        super.listen({ name: 'transferred', params: [param] });
                        this.isTransferred = true;
                    }
                }
            }, this.options.throttle);
            this.mousedownEvt = async (evt) => {
                let resp = await this.commTrigger(evt);
                if (resp === false)
                    return;
            };
            this.mouseupEvt = (evt) => {
                this.commFinished(evt);
            };
            this.setMutationObs();
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.triggered = false;
            this.parentEl = getEl(this.options.parent);
            this.selfEls = [];
            this.dragEls = [];
            this.dropEls = [];
            this.hoverCount = 0;
            this.cloned = false;
            this.updateWrapEls();
            this.updateHandleEls();
            this.setWrapsObs();
            this.updateIgnoreEls();
            this.sourceNode = null;
            this.setAttrs();
            this.holderAttr = ['left', 'right'].includes(this.options.arrow.placement) ? 'height' :
                ['top', 'bottom'].includes(this.options.arrow.placement) ? 'width' : '';
            this.setFlip();
            if (this.options.original) {
                orca.isTouchScr ? this.setCommDrag() : this.setDestopDrag();
            }
            else {
                this.setCommDrag();
            }
            this.handleEmpty();
            super.listen({ name: 'initiated', cb });
        }
        setCommDrag() {
            this.gestureIns = new Gesture(this.targetEl, {
                rotate: false,
                scale: false,
                drift: false,
                wheel: false,
                translate: {
                    target: this.options.handle,
                },
                b4Trigger: (evt) => {
                    return new Promise(async (resolve, reject) => {
                        let resp = await this.commTrigger(evt);
                        resp === false ? reject() : resolve(null);
                    });
                },
                onStart: (evt) => {
                    this.commDragStart(evt);
                    this.ghostEl = this.getGhostNode(this.sourceNode);
                    this.sourceNode.parentNode.appendChild(this.ghostEl);
                },
                onEnter: (evt) => {
                    this.commDragEnter(evt.evtTarget, evt);
                },
                onLeave: (evt) => {
                    this.commDragLeave(evt.evtTarget, evt.relatedTarget, evt);
                },
                onMove: (evt) => {
                    this.setGhostPos(evt.translate.value);
                    let resp = this.commDragOver(evt.evtTarget, evt);
                    resp === false && super.listen({ name: 'dragOut', params: [evt] });
                },
                onEnd: async (evt) => {
                    let resp = await this.commDragDrop(evt.evtTarget, evt);
                    resp === false && super.listen({ name: 'dropOut', params: [evt] });
                    this.commDragEnd(evt.evtTarget, evt);
                    return;
                },
                onFinished: (evt) => {
                    this.revert();
                    super.listen({ name: 'finished', params: [evt] });
                },
                onCanceled: (data) => {
                    this.revert();
                    super.listen({ name: 'dragCancel', params: [{ ...data }] });
                }
            });
        }
        canClone(target) {
            let tmp = this.options.original && !orca.isTouchScr ? !this.selfEls.includes(orca.dragNode) : this.otherGroupIns.find((k) => k.targetEl.contains(target));
            return this.options.pushable.intent === 'clone' && tmp;
        }
        cloneStart(bool = true) {
            if (!bool || this.cloned)
                return;
            let copyNode = this.getCopyNode(this.sourceNode);
            this.flipIns && this.flipIns.add(copyNode);
            this.sourceNode.style.position = 'absolute';
            this.sourceNode.insertAdjacentElement('afterend', copyNode);
            return copyNode;
        }
        cloneEnd(param, cb) {
            if (!param.relatedTarget)
                return;
            super.listen({ name: 'cloned', params: [param] });
            this.sourceNode.style.position = '';
            this.cloned = true;
            if (cb) {
                cb(param.relatedTarget);
            }
            else {
                this.sourceNode = param.relatedTarget;
            }
        }
        getTransferType() {
            return this.options.purpose === 'auto' ? (this.lastPoint === 'inside' ? 'embed' : 'sort') : this.options.purpose;
        }
        getFlipChldren() {
            return this.options.drags ? [...this.dragEls, ...this.dropEls] : this.dropEls;
        }
        getCopyNode(node) {
            let tmp = node.cloneNode(true);
            tmp.removeAttribute('draggable');
            tmp.classList.remove(`${orca.prefix}drag-wait`);
            tmp.toggleAttribute('cloned', true);
            return tmp;
        }
        getGhostNode(node) {
            let tmp = node.cloneNode(true), styles = style(node), rects = node.getBoundingClientRect(), left = rects.left - parseFloat(styles.marginLeft), top = rects.top - parseFloat(styles.marginTop);
            tmp.removeAttribute('draggable');
            tmp.classList.remove(`${orca.prefix}drag-wait`);
            tmp.classList.add(`${orca.prefix}drag-ghost`);
            tmp.style.width = `min(${styles.width},100%)`;
            tmp.style.height = styles.height;
            tmp.style.left = left + 'px';
            tmp.style.top = top + 'px';
            tmp.initVal = { left, top };
            return tmp;
        }
        setGhostPos(value) {
            this.ghostEl.style.left = this.ghostEl.initVal.left + value.x + 'px';
            this.ghostEl.style.top = this.ghostEl.initVal.top + value.y + 'px';
        }
        hideGhost() {
            if (!this.ghostEl || elState(this.ghostEl).isVirtual)
                return;
            if (this.isTransferred) {
                this.ghostEl.remove();
                return;
            }
            let rects = this.sourceNode.getBoundingClientRect(), styles = style(this.ghostEl), left = rects.left - parseFloat(styles.marginLeft), top = rects.top - parseFloat(styles.marginTop), anim = this.ghostEl.animate([
                {
                    opacity: styles.opacity,
                    left: styles.left,
                    top: styles.top,
                },
                {
                    opacity: 0,
                    left: left + 'px',
                    top: top + 'px',
                }
            ], {
                duration: this.options.duration,
                easing: this.flipIns ? this.flipIns.options.easing : 'ease-out',
                fill: 'forwards'
            });
            anim.addEventListener('finish', () => {
                this.ghostEl.remove();
            });
        }
        updateHandleEls() {
            if (this.handleEls.length) {
                for (let k of this.handleEls)
                    k.removeAttribute('handle');
            }
            this.handleEls = getEls(this.options.handle, this.parentEl);
            for (let k of this.handleEls)
                k.setAttribute('handle', '');
        }
        updateIgnoreEls() {
            this.ignoreEls = getEls(this.options.ignore, this.targetEl);
        }
        updateWrapEls() {
            this.wrapEls = this.options.wraps ? getEls(this.options.wraps, this.targetEl) : [this.targetEl];
        }
        setMutationObs() {
            this.childObs = new MutationObserver(k => {
                this.options.showEmpty && this.handleEmpty();
            });
            this.childObsOpts = { childList: true, subtree: false };
        }
        setWrapsObs() {
            if (!this.options.showEmpty)
                return;
            for (let k of this.wrapEls)
                this.childObs.observe(k, this.childObsOpts);
        }
        hideHolder() {
            this.holderDrop.toggleAttribute('dropping', false);
            if (elState(this.holderDrop).isVisible) {
                this.holderDrop.classList.add(`${orca.prefix}d-none`);
                this.holderDrop.remove();
            }
        }
        replaceNodes(target, source) {
            let pTarget = target.parentNode, pSource = source.parentNode, nTarget = target.nextElementSibling, nSource = source.nextElementSibling;
            pTarget.insertBefore(source, nTarget);
            pSource.insertBefore(target, nSource);
        }
        swapNodes(target, source) {
            this.replaceNodes(target, source);
            super.listen({ name: 'swapped', params: [{ target, source }] });
        }
        getEmbedEl(target) {
            return getEl(this.options.embed.selector, target) || target;
        }
        insertable(target, source) {
            let embedPoint = this.getEmbedPoint(), embedWrap = this.getEmbedEl(target), isAfter = target.nextElementSibling === source && this.lastPoint === 'after', isBefore = target.previousElementSibling === source && this.lastPoint === 'before', isSwap = this.options.purpose === 'swap', isInside = source.parentNode === embedWrap, isFirst = embedPoint === 'afterbegin' && target.firstChildElement === source, isLast = embedPoint === 'beforeend' && target.lastChildElement === source, condition = this.options.purpose === 'embed' ? isInside : (this.lastPoint === 'inside' && this.options.purpose === 'auto') ? isFirst || isLast : isAfter || isBefore;
            return isSwap ? true : !condition;
        }
        getEmbedPoint() {
            return this.options.embed.position === 'after' ? 'beforeend' :
                this.options.embed.position === 'before' ? 'afterbegin' :
                    this.targetPoints.includes('t/2') || this.targetPoints.includes('l/2') ? 'afterbegin' : 'beforeend';
        }
        insertEl(target, source, event, position) {
            if (position) {
                target.insertAdjacentElement(position, source);
                super.listen({ name: 'embeded', params: [{ target, source, position, event }] });
            }
            else {
                if (target === this.holderDrop) {
                    target.insertAdjacentElement('beforebegin', source);
                }
                else {
                    if (this.options.purpose === 'embed' || (this.lastPoint === 'inside' && this.options.purpose === 'auto')) {
                        let embedWrap = this.getEmbedEl(target), position = this.getEmbedPoint();
                        if (this.options.purpose === 'embed' && source.parentNode === embedWrap)
                            return;
                        embedWrap.insertAdjacentElement(position, source);
                        super.listen({ name: 'embeded', params: [{ target: embedWrap, source, position, event }] });
                    }
                    else {
                        if ((target.nextElementSibling === source && this.lastPoint === 'after')
                            ||
                                (target.previousElementSibling === source && this.lastPoint === 'before'))
                            return;
                        target.insertAdjacentElement(this.lastPoint === 'before' ? 'beforebegin' : 'afterend', source);
                        super.listen({ name: 'sorted', params: [{ target, source, position: this.lastPoint, event }] });
                    }
                }
            }
        }
        updatePoints(evt, target) {
            this.targetPoints = getRectPoints(evt.orgEvt || evt, target);
            let isBefore = this.targetPoints.find((k) => this.options.point.before.includes(k)), isAfter = this.targetPoints.find((k) => this.options.point.after.includes(k));
            this.lastPoint = this.targetPoints.includes('outside') ? '' : isBefore ? 'before' : isAfter ? 'after' : 'inside';
        }
        insertUpdateArrow(target) {
            if (!this.options.arrow.enable)
                return;
            if (!this.lastPoint) {
                this.dropArrow.remove();
            }
            else {
                this.dropArrow.setAttribute('point', this.lastPoint);
                if (elState(this.dropArrow).isVirtual) {
                    let tmp = getEl(this.options.arrow.selector, target) || target;
                    tmp.appendChild(this.dropArrow);
                }
            }
        }
        removeArrow() {
            this.options.arrow.enable && !elState(this.dropArrow).isVirtual && this.dropArrow.remove();
        }
        setHolderAttrs() {
            if (!this.options.holder.enable)
                return;
            let tmp = style(this.sourceNode);
            this.holderDrop.style.setProperty(`--${orca.prefix}holder-w`, `min(${tmp.width},100%)`);
            this.holderDrop.style.setProperty(`--${orca.prefix}holder-h`, tmp.height);
            this.holderDrop.style.setProperty(`--${orca.prefix}holder-r`, tmp.borderRadius);
            this.holderDrop.style.setProperty(`--${orca.prefix}holder-m`, tmp.margin);
            if (this.options.holder.style.length) {
                for (let k of this.options.holder.style)
                    this.holderDrop.style.setProperty(k, tmp[k]);
            }
        }
        toggleDropped(target, bool = true) {
            target && target.toggleAttribute('dropped', bool);
        }
        removeDroppeds() {
            for (let k of [...this.dragEls])
                k.toggleAttribute('dropped', false);
        }
        toggleDropping(target, bool = true) {
            (this.dropEls.includes(target) || this.wrapEls.includes(target)) && target.toggleAttribute('dropping', bool);
        }
        removeDroppings() {
            for (let k of [...this.dropEls, ...this.wrapEls])
                k.toggleAttribute('dropping', false);
        }
        removeDraggables() {
            for (let k of [...this.dragEls])
                k.removeAttribute('draggable');
        }
        setFlip() {
            if (!this.options.flip.enable)
                return;
            let opts = extend({
                target: {
                    children: this.getFlipChldren(),
                    b4Play: (data) => {
                        return new Promise(resolve => {
                            if (data !== this.holderDrop || (data === this.holderDrop && !this.holderDrop.classList.contains(`${orca.prefix}d-none`))) {
                                resolve(null);
                            }
                            else if (data === this.holderDrop && this.holderDrop.classList.contains(`${orca.prefix}d-none`)) {
                                data.classList.remove(`${orca.prefix}d-none`);
                            }
                        });
                    },
                    onPlayedAll: () => {
                        this.commDragThrot.cancel();
                    }
                },
                source: this.options.flip
            });
            this.flipIns = new Flip(opts);
        }
        setDestopDrag() {
            if (orca.isTouchScr || !this.options.original)
                return;
            this.removeMouseEvents();
            this.addMouseEvents();
        }
        addMouseEvents() {
            if (orca.isTouchScr || !this.options.original)
                return;
            document.addEventListener('mousedown', this.mousedownEvt, { passive: false });
            document.addEventListener('mouseup', this.mouseupEvt, { passive: false });
        }
        removeMouseEvents() {
            if (orca.isTouchScr || !this.options.original)
                return;
            document.removeEventListener('mousedown', this.mousedownEvt);
            document.removeEventListener('mouseup', this.mouseupEvt);
        }
        addDestopEvents() {
            if (orca.isTouchScr || !this.options.original)
                return;
            this.targetEl.addEventListener('dragstart', this.dragstartEvt, { passive: false });
            this.targetEl.addEventListener('dragenter', this.dragenterEvt, { passive: false });
            this.targetEl.addEventListener('dragover', this.dragoverEvt, { passive: false });
            this.targetEl.addEventListener('dragleave', this.dragleaveEvt, { passive: false });
            this.targetEl.addEventListener('drop', this.dragdropEvt, { passive: false });
            this.targetEl.addEventListener('dragend', this.dragendEvt, { passive: false });
        }
        removeDestopEvents() {
            if (orca.isTouchScr || !this.options.original)
                return;
            this.targetEl.removeEventListener('dragstart', this.dragstartEvt);
            this.targetEl.removeEventListener('dragenter', this.dragenterEvt);
            this.targetEl.removeEventListener('dragover', this.dragoverEvt);
            this.targetEl.removeEventListener('dragleave', this.dragleaveEvt);
            this.targetEl.removeEventListener('drop', this.dragdropEvt);
            this.targetEl.removeEventListener('dragend', this.dragendEvt);
        }
        setAttrs() {
        }
        getGoupDrags() {
            this.otherGroupIns = instance.findAll('drag').filter((k) => k !== this && this.options.group && k.options.group === this.options.group);
            if (!this.otherGroupIns.length)
                return [];
            return this.otherGroupIns.map((k) => k.options.drags ? k.getSelfDragEls() : k.getSelfDropEls()).flat();
        }
        getSelfDropEls(drops = this.options.drops) {
            let tmp1 = getEls(drops, this.parentEl), tmp2 = !tmp1.length ? getEls(`[dropnode]`, this.parentEl || this.targetEl) : tmp1, tmp3 = !tmp2.length ? [...this.targetEl.children] : elsSort(tmp2), tmp4 = [];
            if (this.ignoreEls.length) {
                tmp4 = tmp3.filter((k) => !this.ignoreEls.includes(k) && k.getAttribute('draggable') !== 'false');
            }
            else {
                tmp4 = tmp3.filter((k) => k.getAttribute('draggable') !== 'false');
            }
            return tmp4;
        }
        getSelfDragEls(drags = this.options.drags) {
            let tmp1 = getEls(drags, this.targetEl), tmp2 = !tmp1.length ? getEls(`[dragnode]`, this.targetEl) : tmp1, tmp3 = [];
            if (this.ignoreEls.length) {
                tmp3 = tmp2.filter((k) => !this.ignoreEls.includes(k) && k.getAttribute('draggable') !== 'false');
            }
            else {
                tmp3 = tmp2.filter((k) => k.getAttribute('draggable') !== 'false');
            }
            return tmp3;
        }
        updateDragsDrops() {
            if (this.options.drags) {
                this.selfEls = this.getSelfDragEls(this.options.drags);
                this.dragEls = [...this.selfEls, ...this.getGoupDrags()];
                this.dropEls = [this.holderDrop, ...this.getSelfDropEls(this.options.drops).filter((k) => !this.dragEls.includes(k))];
            }
            else {
                this.selfEls = this.getSelfDropEls(this.options.drops);
                this.dragEls = [...this.selfEls, ...this.getGoupDrags()];
                this.dropEls = [this.holderDrop, ...this.dragEls];
            }
        }
        handleEmpty(target) {
            if (!this.options.showEmpty)
                return;
            let fn = (el) => {
                let len = el.children.length, tmp = getEl(`:scope > .${orca.prefix}holder-empty`, el);
                if (!len) {
                    el.appendChild(this.holderEmpty.cloneNode(true));
                }
                else if (len > 1 && tmp) {
                    tmp && tmp.remove();
                }
            };
            if (target) {
                fn(target);
            }
            else {
                for (let k of this.wrapEls) {
                    fn(k);
                }
            }
        }
        updateList(data, cb) {
            if (this.destroyed)
                return this;
            Object.assign(this.options, data);
            super.listen({ name: 'updatedList', cb, params: [data] });
            return this;
        }
        revert() {
            if (!this.triggered)
                return;
            this.hideGhost();
            this.targetPoints = [];
            this.lastPoint = '';
            this.hideHolder();
            this.sourceNode.classList.remove(`${orca.prefix}drag-wait`);
            this.removeDroppings();
            this.removeDraggables();
            this.removeArrow();
            this.removeDestopEvents();
            this.gestureIns && this.gestureIns.removeSecondEvents();
            this.hoverCount = 0;
            this.cloned = false;
            document.body.toggleAttribute('dragbody', false);
            this.isTransferred = false;
            this.triggered = false;
        }
        destroy(cb) {
            if (this.destroyed)
                return;
            this.revert();
            this.gestureIns && this.gestureIns.destroy();
            this.removeMouseEvents();
            this.removeDestopEvents();
            this.options.showEmpty && this.childObs.disconnect();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    let OCTMP_emptyTpl = `<i class="${orca.prefix}c-ignore">${config.lang.tags.emptyholder}</i>`, OCTMP_editorHolder = config.lang.tags.placeholder, OCTMP_separator$3 = config.splitHyphen;
    const optTags = [
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {}
        },
        {
            attr: 'content',
            prop: 'content',
            value: ''
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'theme',
            prop: 'theme',
            value: '',
        },
        {
            attr: 'size',
            prop: 'size',
            value: 'md',
        },
        {
            attr: 'field',
            prop: 'field',
            value: 'label',
        },
        {
            attr: 'type',
            prop: 'type',
            value: '',
        },
        {
            attr: 'compact',
            prop: 'compact',
            value: false,
        },
        {
            attr: 'shape',
            prop: 'shape',
            value: '',
        },
        {
            attr: 'max',
            prop: 'max',
            value: 0,
        },
        {
            attr: 'min',
            prop: 'min',
            value: 0,
        },
        {
            attr: 'sliced',
            prop: 'sliced',
            value: true,
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'unique',
            prop: 'unique',
            value: {
                enable: false,
                refer: 'id',
                template: `{{this.field}}<i class="${orca.prefix}c-brief">({{this.key}}:{{this.value}})</i>`,
            },
        },
        {
            attr: 'empty',
            prop: 'empty',
            value: {
                enable: true,
                content: OCTMP_emptyTpl,
            }
        },
        {
            attr: 'editor',
            prop: 'editor',
            value: {
                enable: false,
                addable: true,
                deletable: true,
                selector: '',
                placeholder: OCTMP_editorHolder,
            },
        },
        {
            attr: 'removable',
            prop: 'removable',
            value: false,
        },
        {
            attr: 'separator',
            prop: 'separator',
            value: OCTMP_separator$3,
        },
        {
            attr: 'b4-fill',
            prop: 'b4Fill',
            value: null,
        },
        {
            attr: 'b4-add',
            prop: 'b4Add',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'b4-edit',
            prop: 'b4Edit',
            value: null,
        },
        {
            attr: 'b4-clear',
            prop: 'b4Clear',
            value: null,
        },
        {
            attr: 'on-added',
            prop: 'onAdded',
            value: null,
        },
        {
            attr: 'on-removed',
            prop: 'onRemoved',
            value: null,
        },
        {
            attr: 'on-edited',
            prop: 'onEdited',
            value: null,
        },
        {
            attr: 'on-cleared',
            prop: 'onCleared',
            value: null,
        },
        {
            attr: 'on-duplicated',
            prop: 'onDuplicated',
            value: null,
        },
        {
            attr: 'on-request',
            prop: 'onRequest',
            value: null
        },
        {
            attr: 'on-output',
            prop: 'onOutput',
            value: null
        },
        ...optBase
    ];

    class Tags extends ModBaseListenCache {
        options = {};
        emptyEl;
        content;
        editEvent;
        toggleSelected;
        output;
        maxIndex;
        dataOrig;
        dataObs;
        data;
        editEl;
        last;
        labelEl;
        imgNone;
        static hostType = 'node';
        static optMaps = optTags;
        constructor(elem, options = {}, initial = config.initial) {
            super();
            super.ready({
                options,
                maps: Tags.optMaps,
                host: elem,
                component: true,
                spread: ['edit', 'unique', 'empty']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            this.emptyEl = createEl('span', { [orca.alias]: 'empty' }, this.options.empty.content);
            
            this.content = '';
            let _this = this;
            this.editEvent = async (e) => {
                let label = this.editEl.value.trim(), selectedItem = this.data.find((k) => k.selected);
                if (label) {
                    this.editEl.style.width = label.length + 'em';
                    if (this.options.editor.addable && e.code === 'Enter') {
                        this.add(label, () => {
                            this.editEl.value = '';
                            this.editEl.focus();
                        });
                    }
                    selectedItem && (selectedItem.selected = false);
                }
                else {
                    this.editEl.style.cssText = this.editEl.style.cssText.replace('width:', '');
                    if (this.options.editor.deletable && e.code === 'Backspace' && this.data.length > 0) {
                        let endItem = this.data.slice(-1)[0];
                        if (endItem.selected) {
                            this.remove(endItem);
                        }
                        else {
                            endItem.selected = true;
                        }
                    }
                    else {
                        selectedItem && (selectedItem.selected = false);
                    }
                }
            };
            this.toggleSelected = function (e) {
                if (e.target.getAttribute(orca.alias) !== 'remove') {
                    let item = _this.data.find((k) => k.wrapEl === this);
                    item.selected = true;
                    _this.data.filter((k) => k !== item).forEach((k) => {
                        k.selected = false;
                    });
                }
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch (err) {
                err ? console.error(err) : console.warn(config.warn.init);
                return this;
            }
            this.output = { value: '', raw: '', items: [] };
            this.maxIndex = 0;
            this.initContent();
            this.setEmpty();
            this.createEditor();
            await getContent.call(this, {
                content: this.content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: {
                    xhrName: 'contXhr',
                    spinSel: this.targetEl,
                    ...this.options.ajax
                },
                cb: async (data) => {
                    await this.renderContent(data);
                }
            });
            this.setAttrs();
            this.renderFinish();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        initContent() {
            if (this.options.content) {
                this.content = this.options.content;
            }
            else {
                this.content = this.rawHtml || this.targetEl.innerHTML;
            }
        }
        setDataObs() {
            this.dataOrig = [];
            this.dataObs = new Observe(this.dataOrig, {
                deep: true,
                onSet: (obj) => {
                    if (obj.key === this.options.field || obj.key === 'label') {
                        obj.target.labelEl.innerHTML = obj.value;
                    }
                    else if (['selected', 'disabled'].includes(obj.key)) {
                        obj.target.wrapEl.toggleAttribute(obj.key, obj.value);
                    }
                    else if (obj.key === 'theme') {
                        obj.target.wrapEl.setAttribute(obj.key, obj.value);
                    }
                    else if (obj.key === 'icon' && obj.proxy.iconEl) {
                        classes(obj.proxy.iconEl).replace(obj.raw, obj.value);
                    }
                    else if (obj.key === 'cube' && obj.proxy.cubeEl) {
                        obj.proxy.cubeEl.src = obj.value;
                    }
                    else if (obj.key === 'disk' && obj.proxy.diskEl) {
                        obj.proxy.diskEl.src = obj.value;
                    }
                    else if (obj.key === 'image' && obj.proxy.imageEl) {
                        obj.proxy.imageEl.src = obj.value;
                    }
                    else if (['href', 'target', 'rel', 'download'].includes(obj.key) && this.labelEl.nodeName === 'A') {
                        obj.target.labelEl[obj.key] = obj.value;
                    }
                },
                onCompleted: (data) => {
                    this.toggleEmpty();
                    if (this.options.storName) {
                        let tmp = {
                            content: !isEmpty(this.options.content) ? deepClone(this.dataOrig) : '',
                        };
                        super.updateCache(tmp);
                    }
                    this.output.value = this.getStrVals();
                    this.output.items = [...this.data];
                    super.listen({ name: 'output', params: [this.output] });
                }
            });
            this.data = this.dataObs.proxy;
        }
        async renderContent(data) {
            try {
                if (this.options.b4Fill) {
                    let resp = await this.options.b4Fill.call(this, data, this.targetEl);
                    resp && (data = resp);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('The content was blocked from being filled!');
                return this;
            }
            this.setDataObs();
            let tmp = this.getSource(data);
            try {
                let resp = await this.moreExceed({ data: tmp, source: this.data });
                resp && (tmp = resp);
            }
            catch {
                return;
            }
            this.render(tmp);
            this.data.push(...tmp);
        }
        getStrVals() {
            return this.data.map((k) => k[this.options.field]).join(this.options.separator);
        }
        getSource(obj) {
            let result = [];
            if (!isEmpty(obj)) {
                if (Array.isArray(obj)) {
                    if (typeof obj[0] === 'string') {
                        result = obj.map(k => {
                            return { [this.options.field]: k, theme: '' };
                        });
                    }
                    else {
                        result = obj;
                    }
                }
                else if (typeof obj === 'object') {
                    result = [obj];
                }
                else if (typeof obj === 'string') {
                    let tmp = createEl('div', {}, obj), children = [...tmp.children];
                    if (children.length) {
                        if (children[0].nodeName === 'SELECT') {
                            result = select2Tree(children[0]);
                        }
                        else if (children[0].nodeName === 'INPUT') {
                            result = treeTools.fromInput(children[0], this.options.separator);
                        }
                        else {
                            for (let k of children) {
                                let obj = {};
                                k.hasAttribute('label') && (obj.label = k.getAttribute('label'));
                                k.hasAttribute('value') && (obj.value = k.getAttribute('value'));
                                k.hasAttribute('icon') && (obj.icon = k.getAttribute('icon'));
                                k.hasAttribute('disk') && (obj.disk = k.getAttribute('disk'));
                                k.hasAttribute('cube') && (obj.cube = k.getAttribute('cube'));
                                k.hasAttribute('image') && (obj.image = k.getAttribute('image'));
                                k.hasAttribute('disabled') && (obj.disabled = true);
                                k.hasAttribute('theme') && (obj.theme = k.getAttribute('theme'));
                                obj[this.options.field] = k.hasAttribute(this.options.field) ? k.getAttribute(this.options.field) : k.textContent;
                                if (k.nodeName === 'A') {
                                    obj = {
                                        ...obj,
                                        href: k.getAttribute('href'),
                                        target: k.target,
                                        rel: k.rel,
                                        download: k.download,
                                    };
                                }
                                result.push(obj);
                            }
                        }
                    }
                    else {
                        let arr = obj.trim().split(this.options.separator);
                        result = arr.map(k => {
                            return { [this.options.field]: k, theme: '' };
                        });
                    }
                }
            }
            result = result.filter((k) => k && !this.data.includes(k));
            result.forEach((k, i) => {
                !k.hasOwnProperty('id') && (k.id = this.maxIndex + i);
            });
            this.maxIndex += result.length;
            return result;
        }
        render(content) {
            if (!isEmpty(content)) {
                let fragment = document.createDocumentFragment();
                for (let k of content) {
                    k.wrapEl = this.createTag(k);
                    fragment.appendChild(k.wrapEl);
                }
                this.targetEl.appendChild(fragment);
            }
            this.options.editor.enable && !this.options.editor.selector && this.targetEl.appendChild(this.editEl);
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}tags`);
            classes(this.targetEl).add(this.options.classes);
            this.options.theme ? this.targetEl.setAttribute('theme', this.options.theme) : this.targetEl.removeAttribute('theme');
            this.options.type ? this.targetEl.setAttribute('type', this.options.type) : this.targetEl.removeAttribute('type');
            this.targetEl.toggleAttribute('compact', this.options.compact);
            this.options.shape ? this.targetEl.setAttribute('shape', this.options.shape) : this.targetEl.removeAttribute('shape');
            this.options.size ? this.targetEl.setAttribute('size', this.options.size) : this.targetEl.removeAttribute('size');
        }
        setEmpty() {
            this.targetEl.innerHTML = '';
        }
        useLegend(obj) {
            if (obj.hasOwnProperty('icon')) {
                obj.iconEl = createEl('i', { [orca.alias]: 'icon', class: `${obj.icon}` });
                obj.labelEl.insertAdjacentElement('beforebegin', obj.iconEl);
            }
            if (obj.hasOwnProperty('disk')) {
                obj.diskEl = createEl('img', { [orca.alias]: 'disk', src: `${obj.disk || orca.images.none}` });
                obj.labelEl.insertAdjacentElement('beforebegin', obj.diskEl);
            }
            if (obj.hasOwnProperty('cube')) {
                obj.cubeEl = createEl('img', { [orca.alias]: 'cube', src: `${obj.cube || orca.images.none}` });
                obj.labelEl.insertAdjacentElement('beforebegin', obj.cubeEl);
            }
            if (obj.hasOwnProperty('image')) {
                obj.imageEl = createEl('img', { [orca.alias]: 'image', src: `${obj.image || orca.images.none}` });
                obj.labelEl.insertAdjacentElement('beforebegin', obj.imageEl);
            }
        }
        createTag(obj) {
            let labelObj = { [orca.alias]: 'label' }, text = this.data.find((k) => k !== obj && k[this.options.field] === obj[this.options.field]) ?
                renderTpl(this.options.unique.template, { field: obj[this.options.field], value: obj[this.options.unique.refer], key: this.options.unique.refer }) :
                obj[this.options.field];
            obj.hasOwnProperty('href') && (labelObj.href = obj.href);
            obj.hasOwnProperty('href') && obj.target && (labelObj.target = obj.target);
            obj.hasOwnProperty('href') && obj.rel && (labelObj.rel = obj.rel);
            obj.hasOwnProperty('href') && obj.download && (labelObj.download = obj.download);
            obj.labelEl = createEl(labelObj.hasOwnProperty('href') ? 'a' : 'i', labelObj, text);
            obj.wrapEl = createEl('span', { class: `${orca.prefix}tag` }, obj.labelEl);
            obj.removeEl = createEl('i', { [orca.alias]: 'remove' });
            this.options.removable && obj.wrapEl.appendChild(obj.removeEl);
            this.useLegend(obj);
            !this.options.theme && obj.theme && obj.wrapEl.setAttribute('theme', obj.theme);
            obj.disabled && obj.wrapEl.setAttribute('disabled', '');
            obj.selected && obj.wrapEl.setAttribute('selected', '');
            return obj.wrapEl;
        }
        createEditor() {
            if (!this.options.editor.enable || this.destroyed)
                return;
            let tmp = getEl(this.options.editor.selector);
            if (!tmp) {
                this.editEl = createEl('input', { type: 'text', placeholder: this.options.editor.placeholder });
            }
            else {
                this.editEl = tmp;
                !this.editEl.hasAttribute('placeholder') && this.editEl.setAttribute('placeholder', this.options.editor.placeholder);
            }
            this.editEl.removeEventListener('keyup', this.editEvent);
            this.editEl.addEventListener('keyup', this.editEvent);
        }
        toggleEmpty() {
            if (!this.options.empty.enable)
                return;
            if (!this.data.length) {
                this.targetEl.insertAdjacentElement('afterbegin', this.emptyEl);
                this.maxIndex = 0;
            }
            else {
                this.emptyEl.remove();
            }
        }
        renderFinish() {
            this.toggleEmpty();
            for (let k of this.data) {
                k.wrapEl.addEventListener('click', this.toggleSelected, false);
                k.removeEl.onclick = () => {
                    this.remove(k);
                };
            }
            this.last = this.dataOrig[this.data.length - 1];
        }
        getVals(cb) {
            if (this.destroyed)
                return this;
            let value = {
                value: this.getStrVals(),
                items: [...this.data],
            };
            super.listen({ name: 'got', cb, params: [value] });
            return value;
        }
        
        async updateCont(content, cb) {
            if (this.destroyed)
                return this;
            this.setEmpty();
            await getContent.call(this, {
                content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: {
                    xhrName: 'contXhr',
                    spinSel: this.targetEl,
                    ...this.options.ajax
                },
                cb: async (data) => {
                    this.saveRaw();
                    await this.renderContent(data);
                    this.renderFinish();
                    super.updateCache({ content });
                    super.listen({ name: 'updatedCont', cb, params: [this.dataOrig] });
                }
            });
            return this;
        }
        saveRaw() {
            this.output.raw = this.getStrVals();
        }
        async add(data, cb) {
            if (isEmpty(data) || this.destroyed)
                return this;
            let arr = this.getSource(data), dupTags = [], oldLen = 0, oldValues = this.data.map((k) => k[this.options.field]);
            if (this.options.unique.enable) {
                arr = unique(arr, this.options.field);
                oldLen = arr.length;
                arr = arr.map((k) => {
                    let output;
                    if (oldValues.includes(k[this.options.field])) {
                        dupTags.push(k);
                    }
                    else {
                        output = k;
                    }
                    return output;
                }).filter(Boolean);
                if (oldLen !== arr.length) {
                    new Message({
                        content: arr.length === 0 ? this.options.lang.includeFull : this.options.lang.includePart,
                        status: 'warn',
                        iconShow: true,
                    }).show();
                    super.listen({ name: 'duplicated', params: [dupTags] });
                }
            }
            if (arr.length === 0)
                return this;
            try {
                let resp = await super.moreExceed({ data: arr, source: this.data });
                resp && (arr = resp);
            }
            catch {
                return;
            }
            try {
                if (this.options.b4Add) {
                    let resp = await this.options.b4Add.call(this, arr);
                    resp && (arr = resp);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('Failed to add a new tags!');
                return this;
            }
            if (!Array.isArray(arr) || !arr.length)
                return this;
            this.saveRaw();
            this.render(arr);
            this.data.push(...arr);
            this.renderFinish();
            super.listen({ name: 'added', cb, params: [arr] });
            return this;
        }
        async remove(data, cb) {
            if (isEmpty(data) || this.destroyed || !this.data.length)
                return this;
            let tags = findItems(data, this.data, '', { node: 'wrapEl', string: this.options.field, separator: this.options.separator });
            try {
                if (this.options.b4Remove) {
                    let resp = await this.options.b4Remove.call(this, tags);
                    resp && (tags = resp);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('Failed to delete the old tags!');
                return this;
            }
            try {
                let resp = await this.lessExceed({ data: tags, source: this.data });
                resp && (tags = resp);
            }
            catch {
                return;
            }
            if (!Array.isArray(tags) || !tags.length)
                return this;
            this.saveRaw();
            for (let i = 0; i < this.data.length; i++) {
                let tmp = this.data[i];
                if (tags.includes(tmp)) {
                    this.data.splice(i--, 1);
                    tmp.wrapEl.remove();
                }
            }
            super.listen({ name: 'removed', cb, params: [tags] });
            return this;
        }
        async edit(item, data, cb) {
            if (isEmpty(item) || this.destroyed || !this.data.length)
                return this;
            let tag = findItem(item, this.data, '', { node: 'wrapEl', string: this.options.field });
            if (!tag) {
                return this;
            }
            try {
                if (this.options.b4Edit) {
                    let resp = await this.options.b4Edit.call(this, tag);
                    resp && (tag = resp);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('Failed to eidit the tag!');
                return this;
            }
            if (!tag)
                return this;
            Object.assign(tag, data);
            super.listen({ name: 'edited', cb, params: [tag] });
            return this;
        }
        async clear(cb) {
            if (this.destroyed || !this.data.length)
                return this;
            this.options.b4Clear && await this.options.b4Clear.call(this);
            this.saveRaw();
            this.data.splice(0);
            this.maxIndex = 0;
            this.targetEl.innerHTML = '';
            this.options.editor.enable && this.targetEl.appendChild(this.editEl);
            super.listen({ name: 'cleared', cb });
            return this;
        }
        
        destroy(cb) {
            this.data.forEach((k) => {
                k.wrapEl.removeEventListener('click', this.toggleSelected);
                k.removeEl.onclick = null;
            });
            this.options.editor.enable && this.editEl.removeEventListener('keyup', this.editEvent);
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    class Tree extends ModBaseListenCacheNest {
        options = {};
        treeDataOrig;
        searchs;
        ignores;
        editorEl;
        lastExpanded;
        dropTag;
        pagination;
        searchEl;
        resultIns;
        resultEl;
        inputEl;
        output;
        value;
        expandEvt;
        selectEvt;
        searchEvgt;
        lineEvt;
        bubbleIns;
        receiver;
        hoverIns;
        contXhr;
        floorMax;
        chainChecking;
        seqItems;
        maxIndex;
        excludeDrags;
        rawData;
        observeIns;
        static hostType = 'node';
        static optMaps = optTree;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Tree.optMaps,
                component: true,
                spread: ['output', 'arrow', 'check', 'legend', 'select', 'shortcut', 'tools', 'drag', 'paginated', 'bubble']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            
            let _this = this;
            this.expandEvt = debounce(function () {
                let attr = this.getAttribute(orca.alias) === 'arrow' ? 'arrowEl' : this.getAttribute(orca.alias) === 'legend' ? 'legendEl' : 'headEl', item = findItem(this, _this.flatData, attr);
                _this.toggleExpanded(item);
            }, this.options.delay);
            this.selectEvt = debounce(function () {
                let item = findItem(this, _this.flatData, 'labelEl');
                _this.toggleSelected(item);
                if (item && item.toolsEl && _this.options.tools.trigger === 'click') {
                    if (item.selected) {
                        show({ el: item.toolsEl });
                    }
                    else {
                        hide({ el: item.toolsEl });
                    }
                }
            }, this.options.delay);
            this.searchEvgt = debounce(function () {
                _this.search(this.value);
            }, this.options.search.delay);
            this.lineEvt = debounce(function (e) {
                if (!_this.options.shortcut.enable)
                    return;
                let item = findItem(this, _this.flatData, 'headEl'), condition = false;
                if (!item)
                    return;
                if (_this.options.shortcut.span === 'blank' && (e.target === item.headEl || ['holder', 'group', 'gap'].includes(e.target.getAttribute(orca.alias)))) {
                    condition = true;
                }
                else if (!contains(e.target, [item.arrowEl, item.checkEl, item.toolsEl, ((_this.options.select.enable && !item.headEl.hasAttribute('unselectable')) || (item.labelEl.nodeName === 'A' && item.labelEl.hasAttribute('href'))) ? item.labelEl : null])) {
                    condition = true;
                }
                if (!condition)
                    return;
                if (_this.options.shortcut.mean === 'selected') {
                    _this.toggleSelected(item);
                }
                else if (_this.options.shortcut.mean === 'checked') {
                    !item.checkEl.hasAttribute('disabled') && _this.toggleCheck(item);
                }
                else if (_this.options.shortcut.mean === 'expanded') {
                    _this.toggleExpanded(item);
                }
                else if (_this.options.shortcut.mean === 'auto') {
                    if (item.children) {
                        _this.toggleExpanded(item);
                    }
                    else {
                        _this.options.check.enable && !item.checkEl.hasAttribute('disabled') ? _this.toggleCheck(item) : _this.toggleSelected(item);
                    }
                }
            }, this.options.delay);
            this.editorEl = createEl('input', { type: 'text' });
            this.lastExpanded = -1;
            this.dropTag = this.options.drop.attr || 'dropnode';
            this.treeDataOrig = [];
            this.pagination = { label: this.options.lang.paginated.main, id: this.options.rootStart, children: [], wrapEl: this.targetEl };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch (err) {
                err ? console.error(err) : console.warn(config.warn.init);
                return this;
            }
            this.output = { value: '', raw: '', items: [] };
            this.correctOpts();
            super.useTpl();
            this.searchs = [];
            this.floorMax = 0;
            this.chainChecking = false;
            this.seqItems = [];
            this.setFeature();
            this.maxIndex = this.options.idStart;
            if (this.options.bubble.enable) {
                let host = this.targetEl;
                this.receiver = getEl(this.options.output.target) || this.targetEl;
                (this.receiver.nodeName.includes('INPUT') || this.receiver.nodeName.includes('TEXTAREA')) && this.receiver.toggleAttribute('readonly', true);
                this.targetEl = createEl('div');
                let footParam = this.options.output.enable && !this.options.output.instant ? {
                    enable: true,
                    children: [
                        'close',
                        {
                            name: 'clear',
                            action: (resp) => {
                                resp.el.onclick = () => {
                                    this.clearVals();
                                };
                            },
                        },
                        {
                            name: 'confirm',
                            action: (resp) => {
                                resp.el.onclick = () => {
                                    this.setVals();
                                    this.bubbleIns.hide();
                                };
                            }
                        }
                    ]
                } : false;
                this.bubbleIns = new Function('host', 'module', 'options', `"use strict";return new module(host,options)`)(host, orca[capStart(this.options.bubble.type.trim())], Object.assign({
                    trigger: 'click',
                    content: this.targetEl,
                    contType: 'node',
                    placement: this.options.bubble.type === 'popup' ? 'bottom-start' : '',
                    footer: footParam,
                }, this.options.bubble));
            }
            else {
                this.receiver = getEl(this.options.output.target);
            }
            await this.getDataToRender();
            this.excludeDrags = !isEmpty(this.options.drag.exclude) ? findItems(this.options.drag.exclude, this.flatData) : [];
            this.setAttrs();
            this.setResult();
            this.renderFinish();
            super.initCheckeds();
            this.initExpandeds();
            this.initSelecteds();
            super.initDisableds();
            super.initReadonlys();
            this.updateResult(this.getVals().value);
            this.setSearch();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        correctOpts() {
            if (!isEmpty(this.options.value)) {
                if (this.options.output.from === 'checked') {
                    this.options.check.value = this.options.value;
                }
                else {
                    this.options.select.value = this.options.value;
                }
            }
        }
        setFeature() {
            if (!this.options.feature.type)
                return;
            extend({
                target: this.options,
                source: {
                    shortcut: {
                        enable: true,
                        mean: 'checked',
                        span: 'whole'
                    },
                    expand: { ...this.options.feature.expand },
                    check: {
                        enable: true,
                        ...this.options.feature.check
                    },
                    select: {
                        enable: false,
                    },
                    arrow: {
                        enable: !this.options.feature.expand.all || this.options.feature.expand.only ? true : false
                    },
                    output: {
                        from: 'checked'
                    },
                    layout: this.options.feature.layout[this.options.feature.type]
                }
            });
        }
        async sqlToAdd(item) {
            if (!this.options.content)
                return;
            let promise = treeTools.allToTree({
                content: this.options.content,
                contType: this.options.contType,
                contData: { pId: item.id, pLabel: item.label, pValue: item.value, ...this.options.sqlData },
                ajax: { spinSel: item.arrowEl, xhrName: 'contXhr' },
                ins: this,
                fill: false,
            });
            await promise.then(async (resp) => {
                let data = resp.hasOwnProperty('data') && Array.isArray(resp.data) ? resp.data : resp;
                await this.add({
                    data,
                    target: item,
                    isFront: false,
                    autoFill: !this.options.paginated.enable,
                });
                this.options.paginated.enable && this.turnFirstPage(item);
            });
        }
        async getDataToRender() {
            let base = {
                rootStart: this.options.rootStart,
                idStart: this.options.idStart,
                floorStart: this.options.floorStart,
            }, promise;
            if (this.options.content) {
                promise = treeTools.allToTree({
                    content: this.options.content,
                    contType: this.options.contType,
                    contData: this.options.contData,
                    ajax: { spinSel: this.targetEl, xhrName: 'contXhr' },
                    ins: this,
                    ...base
                });
            }
            else {
                promise = treeTools.allToTree({
                    content: this.targetEl.innerHTML,
                    ...base
                });
            }
            await promise.then((res) => {
                
                this.treeDataOrig = res.data && Array.isArray(res.data) ? res.data : res;
                this.rawData = res;
            });
            this.targetEl.innerHTML = '';
            await this.renderData(this.treeDataOrig);
            this.getTreeFlat();
            super.listen({ name: 'rendered', params: [this.treeData, this.flatData] });
            return this;
        }
        getTreeFlat() {
            this.treeData = this.getObserver(this.treeDataOrig).proxy;
            this.pagination.children = this.treeData;
            
            this.flatData = treeTools.toFlat(this.treeData);
        }
        getObserver(data) {
            this.observeIns = new Observe(data, {
                deep: {
                    enable: true,
                    exclude: ['tools'],
                },
                onSet: (obj) => {
                    if (obj.key === 'icon' && obj.proxy.iconEl) {
                        classes(obj.proxy.iconEl).replace(obj.raw, obj.value);
                    }
                    else if (obj.key === 'cube' && obj.proxy.cubeEl) {
                        obj.proxy.cubeEl.src = obj.value;
                    }
                    else if (obj.key === 'disk' && obj.proxy.diskEl) {
                        obj.proxy.diskEl.src = obj.value;
                    }
                    else if (obj.key === 'image' && obj.proxy.imageEl) {
                        obj.proxy.imageEl.src = obj.value;
                    }
                    else if (obj.key === 'label') {
                        obj.proxy.labelEl.innerHTML = obj.value;
                    }
                    else if (obj.key === 'tips' && obj.proxy.tipsEl) {
                        obj.proxy.tipsEl.innerHTML = obj.value;
                    }
                    else if (obj.key === 'brief' && obj.proxy.briefEl) {
                        super.updateElCont(obj.proxy, obj.value);
                    }
                    else if (obj.key === 'custom' && obj.proxy.customEl) {
                        super.updateElCont(obj.proxy, obj.value, 'custom');
                    }
                    else if (obj.key === 'badge' && obj.proxy.badgeEl) {
                        obj.proxy.badgeEl.setAttribute('label', obj.value);
                    }
                    else if (obj.key === 'href' && obj.proxy.labelEl.nodeName === 'A') {
                        obj.proxy.labelEl.href = obj.value;
                    }
                    else if (obj.key === 'rel' && obj.proxy.labelEl.nodeName === 'A') {
                        obj.proxy.labelEl.rel = obj.value;
                    }
                    else if (obj.key === 'target' && obj.proxy.labelEl.nodeName === 'A') {
                        obj.proxy.labelEl.target = obj.value;
                    }
                    else if (obj.key === 'onclilck') {
                        obj.proxy.labelEl.setAttribute(obj.key, obj.value);
                    }
                    else if (obj.key === 'floor') {
                        obj.proxy.indentHeadEl.innerHTML = obj.proxy.indentBodyEl.innerHTML = obj.proxy.indentFootEl.innerHTML = this.getIndentHtml(obj.value);
                        this.updateChildrenFloor(obj.proxy);
                    }
                    else if (obj.key === 'atEnd') ;
                    else if (obj.key === 'expanded' && obj.proxy.children) {
                        obj.proxy.arrowEl && super.toggleArrow(obj.value, obj.proxy);
                        this.toggleParentLegend(obj.proxy);
                    }
                    else if (obj.key === 'selected') {
                        obj.proxy.headEl.toggleAttribute('selected', obj.value);
                        this.updateSeqItems(obj, 'selected');
                    }
                    else if (obj.key === 'disabled') {
                        obj.proxy.headEl.toggleAttribute('disabled', obj.value);
                    }
                    else if (obj.key === 'readonly') {
                        obj.proxy.headEl.toggleAttribute('readonly', obj.value);
                    }
                    else if (obj.key === 'checked') {
                        obj.proxy.headEl.toggleAttribute('checked', obj.value);
                        obj.proxy.checkEl && obj.proxy.checkEl.setAttribute('check', obj.value ? 'ed' : '');
                        this.updateSeqItems(obj, 'checked');
                    }
                    else if (obj.key === 'children') {
                        if (!obj.raw && obj.value) {
                            this.child2Parent(obj.proxy);
                        }
                        else if (obj.raw && !obj.value) {
                            this.parent2Child(obj.proxy);
                        }
                    }
                },
                onDeleted: (obj) => {
                    if (obj.key === 'children') {
                        treeTools.parentToChild(obj.proxy);
                    }
                },
                onCompleted: (data) => {
                    ((data.keys.set.includes('selected') && this.options.output.from === 'selected')
                        ||
                            (data.keys.set.includes('checked') && this.options.output.from === 'checked'))
                        && this.updateVals();
                    if (this.options.check.enable && this.options.check.max) {
                        let checkeds = super.getCheckeds(), uncheckeds = super.getUncheckeds(), setDisabled = (data) => {
                            for (let k of data) {
                                !k.disabled && k.checkEl.toggleAttribute('disabled', true);
                                k.headEl.toggleAttribute('exceeded', true);
                            }
                        };
                        if (checkeds.length >= this.options.check.max) {
                            setDisabled(uncheckeds);
                            super.listen({ name: 'stopChecked', params: [uncheckeds] });
                        }
                        else if (checkeds.length <= this.options.check.min) {
                            setDisabled(checkeds);
                            super.listen({ name: 'stopUnchecked', params: [checkeds] });
                        }
                        else {
                            for (let k of this.flatData) {
                                k.checkEl.removeAttribute('disabled');
                                k.headEl.toggleAttribute('exceeded', false);
                            }
                            super.listen({ name: 'rechecked' });
                        }
                    }
                    if (this.options.storName) {
                        let tmp = {
                            select: { value: treeTools.getBoolItems(this.flatData, 'selected').map((k) => k.id) },
                            check: { value: treeTools.getBoolItems(this.flatData, 'checked').map((k) => k.id) },
                            expand: treeTools.getBoolItems(this.flatData, 'expanded').map((k) => k.id),
                            disable: treeTools.getBoolItems(this.flatData, 'disabled').map((k) => k.id),
                            readonly: treeTools.getBoolItems(this.flatData, 'readonly').map((k) => k.id),
                            content: !isEmpty(this.options.content) ? deepClone(this.treeDataOrig) : '',
                        };
                        super.updateCache(tmp);
                    }
                }
            });
            return this.observeIns;
        }
        updateSeqItems(data, type = 'selected') {
            this.options.output.from === type && splice({ host: this.seqItems, source: data.proxy, intent: data.value ? 'end+' : 'remove' });
            if (this.seqItems.length) {
                if ((type === 'checked' && this.options.check.type === 'radio') || (type === 'selected' && this.options.select.only)) {
                    this.seqItems = this.seqItems.slice(-1);
                }
            }
        }
        initExpandeds() {
            let vals = valToArr(this.options.expand.value).map((k) => findItem(k, this.flatData)).filter(Boolean), items = this.flatData.filter((k) => k.expanded && k.children), tmp = [...items, ...vals];
            for (let k of items)
                k.expanded = false;
            if (this.options.expand.all) {
                if (this.options.expand.only) {
                    let firsts = this.getParentsGroupBy(this.flatData);
                    for (let k in firsts) {
                        firsts[k][0] && super.expand(firsts[k][0]);
                    }
                }
                else {
                    super.expandAll();
                }
            }
            else {
                if (this.options.expand.only) {
                    let firsts = this.getParentsGroupBy(tmp);
                    for (let k in firsts) {
                        firsts[k][0] && super.expand(firsts[k][0]);
                    }
                }
                else {
                    super.expand(tmp);
                }
            }
        }
        initSelecteds() {
            if (!this.options.select.enable)
                return;
            let vals = valToArr(this.options.select.value).map((k) => findItem(k, this.flatData)).filter(Boolean), items = this.flatData.filter((k) => k.selected), tmp = [...items, ...vals];
            for (let k of items)
                k.selected = false;
            this.select(this.options.select.only ? tmp[0] : tmp);
        }
        getSelecteds() {
            return this.flatData.filter((k) => k.selected);
        }
        getParentsGroupBy(items, key = 'pId') {
            if (isEmpty(items))
                return [];
            return items.reduce((result, item) => {
                let groupKey = item[key];
                if (!result[groupKey]) {
                    result[groupKey] = [];
                }
                item.children && result[groupKey].push(item);
                return result;
            }, {});
        }
        getIndentHtml(floor) {
            return '<i></i>'.repeat(floor);
        }
        updateChildrenFloor(item) {
            if (item.children) {
                for (let k of item.children) {
                    k.floor = item.floor + 1;
                    this.updateChildrenFloor(k);
                }
            }
        }
        async renderData(data) {
            if (!data.length) {
                this.targetEl.innerHTML = `<div class="${orca.prefix}tree-empty">${this.options.lang.empty}</div>`;
                return;
            }
            let outer = createEl('ul');
            let plantTree = async (parent, data) => {
                let ul = createEl('ul', { class: `${orca.prefix}reset ${orca.prefix}tree-children` });
                for (let k of data) {
                    this.createHeadEl(k, parent);
                    await this.createBodyEl(k);
                    if (k.hasOwnProperty('children')) {
                        k.childrenEl = await plantTree(k, k.children);
                    }
                    
                    ((!this.options.deferred && !this.options.paginated.enable)
                        ||
                            (this.options.deferred && !this.options.paginated.enable && k.floor === this.options.floorStart)
                        ||
                            (this.options.paginated.enable && k.floor === this.options.floorStart && this.options.paginated.exception))
                        && ul.appendChild(k.wrapEl);
                }
                (parent.wrapEl || parent).appendChild(ul);
                parent.wrapEl && this.createFootEl(parent);
                return ul;
            };
            await plantTree(outer, data);
            this.resultEl = createEl('div', { class: `${orca.prefix}tree-result` });
            this.options.output.enable && !this.options.output.instant && this.targetEl.appendChild(this.resultEl);
            if (this.options.name) {
                this.inputEl = createEl('input', { type: 'hidden', name: this.options.name });
                this.targetEl.appendChild(this.inputEl);
            }
            this.pagination.childrenEl = outer.childNodes[0];
            super.listen({ name: 'insertItems', params: [data] });
            this.targetEl.appendChild(this.pagination.childrenEl);
            if (this.options.paginated.enable && !this.options.paginated.exception) {
                this.createFootEl(this.pagination);
            }
        }
        updateArrowEl(item) {
            if (!this.options.arrow.enable)
                return;
            if (item.hasOwnProperty('children')) {
                item.arrowEl.setAttribute('type', this.options.arrow.type);
                this.options.lang.title.arrow && item.arrowEl.setAttribute('title', this.options.lang.title.arrow);
                if (this.options.arrow.type === 'image') {
                    this.options.arrow.hide && (item.arrowEl.style.backgroundImage = `url("${this.options.arrow.hide}")`);
                }
                else {
                    item.arrowEl.classList.remove(`${orca.prefix}none`);
                    this.options.arrow.hide && item.arrowEl.classList.add(this.options.arrow.hide);
                }
            }
            else {
                item.arrowEl.removeAttribute('type');
                item.arrowEl.removeAttribute('title');
                if (this.options.arrow.type === 'image') {
                    item.arrowEl.removeAttribute('style');
                }
                else {
                    classes(item.arrowEl).remove([this.options.arrow.show, this.options.arrow.hide]).add(`${orca.prefix}none`);
                }
            }
        }
        async setBrief(target, data = {}, cb) {
            if (this.destroyed)
                return;
            let item = findItem(target, this.flatData);
            await this.createBodyEl(item, false);
            await super.setElCont({
                item,
                data,
                cb: (cont, target) => {
                    super.listen({ name: 'filled', cb, params: [cont, target] });
                }
            });
            return this;
        }
        setLegendVal(el, val, type = 'icon') {
            if (type === 'image') {
                el.removeAttribute('class');
                el.style.backgroundImage = `url("${val}")`;
            }
            else {
                el.removeAttribute('style');
                el.setAttribute('class', val);
            }
        }
        toggleParentLegend(item) {
            if (!this.options.legend.enable || item.legend || !Array.isArray(this.options.legend.parent) || !this.options.legend.parent[1])
                return;
            this.setLegendVal(item.legendEl, this.options.legend.parent[item.expanded ? 1 : 0], this.options.legend.type);
        }
        updateLegendEl(item) {
            if (!this.options.legend.enable)
                return;
            if (item.legend) {
                this.setLegendVal(item.legendEl, item.legend, this.options.legend.type);
            }
            else {
                if (item.hasOwnProperty('children')) {
                    this.setLegendVal(item.legendEl, this.options.legend.parent[item.expanded ? 1 : 0], this.options.legend.type);
                }
                else {
                    this.setLegendVal(item.legendEl, this.options.legend.child, this.options.legend.type);
                }
            }
        }
        getLegendEl(item) {
            item.legendEl = createEl('i', { [orca.alias]: 'legend' });
            this.updateLegendEl(item);
        }
        createHeadEl(item, parent) {
            if (item.wrapEl)
                return;
            item.wrapEl = createEl('li', { class: `${orca.prefix}tree-wrap` });
            item.groupEl = createEl('div', { [orca.alias]: 'group' });
            if (item.headEl) {
                if (!item.labelEl) {
                    item.labelEl = createEl(item.hasOwnProperty('href') ? 'a' : 'i', { [orca.alias]: 'label' }, item.label);
                    item.headEl.appendChild(item.labelEl);
                }
            }
            else {
                item.headEl = createEl('div', { class: `${orca.prefix}tree-head` });
                !item.labelEl && (item.labelEl = createEl(item.hasOwnProperty('href') ? 'a' : 'i', { [orca.alias]: 'label' }, item.label));
                item.headEl.appendChild(item.labelEl);
            }
            item.wrapEl.appendChild(item.headEl);
            item.href && (item.labelEl.href = item.href);
            item.target && (item.labelEl.target = item.target);
            item.indentHeadEl = createEl('span', { [orca.alias]: 'indent' });
            item.indentBodyEl = createEl('span', { [orca.alias]: 'indent' });
            item.indentFootEl = createEl('span', { [orca.alias]: 'indent' });
            item.indentHeadEl.innerHTML = item.indentBodyEl.innerHTML = item.indentFootEl.innerHTML = this.getIndentHtml(item.floor);
            item.onclick && item.labelEl.setAttribute('onclick', item.onclick);
            this.options.arrow.enable && super.getArrowEl(item);
            if (!item.iconEl) {
                item.iconEl = item.hasOwnProperty('icon') ? createEl('i', { [orca.alias]: 'icon', class: item.icon }) : null;
            }
            if (!item.diskEl) {
                item.diskEl = item.hasOwnProperty('disk') ? createEl('img', { [orca.alias]: 'disk', src: item.disk || orca.images.none }) : null;
            }
            if (!item.cubeEl) {
                item.cubeEl = item.hasOwnProperty('cube') ? createEl('img', { [orca.alias]: 'cube', src: item.cube || orca.images.none }) : null;
            }
            if (!item.imageEl) {
                item.imageEl = item.hasOwnProperty('image') ? createEl('img', { [orca.alias]: 'image', src: item.image || orca.images.none }) : null;
            }
            if (!item.badgeEl) {
                item.badgeEl = item.badge ? createEl('oc-badge', { [orca.alias]: 'badge', label: item.badge.toString().trim() }) : null;
            }
            if (!item.tipsEl) {
                item.tipsEl = item.tips ? createEl('i', { [orca.alias]: 'tips' }, item.tips) : null;
            }
            if (!item.customEl) {
                item.customEl = item.custom ? createEl('div', { [orca.alias]: 'custom' }, item.custom) : null;
            }
            item.expanded && item.headEl.toggleAttribute('expanded', true);
            item.selected && item.headEl.toggleAttribute('selected', true);
            item.disabled && item.headEl.toggleAttribute('disabled', true);
            item.readonly && item.headEl.toggleAttribute('readonly', true);
            item.checked && item.headEl.toggleAttribute('checked', true);
            this.options.drag.enable && item.headEl.toggleAttribute([this.dropTag], true);
            if (this.options.check.enable) {
                item.checkType = this.getCheckType(parent);
                item.checkEl = createEl(`oc-${item.checkType}`, { [orca.alias]: 'check' });
            }
            if (this.options.legend.enable) {
                this.getLegendEl(item);
            }
            if (this.options.tools.enable) {
                item.toolsEl = createTools(this.options.tools.children, item.headEl);
                item.toolsEl.setAttribute(orca.alias, 'tools');
                item.tools = deepClone(this.options.tools.children);
                for (let k of item.tools) {
                    this.options.lang.title[k.name] && k.wrapEl.setAttribute('title', this.options.lang.title[k.name]);
                    if (k.name === 'file') {
                        item.addfileEl = k.wrapEl;
                    }
                    else if (k.name === 'folder') {
                        item.addfolderEl = k.wrapEl;
                    }
                    else if (k.name === 'remove') {
                        item.removeEl = k.wrapEl;
                    }
                    else if (k.name === 'edit') {
                        item.editEl = k.wrapEl;
                    }
                }
            }
            super.parseLayout(item.headEl, this.options.layout, {
                indent: item.indentHeadEl,
                arrow: item.arrowEl,
                label: item.labelEl,
                check: item.checkEl,
                legend: item.legendEl,
                icon: item.iconEl,
                disk: item.diskEl,
                cube: item.cubeEl,
                image: item.imageEl,
                badge: item.badgeEl,
                tips: item.tipsEl,
                custom: item.customEl,
                tools: item.toolsEl,
                group: item.groupEl,
            });
        }
        async createBodyEl(item, autoFill = this.options.autoFill) {
            if (item.bodyEl)
                return;
            item.bodyEl = createEl('div', { class: `${orca.prefix}tree-body` });
            item.bodyEl.appendChild(item.indentBodyEl);
            item.indentBodyEl.insertAdjacentHTML('afterend', `<i  class="${orca.prefix}none"></i>`);
            if (!item.briefEl) {
                item.briefEl = createEl('div', { class: `${orca.prefix}tree-brief` });
                if (autoFill) {
                    
                    await super.getElCont({
                        target: item,
                        data: item.brief,
                        cb: (cont) => {
                            item.brief = cont;
                            super.updateElCont(item);
                        }
                    });
                }
            }
            item.bodyEl.appendChild(item.briefEl);
            item.headEl.insertAdjacentElement('afterend', item.bodyEl);
        }
        createFootEl(item) {
            if (!this.options.paginated.enable || item.pageEl)
                return;
            item.moreEl = createEl('i', { [orca.alias]: 'more' }, this.options.lang.paginated.more);
            item.nextEl = createEl('i', { [orca.alias]: 'next' }, this.options.lang.paginated.next);
            item.firstEl = createEl('i', { [orca.alias]: 'first' }, this.options.lang.paginated.first);
            item.infoEl = createEl('i', { [orca.alias]: 'info' });
            item.pageEl = createEl('div', { class: `${orca.prefix}tree-page` }, item.infoEl);
            this.options.paginated.override ? item.pageEl.append(item.nextEl, item.firstEl) : item.pageEl.appendChild(item.moreEl);
            item.footEl = createEl('div', { class: `${orca.prefix}tree-foot` });
            if (item !== this.pagination) {
                item.footEl.appendChild(item.indentFootEl);
                item.indentFootEl.insertAdjacentHTML('afterend', `<i  class="${orca.prefix}none"></i>`);
            }
            item.footEl.appendChild(item.pageEl);
            item.children && item.wrapEl.appendChild(item.footEl);
        }
        togglePgnDisabled(item) {
            if (this.options.paginated.enable) {
                item.moreEl.toggleAttribute('disabled', item.atEnd);
                item.nextEl.toggleAttribute('disabled', item.atEnd);
                item.firstEl.toggleAttribute('disabled', item.current == 1 ? true : false);
            }
        }
        turnNextPage(item, cb) {
            if (this.destroyed)
                return;
            let target = item === this.pagination ? this.pagination : findItem(item, this.flatData);
            if (!target)
                return;
            if (!this.options.paginated.enable || !target.children)
                return;
            let pages = Math.ceil(target.children.length / this.options.paginated.count);
            if (this.options.paginated.override) {
                if (target.current >= pages)
                    return;
                target.current = target.current || 1;
                let nextData = target.children.slice(target.current * this.options.paginated.count, (target.current + 1) * this.options.paginated.count);
                target.childrenEl.innerHTML = '';
                target.childrenEl.append(...nextData.map((k) => k.wrapEl));
                target.current++;
            }
            else {
                if (target.childrenEl.children.length >= target.children.length)
                    return;
                let curCount = target.childrenEl.children.length, nextData = target.children.slice(curCount, curCount + this.options.paginated.count);
                target.childrenEl.append(...nextData.map((k) => k.wrapEl));
                target.current = Math.ceil(target.childrenEl.children.length / this.options.paginated.count);
            }
            target.atEnd = (pages === target.current) ? true : false;
            this.togglePgnDisabled(target);
            this.updateInfoEl(target);
            super.listen({ name: 'turned', cb, params: [target] });
            return this;
        }
        turnFirstPage(item, cb) {
            if (this.destroyed)
                return;
            let target = item === this.pagination ? this.pagination : findItem(item, this.flatData);
            if (!target)
                return;
            if (!this.options.paginated.enable || !target.children)
                return;
            let firstData = target.children.slice(0, this.options.paginated.count);
            this.options.paginated.override && (target.childrenEl.innerHTML = '');
            target.childrenEl.append(...firstData.map((k) => k.wrapEl));
            target.current = 1;
            target.atEnd = (target.childrenEl.children.length === target.children.length) ? true : false;
            this.togglePgnDisabled(target);
            this.updateInfoEl(target);
            super.listen({ name: 'turned', cb, params: [target] });
            return this;
        }
        updateInfoEl(item) {
            if (!this.options.paginated.enable)
                return;
            let total = item.children.length, pages = Math.ceil(total / this.options.paginated.count), current = item.current, rest = Math.max(total - current * this.options.paginated.count, 0), obj = { total, current, pages, rest, count: this.options.paginated.count, label: item.label, id: item.id };
            item.infoEl.innerHTML = renderTpl(this.options.lang.paginated.info, obj);
        }
        createChildrenEl(item) {
            if (item.childrenEl)
                return;
            item.childrenEl = createEl('ul', { class: `${orca.prefix}reset ${orca.prefix}tree-children` });
            let target = item.hasOwnProperty('brief') ? item.bodyEl : item.headEl;
            target.insertAdjacentElement('afterEnd', item.childrenEl);
        }
        child2Parent(item) {
            this.createChildrenEl(item);
            this.updateArrowEl(item);
            this.updateLegendEl(item);
            this.updateEvt(item);
        }
        parent2Child(item) {
            item.childrenEl.remove();
            this.updateArrowEl(item);
            this.updateLegendEl(item);
            this.updateEvt(item);
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}tree`);
            this.options.classes && classes(this.targetEl).add(this.options.classes);
            this.targetEl.toggleAttribute('inert', this.options.passive);
            this.targetEl.setAttribute('tools-trigger', this.options.tools.trigger);
            this.targetEl.toggleAttribute('chain', this.options.chain);
            this.options.feature.type && this.targetEl.setAttribute('feature', this.options.feature.type);
            this.options.check.enable ? this.targetEl.setAttribute('check', this.options.check.span) : this.targetEl.removeAttribute('check');
            this.options.select.enable ? this.targetEl.setAttribute('select', this.options.select.span) : this.targetEl.removeAttribute('select');
        }
        setDragDrop(item) {
            if (!this.options.drag.enable || item.disabled || this.excludeDrags.includes(item))
                return;
            item.dragIns = new Drag(item.wrapEl, extend({
                target: {
                    drops: `[${this.dropTag}]`,
                    handle: item.headEl,
                    purpose: 'auto',
                    parent: !this.options.drop.global ? this.targetEl : null,
                    gesture: {
                        unbound: [item.toolsEl]
                    },
                    onDropped: (data) => {
                        if (data.point === 'before') {
                            this.graft({ source: data.from, target: data.to, isFront: true, isChild: false });
                        }
                        else if (data.point === 'after') {
                            this.graft({ source: data.from, target: data.to, isFront: false, isChild: false });
                        }
                        else if (data.point === 'inside') {
                            this.graft({ source: data.from, target: data.to, isFront: true, isChild: true });
                        }
                    }
                },
                source: this.options.drag,
            }));
        }
        updateExpandEvt(k) {
            if (k.children) {
                if (k.arrowEl) {
                    if (this.options.arrow.trigger === 'click') {
                        k.arrowEl.removeEventListener('click', this.expandEvt);
                        k.arrowEl.addEventListener('click', this.expandEvt, false);
                    }
                    else if (this.options.arrow.trigger === 'hover') {
                        k.hoverIns && k.hoverIns.destroy();
                        k.hoverIns = new Hover(k.arrowEl, {
                            onMove: (isIn) => {
                                !isIn && this.options.expand.only ? super.collapse(k) : null;
                            },
                            onEnter: () => {
                                super.expand(k);
                            },
                            onLeave: () => {
                                super.collapse(k);
                            }
                        });
                    }
                }
                if (k.legendEl) {
                    k.legendEl.removeEventListener('click', this.expandEvt);
                    k.legendEl.addEventListener('click', this.expandEvt, false);
                }
            }
            else {
                if (this.options.arrow.trigger === 'click') {
                    k.arrowEl && k.arrowEl.removeEventListener('click', this.expandEvt);
                }
                else if (this.options.arrow.trigger === 'hover') {
                    k.hoverIns && k.hoverIns.destroy();
                }
                k.legendEl && k.legendEl.removeEventListener('click', this.expandEvt);
            }
        }
        updateEvt(k) {
            if (this.options.paginated.enable && k.children) {
                this.turnFirstPage(k);
                k.moreEl.onclick = () => this.turnNextPage(k);
                k.nextEl.onclick = k.moreEl.onclick;
                k.firstEl.onclick = () => this.turnFirstPage(k);
            }
            this.updateExpandEvt(k);
            k.labelEl.removeEventListener('click', this.selectEvt);
            k.labelEl.addEventListener('click', this.selectEvt, false);
            if (k.toolsEl) {
                if (k.removeEl) {
                    k.removeEl.onclick = () => {
                        if (k.readonly)
                            return;
                        this.remove(k);
                    };
                }
                if (k.editEl) {
                    k.editEl.onclick = () => {
                        if (k.readonly)
                            return;
                        this.inputLabel(k);
                    };
                }
                if (k.addfileEl) {
                    k.addfileEl.onclick = () => {
                        if (k.readonly)
                            return;
                        this.add({ target: k, isChild: true, expand: true });
                    };
                }
                if (k.addfolderEl) {
                    k.addfolderEl.onclick = () => {
                        if (k.readonly)
                            return;
                        this.add({ target: k, isChild: true, isLeaf: false, expand: true });
                    };
                }
                for (let [i, o] of this.options.tools.children.entries()) {
                    let tool = k.tools[i], refer = { ins: this, item: k };
                    o.action && o.action.call(refer, tool);
                    tool.action && tool.action.call(refer, tool);
                }
            }
            if (this.options.shortcut.enable) {
                k.headEl.removeEventListener('click', this.lineEvt);
                k.headEl.addEventListener('click', this.lineEvt, false);
            }
            k.disabled && k.headEl.toggleAttribute('disabled', true);
            k.readonly && k.headEl.toggleAttribute('readonly', true);
            if (this.options.check.enable) {
                k.checkEl.on('check', async (val) => {
                    !this.chainChecking && val.checked !== k.checked && await this.check(k, val.checked);
                });
            }
            if (this.options.drag.enable) {
                !k.dragIns && this.setDragDrop(k);
            }
            if (this.options.check.enable) {
                if (this.options.check.span === 'leaf') {
                    k.children && (k.checkEl.toggleAttribute('disabled', true), k.headEl.toggleAttribute('uncheckable', true));
                }
                else if (this.options.check.span === 'branch') {
                    !k.children && (k.checkEl.toggleAttribute('disabled', true), k.headEl.toggleAttribute('uncheckable', true));
                }
            }
            if (this.options.select.enable) {
                if (this.options.select.span === 'leaf') {
                    k.children && k.headEl.toggleAttribute('unselectable', true);
                }
                else if (this.options.select.span === 'branch') {
                    !k.children && k.headEl.toggleAttribute('unselectable', true);
                }
            }
            k.action && k.action.call(this, k);
        }
        renderFinish() {
            for (let k of this.flatData) {
                this.updateEvt(k);
            }
            if (this.options.paginated.enable && !this.options.paginated.exception) {
                this.turnFirstPage(this.pagination);
                this.pagination.moreEl.onclick = () => this.turnNextPage(this.pagination);
                this.pagination.nextEl.onclick = this.pagination.moreEl.onclick;
                this.pagination.firstEl.onclick = () => this.turnFirstPage(this.pagination);
            }
        }
        getDrops() {
            return isEmpty(this.options.drag.drops) ? this.flatData.map((k) => !k.disabled ? k.headEl : null).filter(Boolean) :
                this.options.drag.value.map((k) => findItem(k, this.flatData)).filter((k) => k && !k.disabled).map((k) => k.headEl);
        }
        getReadonly() {
            return this.flatData.find((k) => k.readonly);
        }
        getTriggerEl(item) {
            return (item.href && item.arrowEl ? item.arrowEl : item.headEl);
        }
        addTrigger(item, target) {
            if (item.children) {
                if (!item.disabled) {
                    let triggerEl = target || this.getTriggerEl(item);
                    if (this.options.arrow.trigger === 'click') {
                        triggerEl.removeEventListener('click', this.expandEvt);
                        triggerEl.addEventListener('click', this.expandEvt, false);
                    }
                    else if (this.options.arrow.trigger === 'hover') {
                        this.hoverIns ? this.hoverIns.destroy() : null;
                        this.hoverIns = new Hover(item.wrapEl, {
                            onEnter: () => {
                                super.expand(item);
                                super.listen({ name: 'trigger', params: [item] });
                            },
                            onLeave: () => {
                                super.collapse(item);
                            }
                        });
                    }
                }
            }
            else {
                if (!item.disabled) {
                    item.headEl.removeEventListener('click', this.selectEvt);
                    item.headEl.addEventListener('click', this.selectEvt, false);
                }
            }
        }
        removeTrigger(item, target) {
            if (item.children) {
                if (!item.disabled) {
                    let triggerEl = target || this.getTriggerEl(item);
                    if (this.options.arrow.trigger === 'click') {
                        triggerEl.removeEventListener('click', this.expandEvt);
                    }
                    else if (this.options.arrow.trigger === 'hover') {
                        this.hoverIns ? this.hoverIns.destroy() : null;
                    }
                }
            }
            else {
                if (!item.disabled) {
                    item.headEl.removeEventListener('click', this.selectEvt);
                }
            }
        }
        toggleExpanded(data) {
            if (this.destroyed)
                return;
            let item = findItem(data, this.flatData);
            if (!item || !item.children)
                return;
            item.expanded ? super.collapse(item) : super.expand(item);
            super.listen({ name: 'trigger', params: [item] });
        }
        toggleSelected(data) {
            let item = findItem(data, this.flatData);
            if (!item || item.headEl.hasAttribute('editing') || !this.options.select.enable)
                return;
            if (item.selected) {
                this.deselect(item);
            }
            else {
                this.select(item);
                this.options.select.only && this.deselect(this.flatData.filter((k) => k !== item && k.selected));
            }
        }
        async eachCollapse(data, cb) {
            if (isNull(data))
                return;
            try {
                if (this.options.b4Collapse) {
                    let resp = await this.options.b4Collapse.call(this, data);
                    resp && (data = resp);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('Branch collapsing has been prevented!');
                return;
            }
            let item = findItem(data, this.flatData);
            if (!item || !item.children || !elState(item.childrenEl).isVisible || item.childrenEl.style.height)
                return;
            super.listen({ name: 'collapse', cb, params: [item] });
            item.expanded = false;
            slideUp({
                el: item.childrenEl,
                duration: this.options.duration,
                done: () => {
                    super.listen({ name: 'collapsed', cb, params: [item] });
                }
            });
        }
        async eachExpand(data, cb) {
            if (isNull(data))
                return;
            let item = findItem(data, this.flatData);
            if (!item || !item.children || elState(item.childrenEl).isVisible)
                return;
            try {
                if (this.options.b4Expand) {
                    let resp = await this.options.b4Expand.call(this, data);
                    resp && (data = resp);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('Branch expansion has been prevented!');
                return;
            }
            super.listen({ name: 'expand', cb, params: [item] });
            if (!item.children.length && !isEmpty(this.options.contData) && this.options.contType === 'async') {
                await this.sqlToAdd(item);
            }
            else {
                if (this.options.deferred && !item.childrenEl.firstElementChild) {
                    item.arrowEl && item.arrowEl.toggleAttribute('spinning', true);
                    this.options.paginated.enable ? this.turnFirstPage(item) : item.childrenEl.append(...item.children.map((k) => k.wrapEl));
                    item.arrowEl && item.arrowEl.removeAttribute('spinning');
                }
            }
            item.expanded = true;
            this.options.expand.linkage && this.expandParents(item);
            this.lastExpanded = item.id;
            slideDown({
                el: item.childrenEl,
                duration: this.options.duration,
                done: () => {
                    super.listen({ name: 'expanded', cb, params: [item] });
                }
            });
            if (this.options.expand.only) {
                let others = this.flatData.filter((k) => (k !== item && k.expanded && k.floor === item.floor && k.children));
                for (let k of others)
                    super.collapse(k);
            }
        }
        floatDown(obj) {
            if (!obj.hasOwnProperty('children') || !Array.isArray(obj.children))
                return;
            let enables = obj.children.filter((k) => !k.disabled), type = this.getCheckType(obj);
            for (let k of enables) {
                if (obj.checked) {
                    type === 'checkbox' && (k.checked = true);
                }
                else {
                    k.checked = false;
                }
                k.hasOwnProperty('children') && this.floatDown(k);
            }
        }
        floatUp(obj) {
            if (obj.floor === this.options.floorStart)
                return;
            let parents = treeTools.getParentsFromPath({ path: obj.path, flatData: this.flatData, pathHyphen: this.options.pathHyphen, pop: true }).parents.reverse(), setCheck = (item, enables, type) => {
                if (type === 'checkbox') {
                    if (enables.every((k) => !k.checked)) {
                        item.checked = false;
                        item.checkEl.setAttribute('check', '');
                    }
                    else if (enables.every((k) => k.checked)) {
                        item.checked = true;
                        item.checkType === 'radio' && this.uncheckSibings(item);
                    }
                    else {
                        item.checked = false;
                        item.checkEl.setAttribute('check', 'ing');
                    }
                }
                else if (type === 'radio') {
                    if (enables.some((k) => k.checked)) {
                        item.checked = true;
                        item.checkType === 'radio' && this.uncheckSibings(item);
                    }
                    else {
                        item.checked = false;
                        item.checkEl.setAttribute('check', item.children.some((k) => k.checkEl.properties.check === 'ing') ? 'ing' : '');
                    }
                }
            };
            for (let i of parents) {
                let enables = i.children.filter((k) => !k.disabled), type = this.getCheckType(i);
                setCheck(i, enables, type);
            }
        }
        eachCheck(item) {
            this.chainChecking = true;
            this.floatDown(item);
            this.floatUp(item);
            this.chainChecking = false;
        }
        getCheckType(parent) {
            return parent?.childType || (['checkbox', 'radio'].includes(this.options.check.type) ? this.options.check.type : 'checkbox');
        }
        uncheckSibings(item) {
            this.chainChecking = true;
            let siblings = super.getSiblings(item).filter((k) => k.checked);
            for (let k of siblings) {
                k.checked = false;
                this.options.check.linkage && this.floatDown(k);
            }
            this.chainChecking = false;
        }
        expandParents(data, cb) {
            let tmp = findItems(data, this.flatData), items = tmp.map((k) => findItem(k, this.flatData)).filter(Boolean), pSet = [];
            if (items.length) {
                let parents = [];
                for (let k of items) {
                    let p = treeTools.getParentsFromPath({ path: k.path, flatData: this.flatData, field: 'id', pathHyphen: this.options.pathHyphen }).parents;
                    p.pop();
                    parents.push(...p);
                }
                pSet = unique(parents);
                for (let k of pSet)
                    super.expand(k);
            }
            cb && cb(pSet);
        }
        select(data, flag = true, cb) {
            if (this.destroyed || !this.options.select.enable || isNull(data))
                return;
            let tmp = findItems(data, this.flatData), items = tmp.map((k) => findItem(k, this.flatData)).filter((k) => !k.selected === flag && (this.options.select.span === 'leaf' ? !k.children : this.options.select.span === 'branch' ? k.children : true)), param = items, fn = (obj) => {
                if (obj.headEl.hasAttribute('editing') || obj.headEl.hasAttribute('unselectable') || obj.selected)
                    return;
                obj.selected = true;
            };
            if (!items.length)
                return;
            if (flag) {
                if (this.options.select.only) {
                    let item = items[0];
                    if (item) {
                        fn(item);
                        this.deselect(this.flatData.filter((k) => k !== item && k.selected));
                    }
                    param = [item];
                }
                else {
                    this.saveRaw();
                    for (let k of items)
                        fn(k);
                }
                this.options.select.linkage && this.expandParents(param);
            }
            else {
                this.deselect(items);
            }
            super.listen({ name: flag ? 'selected' : 'deselected', cb, params: [param] });
            return this;
        }
        selectAll(cb) {
            if (this.destroyed || !this.options.select.enable || this.options.select.only)
                return;
            this.select(this.flatData);
            super.listen({ name: 'selectedAll', cb });
            return this;
        }
        deselectAll(cb) {
            if (this.destroyed || !this.options.select.enable)
                return;
            this.select(this.flatData, false);
            super.listen({ name: 'deselectedAll', cb });
            return this;
        }
        deselect(data) {
            if (isNull(data))
                return;
            let items = Array.isArray(data) ? data : [data], fn = (obj) => {
                if (!obj.selected)
                    return;
                obj.selected = false;
            };
            this.saveRaw();
            for (let k of items)
                fn(k);
        }
        checkOnlyone(item) {
            this.saveRaw();
            item.checked = true;
            this.chainChecking = true;
            let others = this.flatData.filter((k) => k !== item);
            for (let k of others) {
                k.checked = false;
                k.checkEl && k.checkEl.removeAttribute('check');
            }
            this.chainChecking = false;
        }
        async check(data, flag = true, cb) {
            if (this.destroyed)
                return;
            let filters = findItems(data, this.flatData), items = filters.filter((k) => !k.checked === flag && (flag ? (this.options.check.span === 'leaf' ? !k.children : this.options.check.span === 'branch' ? !!k.children : true) : true)), fn = (obj) => {
                obj.checked = flag;
                flag && obj.checkType === 'radio' && this.uncheckSibings(obj);
                this.options.check.linkage && this.eachCheck(obj);
            };
            if (!items.length)
                return;
            if (this.options.check.max) {
                try {
                    let param = { data: items, source: this.getCheckeds(), min: this.options.check.min, max: this.options.check.max, sliced: this.options.check.sliced }, resp = await (flag ? this.moreExceed(param) : this.lessExceed(param));
                    resp && (items = resp);
                }
                catch {
                    return;
                }
            }
            if (flag && this.options.check.only) {
                this.checkOnlyone(items[0]);
            }
            else {
                this.saveRaw();
                for (let k of items)
                    fn(k);
            }
            
            super.listen({ name: flag ? 'checked' : 'unchecked', cb, params: [items] });
            return this;
        }
        checkAll(cb) {
            if (this.destroyed || !this.options.check.enable || this.options.check.type !== 'checkbox' || this.options.check.only)
                return;
            this.saveRaw();
            for (let k of this.flatData) {
                k.checked = true;
            }
            super.listen({ name: 'checkedAll', cb });
            return this;
        }
        async add(options) {
            if (this.destroyed)
                return;
            
            let opts = Object.assign({ isChild: true, isFront: true, repeat: true, isLeaf: true, autoFill: true, expand: true, }, options), type = getDataType(opts.data), target = findItem(opts.target, this.flatData), brother = findItem(opts.brother, this.flatData), tmp = [], items = [], appendFun = async (data) => {
                let obj = treeTools.createBranchObj({
                    source: data,
                    flatData: this.flatData,
                    target,
                    isLeaf: opts.isLeaf,
                    isChild: opts.isChild
                });
                this.createHeadEl(obj);
                await this.createBodyEl(obj);
                this.createFootEl(obj);
                this.createChildrenEl(obj);
                super.listen({ name: 'insertItem', params: [obj] });
                treeTools.addBranch({
                    source: obj,
                    rootEl: this.targetEl,
                    flatData: this.flatData,
                    treeData: this.treeData,
                    brother: target && !opts.isChild ? target : brother,
                    isFront: opts.isFront,
                    repeat: opts.repeat,
                    autoFill: opts.autoFill,
                    cb: (item) => {
                        items.push(item);
                        this.updateEvt(item);
                    }
                });
            };
            tmp = isNull(opts.data) ? [null] : ((type === 'Array' && opts.data.length > 0) ? opts.data : [opts.data]);
            try {
                let resp = await super.moreExceed({ data: tmp, source: this.flatData });
                resp && (tmp = resp);
            }
            catch {
                return;
            }
            for (let k of tmp) {
                try {
                    if (this.options.b4Add) {
                        let resp = await this.options.b4Add.call(this, k);
                        resp && (k = resp);
                    }
                }
                catch (err) {
                    err ? console.error(err) : console.warn(`Adding new branche (${JSON.stringify(k)}) has been prevented!`);
                    continue;
                }
                await appendFun(k);
            }
            if (items.length > 0) {
                this.flatData = treeTools.toFlat(this.treeData);
                opts.isChild && opts.expand && target && this.eachExpand(target);
                if (this.options.select.enable && this.options.select.addSelected) {
                    if (!this.options.select.only) {
                        for (let k of items)
                            this.select(k);
                    }
                    else {
                        this.select(items.at(-1));
                    }
                }
            }
            super.listen({ name: 'added', cb: opts.cb, params: [items, target] });
            return this;
        }
        async remove(data, cb) {
            if (this.destroyed || isNull(data) || !this.flatData.length)
                return;
            if (this.flatData.length === 0) {
                console.warn('The source data is already empty!');
                return;
            }
            let tmp = [], items = [], removeItem = (child) => {
                treeTools.removeBranch({
                    source: child,
                    flatData: this.flatData,
                    treeData: this.treeData,
                    remove: false,
                    cb: (obj) => {
                        items.push(obj);
                        setTimeout(() => {
                            let parent = this.flatData.find((k) => k.id === obj.pId);
                            parent && !parent.children.length && super.collapse(parent);
                        }, 0);
                    }
                });
            };
            tmp = findItems(data, this.flatData);
            try {
                let resp = await super.lessExceed({ data: tmp, source: this.flatData });
                resp && (tmp = resp);
            }
            catch {
                return;
            }
            for (let k of tmp) {
                try {
                    if (this.options.b4Remove) {
                        let resp = await this.options.b4Remove.call(this, k);
                        resp && (k = resp);
                    }
                }
                catch (err) {
                    err ? console.error(err) : console.warn(`Removing old branch (${JSON.stringify(k)}) has been prevented!`);
                    continue;
                }
                removeItem(k);
            }
            this.flatData = treeTools.toFlat(this.treeData);
            super.listen({ name: 'removed', cb, params: [items] });
            return this;
        }
        search(value, opts = {}, cb) {
            if (this.destroyed || !this.flatData.length)
                return;
            let hyphen = config.splitHyphen;
            if (typeof value === 'string') {
                let tmp = value.trim();
                hyphen = tmp.includes('，') ? '，' : tmp.includes(',') ? ',' : tmp.includes(' ') ? ' ' : config.splitHyphen;
            }
            let keys = valToArr(value, hyphen, false).map((k) => clearRegx(k)).filter(Boolean);
            if (!keys.length) {
                for (let k of this.searchs) {
                    k.labelEl.innerHTML = k.label;
                }
                if (!isEmpty(this.ignores)) {
                    for (let k of this.ignores)
                        k.wrapEl.classList.remove(`${orca.prefix}d-none`);
                }
                this.searchs = [];
                this.ignores = [];
            }
            else {
                let tmp = this.searchs;
                this.searchs = arrSearch(Object.assign({ keys, props: 'label', source: this.flatData }, { fuzzy: this.options.search.fuzzy, ignore: this.options.search.ignore }, opts)).map((k) => k.source);
                for (let k of this.searchs) {
                    k.labelEl.innerHTML = super.replaceMult(k.label, keys);
                }
                if (!isEmpty(tmp)) {
                    for (let k of tmp) {
                        if (!this.searchs.includes(k)) {
                            k.labelEl.innerHTML = k.label;
                        }
                    }
                }
                this.expandParents(this.searchs, (p) => {
                    let currents = unique([...p, ...this.searchs]);
                    this.ignores = this.flatData.filter((k) => !currents.includes(k));
                    for (let k of this.ignores)
                        k.wrapEl.classList.add(`${orca.prefix}d-none`);
                    for (let k of currents)
                        k.wrapEl.classList.remove(`${orca.prefix}d-none`);
                });
            }
            super.updateCache({ search: { value: keys } });
            super.listen({ name: 'searched', cb, params: [this.searchs, keys] });
            return this;
        }
        inputLabel(item) {
            let headEl = item.headEl, labelEl = item.labelEl;
            if (headEl.hasAttribute('editing'))
                return;
            headEl.toggleAttribute('editing', true);
            labelEl.innerHTML = '';
            labelEl.appendChild(this.editorEl);
            this.editorEl.focus();
            this.editorEl.value = item.label;
            this.editorEl.onblur = async () => {
                let value = this.editorEl.value;
                try {
                    if (this.options.b4Edit) {
                        let resp = await this.options.b4Edit.call(this, { key: 'label', value }, item);
                        resp && (value = resp);
                    }
                    item.label = value;
                    headEl.removeAttribute('editing');
                }
                catch (err) {
                    item.labelEl.innerHTML = item.label;
                    headEl.removeAttribute('editing');
                    err ? console.error(err) : console.warn(`No changes have been made to the label property!`);
                    return;
                }
                super.listen({ name: 'edited', params: [item] });
            };
            this.editorEl.onkeyup = (e) => {
                (e.code === 'Enter') && this.editorEl.blur();
            };
        }
        async edit(item, data, cb) {
            if (this.destroyed || isNull(item) || isEmpty(data) || !this.flatData.length) {
                return this;
            }
            let source = findItem(item, this.flatData);
            if (!source)
                return this;
            for (let k in data) {
                let val = data[k];
                try {
                    if (this.options.b4Edit) {
                        let resp = await this.options.b4Edit.call(this, { key: k, value: val }, source);
                        resp && (val = resp);
                    }
                    if (k === 'action') {
                        source[k] = val.call({ ins: this, item: k }, source);
                    }
                    else if (['icon', 'disk', 'cube', 'onclick', 'href', 'target', 'rel', 'label', 'brief', 'tips', 'badge'].includes(k)) {
                        source[k] = val;
                    }
                }
                catch (err) {
                    err ? console.error(err) : console.warn(`No changes have been made to the ${k} property!`);
                    return this;
                }
            }
            super.listen({ name: 'edited', cb, params: [source] });
            return this;
        }
        async graft({ source, target, isFront = true, isChild = true, cb }) {
            if (this.destroyed || isNull(source))
                return;
            try {
                if (this.options.b4Graft) {
                    let resp = await this.options.b4Graft.call(this, source, target);
                    resp && resp.source && (source = resp.source);
                    resp && resp.target && (source = resp.target);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn(`The branch relationship between source and target in the tree remains unchanged!`);
                return this;
            }
            let sourceObj = findItem(source, this.flatData, '', { node: 'wrapEl' }), targetObj = findItem(target, this.flatData);
            if (!sourceObj)
                return;
            treeTools.graftBranch({
                source: sourceObj,
                target: targetObj,
                isFront,
                isChild,
                flatData: this.flatData,
                treeData: this.treeData,
                rootEl: this.targetEl,
                cb: (obj, refer) => {
                    refer && refer.children && isChild && this.eachExpand(refer);
                    this.flatData = treeTools.toFlat(this.treeData);
                    super.listen({ name: 'grafted', cb, params: [obj, refer] });
                    return this;
                }
            });
            return this;
        }
        setSearch() {
            !isEmpty(this.options.search.value) && this.search(this.options.search.value);
            this.searchEl = getEl(this.options.search.target);
            if (this.searchEl) {
                if (this.searchEl[orca.compSign]) {
                    this.searchEl.on(this.options.search.trigger, this.searchEvgt);
                }
                else {
                    this.searchEl.addEventListener(this.options.search.trigger, this.searchEvgt, false);
                }
            }
        }
        setResult() {
            if (!this.options.output.enable || this.options.output.instant)
                return;
            this.resultIns = this.resultIns || new Tags(this.resultEl, {
                content: '',
                size: 'sm',
                type: 'plain',
                removable: true,
                empty: { enable: true, content: this.options.lang.result },
            });
            this.resultIns.on('removed', async (items) => {
                for (let k of items) {
                    let tmp = k.label.split(this.options.output.connector);
                    for (let i of tmp) {
                        this.options.output.form === 'checked' ? await this.check(i, false) : this.select(i, false);
                    }
                }
            });
        }
        updateVals() {
            if (!this.options.output.enable)
                return;
            let { value, items } = this.getVals();
            this.updateResult(value);
            this.options.name && (this.inputEl.value = value);
            this.output.value = value;
            this.output.items = items;
            super.listen({ name: 'output', params: [this.output] });
            if (!this.options.output.instant)
                return;
            this.setVals();
        }
        saveRaw() {
            this.output.raw = this.getVals().value;
        }
        updateResult(val) {
            this.resultIns && (val ? this.resultIns.updateCont(val.split(this.options.output.separator)) : this.resultIns.clear());
        }
        clearResult() {
            this.resultIns && this.resultIns.clear();
        }
        setVals(target = this.receiver, cb) {
            if (this.destroyed)
                return;
            let receiver = getEl(target), val = this.getVals().value;
            fieldTools.setVals({ target: receiver, value: val });
            super.listen({ name: 'set', cb, params: [val] });
            return this;
        }
        clearVals(all = false, cb) {
            if (this.destroyed || !this.flatData.length)
                return this;
            if (all) {
                super.uncheckAll();
                this.deselectAll();
            }
            else {
                this.options.output.from === 'checked' ? super.uncheckAll() : this.deselectAll();
            }
            this.value = '';
            this.clearResult();
            super.listen({ name: 'cleared', cb });
            return this;
        }
        getVals(opt = {}, cb) {
            if (this.destroyed)
                return this;
            let options = Object.assign({ ...this.options.output, isStr: true }, opt), items = this.getValItems(options.from), result = [];
            if (options.type === 'chain') {
                result = items.map((k) => {
                    let tmp = treeTools
                        .getParentsFromPath({ path: k.path, flatData: this.flatData, pathHyphen: this.options.pathHyphen, labelHyphen: options.connector, field: options.field })
                        .parents
                        .map((k) => k[options.field]);
                    return options.isStr ? tmp.join(options.connector) : tmp;
                });
            }
            else {
                let tmp = (options.type === 'leaf') ? items.filter((k) => !k.children) : (options.type === 'branch') ? items.filter((k) => k.children) : items;
                result = tmp.map((k) => k[options.field]);
            }
            let value = options.isStr ? result.join(options.separator) : result;
            super.listen({ name: 'got', cb, params: [value] });
            return { value, items };
        }
        getValItems(from = 'selected') {
            return !this.options.output.autosort ? this.seqItems : (from === 'checked' ? super.getCheckeds() : this.getSelecteds());
        }
        
        async updateCont(content, cb) {
            if (this.destroyed)
                return this;
            await getContent.call(this, {
                content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: {
                    xhrName: 'contXhr',
                    ...this.options.ajax
                },
                request: (data) => {
                    this.listen({ name: 'request', params: [data] });
                },
                cb: async (data) => {
                    if (Array.isArray(data)) {
                        this.treeDataOrig = deepClone(data);
                        treeTools.addIdPath({ source: this.treeDataOrig });
                        this.targetEl.innerHTML = '';
                        await this.renderData(this.treeDataOrig);
                        this.getTreeFlat();
                        this.renderFinish();
                        super.updateCache({ content });
                        super.listen({ name: 'updatedCont', cb, params: [this.treeDataOrig] });
                    }
                }
            });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            for (let k of this.flatData) {
                if (k.children) {
                    if (this.options.arrow.trigger === 'click') {
                        let triggerEl = k.hasOwnProperty('href') && k.arrowEl ? k.arrowEl : k.headEl;
                        triggerEl.removeEventListener('click', this.expandEvt);
                    }
                    else if (this.options.arrow.trigger === 'hover') {
                        this.hoverIns.destroy();
                    }
                    k.legendEl && k.legendEl.removeEventListener('click', this.expandEvt);
                }
                !k.children && k.headEl.removeEventListener('click', this.selectEvt);
                this.options.shortcut.enable && k.headEl.removeEventListener('click', this.lineEvt);
                this.options.drag.enable && k.dragIns.destroy();
                if (this.options.paginated.enable && !this.options.deferred) {
                    k.moreEl.onclick = null;
                    k.nextEl.onclick = null;
                    k.firstEl.onclick = null;
                }
            }
            this.resultIns && this.resultIns.destroy();
            if (this.searchEl) {
                if (this.searchEl[orca.compSign]) {
                    this.searchEl.off(this.options.search.trigger, this.searchEvgt);
                }
                else {
                    this.searchEl.removeEventListener(this.options.search.trigger, this.searchEvgt);
                }
            }
            this.contXhr && this.contXhr.abort();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    class Menu extends ModBaseListenCache {
        options = {};
        flatData;
        treeData;
        expandEvt;
        selectEvt;
        pageEvt;
        lastExpanded;
        treeDataOrig;
        drawerHost;
        drawerIns;
        treeIns;
        hoverIns;
        contXhr;
        observeIns;
        static hostType = 'node';
        static optMaps = optMenu$1;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Menu.optMaps,
                component: true,
                spread: ['arrow', 'nav']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            
            let _this = this;
            this.pageEvt = function (event) {
                if (!contains(event.target, _this.targetEl)) {
                    _this.treeIns.collapseAll();
                }
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setAttrs();
            this.getTree();
            await this.treeIns.init();
            this.drawerHost = getEl(this.options.drawer.host);
            if (this.drawerHost) {
                this.drawerIns = new Drawer(this.drawerHost, Object.assign({
                    content: this.targetEl,
                    contType: 'node',
                }, this.options.drawer));
            }
            
            super.listen({ name: 'initiated', cb });
            return this;
        }
        getTree() {
            let _this = this;
            let targetObj = {
                storName: this.options.storName ? this.options.storName + '_tree' : '',
                content: this.options.content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: this.options.ajax,
                passive: this.options.passive,
                layout: this.options.layout,
                disable: this.options.disable,
                duration: this.options.duration,
                select: {
                    value: this.options.active,
                    linkage: this.options.linkage,
                    span: 'leaf',
                },
                expand: {
                    value: this.options.active,
                    all: this.options.expose || this.options.expandAll ? true : false,
                    only: this.options.multiple || this.options.expose ? false : true,
                    linkage: this.options.linkage,
                },
                shortcut: {
                    enable: !this.options.expose,
                    span: 'blank',
                    mean: this.options.trigger === 'hover' ? 'selected' : 'auto',
                },
                arrow: {
                    enable: this.options.arrow.enable,
                    show: this.options.arrow.icon || `${orca.prefix}icon-${this.options.nav.enable ? 'down' : 'right'}`,
                    hide: this.options.arrow.icon || `${orca.prefix}icon-${this.options.nav.enable ? 'down' : 'right'}`,
                    anim: `${orca.prefix}rotate${this.options.nav.enable || this.options.spill ? '180' : '90'}`,
                    type: 'icon',
                    trigger: this.options.trigger,
                },
                onInitiated: function () {
                    if (_this.options.trigger === 'click' && _this.options.pageClose) {
                        document.body.removeEventListener('click', _this.pageEvt);
                        document.body.addEventListener('click', _this.pageEvt, false);
                    }
                },
                onAdded: (items, refer) => {
                    this.setHover(refer);
                },
                onGrafted: (item, refer) => {
                    this.setHover(refer);
                },
                onInsertItem: (item) => {
                    this.options.nav.enable && this.addNavAttr(item, item.floor === this.options.floorStart);
                },
                onInsertItems: (items) => {
                    let tmp = treeTools.toFlat(items);
                    for (let k of tmp) {
                        this.options.nav.enable && this.addNavAttr(k, k.floor === this.options.floorStart);
                        k?.children && this.setHover(k);
                    }
                }
            }, params = extend({ target: targetObj, source: this.options.tree, });
            this.treeIns && this.treeIns.initiated && this.treeIns.destroy();
            this.treeIns = new Tree(this.targetEl, params, false);
        }
        setHover(item) {
            if (this.options.trigger !== 'hover' || !item?.children)
                return;
            item.triggerIns && item.triggerIns.destroy();
            item.triggerIns = new Hover(item.wrapEl, {
                onEnter: () => {
                    this.treeIns.expand(item.id);
                },
                onLeave: () => {
                    this.treeIns.collapse(item.id);
                }
            });
        }
        addNavAttr(item, firstItem = false) {
            if (this.options.nav.bodyWidth) {
                item.childrenEl ? addStyle(item.childrenEl, 'width', this.options.nav.bodyWidth) : removeStyle(item.childrenEl, 'width');
            }
            if (firstItem) {
                this.options.nav.headWidth ? addStyle(item.wrapEl, 'width', this.options.nav.headWidth) : removeStyle(item.wrapEl, 'width');
                this.options.nav.marginLeft ? addStyle(item.wrapEl, 'margin-left', this.options.nav.marginLeft) : removeStyle(item.wrapEl, 'margin-left');
                this.options.nav.marginRight ? addStyle(item.wrapEl, 'margin-right', this.options.nav.marginRight) : removeStyle(item.wrapEl, 'margin-right');
            }
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}menu`);
            this.options.classes && classes(this.targetEl).add(this.options.classes);
            this.targetEl.setAttribute('theme', this.options.theme);
            this.targetEl.toggleAttribute('inert', this.options.passive);
            this.targetEl.toggleAttribute('expose', this.options.expose);
            this.targetEl.setAttribute('trigger', this.options.trigger);
            this.targetEl.toggleAttribute('spill', (this.options.spill && !this.options.nav.enable));
            this.targetEl.toggleAttribute('unpadded', this.options.unpadded);
            this.options.lamp ? this.targetEl.setAttribute('lamp', this.options.lamp) : this.targetEl.removeAttribute('lamp');
            this.targetEl.toggleAttribute('full', (this.options.full && !this.options.nav.enable));
            this.options.zIndex ? addStyle(this.targetEl, 'z-index', this.options.zIndex) : removeStyle(this.targetEl, 'z-index');
            this.targetEl.toggleAttribute('nav', this.options.nav.enable);
            this.options.nav.align ? this.targetEl.setAttribute('align', this.options.nav.align) : this.targetEl.removeAttribute('align');
        }
        activate(data, cb) {
            if (this.destroyed)
                return;
            let tmp = findItems(data, this.treeIns.flatData), branches = tmp.filter((k) => k.children), leaves = tmp.filter((k) => !k.children);
            if (leaves.length) {
                this.treeIns.select(leaves, true, () => {
                    this.treeIns.expand(branches);
                });
            }
            else {
                this.treeIns.expand(branches);
            }
            super.listen({ name: 'activated', cb, params: [tmp] });
            return this;
        }
        
        async updateCont(content, cb) {
            if (this.destroyed)
                return this;
            await this.treeIns.updateCont(content, (resp) => {
                super.listen({ name: 'updatedCont', cb, params: [resp] });
            });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.treeIns.destroy();
            document.body.removeEventListener('click', this.pageEvt);
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optMenu = [
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'passive',
            prop: 'passive',
            value: false,
        },
        {
            attr: 'active',
            prop: 'active',
            value: '',
        },
        {
            attr: 'disable',
            prop: 'disable',
            value: '',
        },
        {
            attr: 'trigger',
            prop: 'trigger',
            value: 'click',
        },
        {
            attr: 'duration',
            prop: 'duration',
            value: 0,
        },
        {
            attr: 'max',
            prop: 'max',
            value: 0,
        },
        {
            attr: 'embed',
            prop: 'embed',
            value: false,
        },
        {
            attr: 'slider',
            prop: 'slider',
            value: {
                enable: false,
                arrowShow: false,
                options: {
                    slides: 'auto',
                    scroll: {
                        drift: { mode: 'free', coef: 1 }
                    }
                },
            },
        },
        {
            attr: 'menu',
            prop: 'menu',
            value: {
                enable: false,
                options: {
                    columns: 4,
                    size: 'lg',
                }
            },
        },
        {
            attr: 'col',
            prop: 'col',
            value: {
                enable: false,
                position: 'left',
            },
        },
        {
            attr: 'attrs',
            prop: 'attrs',
            value: {
                target: {},
                head: {},
                body: {},
            },
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: {
                target: '',
                head: '',
                body: '',
            },
        },
        {
            attr: 'divider',
            prop: 'divider',
            value: {
                enable: false,
                size: '',
            },
        },
        {
            attr: 'add-active',
            prop: 'addActive',
            value: true,
        },
        {
            attr: 'tools',
            prop: 'tools',
            value: {
                enable: false,
                children: ['close'],
            },
        },
        {
            attr: 'layout',
            prop: 'layout',
            value: 'lamp',
        },
        {
            attr: 'selector',
            prop: 'selector',
            value: {
                head: '',
                body: '',
            },
        },
        {
            attr: 'sticky',
            prop: 'sticky',
            value: 0,
        },
        {
            attr: 'b4-activate',
            prop: 'b4Activate',
            value: null,
        },
        {
            attr: 'b4-add',
            prop: 'b4Add',
            value: null,
        },
        {
            attr: 'b4-edit',
            prop: 'b4Edit',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'b4-graft',
            prop: 'b4Graft',
            value: null,
        },
        {
            attr: 'on-rendered',
            prop: 'onRendered',
            value: null,
        },
        {
            attr: 'on-insertitem',
            prop: 'onInsertItem',
            value: null,
        },
        {
            attr: 'on-insertitems',
            prop: 'onInsertItems',
            value: null,
        },
        {
            attr: 'on-trigger',
            prop: 'onTrigger',
            value: null
        },
        {
            attr: 'on-added',
            prop: 'onAdded',
            value: null
        },
        {
            attr: 'on-removed',
            prop: 'onRemoved',
            value: null
        },
        {
            attr: 'on-edited',
            prop: 'onEdited',
            value: null
        },
        {
            attr: 'on-grafted',
            prop: 'onGrafted',
            value: null
        },
        {
            attr: 'on-disabled',
            prop: 'onDisabled',
            value: null
        },
        {
            attr: 'on-enabled',
            prop: 'onEnabled',
            value: null
        },
        {
            attr: 'on-disabledAll',
            prop: 'onDisabledAll',
            value: null
        },
        {
            attr: 'on-enabledAll',
            prop: 'onEnabledAll',
            value: null
        },
        {
            attr: 'on-activated',
            prop: 'onActivated',
            value: null
        },
        {
            attr: 'on-updatedItemcont',
            prop: 'onUpdatedItemCont',
            value: null
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null
        },
        {
            attr: 'on-request',
            prop: 'onRequest',
            value: null
        },
        ...optBase
    ];

    class Tab extends ModBaseListenCacheNest {
        options = {};
        actEvt;
        trigger;
        treeDataOrig;
        observeIns;
        headsEl;
        bodiesEl;
        dividerEl;
        rawData;
        headLayout;
        contXhr;
        static hostType = 'node';
        static optMaps = optMenu;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Tab.optMaps,
                component: false,
                spread: ['slider', 'col', 'menu', 'tools', 'divider']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            let _this = this;
            this.actEvt = function (evt) {
                if (this.hasAttribute('selected') || this.hasAttribute('disabled'))
                    return;
                let toolsEl = this.querySelector(`:scope > [${orca.alias}="tools"]`);
                if (toolsEl && toolsEl.contains(evt.target))
                    return;
                let item = _this.treeData.find((k) => k.headEl === this);
                _this.activate(item);
            };
            this.trigger = this.options.trigger === 'hover' ? 'mouseenter' : 'click';
            this.treeDataOrig = [];
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            super.useTpl();
            await this.getDataToRender();
            this.setAttrs();
            super.initDisableds();
            this.renderFinish();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        initActive() {
            let activeItem = this.treeData.findIndex((k) => k.selected);
            if (this.options.active === 0 || this.options.active) {
                this.activate(this.options.active);
            }
            else if (activeItem < 0) {
                this.activate(0);
            }
        }
        async getDataToRender() {
            let base = {
                nodeType: 'tab',
            }, promise;
            if (this.options.content) {
                promise = treeTools.allToTree({
                    content: this.options.content,
                    contType: this.options.contType,
                    contData: this.options.contData,
                    ajax: { spinSel: this.targetEl, xhrName: 'contXhr' },
                    ins: this,
                    ...base
                });
            }
            else {
                if (this.targetEl.querySelector(`.${orca.prefix}tab-head`) && this.targetEl.querySelector(`.${orca.prefix}tab-body`)) {
                    this.treeDataOrig = this.htmlToArr();
                    treeTools.addIdPath({ source: this.treeDataOrig });
                    this.rawData = this.treeDataOrig;
                    this.updateHeadBodyAttrs();
                }
                else {
                    promise = treeTools.allToTree({
                        content: this.targetEl.innerHTML,
                        ...base
                    });
                }
            }
            if (promise) {
                await promise.then((res) => {
                    
                    this.treeDataOrig = res.data && Array.isArray(res.data) ? res.data : res;
                    this.rawData = res;
                });
                this.targetEl.innerHTML = '';
                this.renderData(this.treeDataOrig);
            }
            this.getTreeFlat();
            super.listen({ name: 'rendered', params: [this.treeData] });
            return this;
        }
        getTreeFlat() {
            this.treeData = this.getObserver(this.treeDataOrig).proxy;
        }
        getObserver(data) {
            this.observeIns ? this.observeIns.destroy() : null;
            this.observeIns = new Observe(data, {
                deep: {
                    enable: true,
                    exclude: ['tools'],
                },
                onSet: (obj) => {
                    if (obj.key === 'icon' && obj.target.iconEl) {
                        obj.target.iconEl.className = obj.value;
                    }
                    else if (obj.key === 'cube' && obj.target.cubeEl) {
                        obj.target.cubeEl.src = obj.value;
                    }
                    else if (obj.key === 'disk' && obj.target.diskEl) {
                        obj.target.diskEl.src = obj.value;
                    }
                    else if (obj.key === 'image' && obj.target.imageEl) {
                        obj.target.imageEl.src = obj.value;
                    }
                    else if (obj.key === 'label') {
                        obj.target.labelEl.innerHTML = obj.value;
                    }
                    else if (obj.key === 'tips' && obj.target.tipsEl) {
                        obj.target.tipsEl.innerHTML = obj.value;
                    }
                    else if (obj.key === 'badge' && obj.target.badgeEl) {
                        obj.target.badgeEl.setAttribute('label', obj.value);
                    }
                    else if (obj.key === 'selected') {
                        if (obj.value === true) {
                            obj.target.headEl.setAttribute('selected', '');
                            obj.target.bodyEl.setAttribute('selected', '');
                            !obj.target.bodyEl.innerHTML && this.fillContent(obj.target);
                        }
                        else {
                            obj.target.headEl.removeAttribute('selected');
                            obj.target.bodyEl.removeAttribute('selected');
                        }
                    }
                    else if (obj.key === 'disabled') {
                        obj.target.headEl.toggleAttribute('disabled', obj.value);
                    }
                    else if (obj.key === 'content') {
                        this.fillContent(obj.target);
                    }
                },
                onCompleted: () => {
                    let activeItem = this.getSelected(), tmp = {
                        active: activeItem ? (activeItem.hasOwnProperty('id') ? activeItem.id : this.treeData.indexOf(activeItem)) : 0,
                        disabled: super.getDisableds().map((k, i) => k.hasOwnProperty('id') ? k.id : i),
                        content: !isEmpty(this.options.content) ? deepClone(this.treeDataOrig) : [],
                    };
                    super.updateCache(tmp);
                }
            });
            return this.observeIns;
        }
        htmlToArr() {
            
            let data = [];
            this.headsEl = this.targetEl.querySelector(`.${orca.prefix}tab-head`);
            this.bodiesEl = this.targetEl.querySelector(`.${orca.prefix}tab-body`);
            if (!this.headsEl || !this.bodiesEl) {
                return data;
            }
            let tmpHeads = getEls(this.options.selector.head, this.headsEl), tmpBodys = getEls(this.options.selector.body, this.bodiesEl), headsArr = tmpHeads.length ? tmpHeads : [...this.headsEl.children], bodiesArr = tmpBodys.length ? tmpBodys : [...this.bodiesEl.children];
            if (headsArr.length !== bodiesArr.length) {
                console.warn('Inconsistent number of heads and bodies!');
                return data;
            }
            let setBoolean = (obj, props) => {
                let loop = (prop) => {
                    let val = obj.headEl.hasAttribute(prop);
                    if (val && val !== 'false' && val !== '0') {
                        obj[prop] = true;
                        obj.headEl.setAttribute(prop, '');
                    }
                    else {
                        obj[prop] = false;
                    }
                };
                if (Array.isArray(props)) {
                    props.forEach((k) => {
                        loop(k);
                    });
                }
                else {
                    loop(props);
                }
            }, getPropsFromHead = (elem) => {
                let obj = {}, tmpLabel = elem.querySelector(`[${orca.alias}="label"]`);
                obj.headEl = elem;
                obj.labelEl = tmpLabel || elem;
                obj.label = obj.labelEl.textContent.trim();
                obj.tipsEl = elem.querySelector(`[${orca.alias}="tips"]`);
                obj.tips = obj.tipsEl ? obj.tipsEl.textContent.trim() : '';
                obj.iconEl = elem.querySelector(`[${orca.alias}="icon"]`);
                obj.icon = obj.iconEl ? obj.iconEl.getAttribute('class') : '';
                obj.cubeEl = elem.querySelector(`[${orca.alias}="cube"]`);
                obj.cube = obj.cubeEl ? obj.cubeEl.src : '';
                obj.diskEl = elem.querySelector(`[${orca.alias}="disk"]`);
                obj.disk = obj.diskEl ? obj.diskEl.src : '';
                obj.badgeEl = elem.querySelector(`[${orca.alias}="badge"],oc-badge`);
                obj.badge = obj.badgeEl ? obj.badgeEl.getAttribute('label') || obj.badgeEl.textContent.trim() : '';
                setBoolean(obj, ['selected', 'disabled']);
                return obj;
            };
            data = headsArr.map((k, i) => {
                let tmp = getPropsFromHead(k), bodyEl = bodiesArr[i];
                bodyEl.toggleAttribute('selected', !!tmp.selected);
                this.options.tools.enable && this.getTools(tmp);
                return { ...tmp, bodyEl, content: bodyEl.innerHTML };
            });
            return data;
        }
        renderData(data) {
            this.dividerEl = createEl('oc-br');
            this.options.divider.size && this.dividerEl.setAttribute('size', this.options.divider.size);
            this.headsEl = createEl('ul', { class: `${orca.prefix}tab-head` });
            this.bodiesEl = createEl('ul', { class: `${orca.prefix}tab-body` });
            this.updateHeadBodyAttrs();
            for (let k of data) {
                if (!k.hasOwnProperty('label') || !k.hasOwnProperty('content')) {
                    continue;
                }
                else {
                    this.createItemEl(k);
                    this.headsEl.appendChild(k.headEl);
                    this.bodiesEl.appendChild(k.bodyEl);
                }
            }
            super.listen({ name: 'insertItems', params: [data] });
            this.targetEl.append(this.headsEl, this.options.divider.enable ? this.dividerEl : '', this.bodiesEl);
        }
        createItemEl(item) {
            item.labelEl = createEl('i', { [orca.alias]: 'label' }, item.label);
            item.iconEl = item.icon ? createEl('i', { [orca.alias]: 'icon', class: item.icon }) : null;
            item.diskEl = item.disk ? createEl('img', { [orca.alias]: 'disk', src: item.disk }) : null;
            item.cubeEl = item.cube ? createEl('img', { [orca.alias]: 'cube', src: item.cube }) : null;
            item.imageEl = item.image ? createEl('img', { [orca.alias]: 'image', src: item.image }) : null;
            item.headEl = createEl('li');
            item.bodyEl = createEl('li');
            item.badgeEl = item.badge ? createEl('oc-badge', { [orca.alias]: 'badge' }, item?.badge?.trim()) : null;
            item.tipsEl = item.tips ? createEl('i', { [orca.alias]: 'tips' }, item.tips) : null;
            item.selected && (item.headEl.toggleAttribute('selected', true), item.bodyEl.toggleAttribute('selected', true));
            item.disabled && item.headEl.toggleAttribute('disabled', true);
            item.headEl.append(...[item.iconEl, item.diskEl, item.cubeEl, item.imageEl, item.labelEl, item.tipsEl, item.badgeEl].filter(Boolean));
            this.options.tools.enable && this.getTools(item);
        }
        getTools(item) {
            if (this.options.tools.enable) {
                item.toolsEl = createTools(this.options.tools.children, item.headEl);
                item.toolsEl.setAttribute(orca.alias, 'tools');
                item.tools = deepClone(this.options.tools.children);
                for (let k of item.tools) {
                    this.options.lang.title[k.name] && k.wrapEl.setAttribute('title', this.options.lang.title[k.name]);
                    if (k.name === 'add') {
                        item.addEl = k.wrapEl;
                    }
                    else if (k.name === 'edit') {
                        item.editEl = k.wrapEl;
                    }
                    else if (k.name === 'close') {
                        item.closeEl = k.wrapEl;
                    }
                    else if (k.name === 'update') {
                        item.updateEl = k.wrapEl;
                    }
                    else if (k.name === 'move') {
                        item.moveEl = k.wrapEl;
                    }
                }
            }
        }
        async fillContent(obj, cb) {
            await getContent.call(this, {
                content: obj.content,
                contType: obj.contType,
                contData: obj.contData,
                ajax: {
                    ajaxType: obj.ajaxType || this.options.ajaxType,
                    xhrName: 'contXhr',
                    spinSel: obj.bodyEl,
                },
                cb: (data) => {
                    setContent({
                        content: data,
                        target: obj.bodyEl,
                        engine: obj.engine || this.tplStr,
                        template: obj.template || this.tplEng
                    });
                    cb && cb(data);
                }
            });
        }
        updateHeadBodyAttrs() {
            this.options.classes?.head && classes(this.headsEl).add(this.options.classes.head);
            this.options.classes?.body && classes(this.bodiesEl).add(this.options.classes.body);
            !isEmpty(this.options.attrs?.head) && setAttrs(this.headsEl, this.options.attrs.head);
            !isEmpty(this.options.attrs?.body) && setAttrs(this.bodiesEl, this.options.attrs.body);
            if (this.options.layout) {
                if (!this.headsEl.getAttribute('class')?.includes(`${orca.prefix}group-`)) {
                    this.headLayout = `${orca.prefix}group-${this.options.layout}`;
                    this.headsEl.classList.add(this.headLayout);
                }
            }
            else {
                this.headLayout && this.headsEl.classList.remove(this.headLayout);
            }
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}tab`);
            this.options.classes?.target && classes(this.targetEl).add(this.options.classes.target);
            !isEmpty(this.options.attrs?.target) && setAttrs(this.targetEl, this.options.attrs.target);
            this.targetEl.toggleAttribute('inert', this.options.passive);
            this.targetEl.toggleAttribute('embed', this.options.embed);
            this.options.col.enable ? this.targetEl.setAttribute('col', this.options.col.position) : this.targetEl.removeAttribute('col');
        }
        updateEvt(k) {
            this.addTrigger(k);
            if (k.toolsEl) {
                if (k.closeEl) {
                    k.closeEl.onclick = () => {
                        if (k.readonly)
                            return;
                        this.remove(k);
                    };
                }
                if (k.editEl) {
                    k.editEl.onclick = debounce(() => {
                    });
                }
                if (k.addEl) {
                    k.addEl.onclick = debounce(() => {
                        if (k.disabled)
                            return;
                        this.add({ data: {}, isFront: false, target: k });
                    });
                }
                if (k.updateEl) {
                    k.updateEl.onclick = debounce(() => {
                        if (k.disabled)
                            return;
                        this.updateItemCont({ content: k.content, target: k });
                    });
                }
                for (let [i, o] of this.options.tools.children.entries()) {
                    let tool = k.tools[i], refer = { ins: this, item: k };
                    o.action && o.action.call(refer, tool);
                    tool.action && tool.action.call(refer, tool);
                }
            }
            k.disabled && k.headEl.toggleAttribute('disabled', true);
            k.action && k.action.call(this, k);
        }
        renderFinish() {
            this.initActive();
            for (let k of this.treeData) {
                this.updateEvt(k);
            }
        }
        getSelected() {
            return this.treeData.find((k) => k.selected);
        }
        addTrigger(item) {
            if (!item.disabled) {
                item.headEl.removeEventListener(this.trigger, this.actEvt);
                item.headEl.addEventListener(this.trigger, this.actEvt, false);
            }
        }
        removeTrigger(item) {
            if (item.disabled) {
                item.headEl.removeEventListener(this.trigger, this.actEvt);
            }
        }
        toggleDisabled(item, type = 'disable') {
            if (type === 'enable') {
                item.disabled = false;
                this.addTrigger(item);
            }
            else if (type === 'disable') {
                item.disabled = true;
                this.removeTrigger(item);
            }
        }
        disable(data, cb) {
            if (this.destroyed || (data !== 0 && isEmpty(data))) {
                return this;
            }
            let tmp = Array.isArray(data) ? data : [data], arr = tmp.map((k) => findItem(k, this.treeData)).filter(Boolean), fun = (k) => this.toggleDisabled(k, 'disable');
            arr.forEach(k => fun(k));
            super.listen({ name: 'disabled', cb, params: [arr] });
            return this;
        }
        disableAll(cb) {
            if (this.destroyed) {
                return this;
            }
            this.disable(this.treeData);
            super.listen({ name: 'disabledAll', cb });
            return this;
        }
        enable(data, cb) {
            if (this.destroyed || (data !== 0 && isEmpty(data))) {
                return this;
            }
            let tmp = Array.isArray(data) ? data : [data], arr = tmp.map((k) => findItem(k, this.treeData)).filter(Boolean), fun = (k) => this.toggleDisabled(k, 'enable');
            arr.forEach(k => fun(k));
            super.listen({ name: 'enabled', cb, params: [arr] });
            return this;
        }
        enableAll(cb) {
            if (this.destroyed) {
                return this;
            }
            this.enable(this.treeData);
            super.listen({ name: 'enabledAll', cb });
            return this;
        }
        async activate(data, cb) {
            if (this.destroyed || isNull(data))
                return;
            let item = findItem(data, this.treeData), other = this.treeData.find((k) => k !== item && k.selected);
            if (!item)
                return;
            if (item.selected) {
                !item.bodyEl.innerHTML && this.fillContent(item);
            }
            else {
                try {
                    if (this.options.b4Activate) {
                        let resp = await this.options.b4Add.call(this, item);
                        resp && (item = resp);
                    }
                }
                catch (err) {
                    err ? console.error(err) : console.warn(`Activating branche (${item.label}) has been prevented!`);
                }
                other && (other.selected = false);
                item.selected = true;
                item.disabled = false;
                super.listen({ name: 'activated', cb, params: [item] });
            }
            return this;
        }
        async add(options) {
            if (this.destroyed)
                return this;
            if (this.treeData.length >= this.options.max && this.options.max > 0) {
                throw new Error('The number of children exceeds the maximum!');
            }
            let opts = Object.assign({ repeat: true, autoFill: true, isFront: false }, options), type = getDataType(opts.data), targetObj = findItem(opts.target, this.treeData), items = type === 'Array' ? opts.data : type === 'Object' ? [opts.data] : [{}];
            if (!opts.repeat) {
                let labels = this.treeData.map((k) => k.label);
                items = items.filter((k) => !labels.includes(k.label));
            }
            if (items.length === 0) {
                return this;
            }
            for (let k of items) {
                try {
                    if (this.options.b4Add) {
                        let resp = await this.options.b4Add.call(this, k);
                        resp && (k = resp);
                    }
                }
                catch (err) {
                    err ? console.error(err) : console.warn(`Adding new branche (${JSON.stringify(k)}) has been prevented!`);
                    continue;
                }
                !k.hasOwnProperty('id') && (k.id = increaseId(this.treeData));
                !k.hasOwnProperty('label') && (k.label = `${this.options.lang.label}${k.id}`);
                !k.hasOwnProperty('content') && (k.content = `${this.options.lang.content}${k.id}`);
                this.createItemEl(k);
            }
            if (targetObj) {
                let tmp = this.treeData.indexOf(targetObj), index = opts.isFront ? tmp : tmp + 1;
                splice({
                    host: this.treeData,
                    intent: 'add',
                    source: items,
                    index,
                });
            }
            else {
                splice({
                    host: this.treeData,
                    intent: opts.isFront ? 'start+' : 'end+',
                    source: items,
                });
            }
            let heads = items.map((k) => k.headEl), bodies = items.map((k) => k.bodyEl);
            appendEls({ parent: this.headsEl, nodes: heads, target: targetObj?.headEl, prepend: opts.isFront ? true : false });
            appendEls({ parent: this.bodiesEl, nodes: bodies, target: targetObj?.bodyEl, prepend: opts.isFront ? true : false });
            this.options.addActive && this.activate(items[items.length - 1]);
            let tmp = items.map((k) => {
                let _tmp = this.treeData.find((i) => (i.id === k.id));
                this.updateEvt(_tmp);
                return _tmp;
            });
            super.listen({ name: 'added', cb: opts.cb, params: [tmp] });
            return this;
        }
        async remove(data, cb) {
            if (this.destroyed || isNull(data)) {
                return this;
            }
            if (this.treeData.length === 0) {
                console.warn('The source data is already empty!');
                return this;
            }
            let tmp = Array.isArray(data) ? data : [data], items = tmp.map((k) => findItem(k, this.treeData)).filter(Boolean), removeItem = (obj) => {
                let index = this.treeData.indexOf(obj);
                this.treeData.splice(index, 1);
                obj.headEl.remove();
                obj.bodyEl.remove();
            };
            for (let k of items) {
                try {
                    if (this.options.b4Remove) {
                        let resp = await this.options.b4Remove.call(this, k);
                        resp && (k = resp);
                    }
                }
                catch (err) {
                    err ? console.error(err) : console.warn(`Removing old branch (${JSON.stringify(k)}) has been prevented!`);
                    continue;
                }
                removeItem(k);
            }
            super.listen({ name: 'removed', cb, params: [items] });
            return this;
        }
        async edit({ source, target, cb }) {
            if (this.destroyed || isEmpty(source) || isNull(target)) {
                return this;
            }
            let item = findItem(target, this.treeData);
            if (!item)
                return this;
            for (let k in source) {
                let val = source[k];
                try {
                    if (this.options.b4Edit) {
                        let resp = await this.options.b4Edit.call(this, { key: k, value: val }, item);
                        resp && (val = resp);
                    }
                    if (k === 'action') {
                        item[k] = val.call({ ins: this, item: k }, item);
                    }
                    else if (['icon', 'disk', 'cube', 'image', 'label', 'tips', 'badge', 'disabled', 'content', 'contType', 'contData', 'ajaxType'].includes(k)) {
                        item[k] = val;
                    }
                    else if (k === 'selected') {
                        val === true ? this.activate(item) : item[k] = val;
                    }
                }
                catch (err) {
                    err ? console.error(err) : console.warn(`No changes have been made to the ${k} property!`);
                    return this;
                }
            }
            super.listen({ name: 'edited', cb, params: [item] });
            return this;
        }
        async graft({ source, target, isFront = true, cb }) {
            if (this.destroyed || isNull(source)) {
                return this;
            }
            let sourceObj = findItem(source, this.treeData), targetObj = findItem(target, this.treeData);
            if (!sourceObj)
                return this;
            try {
                if (this.options.b4Graft) {
                    let resp = await this.options.b4Graft.call(this, sourceObj, targetObj);
                    resp && resp.source && (sourceObj = resp.source);
                    resp && resp.target && (targetObj = resp.target);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn(`The branch relationship between source and target in the tree remains unchanged!`);
                return this;
            }
            let position = '';
            if (targetObj) {
                position = isFront ? 'beforeBegin' : 'afterEnd';
                targetObj.headEl.insertAdjacentElement(position, sourceObj.headEl);
                targetObj.bodyEl.insertAdjacentElement(position, sourceObj.bodyEl);
            }
            else {
                position = isFront ? 'afterBegin' : 'beforeEnd';
                this.headsEl.insertAdjacentElement(position, sourceObj.headEl);
                this.bodiesEl.insertAdjacentElement('beforeEnd', sourceObj.bodyEl);
            }
            moveItem({ source: sourceObj, target: targetObj, data: this.treeData, isFront });
            super.listen({ name: 'grafted', cb, params: [sourceObj, targetObj] });
            return this;
        }
        updateItemCont({ target, content, contType, contData, ajaxType, cb }) {
            if (this.destroyed)
                return this;
            let targetObj = findItem(target, this.treeData);
            if (isEmpty(content) || !targetObj || content == targetObj.content)
                return this;
            contType ? (targetObj.contType = contType) : this.options.contType !== 'text' ? (targetObj.contType = this.options.contType) : null;
            contData && (targetObj.contData = contData);
            ajaxType && (targetObj.ajaxType = ajaxType);
            targetObj.content = content;
            super.listen({ name: 'updatedItemCont', cb, params: [targetObj] });
            return this;
        }
        
        async updateCont(content, cb) {
            if (this.destroyed) {
                return this;
            }
            await getContent.call(this, {
                content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: {
                    ajaxType: this.options.ajaxType,
                    xhrName: 'contXhr',
                },
                cb: (data) => {
                    if (Array.isArray(data)) {
                        this.treeDataOrig = deepClone(data);
                        treeTools.addIdPath({ source: this.treeDataOrig });
                        this.targetEl.innerHTML = '';
                        this.renderData(this.treeDataOrig);
                        this.getTreeFlat();
                        this.renderFinish();
                        super.updateCache({ content });
                        super.listen({ name: 'updatedCont', cb, params: [this.treeDataOrig] });
                    }
                }
            });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed) {
                return this;
            }
            this.treeData.forEach((k) => {
                this.removeTrigger(k);
            });
            this.contXhr && this.contXhr.abort();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    class Tooltip extends Popup {
        constructor(elem, options = {}, initial = config.initial) {
            isNull(options.size) ? options.size = 'sm' : null;
            options?.tools === true ? options.tools = { enable: true, placement: 'outside' } : !options?.tools ? options.tools = { enable: false, placement: 'outside' } : null;
            !options?.placement ? options.placement = 'top' : null;
            !options?.footer ? options.footer = false : null;
            !options?.padding ? options.padding = false : null;
            !options?.theme ? options.theme = 'text' : null;
            super(elem, options, initial);
            this.on('initiated', () => {
                this.mainEl.classList.add(`${orca.prefix}tooltip`);
            });
        }
    }

    var Tooltip$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        default: Tooltip
    });

    const optDropdown = [
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'placement',
            prop: 'placement',
            value: 'bottom-start',
        },
        {
            attr: 'list-type',
            prop: 'listType',
            value: '',
        },
        {
            attr: 'unpadded',
            prop: 'unpadded',
            value: false,
        },
        {
            attr: 'hoverable',
            prop: 'hoverable',
            value: false,
        },
        {
            attr: 'divisible',
            prop: 'divisible',
            value: false,
        },
        {
            attr: 'multiline',
            prop: 'multiline',
            value: false,
        },
        {
            attr: 'cols',
            prop: 'cols',
            value: 0,
        },
        {
            attr: 'lines',
            prop: 'lines',
            value: '',
        },
        {
            attr: 'detectable',
            prop: 'detectable',
            value: false,
        },
        {
            attr: 'child-sel',
            prop: 'childSel',
            value: `[${orca.alias}="label"]`,
        },
        {
            attr: 'val-key',
            prop: 'valKey',
            value: '',
        },
        {
            attr: 'feature',
            prop: 'feature',
            value: '',
        },
        {
            attr: 'popup',
            prop: 'popup',
            value: {},
        },
        ...optBase
    ];

    class Dropdown extends ModBaseListenCache {
        popupIns;
        static hostType = 'node';
        static optMaps = optDropdown;
        constructor(elem, options = {}, initial = config.initial) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Dropdown.optMaps,
                component: true,
                spread: []
            });
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.popupIns && this.popupIns.destroy();
            let _this = this, dftParams = {
                content: this.options.content,
                contType: this.options.contType,
                contData: this.options.contData,
                tools: false,
                trigger: 'click',
                placement: 'bottom-start',
                classes: `${orca.prefix}dropdown`,
                autoFill: {
                    enable: true,
                    childSel: this.options.childSel,
                    detectable: this.options.detectable,
                    key: this.options.valKey,
                },
                bullet: {
                    enable: !!this.options.listType,
                    type: this.options.listType,
                    unpadded: this.options.unpadded,
                    hoverable: this.options.hoverable,
                    divisible: this.options.divisible,
                    multiline: this.options.multiline,
                    cols: this.options.cols,
                    lines: this.options.lines,
                    action: this.options.action ? this.options.action.bind(this) : null,
                },
                padding: this.options.divisible || this.options.lines === 'fence' ? false : true,
                onInitiated: function () {
                    _this.options.feature && this.mainEl.setAttribute('feature', _this.options.feature);
                }
            }, params = extend({
                target: dftParams,
                source: this.options.popup,
            });
            this.setFeature(params);
            this.popupIns = new Popup(this.targetEl, params);
            this.setAttrs();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setAttrs() {
        }
        setFeature(params) {
            if (this.options.feature === 'button') {
                params.footer = params.padding = params.autoFill.enable = false;
                params.bullet.enable = params.bullet.divisible = true;
                params.bullet.type = params.bullet.type || 'custom';
                params.placement = 'bottom-center';
                params.size = '';
            }
            else if (this.options.feature === 'tooltip') {
                params.footer = params.bullet.enable = false;
                params.placement = 'top-center';
                params.size = '';
            }
            else if (this.options.feature === 'select') {
                params.footer = params.padding = false;
                params.bullet.enable = params.autoFill.enable = params.bullet.divisible = true;
                params.bullet.type = 'select-single';
                params.placement = 'bottom-center';
                params.size = 'sm';
            }
        }
        destroy() {
            if (this.destroyed)
                return this;
            this.popupIns.destroy();
            return this;
        }
    }

    let OCTMP_hyphen$3 = config.splitHyphen;
    const optRetrieval = [
        {
            attr: 'keys',
            prop: 'keys',
            value: '',
        },
        {
            attr: 'props',
            prop: 'props',
            value: 'label',
        },
        {
            attr: 'fuzzy',
            prop: 'fuzzy',
            value: true,
        },
        {
            attr: 'order',
            prop: 'order',
            value: '',
        },
        {
            attr: 'limit',
            prop: 'limit',
            value: 0,
        },
        {
            attr: 'ignore',
            prop: 'ignore',
            value: true,
        },
        {
            attr: 'hyphen',
            prop: 'hyphen',
            value: OCTMP_hyphen$3,
        },
        {
            attr: 'null-handle',
            prop: 'nullHandle',
            value: 'reset',
        },
        {
            attr: 'highlight',
            prop: 'highlight',
            value: {
                enable: false,
                props: 'label',
                node: 'i',
                classes: `${orca.prefix}c-issue`,
            },
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'target',
            prop: 'target',
            value: '',
        },
        {
            attr: 'editor',
            prop: 'editor',
            value: '',
        },
        {
            attr: 'trigger',
            prop: 'trigger',
            value: 'input',
        },
        {
            attr: 'delay',
            prop: 'delay',
            value: 200,
        },
        {
            attr: 'status',
            prop: 'status',
            value: {
                enable: false,
                placement: 'list-top',
            },
        },
        {
            attr: 'tpl-str',
            prop: 'tplStr',
            value: '',
        },
        {
            attr: 'tpl-eng',
            prop: 'tplEng',
            value: null,
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'bullet',
            prop: 'bullet',
            value: {
                type: 'custom',
                childNode: 'div',
                unpadded: false,
                hoverable: false,
                divisible: false,
                multiline: false,
            },
        },
        {
            attr: 'b4-fill',
            prop: 'b4Fill',
            value: null,
        },
        {
            attr: 'on-rendered',
            prop: 'onRendered',
            value: null,
        },
        {
            attr: 'on-searched',
            prop: 'onSearched',
            value: null
        },
        {
            attr: 'on-processed"',
            prop: 'onProcessed"',
            value: null
        },
        {
            attr: 'on-updatedkeys',
            prop: 'onUpdatedKeys',
            value: null
        },
        {
            attr: 'on-request',
            prop: 'onRequest',
            value: null
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null
        },
        ...optBase
    ];

    class Retrieval extends ModBaseListenCache {
        options = {};
        mainEl;
        inputEl;
        statusEl;
        inputEvt;
        keys;
        data;
        output;
        contXhr;
        editorEl;
        static hostType = 'none';
        static optMaps = optRetrieval;
        constructor(options = {}, initial = true) {
            super();
            super.ready({
                options,
                type: Retrieval.hostType,
                maps: Retrieval.optMaps,
                component: false,
                spread: ['status', 'highlight']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            this.targetEl = getEl(this.options.target);
            this.inputEl = getEl(this.options.editor);
            this.statusEl = createEl('div', { class: `${orca.prefix}retrieval-status` });
            this.inputEvt = debounce(() => {
                let keys = this.getInputVals();
                this.updateKeys(keys);
            }, this.options.delay);
            
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setEmpty();
            this.keys = this.options.keys || this.getInputVals();
            this.useTpl();
            await getContent.call(this, {
                content: this.options.content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: {
                    xhrName: 'contXhr',
                    spinSel: this.targetEl,
                    ...this.options.ajax
                },
                cb: (data) => {
                    if (isEmpty(data))
                        return this;
                    this.data = this.getStdData(data);
                    super.listen({ name: 'processed', params: [this.data] });
                    this.searchData();
                    this.render();
                }
            });
            if (elState(this.statusEl).isVirtual && this.options.status.enable) {
                if (this.options.status.placement === 'list-top') {
                    this.targetEl.insertAdjacentElement('beforebegin', this.statusEl);
                }
                else if (this.options.status.placement === 'list-btm') {
                    this.targetEl.insertAdjacentElement('afterend', this.statusEl);
                }
                else if (this.options.status.placement === 'editor-top') {
                    this.editorEl && this.editorEl.insertAdjacentElement('beforebegin', this.statusEl);
                }
                else if (this.options.status.placement === 'editor-btm') {
                    this.editorEl && this.editorEl.insertAdjacentElement('afterend', this.statusEl);
                }
                else {
                    let target = getEl(this.options.status.placement);
                    target && target.appendChild(this.statusEl);
                }
            }
            this.input2Render();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setEmpty() {
            this.targetEl && (this.targetEl.innerHTML = '');
        }
        setAttrs() {
            if (this.targetEl) {
                this.targetEl.classList.add(`${orca.prefix}retrieval`);
                this.options.classes && classes(this.targetEl).add(this.options.classes);
            }
        }
        getStdData(data) {
            let dataType = getDataType(data), result = [];
            if (dataType === 'String') {
                let tmp = valToArr(data, this.options.hyphen, false);
                result = tmp.filter(Boolean).map((k) => {
                    let obj = { label: k, value: k };
                    return obj;
                });
            }
            else if (dataType === 'Array') {
                if (data.length === 0)
                    return [];
                let childType = getDataType(data[0]);
                if (['String', 'Number'].includes(childType)) {
                    result = data.filter(Boolean).map((k) => {
                        let obj = { label: k + '', value: k + '' };
                        return obj;
                    });
                }
                else if (childType === 'Object') {
                    if (data[0].hasOwnProperty('label')) {
                        result = data.filter(Boolean).map((k) => {
                            !k.hasOwnProperty('value') && (k.value = k.label);
                            return k;
                        });
                    }
                    else {
                        console.error(`The object array must contain the "label" property.`);
                        result = [];
                    }
                }
                else {
                    console.error(`The items in the object array must be either strings or objects containing the "label" property.`);
                    result = [];
                }
            }
            else {
                console.error(`The data type received is incorrect; a string, string array, or object array is required.`);
                result = [];
            }
            return result;
        }
        searchData(keys = this.keys, data = this.data) {
            if (this.destroyed)
                return this;
            if (isEmpty(keys) && this.options.nullHandle === 'reset') {
                this.output = data.map((k) => {
                    return { source: k, weight: 0, keys: [] };
                });
            }
            else {
                this.output = arrSearch({
                    keys,
                    props: this.options.props,
                    source: data,
                    hyphen: this.options.hyphen,
                    fuzzy: this.options.fuzzy,
                    ignore: this.options.ignore,
                    order: this.options.order,
                    limit: this.options.limit
                });
            }
            for (let k of this.output) {
                k.source.el = this.createItemEl(k);
                k.source.action && k.source.action.call(this, k);
            }
            this.updateStatus();
            super.listen({ name: 'searched', params: [this.output] });
        }
        useTpl() {
            let tplEl = getEl(this.options.tplStr);
            this.tplEng = this.options.tplEng || renderTpl;
            this.tplStr = tplEl?.innerHTML || this.options.tplStr || bulletTools.getIBulletTpl(this.options.bullet);
        }
        createItemEl(item) {
            let tplData = this.options.highlight.enable ? this.getHighlightData(item) : item.source, html = super.getTplcont(tplData);
            return tplToEl(html);
        }
        getHighlightData(data) {
            if (!this.options.highlight.enable)
                return data;
            let props = getIntArr([valToArr(this.options.highlight.props, this.options.hyphen, false), valToArr(this.options.props, this.options.hyphen, false)]), copy = { ...data.source }, keys = data.keys.map((k) => clearRegx(k)).filter(Boolean);
            for (let k in copy) {
                if (props.includes(k) && keys.length !== 0) {
                    copy[k] = super.replaceMult(copy[k], keys, { ignore: this.options.ignore, nodename: this.options.highlight.node, classes: this.options.highlight.classes });
                    
                }
            }
            return copy;
        }
        async render(data = this.output) {
            if (this.destroyed)
                return this;
            isEmpty(data) && console.warn('There is no content to render, but no errors occurred!');
            if (this.options.b4Fill) {
                let resp = await this.options.b4Fill.call(this, data, this.targetEl);
                resp && (data = resp);
            }
            if (this.targetEl) {
                this.targetEl.innerHTML = '';
                data.length > 0 && this.targetEl.append(...data.map((k) => k.source.el));
                super.listen({ name: 'rendered', params: [data, this.targetEl] });
            }
            this.renderCount++;
        }
        updateKeys(keys = this.getInputVals()) {
            if (this.destroyed || keys.toString() == this.keys.toString())
                return this;
            this.keys = keys;
            this.searchData();
            this.render();
            super.listen({ name: 'updatedKeys', params: [keys] });
        }
        input2Render() {
            if (!this.inputEl || this.destroyed)
                return this;
            this.inputEl.removeEventListener(this.options.trigger, this.inputEvt);
            this.inputEl.addEventListener(this.options.trigger, this.inputEvt, false);
        }
        getInputVals() {
            if (['radio', 'checkbox', 'radio-comp', 'checkbox-comp'].includes(this.inputEl.type)) {
                return this.inputEl.checked ? this.inputEl.value : '';
            }
            else {
                return this.inputEl?.value || '';
            }
        }
        resetList() {
            if (this.destroyed)
                return this;
            this.output = this.data.map((k) => {
                return { source: k, weight: 0, keys: [] };
            });
            for (let k of this.output) {
                k.source.el = this.createItemEl(k);
                k.source.action && k.source.action.call(this, k);
            }
            this.render();
        }
        clearList() {
            if (this.destroyed)
                return this;
            if (this.inputEl) {
                
                this.inputEl?.clear ? this.inputEl.clear() : this.inputEl.value = '';
            }
            this.keys = '';
            this.output = [];
            this.render();
        }
        updateStatus() {
            let data = { value: this.output.length, keys: this.keys };
            this.statusEl.innerHTML = isEmpty(data.keys) ? this.options.lang.nullKeys : renderTpl(this.options.lang.status, data);
        }
        async updateCont(content, cb) {
            if (this.destroyed)
                return this;
            await getContent.call(this, {
                content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: {
                    xhrName: 'contXhr',
                    spinSel: this.targetEl,
                    ...this.options.ajax
                },
                request: (data) => {
                    this.listen({ name: 'request', params: [data] });
                },
                cb: (data) => {
                    if (isEmpty(data))
                        return this;
                    this.data = this.getStdData(data);
                    super.listen({ name: 'processed', params: [this.data] });
                    this.searchData();
                    this.render();
                    this.updateCache({ content });
                    this.listen({ name: 'updatedCont', cb, params: [data] });
                }
            });
            return this;
        }
        destroy(cb) {
            if (this.inputEl) {
                this.inputEl.removeEventListener(this.options.trigger, this.inputEvt);
            }
            this.contXhr && this.contXhr.abort();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optAutocomplete = [
        {
            attr: 'field',
            prop: 'field',
            value: 'value',
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'tpl-str',
            prop: 'tplStr',
            value: '',
        },
        {
            attr: 'tpl-eng',
            prop: 'tplEng',
            value: null,
        },
        {
            attr: 'popup',
            prop: 'popup',
            value: {},
        },
        {
            attr: 'retrieval',
            prop: 'retrieval',
            value: {},
        },
        {
            attr: 'b4-fill',
            prop: 'b4Fill',
            value: null,
        },
        {
            attr: 'on-shown',
            prop: 'onShown',
            value: null,
        },
        {
            attr: 'on-hidden',
            prop: 'onHidden',
            value: null,
        },
        {
            attr: 'on-cleared',
            prop: 'onCleared',
            value: null,
        },
        {
            attr: 'on-reset2show',
            prop: 'onReset2Show',
            value: null,
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null,
        },
        ...optBase
    ];

    class Autocomplete extends ModBaseListenCache {
        options = {};
        mainEl;
        rendered;
        popupIns;
        retrievalIns;
        contXhr;
        static hostType = 'node';
        static optMaps = optAutocomplete;
        constructor(elem, options = {}, initial = config.initial) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Autocomplete.optMaps,
                component: false,
                spread: []
            });
            this.rendered = false;
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setEmpty();
            if (!this.targetEl)
                return this;
            super.getDirRtl();
            this.createPopup();
            this.createRetrieval();
            this.setAttrs();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setVals(val) {
            let nodeName = this.targetEl.nodeName;
            if (['OC-INPUT', 'OC-TEXTAREA'].includes(nodeName)) {
                this.targetEl.setAttribute('value', val);
            }
            else if (['INPUT', 'TEXTAREA'].includes(nodeName)) {
                this.targetEl.value = val;
            }
        }
        setEmpty() {
            this.popupIns && this.popupIns.destroy();
            this.popupIns?.contEl && (this.popupIns.contEl.innerHTML = '');
            this.retrievalIns && this.retrievalIns.destroy();
        }
        setAttrs() {
            this.popupIns.mainEl.classList.add(`${orca.prefix}autocomplete`);
        }
        createPopup() {
            this.popupIns = new Popup(this.targetEl, extend({
                target: {
                    placement: this.isRtl ? 'bottom-end' : 'bottom-start',
                    tools: { enable: true, placement: 'outside' },
                    pageClose: false,
                    footer: false,
                    trigger: 'input',
                    content: '',
                    padding: false,
                    b4Show: () => {
                        return new Promise((resolve) => {
                            if (this.rendered) {
                                resolve();
                            }
                            else {
                                this.popupIns.state = 'hidden';
                            }
                        });
                    },
                    onHidden: () => {
                        this.rendered = false;
                    }
                },
                source: this.options.popup
            }));
        }
        createRetrieval() {
            this.retrievalIns = new Retrieval(extend({
                target: {
                    target: this.popupIns.contEl,
                    editor: this.targetEl,
                    content: this.options.content,
                    contType: this.options.contType,
                    contData: this.options.contData,
                    ajax: this.options.ajax,
                    tplStr: this.options.tplStr,
                    tplEng: this.options.tplEng,
                    status: true,
                    highlight: true,
                    nullHandle: 'clear',
                    bubble: {
                        divisible: true,
                        hoverable: true,
                    },
                },
                source: this.options.retrieval
            }));
            this.retrievalIns.on('rendered', (data) => {
                for (let k of data) {
                    k.source.el.onclick = async () => {
                        let val = k.source[this.options.field];
                        if (this.options.b4Fill) {
                            let resp = await this.options.b4Fill.call(this, k, this.targetEl);
                            resp && (val = resp);
                        }
                        this.setVals(val);
                        this.hide();
                    };
                }
                if (this.retrievalIns.renderCount > 0) {
                    this.rendered = true;
                    this.retrievalIns.getInputVals().trim() && this.popupIns.show();
                    this.rendered = false;
                }
            });
        }
        reset2Show(cb) {
            if (this.destroyed)
                return this;
            this.retrievalIns.resetList();
            this.show();
            super.listen({ name: 'reset2Show', cb });
            return this;
        }
        clear(cb) {
            if (this.destroyed)
                return this;
            this.retrievalIns.clearList();
            this.hide();
            super.listen({ name: 'cleared', cb });
            return this;
        }
        show(cb) {
            if (this.destroyed)
                return this;
            this.rendered = true;
            this.popupIns.show();
            super.listen({ name: 'shown', cb });
            return this;
        }
        hide(cb) {
            if (this.destroyed)
                return this;
            this.popupIns.hide();
            super.listen({ name: 'hidden', cb });
            return this;
        }
        updateCont(content, cb) {
            if (this.destroyed)
                return this;
            this.retrievalIns.updateCont(content, (data) => {
                this.updateCache({ content });
                this.listen({ name: 'updatedCont', cb, params: [data] });
            });
            return this;
        }
        destroy(cb) {
            this.retrievalIns.destroy();
            this.popupIns.destroy();
            this.contXhr && this.contXhr.abort();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optScroll = [
        {
            attr: 'wrapper',
            prop: 'wrapper',
            value: '',
        },
        {
            attr: 'axis',
            prop: 'axis',
            value: 'y',
        },
        {
            attr: 'bounce',
            prop: 'bounce',
            value: true,
        },
        {
            attr: 'delay',
            prop: 'delay',
            value: 200,
        },
        {
            attr: 'gridded',
            prop: 'gridded',
            value: false,
        },
        {
            attr: 'snap',
            prop: 'snap',
            value: {
                enable: false,
                mode: 'auto',
                force: false,
                offset: 0,
                selector: '',
            },
        },
        {
            attr: 'drift',
            prop: 'drift',
            value: {
                enable: false,
                mode: 'auto',
                value: 0,
                coef: 2,
            },
        },
        {
            attr: 'swipe',
            prop: 'swipe',
            value: {
                enable: false,
                mode: 'auto',
                value: 0,
                coef: 2,
            },
        },
        {
            attr: 'bar',
            prop: 'bar',
            value: {
                enable: false,
                sticky: false,
                triggerable: true,
            },
        },
        {
            attr: 'dmp-ratio',
            prop: 'dmpRatio',
            value: 0.5,
        },
        {
            attr: 'initial',
            prop: 'initial',
            value: {
                value: null,
                mode: 'scroll',
            },
        },
        {
            attr: 'child',
            prop: 'child',
            value: {
                size: null,
                gap: 0,
                settable: false,
            },
        },
        {
            attr: 'toinit-mode',
            prop: 'toInitMode',
            value: 'scroll',
        },
        {
            attr: 'duration',
            prop: 'duration',
            value: 300,
        },
        {
            attr: 'resize-thr',
            prop: 'resizeThr',
            value: 1,
        },
        {
            attr: 'rtl',
            prop: 'rtl',
            value: false,
        },
        {
            attr: 'wheel',
            prop: 'wheel',
            value: {
                mode: 'const',
                value: 0,
                reverse: false,
            },
        },
        {
            attr: 'keyboard',
            prop: 'keyboard',
            value: false,
        },
        {
            attr: 'completed-thr',
            prop: 'completedThr',
            value: 50,
        },
        {
            attr: 'padding-start',
            prop: 'paddingStart',
            value: 0,
        },
        {
            attr: 'padding-end',
            prop: 'paddingEnd',
            value: 0,
        },
        {
            attr: 'insertable',
            prop: 'insertable',
            value: true,
        },
        {
            attr: 'gesture',
            prop: 'gesture',
            value: {},
        },
        {
            attr: 'b4-tostart',
            prop: 'b4ToStart',
            value: null,
        },
        {
            attr: 'b4-toend',
            prop: 'b4ToEnd',
            value: null,
        },
        {
            attr: 'on-completed',
            prop: 'onCompleted',
            value: null,
        },
        {
            attr: 'on-exceeded',
            prop: 'onExceed',
            value: null,
        },
        {
            attr: 'on-start',
            prop: 'onStart',
            value: null,
        },
        {
            attr: 'on-move',
            prop: 'onMove',
            value: null,
        },
        {
            attr: 'on-end',
            prop: 'onEnd',
            value: null,
        },
        {
            attr: 'on-getsnappeds',
            prop: 'onGetSnappeds',
            value: null,
        },
        {
            attr: 'on-refactored',
            prop: 'onRefactored',
            value: null,
        },
        {
            attr: 'on-snap',
            prop: 'onSnap',
            value: null,
        },
        {
            attr: 'on-snapped',
            prop: 'onSnapped',
            value: null,
        },
        {
            attr: 'on-resized',
            prop: 'onResized',
            value: null,
        },
        {
            attr: 'on-scroll',
            prop: 'onScroll',
            value: null,
        },
        {
            attr: 'on-scrolled',
            prop: 'onScrolled',
            value: null,
        },
        {
            attr: 'on-locate',
            prop: 'onLocate',
            value: null,
        },
        {
            attr: 'on-located',
            prop: 'onLocated',
            value: null,
        },
        ...optBase
    ];

    class Scroll extends ModBaseListenCache {
        options = {};
        forwardMap;
        reverseMap;
        wrapEl;
        snappeds;
        unsnappeds;
        snapped;
        started;
        scrolled;
        cross;
        childAvgSize;
        resizeCount;
        mutateCount;
        canResize;
        canMutate;
        initialResize;
        key2Trans;
        resizeListener;
        mutationListener;
        targetSize;
        reverseSize;
        wrapSize;
        paddingStart;
        paddingEnd;
        rangeEnd;
        rangeStart;
        activeSize;
        baseSize;
        isBaby;
        transNow;
        transLast;
        gap;
        barSize;
        progress;
        trackEl;
        thumbEl;
        barIns;
        gestureIns;
        wrapStyleObs;
        sizeObs;
        lastSnapped;
        respThrot;
        static hostType = 'node';
        static optMaps = optScroll;
        constructor(elem, options = {}, initial = config.initial) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Scroll.optMaps,
                component: false,
                spread: ['snap', 'drift', 'swipe', 'bar', 'keyboard']
            });
            this.forwardMap = propsMap[this.options.axis];
            this.reverseMap = propsMap[this.options.axis === 'x' ? 'y' : 'x'];
            this.wrapEl = this.options.wrapper ? getEl(this.options.wrapper) : this.targetEl.firstElementChild;
            if (!this.wrapEl)
                return this;
            this.snappeds = [];
            this.unsnappeds = [];
            this.snapped = null;
            this.started = false;
            this.scrolled = true;
            this.cross = '';
            this.childAvgSize = null;
            this.resizeCount = 0;
            this.mutateCount = 0;
            this.canResize = true;
            this.canMutate = true;
            this.initialResize = false;
            
            
            this.resizeListener = debounce((data) => {
                this.resizeCount++;
                for (let k of data) {
                    if (!k.contentRect.width && !k.contentRect.height)
                        return;
                    this.response();
                }
                super.listen({ name: 'resized', params: [data] });
                if (this.resizeCount === this.options.resizeThr || (!this.wrapEl.firstElementChild && this.resizeCount === this.options.resizeThr - 1)) {
                    this.setTransInit();
                    this.initialResize = true;
                    super.listen({ name: 'prepared', params: [data] });
                }
            }, this.options.delay);
            this.mutationListener = debounce((data) => {
                this.mutateCount++;
                for (let k of data) {
                    if (k.type === "attributes") {
                        this.updateProg();
                        this.options.bar.enable && this.updateBarProg();
                    }
                    if (k.type === "childList") {
                        this.options.snap.enable && this.getSnappeds();
                        this.response();
                    }
                }
                super.listen({ name: 'refactored', params: [data] });
            }, this.options.delay);
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setEmpty();
            this.setAttrs();
            this.transNow = this.transLast = 0;
            this.gap = toPixel(this.options.child.gap);
            this.createBar();
            this.updateDiff();
            this.initSnapArgs();
            this.getSnappeds();
            await promiseRaf(() => {
                this.getGestureIns();
                this.setObserver();
            });
            super.listen({ name: 'initiated', cb });
            return this;
        }
        initSnapArgs() {
            if (!this.options.snap.enable)
                return this;
            if (this.options.snap.mode === 'auto') {
                !this.options.snap.selector && (this.options.snap.selector = '[unalignable]');
            }
            else {
                !this.options.snap.selector && (this.options.snap.selector = '[alignable]');
                !this.options.snap.offset && (this.options.snap.offset = 50);
            }
        }
        setEmpty() {
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}scroll`);
            this.wrapEl.classList.add(`${orca.prefix}scroll-wrap`);
            this.targetEl.setAttribute('axis', this.options.axis);
            this.targetEl.toggleAttribute('gridded', this.options.gridded);
            this.options.rtl ? this.targetEl.setAttribute('dir', 'rtl') : this.targetEl.removeAttribute('dir');
        }
        getGestureIns() {
            this.gestureIns = new Gesture(this.wrapEl, extend({
                target: {
                    wheel: true,
                    keyboard: {
                        enable: this.options.keyboard,
                        prev: this.options.axis === 'x' ? (this.isRtl ? 'ArrowRight' : 'ArrowLeft') : 'ArrowUp',
                        next: this.options.axis === 'x' ? (this.isRtl ? 'ArrowLeft' : 'ArrowRight') : 'ArrowDown',
                        target: this.targetEl,
                    },
                    spy: this.options.keyboard,
                    step: {
                        mode: 'translate',
                        axis: this.options.axis,
                        value: this.options.wheel.value,
                        linkage: false,
                        duration: this.options.duration,
                    },
                    drift: {
                        enable: this.options.drift.enable,
                        coef: this.options.drift.coef,
                        auto: false,
                    },
                    swipe: {
                        enable: this.options.swipe.enable,
                        coef: 1,
                        auto: false,
                    },
                    initialVal: { [this.options.axis]: this.transNow },
                    onStep: (data) => {
                        this.getStepVal(data.step.direction[this.options.axis]);
                    },
                    onStepped: (data) => {
                        this.scrollTo({
                            target: data.translate.value[this.options.axis],
                            duration: this.options.duration,
                            snap: true,
                        });
                    },
                    onTranslate: (data) => {
                        super.listen({ name: 'start', params: [data.translate] });
                    },
                    onTranslating: (data) => {
                        if (data.translate.diff.h > 2) {
                            this.transNow = data.translate.value[this.options.axis];
                            this.cross = this.crossLinkage();
                            if (this.cross.includes('baby')) {
                                if (data.pointer === 'wheel')
                                    return this;
                                if (this.cross === 'baby-start') {
                                    this.transNow = this.getDmpVals('start+');
                                }
                                else if (this.cross === 'baby-start-reverse') {
                                    this.transNow = this.getDmpVals('start-');
                                }
                            }
                            else if (this.cross === 'teen-start') {
                                if (data.pointer === 'wheel') {
                                    this.toStart();
                                    return this;
                                }
                                this.transNow = this.getDmpVals('start+');
                            }
                            else if (this.cross === 'teen-end') {
                                if (data.pointer === 'wheel') {
                                    this.toEnd();
                                    return this;
                                }
                                this.transNow = this.getDmpVals('end+');
                            }
                            else if (this.cross === 'adult-start') {
                                if (data.pointer === 'wheel') {
                                    this.toStart();
                                    return this;
                                }
                                this.transNow = this.getDmpVals('start+');
                            }
                            else if (this.cross === 'adult-end') {
                                if (data.pointer === 'wheel') {
                                    this.toEnd();
                                    return this;
                                }
                                this.transNow = this.getDmpVals('end+');
                            }
                            transformTools.set({
                                el: this.wrapEl,
                                data: { translate: { [this.options.axis]: this.transNow } }
                            });
                            this.handleExceedLimit({ linkage: this.cross });
                            super.listen({ name: 'move', params: [data.translate] });
                        }
                    },
                    onTranslated: (data) => {
                        this.transLast = this.transNow;
                        this.handleExceedLimit({
                            start: async (ratio) => {
                                this.options.b4ToStart && await this.options.b4ToStart.call(this, ratio);
                                this.toStart();
                                this.gestureIns.preventEase = true;
                            },
                            end: async (ratio) => {
                                this.options.b4ToEnd && await this.options.b4ToEnd.call(this, ratio);
                                this.toEnd(undefined, false);
                                this.gestureIns.preventEase = true;
                            },
                            normal: () => {
                                this.options.snap.enable && !data.translate.canDrfit && this.setSnapped();
                            }
                        });
                        super.listen({ name: 'end', params: [data.translate] });
                    },
                    onSwipe: (data) => {
                        this.setEaseTo(data, 'swipe');
                    },
                    onDrift: (data) => {
                        this.setEaseTo(data);
                    },
                },
                source: this.options.gesture,
            }));
        }
        getRtlRange() {
            let rtlHandler = () => {
                let tmp = this.rangeStart;
                this.rangeStart = this.rangeEnd * -1;
                this.rangeEnd = tmp * -1;
            }, dirAttr = this.targetEl.getAttribute('dir');
            if (dirAttr === 'rtl') {
                rtlHandler();
                this.isRtl = true;
                return;
            }
            if (getRtl()) {
                this.isRtl = true;
                rtlHandler();
            }
        }
        setTransInit() {
            let target = isNull(this.options.initial.value) ? (this.isRtl ? this.rangeStart : this.rangeEnd) : this.options.initial.value, params = { target, snap: true };
            this.options.initial.mode === 'localte' ? this.locateTo(params) : this.scrollTo(params);
        }
        createBar() {
            if (this.options.bar.enable) {
                if (!this.trackEl) {
                    this.thumbEl = createEl('span');
                    this.trackEl = createEl('div', { class: `${orca.prefix}scroll-bar` }, this.thumbEl);
                    this.options.bar.sticky && this.trackEl.setAttribute('shown', '');
                    this.targetEl.appendChild(this.trackEl);
                }
                if (this.options.bar.triggerable && !orca.isTouchScr) {
                    let prog = 0;
                    this.barIns = new Gesture(this.trackEl, {
                        onTranslate: () => {
                            prog = this.progress;
                            this.trackEl.setAttribute('scrolling', '');
                        },
                        onTranslating: (data) => {
                            this.locateTo({
                                target: prog + data.translate.value[this.options.axis] / this.barSize.diff,
                                isRatio: true,
                            });
                        },
                        onTranslated: () => {
                            this.trackEl.removeAttribute('scrolling');
                        }
                    });
                }
            }
        }
        setObserver() {
            this.wrapStyleObs = new MutationObserver(mutations => {
                this.canMutate && this.mutationListener(mutations);
            });
            this.wrapStyleObs.observe(this.wrapEl, {
                childList: true,
                attributes: true,
                attributeFilter: ['style']
            });
            this.sizeObs = new ResizeObserver((entries) => {
                this.canResize && this.resizeListener(entries);
            });
            this.sizeObs.observe(this.targetEl);
            this.sizeObs.observe(this.wrapEl);
        }
        
        response() {
            this.updateDiff();
            if (this.isBaby) {
                this.toStart();
            }
            else if (this.wrapEl[this.forwardMap.offset] > this.paddingStart) {
                this.toStart();
            }
            else if (this.transNow < this.rangeStart) {
                this.toEnd(undefined, false);
            }
            else {
                this.options.snap.enable && this.setSnapped();
            }
        }
        getDmpVals(placement) {
            let val = 0, dmp = this.options.dmpRatio ** 2;
            if (placement === 'start+') {
                val = this.options.bounce ? this.paddingStart * super.getRtlCoef() + (this.transNow - this.paddingStart * super.getRtlCoef()) * dmp : this.paddingStart;
            }
            else if (placement === 'end+') {
                let tmp = this.isRtl ? this.rangeEnd : this.rangeStart;
                val = this.options.bounce ? tmp + (this.transNow - tmp) * dmp : tmp;
            }
            else if (placement === 'start-') {
                val = this.options.bounce ? this.paddingStart * super.getRtlCoef() - (this.paddingStart * super.getRtlCoef() - this.transNow) * dmp : this.paddingStart;
            }
            return val;
        }
        getTruePadding(val) {
            let result;
            if (val === 'center') {
                let firstSize = ~~(style(this.wrapEl.firstElementChild)[this.forwardMap.size]).replace('px', ''), value = !isNull(this.childAvgSize) ? this.childAvgSize : firstSize;
                result = (this.targetSize - value) / 2;
            }
            else if (typeof val === 'number') {
                if (val <= 0) {
                    result = 0;
                }
                else if (val < 1) {
                    result = this.targetSize * val;
                }
                else {
                    result = val;
                }
            }
            else if (typeof val === 'string') {
                result = toPixel(val);
            }
            return result;
        }
        setChildSize() {
            let getVal = (val) => {
                let type = typeof val;
                if (type === 'string') {
                    if (val.includes('/')) {
                        let avg = ~~(val.split('/')[1].trim());
                        return avg <= 1 ? this.targetSize : (this.targetSize - (avg - 1) * this.gap) / avg;
                    }
                    else {
                        return toPixel(val);
                    }
                }
                else if (type === 'number') {
                    return val < 0 ? 0 : (val <= 1 && val >= 0) ? this.targetSize * val : val;
                }
                else {
                    return null;
                }
            };
            if (!isEmpty(this.options.child.size)) {
                let children = [...this.wrapEl.children];
                if (Array.isArray(this.options.child.size)) {
                    if (this.options.child.settable) {
                        let vals = this.options.child.size.map((k) => getVal(k));
                        children.forEach((k, i) => {
                            !isNull(vals[i]) && (k.style[this.forwardMap.size] = vals[i] + 'px');
                        });
                    }
                }
                else {
                    let val = getVal(this.options.child.size);
                    this.childAvgSize = val;
                    if (!isNull(val) && this.options.child.settable) {
                        for (let k of children) {
                            k.style[this.forwardMap.size] = val + 'px';
                        }
                    }
                }
            }
        }
        updateDiff() {
            let targetStyle = style(this.targetEl), wrapStyle = style(this.wrapEl), targetHeight = parseInt(targetStyle.height), wrapHeight = parseInt(wrapStyle.height), targetWidth = parseInt(targetStyle.width), wrapWidth = parseInt(wrapStyle.width), outerSize = 0, reverseSize = 0, innerSize = 0;
            if (this.options.axis === 'x') {
                outerSize = targetWidth;
                reverseSize = targetHeight;
                innerSize = wrapWidth;
            }
            else if (this.options.axis === 'y') {
                outerSize = targetHeight;
                reverseSize = targetWidth;
                innerSize = wrapHeight;
            }
            this.targetSize = outerSize;
            this.reverseSize = reverseSize;
            this.wrapSize = innerSize;
            this.setChildSize();
            this.paddingStart = this.getTruePadding(this.options.paddingStart);
            this.paddingEnd = this.getTruePadding(this.options.paddingEnd);
            if (this.paddingStart + this.paddingEnd >= outerSize) {
                this.paddingStart = this.paddingEnd = 0;
                console.warn('The combined padding values on both sides exceed the container size; padding values have been removed!');
            }
            this.rangeEnd = this.paddingStart;
            this.rangeStart = outerSize - innerSize - this.paddingEnd;
            this.isBaby = outerSize - innerSize - this.paddingEnd - this.paddingStart > 0;
            this.getRtlRange();
            this.activeSize = this.isBaby ? 0 : this.rangeEnd - this.rangeStart;
            this.baseSize = this.targetSize - this.paddingStart - this.paddingEnd;
            this.updateProg();
            this.getBarSize();
            this.updateBarProg();
        }
        getNowTargetDist(target) {
            if (!target)
                return 0;
            let targetType = getDataType(target);
            if (targetType === 'Number') {
                return Math.abs(target - this.transNow);
            }
            else if (targetType.includes('HTML')) {
                if (this.isRtl) {
                    return Math.abs(this.getChildParentOffset(target) + this.transNow + this.rangeStart);
                }
                else {
                    return Math.abs(this.getChildParentOffset(target) + this.transNow - this.rangeEnd);
                }
            }
            else {
                return 0;
            }
        }
        setEaseTo(data, type = 'drift') {
            data[type].value[this.options.axis] = this.getEaseDist(data.translate.direction[this.options.axis], this.getEdgeValue(data[type].value[this.options.axis]), type);
            let target = (this.options.snap.enable && this.options.snap.mode === 'auto') ? this.getNearestSnap(data[type].value[this.options.axis]).nearest : data[type].value[this.options.axis];
            this.scrollTo({
                target,
                snap: true,
            });
        }
        getEaseDist(dir, value, type = 'drift') {
            let result = value;
            if (this.options[type].mode === 'ratio') {
                let dft = this.options[type].value || 1;
                result = this.transNow + this.baseSize * dft * dir;
            }
            else if (this.options[type].mode === 'const') {
                this.options[type].value && (result = this.transNow + this.options[type].value * dir);
            }
            else if (this.options[type].mode === 'snap' && this.options.snap.enable && this.options.snap.mode === 'auto') {
                let tmp = this.getEaseNextTrans(dir, type);
                !isNull(tmp) && (result = tmp);
            }
            else if (this.options[type].mode === 'slide') {
                let tmp = this.getEaseNextTrans(dir, type, 'slide');
                !isNull(tmp) && (result = tmp);
            }
            return result;
        }
        getEaseNextTrans(dir, type = 'drift', mode = 'snap') {
            let result = null, chidlren = mode === 'slide' ? [...this.wrapEl.children] : this.snappeds, nearest = mode === 'slide' ? this.getNearestSlide() : this.snapped, idx = chidlren.findIndex((k) => k === nearest);
            if (idx > -1) {
                let num = [0, 1].includes(this.options[type].value) ? 1 : this.options[type].value, dist = dir === 1 ? this.getNowTargetDist(chidlren[idx - num]) : dir === -1 ? this.getNowTargetDist(chidlren[idx + num]) * -1 : 0;
                result = this.transNow + dist;
            }
            return result;
        }
        getStepVal(dir) {
            if (this.options.wheel.mode === 'ratio') {
                let dft = this.options.wheel.value || 0.25, val = this.baseSize * dft;
                this.gestureIns.stepVal = val;
            }
            else if (this.options.wheel.mode === 'const') {
                this.options.wheel.value && (this.gestureIns.stepVal = this.options.wheel.value);
            }
            else if (this.options.wheel.mode === 'snap' && this.options.snap.enable && this.options.snap.mode === 'auto') {
                this.getWheelNextTrans(dir);
            }
            else if (this.options.wheel.mode === 'slide') {
                this.getWheelNextTrans(dir, 'slide');
            }
            this.gestureIns.stepVal = this.gestureIns.stepVal * super.getRtlCoef();
        }
        getWheelNextTrans(dir, mode = 'snap') {
            let chidlren = mode === 'slide' ? [...this.wrapEl.children] : this.snappeds, nearest = mode === 'slide' ? this.getNearestSlide() : this.snapped, idx = chidlren.findIndex((k) => k === nearest);
            if (idx > -1) {
                let num = [0, 1].includes(this.options.wheel.value) ? 1 : this.options.wheel.value;
                this.gestureIns.stepVal = dir === 1 ? this.getNowTargetDist(chidlren[idx + num]) : dir === -1 ? this.getNowTargetDist(chidlren[idx - num]) : 0;
            }
        }
        getEdgeValue(data, isRatio = false) {
            let value = this.isRtl ? this.rangeStart : this.rangeEnd;
            if (this.isBaby)
                return value;
            let dataType = getDataType(data);
            if (dataType.includes('HTML') || dataType === 'String') {
                let el = getEl(data);
                el && (value -= this.getChildParentOffset(el));
            }
            else {
                if (isRatio) {
                    let ratio = clampVal({ min: 0, max: 1, val: data });
                    value = this.rangeEnd - this.activeSize * ratio;
                }
                else {
                    value = data;
                }
            }
            if (value || value === 0) {
                if (value >= this.rangeEnd) {
                    value = this.rangeEnd;
                }
                else if (value <= this.rangeStart) {
                    value = this.rangeStart;
                }
            }
            return value;
        }
        updateProg(value = this.transNow) {
            if (this.activeSize <= 0) {
                this.progress = 1;
            }
            else {
                this.progress = (this.isRtl ? (value - this.rangeStart) : (this.rangeEnd - value)) / this.activeSize;
            }
        }
        getBarSize() {
            if (this.options.bar.enable) {
                let track = parseInt(style(this.trackEl)[this.forwardMap.size]), ratio = Math.min(this.baseSize / this.wrapSize, 1), thumb = track * ratio;
                this.barSize = { track, thumb, diff: track - thumb };
            }
        }
        updateBarProg() {
            if (this.options.bar.enable) {
                let exceedRatio = this.progress < 0 ? Math.abs(this.progress) : this.progress > 1 ? this.progress - 1 : 0, progress = (this.progress >= 0 || this.progress <= 1) ? this.progress : 1, exceedSize = this.barSize.thumb * (1 - exceedRatio ** 2), thumbPos = (this.barSize.track - exceedSize) * progress;
                this.thumbEl.style[this.forwardMap.size] = exceedSize + 'px';
                this.thumbEl.style[this.forwardMap.start] = thumbPos + 'px';
            }
        }
        exceedListen(ratio, placement) {
            this.listen({ name: 'exceeded', params: [ratio, placement] });
            ratio >= 1 && this.listen({ name: 'completed', params: [ratio, placement] });
        }
        handleExceedLimit({ start, end, normal, linkage }) {
            let ratio = 0, cross = linkage || this.crossLinkage();
            if (cross.includes('start')) {
                ratio = Math.abs(this.transNow / this.options.completedThr);
                start && start(ratio.toFixed(2));
                linkage && this.exceedListen(toNumber(ratio, { places: 2 }), 'start');
            }
            else if (cross.includes('end')) {
                ratio = Math.abs(this.transNow * super.getRtlCoef() - this.rangeStart) / this.options.completedThr;
                end && end(ratio.toFixed(2));
                linkage && this.exceedListen(toNumber(ratio, { places: 2 }), 'end');
            }
            else {
                normal && normal();
            }
        }
        crossLinkage(value = this.transNow) {
            let result = 'regular';
            value = value * super.getRtlCoef();
            if ((this.isRtl ? -this.rangeEnd : this.rangeStart) > 0) {
                if (this.isBaby) {
                    if (value > this.paddingStart) {
                        result = 'baby-start';
                    }
                    else {
                        result = 'baby-start-reverse';
                    }
                }
                else {
                    if (value > this.paddingStart) {
                        result = 'teen-start';
                    }
                    else if (value < this.isRtl ? -this.rangeEnd : this.rangeStart) {
                        result = 'teen-end';
                    }
                }
            }
            else {
                if (value > this.paddingStart) {
                    result = 'adult-start';
                }
                else if (value < (this.isRtl ? -this.rangeEnd : this.rangeStart)) {
                    result = 'adult-end';
                }
            }
            return result;
        }
        toStart(duration, snap = true) {
            if (this.destroyed || this.transNow === this.rangeEnd)
                return this;
            this.scrollTo({
                target: this.paddingStart * super.getRtlCoef(),
                snap,
                duration: duration || this.options.duration,
                after: () => {
                    super.listen({ name: 'toStart' });
                }
            });
        }
        toEnd(duration, snap = true) {
            if (this.destroyed || this.transNow === this.rangeStart)
                return this;
            this.scrollTo({
                target: this.isRtl ? this.rangeEnd : this.rangeStart,
                snap,
                duration: duration || this.options.duration,
                after: () => {
                    super.listen({ name: 'toEnd' });
                }
            });
        }
        toPrev() {
            if (this.destroyed || this.transNow === this.rangeEnd)
                return this;
        }
        toNext() {
            if (this.destroyed || this.transNow === this.rangeStart)
                return this;
        }
        getSnappeds() {
            if (this.options.snap.enable) {
                if (this.options.snap.mode === 'auto') {
                    this.unsnappeds = super.single2Els(this.options.snap.selector, this.wrapEl);
                    this.snappeds = [...this.wrapEl.children].filter(k => !this.unsnappeds.includes(k));
                }
                else {
                    this.snappeds = super.single2Els(this.options.snap.selector, this.wrapEl);
                }
                super.listen({ name: 'getSnappeds', params: [this.snappeds] });
            }
        }
        getChildParentOffset(child, parent = this.wrapEl) {
            let tmp = this.isRtl && this.forwardMap.position === 'left' ? 'right' : this.forwardMap.position;
            return child.getBoundingClientRect()[tmp] - parent.getBoundingClientRect()[tmp];
        }
        sortEls(arr, val = this.transNow) {
            let tmp = arr.map((k) => {
                let offset = Math.abs(val - this.paddingStart * super.getRtlCoef() + this.getChildParentOffset(k));
                return { el: k, offset };
            });
            tmp.sort((a, b) => a.offset - b.offset);
            return tmp;
        }
        getNearestSnap(val = this.transNow) {
            let snappeds = this.sortEls(this.snappeds, val), nearest = null;
            if (this.options.snap.mode === 'auto') {
                if (this.options.snap.offset) {
                    let temp = snappeds.find((k) => k.offset <= this.options.snap.offset);
                    nearest = temp ? temp.el : null;
                }
                else {
                    nearest = snappeds[0].el;
                }
            }
            else {
                nearest = snappeds[0].offset <= this.options.snap.offset ? snappeds[0].el : null;
            }
            return { nearest, snappeds };
        }
        getNearestSlide(val = this.transNow) {
            let tmp = this.sortEls([...this.wrapEl.children], val);
            return tmp[0]?.el;
        }
        setSnapped(options = {}) {
            if (this.destroyed || this.wrapEl.children.length === 0 || !this.options.snap.enable)
                return this;
            this.scrolled = false;
            let opt = Object.assign({ force: this.options.snap.force }, options), current = this.getNearestSnap(), snappeds = current.snappeds, nearest = current.nearest, toEl = opt.target ? getEl(opt.target, this.wrapEl) : null, target = toEl || nearest;
            if (!nearest || !target)
                return this;
            if (target !== this.snapped || opt.force) {
                this.toggleSnappedAttr(target, snappeds);
                super.listen({ name: 'snap', cb: opt.before, params: [target] });
            }
            this.scrollTo({
                target,
                duration: opt.duration || this.options.duration,
                after: () => {
                    if (target === this.snapped) {
                        super.listen({ name: 'snapped', cb: opt.after, params: [target] });
                    }
                }
            });
        }
        toggleSnappedAttr(target, snappeds = this.getNearestSnap().snappeds) {
            let el = getEl(target, this.wrapEl), last;
            if (el) {
                el.setAttribute('snapped', '');
                last = snappeds.find(k => k.el !== el && k.el.hasAttribute('snapped'));
                last && last.el.removeAttribute('snapped');
                this.snapped = el;
            }
        }
        scrollTo({ target = this.transNow, duration, before, after, snap = false, isRatio = false }) {
            if (this.destroyed)
                return this;
            this.scrolled = false;
            let trans = this.getEdgeValue(target, isRatio);
            if (this.transNow === trans)
                return;
            let now = this.transNow, compare = Math.abs(this.transNow - trans) / this.targetSize, dur = duration || duration == 0 ? duration : Math.trunc(this.options.duration * compare);
            this.wrapEl.style.transitionDuration = clampVal({ val: dur, min: 200, max: 2000 }) + 'ms';
            transformTools.set({ el: this.wrapEl, data: { translate: { [this.options.axis]: trans } } });
            super.listen({ name: 'scroll', cb: before, params: [trans, now] });
            this.transLast = this.transNow = trans;
            delay({
                duration: dur,
                done: () => {
                    if (this.options.snap.enable) {
                        snap ? this.setSnapped() : this.getNearestSnap();
                    }
                    super.listen({ name: 'scrolled', cb: after, params: [trans, now] });
                    this.scrolled = true;
                }
            });
        }
        locateTo({ target = this.transNow, before, after, snap = false, isRatio = false }) {
            if (this.destroyed)
                return this;
            let trans = this.getEdgeValue(target, isRatio);
            if (this.transNow === trans)
                return;
            let now = this.transNow;
            this.wrapEl.style.transitionDuration = '0ms';
            transformTools.set({ el: this.wrapEl, data: { translate: { [this.options.axis]: trans } } });
            super.listen({ name: 'locate', cb: before, params: [trans, now] });
            this.transLast = this.transNow = trans;
            if (this.options.snap.enable) {
                snap ? this.setSnapped() : this.getNearestSnap();
            }
            super.listen({ name: 'located', cb: after, params: [trans, now] });
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.sizeObs.disconnect();
            this.wrapStyleObs.disconnect();
            this.options.bar.enable && this.options.bar.triggerable && !orca.isTouchScr && this.barIns.destroy();
            this.gestureIns.destroy();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optMasonry = [
        {
            attr: 'gap',
            prop: 'gap',
            value: 0,
        },
        {
            attr: 'cols',
            prop: 'cols',
            value: 0,
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'content',
            prop: 'content',
            value: ''
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'tpl-str',
            prop: 'tplStr',
            value: '',
        },
        {
            attr: 'tpl-eng',
            prop: 'tplEng',
            value: null,
        },
        {
            attr: 'media',
            prop: 'media',
            value: {
                title: '',
                brief: '',
            },
        },
        {
            attr: 'b4-add',
            prop: 'b4Add',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'b4-clear',
            prop: 'b4Clear',
            value: null,
        },
        {
            attr: 'on-added',
            prop: 'onAdded',
            value: null,
        },
        {
            attr: 'on-removed',
            prop: 'onRemoved',
            value: null,
        },
        {
            attr: 'on-cleared',
            prop: 'onCleared',
            value: null,
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null,
        },
        ...optBase
    ];

    class Masonry extends ModBaseListenCache {
        options = {};
        itemsTmp;
        itemsObs;
        items;
        itemSizeObs;
        gap;
        canListen;
        static hostType = 'node';
        static optMaps = optMasonry;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: Masonry.optMaps,
                host: elem,
                component: false,
            });
            this.itemsTmp = [];
            this.itemsObs = new Observe(this.itemsTmp, {
                onSet: (data) => {
                    if (getDataType(data.value).includes('HTML')) {
                        this.targetEl.appendChild(data.value);
                        this.itemSizeObs.observe(data.value);
                    }
                },
                onDeleted: (data) => { },
                onCompleted: () => {
                }
            });
            this.items = this.itemsObs.proxy;
            this.itemSizeObs = new ResizeObserver((data) => {
                for (let k of data) {
                    this.updateItemStyle(k.target);
                }
            });
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setAttrs();
            this.gap = this.getGap();
            this.targetEl.style.columnGap = `${this.gap}px`;
            if (Array.isArray(this.options.content) && this.options.content.length > 0) {
                this.items.push(...this.options.content);
            }
            else if (this.targetEl.innerHTML.trim()) {
                this.items.push(...this.targetEl.children);
                
            }
            super.listen({ name: 'initiated', cb });
            return this;
        }
        getGap() {
            return Math.ceil(toPixel(this.options.gap || style(this.targetEl).columnGap));
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}masonry`);
            classes(this.targetEl).add(this.options.classes);
            this.options.cols ? addStyle(this.targetEl, 'grid-template-columns', `repeat(${this.options.cols}, 1fr)`) : removeStyle(this.targetEl, 'grid-template-columns');
        }
        updateItemStyle(el) {
            let height = el.offsetHeight;
            el.style.gridRow = `span ${Math.ceil(height + this.gap)}`;
        }
        setItem(el) {
            this.itemSizeObs.observe(el);
        }
        async add(data, cb) {
            if (this.destroyed)
                return this;
            let tmp = Array.isArray(data) ? data : [data];
            this.options.b4Add && await this.options.b4Add.call(this, tmp);
            this.items.push(...tmp);
            super.listen({ name: 'add', cb, params: [tmp] });
            return this;
        }
        async remove(data, cb) {
            if (this.destroyed)
                return this;
            let tmp = Array.isArray(data) ? data : [data];
            this.options.b4Remove && await this.options.b4Remove.call(this, tmp);
            for (let k = 0; k < tmp.length; k++) {
                let item = tmp[k], idx = this.items.findIndex((k) => k === item);
                if (idx > -1) {
                    this.items.splice(idx, 1);
                    this.items[idx].remove();
                }
            }
            super.listen({ name: 'remove', cb, params: [tmp] });
            return this;
        }
        async clear(cb) {
            if (this.destroyed)
                return this;
            this.options.b4Clear && await this.options.b4Clear.call(this);
            this.items.splice(0);
            this.targetEl.innerHTML = '';
            super.listen({ name: 'cleared', cb });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.clearCache();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    let OCTMP_hyphen$2 = config.splitHyphen;
    const optSwipe = [
        {
            attr: 'axis',
            prop: 'axis',
            value: 'x',
        },
        {
            attr: 'keyboard',
            prop: 'keyboard',
            value: false,
        },
        {
            attr: 'active',
            prop: 'active',
            value: 0,
        },
        {
            attr: 'duration',
            prop: 'duration',
            value: 500,
        },
        {
            attr: 'throttle',
            prop: 'throttle',
            value: 0,
        },
        {
            attr: 'slides',
            prop: 'slides',
            value: 1,
        },
        {
            attr: 'divide',
            prop: 'divide',
            value: 1,
        },
        {
            attr: 'group',
            prop: 'group',
            value: 0,
        },
        {
            attr: 'loop',
            prop: 'loop',
            value: false,
        },
        {
            attr: 'autoHeight',
            prop: 'autoHeight',
            value: false,
        },
        {
            attr: 'countdown',
            prop: 'countdown',
            value: {},
        },
        {
            attr: 'gap',
            prop: 'gap',
            value: 0,
        },
        {
            attr: 'unalign',
            prop: 'unalign',
            value: '[unalignable]',
        },
        {
            attr: 'centered',
            prop: 'centered',
            value: {
                enable: false,
                fill: false,
            },
        },
        {
            attr: 'active',
            prop: 'active',
            value: 0,
        },
        {
            attr: 'keyboard',
            prop: 'keyboard',
            value: false,
        },
        {
            attr: 'resize-reset',
            prop: 'resizeReset',
            value: true,
        },
        {
            attr: 'drift',
            prop: 'drift',
            value: 1,
        },
        {
            attr: 'wheel',
            prop: 'wheel',
            value: 1,
        },
        {
            attr: 'scroll',
            prop: 'scroll',
            value: {},
        },
        {
            attr: 'tools',
            prop: 'tools',
            value: {
                enable: false,
                placement: 'right-top',
                children: [],
            },
        },
        {
            attr: 'total',
            prop: 'total',
            value: {
                enable: false,
                placement: 'right-top',
                hyphen: '/',
            },
        },
        {
            attr: 'pgn',
            prop: 'pgn',
            value: {
                enable: false,
                classes: '',
                type: 'lamp',
                selector: '',
                data: [],
                before: null,
                after: null,
            },
        },
        {
            attr: 'nav',
            prop: 'nav',
            value: {
                enable: true,
                classes: '',
                fill: false,
                intvl: 500,
                prev: {
                    selector: '',
                    classes: '',
                    text: '',
                },
                next: {
                    selector: '',
                    classes: '',
                    text: '',
                },
            },
        },
        {
            attr: 'autoplay',
            prop: 'autoplay',
            value: {
                enable: false,
                delay: 4000,
                countdown: false,
            },
        },
        {
            attr: 'integrated',
            prop: 'integrated',
            value: false,
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'hyphen',
            prop: 'hyphen',
            value: OCTMP_hyphen$2,
        },
        {
            attr: 'tpl-str',
            prop: 'tplStr',
            value: '',
        },
        {
            attr: 'tpl-eng',
            prop: 'tplEng',
            value: null,
        },
        {
            attr: 'lazy',
            prop: 'lazy',
            value: false,
        },
        {
            attr: 'media',
            prop: 'media',
            value: {
                title: '',
                brief: '',
            },
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'on-fold',
            prop: 'onFold',
            value: null,
        },
        {
            attr: 'on-unfold',
            prop: 'onUnfold',
            value: null,
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null,
        },
        ...optBase
    ];

    const getSlidersData = async function (opts) {
        let wrapEl = getEl(opts.wrap), parentEl = getEl(opts.parent), grossData = [];
        if (!isEmpty(opts.content)) {
            await getContent.call(this, {
                content: opts.content,
                contType: opts.contType,
                contData: opts.contData,
                hyphen: opts.hyphen,
                ajax: {
                    xhrName: 'contXhr',
                    spinSel: parentEl,
                    ...(opts.ajax || {})
                },
                cb: (data) => {
                    grossData = data;
                }
            });
        }
        else if (wrapEl && wrapEl.innerHTML.trim()) {
            grossData = [...wrapEl.children];
        }
        else {
            grossData = [];
        }
        let fillSlider = async (node, data) => {
            let childType = getDataType(data);
            if (childType === 'String' || childType === 'Number') {
                
                node.innerHTML = data;
            }
            else if (childType === 'Object') {
                if (data.hasOwnProperty('content')) {
                    await getContent.call(this, {
                        content: data.content,
                        contType: data.contType,
                        contData: data.contData,
                        hyphen: data.hyphen || opts.hyphen,
                        ajax: {
                            xhrName: 'contXhr',
                            spinSel: node,
                            ...(data.ajax || {})
                        },
                        cb: (resp) => {
                            let respType = getDataType(resp);
                            if (['String', 'Number'].includes(respType)) {
                                node.innerHTML = resp;
                            }
                            else if (respType.includes('HTML')) {
                                node.appendChild(resp);
                            }
                            else if (['Object', 'Array'].includes(respType)) {
                                node.innerHTML = getStrFromTpl.call(this, resp, data.tplStr, data.tplEng);
                            }
                        }
                    });
                }
                else {
                    node.innerHTML = getStrFromTpl.call(this, data);
                }
            }
            else if (childType === 'Array') {
                node.innerHTML = getStrFromTpl.call(this, data);
            }
        }, dataType = getDataType(grossData), result = [];
        if (dataType.includes('HTML')) {
            result = [{ source: grossData, slider: grossData }];
        }
        else if (dataType === 'String') {
            let tmp = createEl('div', '', grossData), els = [...(tmp.querySelector('ul,ol') || tmp).children];
            result = els.map((k) => {
                return { source: k, slider: k };
            });
        }
        else if (dataType === 'Array' || dataType === 'Object') {
            let tmp = (dataType === 'Object') ? [grossData] : grossData.filter((k) => !isNull(k));
            if (tmp.length === 0)
                return;
            result = tmp.map((k) => {
                let childType = getDataType(k), slider;
                if (childType.includes('HTML')) {
                    slider = k;
                }
                else {
                    slider = createEl('li');
                    if (opts.lazy) {
                        k.spy = new Spy(slider, {
                            root: parentEl || wrapEl,
                            repeat: false,
                            onIn: () => {
                                fillSlider(slider, k);
                            }
                        });
                    }
                    else {
                        fillSlider(slider, k);
                    }
                }
                return { source: k, slider };
            });
        }
        opts.cb && opts.cb(result);
        return result;
    };

    const optProgress = [
        {
            attr: 'type',
            prop: 'type',
            value: 'line',
        },
        {
            attr: 'theme',
            prop: 'theme',
            value: '',
        },
        {
            attr: 'gradient',
            prop: 'gradient',
            value: false
        },
        {
            attr: 'linecap',
            prop: 'linecap',
            value: 'round',
        },
        {
            attr: 'size',
            prop: 'size',
            value: '',
        },
        {
            attr: 'thk',
            prop: 'thk',
            value: '',
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'range',
            prop: 'range',
            value: [0, 100],
        },
        {
            attr: 'value',
            prop: 'value',
            value: 0,
        },
        {
            attr: 'curve',
            prop: 'curve',
            value: 'easeOut',
        },
        {
            attr: 'duration',
            prop: 'duration',
            value: 0,
        },
        {
            attr: 'rotate',
            prop: 'rotate',
            value: false,
        },
        {
            attr: 'simple',
            prop: 'simple',
            value: false,
        },
        {
            attr: 'control',
            prop: 'control',
            value: false,
        },
        {
            attr: 'steps',
            prop: 'steps',
            value: [],
        },
        {
            attr: 'label',
            prop: 'label',
            value: {
                enable: true,
                template: '',
                placement: '',
                unit: '%',
                tips: false,
            },
        },
        {
            attr: 'number',
            prop: 'number',
            value: {
                type: 'percent',
                trunc: true,
                emphatic: false,
            },
        },
        {
            attr: 'b4-set',
            prop: 'b4Set',
            value: null,
        },
        {
            attr: 'on-start',
            prop: 'onStart',
            value: null,
        },
        {
            attr: 'on-move',
            prop: 'onMove',
            value: null,
        },
        {
            attr: 'on-end',
            prop: 'onEnd',
            value: null,
        },
        {
            attr: 'on-zero',
            prop: 'onZero',
            value: null,
        },
        {
            attr: 'on-completed',
            prop: 'onCompleted',
            value: null,
        },
        {
            attr: 'on-set',
            prop: 'onSet',
            value: null,
        },
        {
            attr: 'on-pause',
            prop: 'onPause',
            value: null,
        },
        {
            attr: 'on-continue',
            prop: 'onContinue',
            value: null,
        },
        {
            attr: 'on-restored',
            prop: 'onRestored',
            value: null,
        },
        ...optBase
    ];

    class Progress extends ModBaseListenCache {
        options = {};
        vals;
        valNow;
        barNow;
        range;
        barSize;
        steps;
        completeEl;
        textEl;
        controlEl;
        obsIns;
        obs;
        labelTpl;
        trackEl;
        wrapEl;
        barEl;
        labelEl;
        numEl;
        unitEl;
        tipsEl;
        animFrame;
        durRest;
        initVals;
        startVals;
        endVals;
        toggleCtrl;
        static hostType = 'node';
        static optMaps = optProgress;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: Progress.optMaps,
                host: elem,
                component: true,
                spread: ['label']
            });
            this.vals = {};
            this.valNow = 0;
            this.barNow = 0;
            this.toggleCtrl = () => {
                this.controlEl.classList.contains(`${orca.prefix}icon-pause`) ? this.pause() : this.continue();
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.range = [...this.options.range].sort((a, b) => a - b);
            this.barSize = this.options.type === 'circle' ? 251.2 : this.options.type === 'semicircle' ? 125.6 : this.options.type === 'gapcircle' ? 167.6 : this.range[1];
            this.steps = this.options.steps.length ? [...this.options.steps].sort((a, b) => b.value - a.value) : [];
            this.getInitVals();
            this.completeEl = createEl('span', { [orca.alias]: 'complete' }, this.options.lang.complete);
            this.textEl = createEl('div', { [orca.alias]: 'text' });
            this.controlEl = createEl('i', { [orca.alias]: 'control', class: `${orca.prefix}icon-pause`, disabled: '' });
            this.controlEl.addEventListener('click', this.toggleCtrl, false);
            this.setObs();
            this.render();
            this.setAttrs();
            this.watchEnds();
            this.watchSteps();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setObs() {
            this.obsIns = new Observe({ paused: false, completed: false }, {
                onSet: (resp) => {
                    if (resp.key === 'paused') ;
                    else if (resp.key === 'completed') {
                        if (resp.value) {
                            this.targetEl.setAttribute('completed', '');
                            this.labelEl ? this.labelEl.appendChild(this.completeEl) : null;
                        }
                        else {
                            this.completeEl.remove();
                            this.targetEl.removeAttribute('completed');
                        }
                    }
                }
            });
            this.obs = this.obsIns.proxy;
        }
        setControl(pause, disabled) {
            if (pause) {
                classes(this.controlEl).replace(`${orca.prefix}icon-pause`, `${orca.prefix}icon-play`);
            }
            else {
                classes(this.controlEl).replace(`${orca.prefix}icon-play`, `${orca.prefix}icon-pause`);
            }
            if (disabled) {
                this.controlEl.setAttribute('disabled', '');
            }
            else {
                this.controlEl.removeAttribute('disabled');
            }
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}progress`);
            this.targetEl.setAttribute('linecap', this.options.linecap);
            this.targetEl.setAttribute('type', this.options.type);
            this.options.thk ? this.targetEl.setAttribute('thk', this.options.thk) : this.targetEl.removeAttribute('thk');
            this.options.size ? this.targetEl.setAttribute('size', this.options.size) : this.targetEl.removeAttribute('size');
            this.options.theme ? this.targetEl.setAttribute('theme', this.options.theme) : this.targetEl.removeAttribute('theme');
            this.targetEl.toggleAttribute('gradient', this.options.gradient);
            this.targetEl.toggleAttribute('simple', this.options.simple);
            this.options.classes && classes(this.targetEl).add(this.options.classes);
            let tmp = [`${orca.prefix}rotate360`, `${orca.prefix}loop-inf`];
            (this.options.rotate && this.options.type === 'circle') ? this.wrapEl.classList.add(...tmp) : this.wrapEl.classList.remove(...tmp);
        }
        getInitVals() {
            this.vals = this.getVals();
            this.valNow = this.vals.val;
            this.barNow = this.vals.bar;
            this.initVals = { ...this.vals };
            this.startVals = {
                val: this.range[0],
                bar: this.barSize,
                ratio: 0,
                percent: 0,
                number: this.getNumber(this.range[0], 0),
            };
            this.endVals = {
                val: this.range[1],
                bar: 0,
                ratio: 1,
                percent: 100,
                number: this.getNumber(this.range[1], 100),
            };
        }
        getVal(val = this.vals.val) {
            return isNull(val) ? this.range[0] : clampVal({ val, min: this.range[0], max: this.range[1] });
        }
        getBarVal(val) {
            let result;
            if (val == this.range[0]) {
                result = this.barSize;
            }
            else if (val == this.range[1]) {
                result = 0;
            }
            else {
                let value, ratio, tmp;
                if (isNull(val)) {
                    value = this.vals.val;
                    ratio = this.vals.ratio;
                }
                else {
                    value = clampVal({ val: val, min: this.range[0], max: this.range[1] });
                    ratio = this.getRatio(value);
                }
                tmp = (this.options.type == 'line') ? (value - this.range[0]) : (this.barSize * (1 - ratio));
                result = toNumber(tmp, { mode: 'floor' });
            }
            return result;
        }
        getRatio(val = this.vals.val) {
            let result;
            if (val == this.range[1]) {
                result = 1;
            }
            else if (val == this.range[0]) {
                result = 0;
            }
            else {
                result = toNumber((val - this.range[0]) / (this.range[1] - this.range[0]), { places: 4, mode: 'floor' });
            }
            return result;
        }
        getNumber(value, percent) {
            let tmp = this.options.number.type === 'value' ? value : percent, val = this.options.number.trunc ? ~~tmp : toNumber(tmp, { places: 2, mode: 'floor', zero: true }), result = this.options.number.emphatic ? splitNum(val) : val;
            return result;
        }
        getVals(val = this.options.value) {
            let value = this.getVal(val), ratio = this.getRatio(value), percent = ratio * 100, barVal = this.getBarVal(value), number = this.getNumber(value, percent);
            return {
                val: value,
                bar: barVal,
                ratio,
                percent,
                number,
            };
        }
        render() {
            this.targetEl.innerHTML = '';
            this.labelTpl = this.options.label.template || `<div ${orca.alias}=label><div ${orca.alias}=result><i ${orca.alias}=number></i><i ${orca.alias}=unit></i></div></div>`;
            if (this.options.type == 'line') {
                this.trackEl = createEl('div', { [orca.alias]: 'track' });
                this.wrapEl = this.trackEl;
                this.barEl = createEl('div', { [orca.alias]: 'bar', 'style': `width:${this.vals.percent}%` });
                this.wrapEl.appendChild(this.barEl);
            }
            else {
                let gradient = '', svg = '';
                if (this.options.gradient) {
                    if (this.options.theme == 'prim') {
                        gradient = `
                <linearGradient id="svgbar-prim" >
                    <stop offset="0%" style="stop-color:var(--${orca.prefix}c-prim);" ></stop>
                    <stop offset="100%" style="stop-color:var(--${orca.prefix}c-prim-aj);" ></stop>
                </linearGradient>
              `;
                    }
                    else if (this.options.theme == 'error') {
                        gradient = `
                <linearGradient id="svgbar-error" >
                    <stop offset="0%" style="stop-color:var(--${orca.prefix}c-error);" ></stop>
                    <stop offset="100%" style="stop-color:var(--${orca.prefix}c-error-aj);" ></stop>
                </linearGradient>
              `;
                    }
                    else if (this.options.theme == 'succ') {
                        gradient = `
                <linearGradient id="svgbar-succ" >
                    <stop offset="0%" style="stop-color:var(--${orca.prefix}c-succ);" ></stop>
                    <stop offset="100%" style="stop-color:var(--${orca.prefix}c-succ-aj);" ></stop>
                </linearGradient>
              `;
                    }
                    else if (this.options.theme == 'warn') {
                        gradient = `
            <linearGradient id="svgbar-warn" >
                <stop offset="0%" style="stop-color:var(--${orca.prefix}c-warn);" ></stop>
                <stop offset="100%" style="stop-color:var(--${orca.prefix}c-warn-aj);" ></stop>
            </linearGradient>
          `;
                    }
                    else if (this.options.theme == 'info') {
                        gradient = `
                <linearGradient id="svgbar-info" >
                    <stop offset="0%" style="stop-color:var(--${orca.prefix}c-info);" ></stop>
                    <stop offset="100%" style="stop-color:var(--${orca.prefix}c-info-aj);" ></stop>
                </linearGradient>
              `;
                    }
                    else if (this.options.theme == 'issue') {
                        gradient = `
                <linearGradient id="svgbar-issue" >
                    <stop offset="0%" style="stop-color:var(--${orca.prefix}c-issue);" ></stop>
                    <stop offset="100%" style="stop-color:var(--${orca.prefix}c-issue-aj);"></stop>
                </linearGradient>
              `;
                    }
                }
                if (this.options.type == 'circle') {
                    svg = `<svg viewBox="0 0 100 100">
                            ${gradient}
                            ${!this.options.simple ? `<path d="M 50 50 m -40 0 a 40 40 0 1 1 80 0  a 40 40 0 1 1 -80 0" ${orca.alias}="track"></path>` : ''}
                            <path d="M 50 50 m -40 0 a 40 40 0 1 1 80 0  a 40 40 0 1 1 -80 0" ${orca.alias}="bar" stroke-dasharray=${this.barSize} stroke-linecap=${this.options.linecap}  stroke-dashoffset=${this.vals.bar}></path>
                       </svg>
                        `;
                }
                else if (this.options.type == 'semicircle') {
                    svg = `<svg viewBox="0 0 100 60">
                            ${gradient}
                            ${!this.options.simple ? `<path d="M 50 50 m -40 0 a 40 40 0 1 1 80 0" ${orca.alias}="track" stroke-linecap=${this.options.linecap}></path>` : ''}
                            <path d="M 50 50 m -40 0 a 40 40 0 1 1 80 0" ${orca.alias}="bar" stroke-dasharray=${this.barSize} stroke-linecap=${this.options.linecap} stroke-dashoffset=${this.vals.bar}></path>
                       </svg>
                        `;
                }
                else if (this.options.type == 'gapcircle') {
                    svg = `<svg viewBox="0 0 100 80">
                            ${gradient}
                            ${!this.options.simple ? `<path d="M15.367,70.026C11.954,64.137,10,57.296,10,49.999 C10,27.909,27.909,10,50,10c22.092,0,40,17.909,40,39.999c0,7.295-1.952,14.134-5.363,20.022" ${orca.alias}="track" stroke-linecap=${this.options.linecap}></path>` : ''}
                            <path d="M15.367,70.026C11.954,64.137,10,57.296,10,49.999 C10,27.909,27.909,10,50,10c22.092,0,40,17.909,40,39.999c0,7.295-1.952,14.134-5.363,20.022" ${orca.alias}="bar" stroke-dasharray=${this.barSize} stroke-linecap=${this.options.linecap} stroke-dashoffset=${this.vals.bar}></path>
                       </svg>
                        `;
                }
                this.wrapEl = tplToEl(svg);
                this.barEl = this.wrapEl.querySelector(`[${orca.alias}="bar"]`);
                this.trackEl = this.wrapEl.querySelector(`[${orca.alias}="track"]`);
            }
            this.targetEl.appendChild(this.wrapEl);
            this.targetEl.appendChild(this.textEl);
            if (this.options.label.enable) {
                if (!this.options.label.placement) {
                    this.textEl.insertAdjacentHTML('beforeEnd', this.labelTpl);
                    this.labelEl = this.targetEl.querySelector(`[${orca.alias}="label"]`);
                }
                else {
                    let place = getEl(this.options.label.placement);
                    if (place) {
                        place.insertAdjacentHTML('beforeEnd', this.labelTpl);
                        this.labelEl = place.querySelector(`[${orca.alias}="label"]`);
                    }
                }
                this.numEl = this.labelEl.querySelector(`[${orca.alias}="number"]`);
                this.unitEl = this.labelEl.querySelector(`[${orca.alias}="unit"]`);
                this.numEl && (this.numEl.innerHTML = this.vals.number);
                this.unitEl && (this.unitEl.innerHTML = this.options.label.unit);
                if (this.options.label.tips) {
                    if (!this.labelEl.querySelector(`[${orca.alias}="tips"]`)) {
                        this.tipsEl = createEl('span', { [orca.alias]: 'tips' }, this.options.lang.tips);
                        this.labelEl.insertAdjacentElement('afterbegin', this.tipsEl);
                    }
                    else {
                        this.tipsEl = this.labelEl.querySelector(`[${orca.alias}="tips"]`);
                        this.tipsEl.innerHTML = this.options.lang.tips;
                    }
                }
            }
            this.options.control && this.textEl.appendChild(this.controlEl);
        }
        setAnim(val = this.vals.val, duration) {
            if (this.obs.paused)
                return false;
            if (val === this.valNow)
                return false;
            this.animFrame && cancelAnimationFrame(this.animFrame);
            let vals = this.vals, dftTime = (size) => size * 3 + 200, barDiff = vals.bar - this.barNow, time = duration || dftTime(Math.abs(barDiff));
            this.setControl(false, false);
            ease({
                from: { val: this.valNow },
                to: { val },
                duration: time,
                curve: this.options.curve,
                before: (resp) => {
                    super.listen({ name: 'start', params: [{ ...vals }] });
                },
                progress: (resp) => {
                    vals = this.getVals(resp.value.val);
                    this.durRest = resp.remaining;
                    this.valNow = vals.val;
                    this.barNow = vals.bar;
                    if (this.options.type == 'line') {
                        this.barEl.style.width = vals.percent + '%';
                    }
                    else {
                        this.barEl.setAttribute('stroke-dashoffset', this.barNow);
                    }
                    this.numEl && (this.numEl.innerHTML = vals.number);
                    this.animFrame = resp.frame;
                    this.watchEnds();
                    this.watchSteps();
                },
                doing: (resp) => {
                    super.listen({ name: 'move', params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow }] });
                },
                done: (resp) => {
                    this.setControl(false, true);
                    super.listen({ name: 'end', params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow }] });
                },
            });
        }
        watchEnds() {
            if (this.valNow >= this.range[1]) {
                this.obs.completed = true;
                super.listen({ name: 'completed' });
            }
            else {
                this.obs.completed = false;
                (this.valNow <= this.range[0]) && super.listen({ name: 'zero' });
            }
        }
        watchSteps(val = this.valNow) {
            if (!this.steps.length)
                return;
            let step = this.steps.find((k) => k.value <= val);
            if (step) {
                if (step.color) {
                    if (['prim', 'succ', 'error', 'info', 'warn', 'issue', 'text'].includes(step.color)) {
                        this.targetEl.setAttribute('theme', step.color);
                    }
                    else {
                        if (this.options.type === 'line') {
                            this.barEl.style.background = step.color;
                        }
                        else {
                            this.barEl.style.stroke = step.color;
                        }
                    }
                }
                step.text && (this.textEl.innerHTML = step.text);
                step.action && step.action.call(this, step.value, this.valNow);
            }
        }
        getStepVals(val) {
            let result;
            if (typeof val === 'string') {
                if (val === 'zero') {
                    result = this.startVals;
                }
                else if (val === 'completed') {
                    result = this.endVals;
                }
                else if (val.includes('/')) {
                    let splits = val.split('/'), num = ~~splits[0], demom = ~~splits[1], ratio = num / demom, value = (this.range[1] - this.range[0]) * ratio + this.range[0];
                    result = this.getVals(value);
                }
                else {
                    result = this.getVals();
                }
            }
            else if (typeof val === 'number') {
                result = this.getVals(val);
            }
            return result;
        }
        async animateTo(val, opts) {
            if (this.destroyed)
                return this;
            this.barEl.style.transitionDuration = null;
            this.obs.paused = false;
            this.vals = typeof val === 'string' ? this.getStepVals(val) : this.getVals(val);
            this.options.b4Set && await this.options.b4Set.call(this, this.vals);
            if (this.vals.val === this.valNow)
                return false;
            this.setAnim(this.vals.val, opts?.duration);
            super.listen({ name: 'set', cb: opts?.cb, params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow }] });
            return this;
        }
        async locateTo(val, opts) {
            this.vals = typeof val === 'string' ? this.getStepVals(val) : this.getVals(val);
            this.options.b4Set && await this.options.b4Set.call(this, this.vals);
            this.animFrame && cancelAnimationFrame(this.animFrame);
            this.obs.paused = false;
            this.valNow = this.vals.val;
            this.barNow = this.vals.bar;
            this.numEl && (this.numEl.innerHTML = this.vals.number);
            this.barEl.style.transitionDuration = '0ms';
            if (this.options.type === 'line') {
                this.barEl.style.width = this.vals.percent + '%';
            }
            else {
                this.barEl.setAttribute('stroke-dashoffset', this.barNow);
            }
            this.watchEnds();
            this.watchSteps();
            super.listen({ name: 'set', cb: opts?.cb, params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow }] });
            return this;
        }
        restore(cb) {
            if (this.destroyed)
                return this;
            this.locateTo('restore');
            super.listen({ name: 'restored', cb });
            return this;
        }
        setCompleted(cb) {
            if (this.destroyed)
                return this;
            this.locateTo('completed');
            cb && cb.call(this);
            return this;
        }
        setZero(cb) {
            if (this.destroyed)
                return this;
            this.locateTo('zero');
            cb && cb.call(this);
            return this;
        }
        continue(duration, cb) {
            if (this.destroyed || this.valNow === this.vals.val)
                return this;
            if (!this.obs.paused)
                return false;
            this.obs.paused = false;
            this.setControl(false, false);
            this.setAnim(this.vals.val, duration || this.durRest);
            super.listen({ name: 'continue', cb, params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow, durRest: duration || this.durRest }] });
            return this;
        }
        pause(cb) {
            if (this.destroyed || this.valNow === this.vals.val)
                return this;
            if (this.animFrame) {
                cancelAnimationFrame(this.animFrame);
                this.obs.paused = true;
                this.setControl(true, false);
            }
            super.listen({ name: 'pause', cb, params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow }] });
            return this;
        }
        get() {
            return {
                ...this.vals,
                valNow: this.valNow,
                barNow: this.barNow,
                completed: this.obs.completed,
                paused: this.obs.paused,
                durRest: this.durRest || 0,
            };
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.restore();
            this.controlEl.removeEventListener('click', this.toggleCtrl);
            this.obsIns.ins.destroy();
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    class Swipe extends ModBaseListenCache {
        options = {};
        intercepted;
        button;
        content;
        folded;
        handlers;
        html;
        pureHtml;
        event;
        text;
        ell;
        countdownEl;
        intervalEvt;
        startClone;
        endClone;
        sliderTpl;
        prepareListen;
        resetListener;
        setBulletActive;
        spyIns;
        slidersTmp;
        bulletsTmp;
        paused;
        scrollOpt;
        scrollIns;
        wrapEl;
        navEl;
        pgnEl;
        pgnIns;
        prevEl;
        nextEl;
        totalEl;
        numEl;
        denomEl;
        bullets;
        bulletSeq;
        interval;
        countdownIns;
        toolsEl;
        keyToSwipe;
        sliders;
        group;
        actIdx;
        slidersObs;
        bulletsObs;
        slideSize;
        slideSizeDivide;
        slides;
        totalClone;
        static hostType = 'node';
        static optMaps = optSwipe;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: Swipe.optMaps,
                host: elem,
                component: true,
                spread: ['autoplay', 'total', 'tools', 'pgn', 'nav', 'centered']
            });
            this.countdownEl = createEl('div');
            this.intervalEvt = () => {
                this.toNextBullet();
                this.startCountdown();
            };
            this.startClone = [];
            this.endClone = [];
            this.sliderTpl = { label: '', content: '', thumb: '', brief: '', slider: null, cb: null };
            this.prepareListen = throttle(() => {
                this.fillWedgets();
                this.setBulletActive(this.bullets.find((k) => this.actIdx === k.index) || 0);
                this.toggleNavDisabled();
                this.targetEl.classList.remove(`${orca.prefix}initiating`);
                this.setAutoPlay();
            });
            this.resetListener = throttle(() => {
                this.getSingleSize();
                this.setSlideSize();
                (this.group > this.sliders.length) && (this.group = this.sliders.length);
                super.listen({ name: 'resized' });
            });
            this.setBulletActive = (data) => {
                let bullet = this.findBullet(data);
                if (!bullet || bullet.active)
                    return;
                bullet.active = true;
                let other = this.bullets.find((k) => k !== bullet && k.active);
                other && Reflect.deleteProperty(other, 'active');
                
            };
            super.listen({ name: 'constructed' });
            if (initial) {
                if (this.options.lazy) {
                    this.spyIns = new Spy(this.targetEl, {
                        repeat: false,
                        onIn: () => {
                            this.init();
                        }
                    });
                }
                else {
                    this.init();
                }
            }
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.slidersTmp = [];
            this.bulletsTmp = [];
            this.paused = true;
            this.setAttrs();
            this.createWrap();
            await this.getSliders(this.options.content, (resp) => {
                this.slidersTmp = resp;
            });
            this.setSlidesObs();
            this.setBulletsObs();
            this.actIdx = this.getIdxFromActive(this.options.active);
            this.appendSliders();
            this.group = clampVal({ val: this.options.group, min: 0, max: this.sliders.length });
            this.setScroll();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        
        
        setAttrs() {
            classes(this.targetEl).add(`${orca.prefix}swipe,${orca.prefix}initiating`);
        }
        getDriftParams() {
            if (this.group)
                return { enable: true, mode: 'snap', value: 1 };
            let tmp = { mode: 'auto', coef: 6 };
            if (typeof this.options.drift === 'number' && this.options.drift > 0) {
                tmp = { mode: 'snap', value: this.options.divide * this.options.drift };
            }
            else if (this.options.drift === 'viewport' && this.options.slides > 0) {
                tmp = { mode: 'snap', value: this.options.slides * this.options.divide };
            }
            return { enable: true, ...tmp };
        }
        getWheelVal() {
            return this.options.divide * (this.group ? 1 : this.options.wheel);
        }
        setScroll() {
            this.scrollOpt = extend({
                target: {
                    wrapper: this.wrapEl,
                    gridded: this.options.divide > 1 ? true : false,
                    axis: this.options.axis,
                    keyboard: this.options.keyboard,
                    snap: {
                        enable: true,
                        selector: this.options.unalign,
                    },
                    wheel: {
                        mode: 'snap',
                        value: this.getWheelVal(),
                    },
                    drift: this.getDriftParams(),
                    initial: {
                        value: this.getInitSlider(),
                    },
                    duration: this.options.duration,
                    resizeThr: this.options.slides > 0 ? 2 : 1,
                    paddingStart: this.options.centered.enable ? 'center' : 0,
                    paddingEnd: this.options.centered.enable ? 'center' : 0,
                    child: { size: (this.options.slides > 0 ? `1 / ${this.options.slides}` : null), gap: this.options.gap },
                    onGetSnappeds: function () {
                    },
                    onPrepared: this.prepareListen,
                    onRefactored: this.resetListener,
                    onResized: this.resetListener,
                    onSnap: (slider) => {
                        if (this.scrollIns.initialResize) {
                            this.actIdx = this.sliders.findIndex((k) => k.slider === slider);
                            this.setBulletActive(slider);
                        }
                        (this.options.autoHeight && this.options.axis === 'x') && (this.targetEl.style.height = style(slider).height);
                    },
                    onSnapped: (slider) => {
                    },
                    onMove: () => {
                        this.pause(true);
                    }
                },
                source: this.options.scroll
            });
            if (this.group && this.options.slides > 1) ;
            if (this.options.slides >= 1) ;
            this.scrollIns = new Scroll(this.targetEl, this.scrollOpt);
        }
        async getSliders(data = this.options.content, cb) {
            let result = [];
            await getSlidersData.call(this, {
                content: data,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: this.options.ajax,
                hyphen: this.options.hyphen,
                parent: this.targetEl,
                wrap: this.wrapEl,
                lazy: this.options.lazy,
                tplStr: this.options.tplStr,
                tplEng: this.options.tplEng,
                cb: (resp) => {
                    result = [...resp];
                }
            });
            cb && cb(result);
            return result;
        }
        findSlider(data) {
            let dataType = getDataType(data), result;
            if (dataType === 'Number') {
                result = this.sliders[data]?.slider;
            }
            else if (dataType === 'Object') {
                result = data?.slider;
            }
            else {
                result = getEl(data, this.wrapEl);
            }
            return result;
        }
        appendSliders(data = this.sliders, placement = 'end') {
            let target, sliders = data.map((k) => k.slider);
            if (placement === 'start') {
                sliders.reverse();
                for (let k of sliders) {
                    this.wrapEl.insertAdjacentElement('afterbegin', k);
                }
            }
            else if (placement === 'end') {
                this.wrapEl.append(...sliders);
            }
            else {
                target = this.findSlider(placement);
                if (target) {
                    sliders.reverse();
                    for (let k of sliders) {
                        target.insertAdjacentElement('afterend', k);
                    }
                }
            }
        }
        createWrap() {
            let firstChild = this.targetEl.firstElementChild;
            if (firstChild) {
                firstChild.classList.add(`${orca.prefix}swipe-wrap`);
                this.wrapEl = firstChild;
            }
            else {
                this.wrapEl = createEl('ul', { class: `${orca.prefix}swipe-wrap ${orca.prefix}reset` }, '');
                this.targetEl.appendChild(this.wrapEl);
            }
            if (this.targetEl.querySelector(`.${orca.prefix}swipe-nav`)) {
                this.navEl = this.targetEl.querySelector(`.${orca.prefix}swipe-nav`);
            }
            else if (this.options.integrated) {
                this.navEl = createEl('div', { class: `${orca.prefix}swipe-nav` }, '');
                this.targetEl.appendChild(this.navEl);
            }
        }
        fillWedgets() {
            this.getBullets();
            this.fillNav();
            this.fillPgn();
            this.fillTotal();
        }
        updateWedgets() {
            this.getBullets();
            this.updatePgn();
            this.updateTotal();
        }
        setSlidesObs() {
            this.slidersObs = new Observe(this.slidersTmp, {
                onCompleted: () => {
                    this.updateGap();
                    this.updateWedgets();
                    this.scrollIns.setSnapped({ force: true });
                }
            });
            this.sliders = this.slidersObs.proxy;
        }
        setBulletsObs() {
            this.bulletsObs = new Observe(this.bulletsTmp, {
                deep: true,
                onSet: (resp) => {
                    if (resp.key === 'active' && resp.value === true) {
                        resp.proxy.el.setAttribute('active', '');
                        this.bulletSeq = this.findPrevNextBullet(resp.proxy);
                        this.toBullet(resp.proxy);
                        this.toggleNavDisabled(resp.proxy);
                        this.numEl && (this.numEl.innerHTML = this.bullets.findIndex((k) => k === resp.proxy) + 1);
                    }
                },
                onDeleted: (resp) => {
                    if (resp.key === 'active') {
                        resp.target.el.removeAttribute('active');
                    }
                },
                onCompleted: () => {
                }
            });
            this.bullets = this.bulletsObs.proxy;
        }
        findPrevNextBullet(data) {
            let item = this.findBullet(data);
            if (!item)
                return { prev: null, next: null };
            let idx = this.bullets.findIndex((k) => k === item), prev = this.bullets[idx - 1], next = this.bullets[idx + 1];
            if (!prev) {
                if (this.options.loop) ;
                else if (this.options.autoplay.enable) {
                    prev = this.bullets.at(-1);
                }
            }
            if (!next) {
                if (this.options.loop) ;
                else if (this.options.autoplay.enable) {
                    next = this.bullets[0];
                }
            }
            return { prev, next, current: item };
        }
        toggleNavDisabled(data) {
            if (this.options.loop || !this.options.nav.enable)
                return;
            if (this.bullets.length < 2) {
                this.prevEl.setAttribute('disabled', '');
                this.nextEl.setAttribute('disabled', '');
            }
            else {
                let item = this.findBullet(data);
                if (!item)
                    return;
                if (item === this.bullets[0]) {
                    this.prevEl.setAttribute('disabled', '');
                    this.nextEl.removeAttribute('disabled');
                }
                else if (item === this.bullets.at(-1)) {
                    this.nextEl.setAttribute('disabled', '');
                    this.prevEl.removeAttribute('disabled');
                }
                else {
                    this.prevEl.removeAttribute('disabled');
                    this.nextEl.removeAttribute('disabled');
                }
            }
        }
        setSlideSize() {
            if (this.options.slides > 0) {
                this.sliders.forEach((k) => {
                    this.setSingleSize(k);
                });
                this.updateGap();
            }
        }
        updateGap() {
            if (this.options.slides > 0) {
                if (this.options.divide > 1) {
                    this.sliders.forEach((k, i) => {
                        this.setSingleGap(k, i);
                    });
                }
                else {
                    if (this.options.gap > 0) {
                        this.sliders.forEach((k) => {
                            this.setSingleGap(k);
                        });
                    }
                }
            }
        }
        
        getIdxFromActive(active) {
            let result = this.getActiveIdex(active);
            return clampVal({ val: result, min: 0, max: this.sliders.length - 1 });
        }
        getActiveIdex(data) {
            let result = -1;
            if (typeof data === 'number') {
                result = data;
            }
            else {
                let tmp = getEl(data, this.targetEl);
                tmp && (result = this.sliders.findeIndex((k) => k.slider === tmp));
            }
            result >= this.sliders.length && (result = -1);
            return result;
        }
        getInitSlider() {
            if (this.sliders.length === 0 || this.actIdx === -1)
                return null;
            if (this.options.centered.enable && this.options.centered.fill) {
                if (this.options.slides > 1 && this.actIdx < ~~(this.options.slides / 2)) {
                    this.actIdx = ~~(this.options.slides / 2);
                }
            }
            return this.sliders[this.actIdx].slider;
        }
        getAccuracy(value, higher = true) {
            let places = value.toString().split(".")[1] ? value.toString().split(".")[1].length : 0;
            return places > 3 ? toNumber(value + (higher ? 0.1 : 0), { mode: higher ? 'ceil' : 'floor', places: 1 }) : value;
        }
        getSingleSize() {
            if (!(this.options.slides > 0))
                return;
            this.slideSize = this.getAccuracy(this.scrollIns.childAvgSize, this.scrollIns.gap > 0 ? false : true);
            if (this.options.divide > 1) {
                let netValueDivide = this.scrollIns.reverseSize - this.scrollIns.gap * (this.options.divide - 1), singleValueDivide = netValueDivide / this.options.divide;
                this.slideSizeDivide = this.getAccuracy(singleValueDivide, this.scrollIns.gap > 0 ? false : true);
            }
        }
        setSingleSize(item) {
            if (!(this.options.slides > 0))
                return;
            item.slider.style[this.scrollIns.forwardMap.size] = this.slideSize + 'px';
        }
        setSingleGap(item, index) {
            if (!(this.options.slides > 0))
                return;
            let idx = isNull(index) ? this.sliders.findIndex((k) => k === item) : index;
            if (this.options.divide > 1) {
                item.slider.style[this.scrollIns.reverseMap.size] = this.getAccuracy(this.slideSizeDivide, false) + 'px';
                if (idx % this.options.divide !== 0 && this.scrollIns.gap) {
                    item.slider.style[this.scrollIns.reverseMap.gap] = this.scrollIns.gap + 'px';
                }
                idx >= this.options.divide && (item.slider.style[this.scrollIns.forwardMap.gap] = this.scrollIns.gap + 'px');
            }
            else {
                idx !== 0 && (item.slider.style[this.scrollIns.forwardMap.gap] = this.scrollIns.gap + 'px');
            }
        }
        getBullets() {
            this.bullets.length = 0;
            let unsnappeds = [], len = this.sliders.length;
            if (this.options.slides > 0) {
                this.sliders.forEach((k, i) => {
                    let obj = { target: k, el: createEl('li'), index: i };
                    if (this.options.centered.enable) {
                        this.bullets.push(obj);
                    }
                    else {
                        if (this.options.loop) {
                            if (this.group && this.options.slides > 1) {
                                if (i % (this.options.slides * this.options.divide) === 0) {
                                    this.bullets.push(obj);
                                }
                                else {
                                    k.slider.setAttribute(this.options.unalign, '');
                                }
                            }
                            else {
                                this.bullets.push(obj);
                            }
                        }
                        else {
                            let num = this.options.divide * (this.group || this.options.slides);
                            if ((i % num === 0 && this.sliders.length - i >= num) || i === len - num) {
                                this.bullets.push(obj);
                            }
                            else {
                                if (this.group) {
                                    unsnappeds.push(k.slider);
                                    setSingleSel(k.slider, this.options.unalign);
                                }
                            }
                        }
                        this.updateUnsnappeds(unsnappeds);
                    }
                });
            }
            else {
                if (this.scrollIns.isBaby) {
                    this.bullets.push({ target: this.sliders[0], el: createEl('li'), index: 0 });
                }
                else {
                    let splits = this.getSplits(), tmp = this.getSanpOffsetArr();
                    for (let k of tmp) {
                        for (let v of splits) {
                            ((k.offsetStart <= v && k.offsetEnd > v)) && this.bullets.push({ target: k.target, el: createEl('li'), index: k.index });
                        }
                    }
                }
            }
        }
        updateUnsnappeds(unsnappeds) {
            this.scrollIns.unsnappeds = unique([...this.scrollIns.unsnappeds, ...unsnappeds]);
            this.scrollIns.snappeds = [...this.wrapEl.children].filter(k => !this.scrollIns.unsnappeds.includes(k));
        }
        getSplits() {
            let num = Math.floor(this.scrollIns.wrapSize / this.scrollIns.baseSize), getSplits = (num, unit) => {
                let result = [];
                for (let k = 0; k < num; k++) {
                    result.push(k * unit);
                }
                return result;
            }, result = getSplits(num, this.scrollIns.baseSize);
            result.push(this.scrollIns.wrapSize - this.scrollIns.baseSize);
            return result;
        }
        getSanpOffsetArr() {
            let result = [];
            this.sliders.forEach((k, i) => {
                if (this.scrollIns.snappeds.includes(k.slider)) {
                    let idx = this.scrollIns.snappeds.findIndex((v) => v === k.slider), nextSnapped = this.scrollIns.snappeds[idx + 1], offsetStart = k.slider[this.scrollIns.forwardMap.offset], offsetEnd = nextSnapped ? this.scrollIns.snappeds[idx + 1][this.scrollIns.forwardMap.offset] : offsetStart + k.slider[this.scrollIns.forwardMap.outer];
                    result.push({ offsetStart, offsetEnd, target: k, index: i });
                }
            });
            return result;
        }
        updateTotal(value = this.getTotal()) {
            if (!this.options.total.enable)
                return false;
            if (!value.bullets) {
                this.numEl.innerHTML = this.denomEl.innerHTML = 0;
            }
            else {
                this.numEl.innerHTML = value.curBullet + 1;
                this.denomEl.innerHTML = value.bullets;
            }
        }
        fillTotal() {
            if (!this.options.total.enable)
                return false;
            let total = this.getTotal();
            this.totalEl = createEl('span', { class: `${orca.prefix}swipe-total` }, `<i></i><s>${this.options.total.hyphen}</s><u></u>`);
            this.numEl = this.totalEl.querySelector('i');
            this.denomEl = this.totalEl.querySelector('u');
            this.updateTotal(total);
            this.options.total.placement && this.totalEl.setAttribute('placement', this.options.total.placement);
            this.targetEl.appendChild(this.totalEl);
        }
        getTotal() {
            return { curSlider: this.actIdx, sliders: this.sliders.length, curBullet: this.bullets.findIndex((k) => k.active), bullets: this.bullets.length };
        }
        fillNav() {
            if (!this.options.nav.enable)
                return false;
            let addNav = (type) => {
                let result = null, text = (type === 'prev') ? (this.options.axis === 'x' ? `${orca.prefix}icon-left` : `${orca.prefix}icon-up`) :
                    (type === 'next') ? (this.options.axis === 'x' ? `${orca.prefix}icon-right` : `${orca.prefix}icon-down`) : '', className = `${orca.prefix}swipe-${type}`, el = getEl(`.${className}`, this.targetEl);
                if (el) {
                    result = el;
                }
                else if (this.options.nav[type].selector) {
                    result = getEl(this.options.nav[type].selector);
                }
                else {
                    result = createEl('i', { class: `${className} ${text}` });
                    this.navEl ? this.navEl.appendChild(result) : this.targetEl.appendChild(result);
                }
                if (result) {
                    result.classList.add(`${text}`);
                    this.options.nav[type].classes && classes(result).add(this.options.nav[type].classes);
                    this.options.nav.classes && classes(result).add(this.options.nav.classes);
                    this.options.nav.fill && result.setAttribute('filled', '');
                }
                return result;
            };
            if (this.options.nav.enable) {
                this.prevEl = addNav('prev');
                this.nextEl = addNav('next');
                if (this.prevEl) {
                    this.prevEl.onclick = throttle(() => {
                        this.toPrevBullet();
                    }, { intvl: this.options.nav.intvl, prevent: true });
                }
                if (this.nextEl) {
                    this.nextEl.onclick = throttle(() => {
                        this.toNextBullet();
                    }, { intvl: this.options.nav.intvl, prevent: true });
                }
            }
        }
        fillPgn() {
            if (!this.options.pgn.enable)
                return false;
            this.pgnIns = null;
            let className = `${orca.prefix}swipe-pgn`, pgnTmp = [...this.targetEl.children].find((k) => k.classList.contains(className));
            if (pgnTmp) {
                this.pgnEl = pgnTmp;
            }
            else if (this.options.pgn.selector) {
                let selType = getDataType(this.options.pgn.selector);
                if (selType.includes('HTML')) {
                    this.pgnEl = this.options.pgn.selector;
                }
                else if (selType === 'String') {
                    if (getSelectorType(this.options.pgn.selector)) {
                        this.pgnEl = getEl(this.options.pgn.selector);
                    }
                    else {
                        this.pgnIns = instance.find(this.options.pgn.selector, 'swipe');
                        this.pgnIns && (this.pgnEl = this.pgnIns.wrapEl);
                    }
                }
                else if (selType === 'Object') {
                    this.pgnIns = this.options.pgn.selector;
                    this.pgnEl = this.pgnIns.wrapEl;
                }
            }
            else {
                this.pgnEl = createEl('ul', { class: `${className} ${orca.prefix}reset` }, '');
                this.navEl && this.prevEl ? this.prevEl.insertAdjacentElement('afterend', this.pgnEl) : this.targetEl.appendChild(this.pgnEl);
            }
            if (this.pgnEl) {
                this.options.pgn.type && this.pgnEl.setAttribute('type', this.options.pgn.type);
                this.options.pgn.classes && classes(this.pgnEl).add(this.options.pgn.classes);
                if (this.pgnEl.children.length) {
                    this.bullets.forEach((k, i) => {
                        if (this.pgnEl.children[i]) {
                            k.el = this.pgnEl.children[i];
                            i === this.actIdx && this.setBulletActive(k);
                        }
                    });
                    this.setBulletAction();
                }
                else {
                    this.updatePgn();
                }
            }
        }
        setBulletAction() {
            this.bullets.forEach((k) => {
                k.el.onclick = () => {
                    this.setBulletActive(k);
                    this.scrollIns.scrollTo({ target: k.target.slider, snap: true });
                };
            });
        }
        updatePgn() {
            if (!this.options.pgn.enable)
                return;
            this.pgnEl.innerHTML = '';
            let len = this.bullets.length, fragment = document.createDocumentFragment();
            this.bullets.forEach((k, i) => {
                i === this.actIdx && this.setBulletActive(k);
                let html;
                switch (this.options.pgn.type) {
                    case 'text':
                        html = k.target.source.label || this.options.pgn.data[i];
                        break;
                    case 'thumb':
                        html = `<img src="${k.target.source.thumb || this.options.pgn.data[i]}"/>`;
                        break;
                    case 'index':
                        html = i + 1;
                        break;
                    default:
                        html = '';
                }
                if (this.options.pgn.before) {
                    this.options.pgn.before.call(this, { index: i, total: len, html, bullet: k, parent: this.pgnEl });
                }
                else {
                    k.el.innerHTML = html;
                }
                fragment.appendChild(k.el);
            });
            this.pgnEl.appendChild(fragment);
            this.options.pgn.after && this.options.pgn.after.call(this, { total: len, parent: this.pgnEl });
            this.setBulletAction();
        }
        findNavSnap(type = 'next') {
            let index = this.scrollIns.snappeds.findIndex((k) => k === this.scrollIns.snapped), target = null;
            if (index < 0)
                return target;
            if (type === 'next') {
                if (this.options.loop && index === this.scrollIns.snappeds.length - 1) {
                    target = this.scrollIns.snappeds[0];
                }
                else {
                    index !== this.scrollIns.snappeds.length - 1 && (target = this.scrollIns.snappeds[index + 1]);
                }
            }
            else if (type === 'prev') {
                if (this.options.loop && index === 0) {
                    target = this.scrollIns.snappeds.at(-1);
                }
                else {
                    index !== 0 && (target = this.scrollIns.snappeds[index - 1]);
                }
            }
            else if (type === 'start') {
                target = this.scrollIns.snappeds[0];
            }
            else if (type === 'end') {
                target = this.scrollIns.snappeds.at(-1);
            }
            return target;
        }
        findSnap(data) {
            let dataType = getDataType(data), result;
            if (dataType === 'Number') {
                let tmp = this.sliders[data];
                result = tmp && this.scrollIns.snappeds.includes(tmp.slider) ? tmp : null;
            }
            else if (dataType.includes('HTML') || dataType === 'String') {
                let tmp = getEl(data, this.wrapEl);
                result = tmp && this.scrollIns.snappeds.includes(tmp) ? tmp : null;
            }
            else if (dataType === 'Object' && data.hasOwnProperty('slider')) {
                result = this.scrollIns.snappeds.includes(data.slider) ? data : null;
            }
            return result;
        }
        findBullet(data) {
            let dataType = getDataType(data), result;
            if (dataType === 'Number') {
                result = this.bullets[data];
            }
            else if (dataType.includes('HTML') || dataType === 'String') {
                result = this.bullets.find((k) => k.target.slider === getEl(data, this.wrapEl));
            }
            else if (dataType === 'Object' && data.hasOwnProperty('el')) {
                result = data;
            }
            return result;
        }
        toBullet(data, opt = {}) {
            if (this.destroyed)
                return;
            let bullet = this.findBullet(data);
            if (!bullet || this.bulletSeq.current === bullet)
                return;
            this.scrollIns.scrollTo({
                target: bullet.target.slider,
                snap: true,
                before: () => {
                    this.setBulletActive(bullet);
                    opt.before && opt.before.call(this, bullet);
                },
                after: () => {
                    opt.after && opt.after.call(this, bullet);
                }
            });
        }
        toPrevBullet(cb) {
            if (this.destroyed)
                return;
            this.bulletSeq.prev && this.toBullet(this.bulletSeq.prev, {
                after: () => {
                    cb && cb.call(this, this.bulletSeq.prev);
                }
            });
        }
        toNextBullet(cb) {
            if (this.destroyed)
                return;
            this.bulletSeq.next && this.toBullet(this.bulletSeq.next, {
                after: () => {
                    cb && cb.call(this, this.bulletSeq.next);
                }
            });
        }
        toSnap(data, opt = {}) {
            if (this.destroyed)
                return;
            let target = this.findSnap(data);
            if (!target || this.scrollIns.snapped === target)
                return;
            this.scrollIns.scrollTo({
                target,
                snap: true,
                before: () => {
                    opt.before && opt.before.call(this, target);
                },
                after: () => {
                    opt.after && opt.after.call(this, target);
                }
            });
        }
        toPrevSnap(cb) {
            if (this.destroyed)
                return;
            let target = this.findNavSnap('prev');
            if (!target)
                return;
            this.scrollIns.scrollTo({
                target,
                snap: true,
                after: () => {
                    cb && cb.call(this, target);
                }
            });
        }
        toNextSnap(cb) {
            if (this.destroyed)
                return;
            if (this.destroyed)
                return;
            let target = this.findNavSnap('next');
            if (!target)
                return;
            this.scrollIns.scrollTo({
                target,
                snap: true,
                after: () => {
                    cb && cb.call(this, target);
                }
            });
        }
        toStart(cb) {
            if (this.destroyed)
                return;
            let item = this.bullets[0];
            if (item.active)
                return;
            this.toBullet(item, {
                after: (bullet) => {
                    cb && cb.call(this, bullet);
                }
            });
        }
        toEnd(cb) {
            if (this.destroyed)
                return;
            let item = this.bullets.at(-1);
            if (item.active)
                return;
            this.toBullet(item, {
                after: (bullet) => {
                    cb && cb.call(this, bullet);
                }
            });
        }
        setLoopPlay() {
            if (this.options.loop === false) {
                return false;
            }
            if (this.options.slides === 'auto') {
                this.startClone = this.slides.map((k) => k.dom.cloneNode(true));
                this.endClone = this.slides.map((k) => k.dom.cloneNode(true));
                this.totalClone = this.slides.length;
            }
            else {
                this.startClone = this.slides.slice(0, this.options.slides).map((k) => k.dom.cloneNode(true));
                this.endClone = this.slides.slice(this.slides.length - this.options.slides).map((k) => k.dom.cloneNode(true));
                this.totalClone = this.options.slides;
            }
            this.scrollIns.add(this.endClone, { placement: 'start' });
            this.scrollIns.add(this.startClone, { placement: 'end' });
        }
        startCountdown() {
            if (!this.countdownIns)
                return;
            this.countdownIns.setCompleted();
            this.countdownIns.animateTo(0, { duration: this.options.autoplay.delay });
        }
        setAutoPlay() {
            if (!this.options.autoplay.enable)
                return;
            if (this.options.autoplay.countdown) {
                if (!this.countdownIns) {
                    this.countdownIns = new Progress(this.countdownEl, extend({
                        target: {
                            label: false,
                            type: 'circle',
                            curve: 'linear',
                            size: 'xxs',
                            control: true,
                            duration: this.options.autoplay.delay,
                            onPause: () => {
                                this.pause();
                            },
                            onContinue: (resp) => {
                                this.continue(resp.durRest);
                            }
                        },
                        source: this.options.countdown,
                    }));
                }
                else {
                    this.countdownIns.init();
                }
                this.targetEl.appendChild(this.countdownEl);
            }
            this.play();
        }
        continue(duration) {
            delay({
                duration,
                done: () => {
                    this.toNextBullet(() => {
                        this.play();
                    });
                }
            });
        }
        play(delay, cb) {
            if (this.destroyed || !this.paused)
                return;
            if (!this.options.autoplay.enable)
                return;
            this.interval && clearInterval(this.interval);
            this.interval = setInterval(this.intervalEvt, delay || this.options.autoplay.delay);
            this.startCountdown();
            this.paused = false;
            super.listen({ name: 'play', cb });
            return this;
        }
        pause(clear = false, cb) {
            if (this.destroyed || this.paused)
                return;
            if (!this.options.autoplay.enable)
                return;
            clearInterval(this.interval);
            if (clear && this.countdownIns) {
                this.countdownEl.remove();
                this.countdownIns.destroy();
            }
            this.paused = true;
            super.listen({ name: 'pause', cb });
            return this;
        }
        async add(data, options) {
            if (this.destroyed || isEmpty(data))
                return;
            let tmp, opts = Object.assign({ placement: 'end' }, options);
            await this.getSliders(data, (resp) => {
                tmp = resp;
                this.sliders.push(...tmp);
            });
            this.appendSliders(tmp, opts.placement);
            super.listen({ name: 'add', cb: opts.cb, params: [tmp] });
            return { ins: this, data: tmp };
        }
        remove(data = 'end', cb) {
            if (this.destroyed || isEmpty(data))
                return;
            let tmp;
            if (data === 'start') {
                tmp = this.sliders[0]?.slider;
            }
            else if (data === 'end') {
                tmp = this.sliders.at(-1)?.slider;
            }
            else {
                tmp = this.findSlider(data);
            }
            if (!tmp)
                return;
            tmp.remove();
            super.listen({ name: 'remove', cb, params: [this.sliders.find((k) => k.slider === tmp)] });
            return this;
        }
        destroy(cb) {
            if (this.destroyed)
                return this;
            for (let k of this.sliders) {
                k.spy && k.spy.destroy();
            }
            this.scrollIns.destroy();
            this.spyIns && this.spyIns.destroy();
            this.countdownIns && this.countdownIns.destroy();
            window.removeEventListener('keydown', this.keyToSwipe);
            this.bullets.forEach((k) => {
                k.el.onclick = null;
            });
            this.prevEl && (this.prevEl.onclick = null);
            this.nextEl && (this.nextEl.onclick = null);
            if (this.toolsEl) {
                this.options.tools.children.forEach((k) => {
                    k.el.onclick = null;
                });
            }
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
        updateCont(text, cb) {
            if (this.destroyed) {
                return this;
            }
            this.options.content = text;
            this.init();
            super.updateCache({ content: this.content });
            super.listen({ name: 'updatedCont', cb, params: [this.content] });
            return this;
        }
    }

    let OCTMP_hyphen$1 = config.splitHyphen;
    const optLazy = [
        {
            attr: 'root',
            prop: 'root',
            value: null
        },
        {
            attr: 'content',
            prop: 'content',
            value: ''
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'hyphen',
            prop: 'hyphen',
            value: OCTMP_hyphen$1,
        },
        {
            attr: 'tpl-str',
            prop: 'tplStr',
            value: '',
        },
        {
            attr: 'tpl-eng',
            prop: 'tplEng',
            value: null,
        },
        {
            attr: 'type',
            prop: 'type',
            value: 'src',
        },
        {
            attr: 'spy',
            prop: 'spy',
            value: {},
        },
        {
            attr: 'on-shown',
            prop: 'onShown',
            value: null,
        },
        ...optBase
    ];

    class Lazy extends ModBaseListenCache {
        nodeName;
        resType;
        spyIns;
        removeAttrFn;
        options = {};
        static hostType = 'node';
        static optMaps = optLazy;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: Lazy.optMaps,
                host: elem,
            });
            this.nodeName = this.targetEl.nodeName;
            this.removeAttrFn = () => {
                this.targetEl.removeAttribute('lazy-src');
                super.listen({ name: 'shown', params: [this.targetEl] });
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.resType = this.options.type || (this.targetEl.hasAttribute('src') ? 'src' : 'async');
            if (this.resType === 'src') {
                this.targetEl.src = orca.images.blank;
                !this.targetEl.hasAttribute('lazy-src') && this.targetEl.setAttribute('lazy-src', '');
            }
            this.spyIns = new Spy(this.targetEl, extend({
                target: {
                    root: this.options.root,
                    repeat: false,
                    onShown: async () => {
                        super.listen({ name: 'showing', params: [this.targetEl] });
                        if (this.resType === 'src') {
                            this.targetEl.src = this.options.content;
                            if (['VIDEO', 'AUDIO'].includes(this.nodeName)) {
                                this.targetEl.onloadeddata = this.removeAttrFn;
                            }
                            else if (['IMG', 'IFRAME'].includes(this.nodeName)) {
                                this.targetEl.onload = this.removeAttrFn;
                            }
                            else {
                                this.removeAttrFn();
                            }
                        }
                        else if (this.resType === 'async') {
                            await getContent.call(this, {
                                content: this.options.content,
                                contType: this.options.contType || 'async',
                                contData: this.options.contData,
                                ajax: Object.assign({ target: this.targetEl }, this.options.ajax),
                                hyphen: this.options.hyphen,
                                cb: (data) => {
                                    setContent({
                                        target: this.targetEl,
                                        content: data,
                                        template: this.options.tplStr,
                                        engine: this.options.tplEng,
                                    });
                                    this.targetEl.removeAttribute('lazy-async');
                                    this.targetEl.removeAttribute('lazy-type');
                                    this.targetEl.removeAttribute('lazy-data');
                                    this.targetEl.removeAttribute('lazy-tpl');
                                    super.listen({ name: 'shown', params: [this.targetEl] });
                                }
                            });
                        }
                    },
                },
                source: this.options.spy
            }));
            super.listen({ name: 'initiated', cb });
            return this;
        }
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.spyIns.destroy();
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optInfinite = [
        {
            attr: 'trigger',
            prop: 'trigger',
            value: 'scroll',
        },
        {
            attr: 'spy',
            prop: 'spy',
            value: {
                enable: true,
            },
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'spin',
            prop: 'spin',
            value: '<oc-spin></oc-spin>',
        },
        {
            attr: 'max',
            prop: 'max',
            value: 20,
        },
        {
            attr: 'content',
            prop: 'content',
            value: ''
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'tpl-str',
            prop: 'tplStr',
            value: '',
        },
        {
            attr: 'tpl-eng',
            prop: 'tplEng',
            value: null,
        },
        {
            attr: 'media',
            prop: 'media',
            value: {
                title: '',
                brief: '',
            },
        },
        {
            attr: 'b4-append',
            prop: 'b4Append',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'b4-clear',
            prop: 'b4Clear',
            value: null,
        },
        {
            attr: 'on-append',
            prop: 'onAppend',
            value: null,
        },
        {
            attr: 'on-finish',
            prop: 'onFinish',
            value: null,
        },
        {
            attr: 'on-error',
            prop: 'onError',
            value: null,
        },
        ...optBase
    ];

    class Infinite extends ModBaseListenCache {
        options = {};
        content;
        index;
        contReq;
        contXhr;
        statusEl;
        spinEl;
        nextEl;
        nextBtn;
        tipsEl;
        listSpyIns;
        statusSpyIns;
        static hostType = 'node';
        static optMaps = optInfinite;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: Infinite.optMaps,
                host: elem,
                component: false,
                spread: ['spy']
            });
            this.content = [];
            this.index = 0;
            this.contReq = {
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: {
                    error: (resp) => {
                        this.finish(true);
                        super.listen({ name: 'error', params: [resp] });
                    },
                    xhrName: 'contXhr',
                    ...this.options.ajax,
                },
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setAttrs();
            this.useTpl();
            this.getStatusEl();
            this.targetEl.appendChild(this.statusEl);
            await this.getInitContent();
            this.options.spy.enable && this.getListSpyIns();
            if (this.options.trigger === 'scroll') {
                this.getStatusSpyIns();
            }
            else if (this.options.trigger === 'click') {
                this.nextBtn.onclick = () => {
                    this.getStatusSpyIns();
                };
            }
            else if (this.options.trigger === 'clicks') {
                this.nextBtn.onclick = () => {
                    this.renderList(this.index);
                };
            }
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}infinite`);
            classes(this.targetEl).add(this.options.classes);
            this.targetEl.setAttribute('trigger', this.options.trigger);
        }
        finish(err = false) {
            this.statusEl.setAttribute('status', 'finish');
            this.tipsEl.innerHTML = err ? this.options.lang.error : this.options.lang.finish;
            this.statusSpyIns && this.statusSpyIns.destroy();
            super.listen({ name: 'finish' });
        }
        getListSpyIns() {
            this.listSpyIns = new Spy(null, extend({
                target: {
                    repeat: false,
                    visible: false,
                    in: `${orca.prefix}fadeIn`,
                },
                source: this.options.spy,
            }));
        }
        getStatusSpyIns() {
            this.statusSpyIns = new Spy(this.statusEl, {
                root: this.targetEl,
                onIn: debounce(() => {
                    this.renderList(this.index);
                })
            });
        }
        async renderList(index) {
            if (this.destroyed || index >= this.content.length)
                return;
            this.statusEl.setAttribute('status', 'loading');
            this.tipsEl.innerHTML = this.options.lang.loading;
            await this.getPageData(this.content[index], async (data) => {
                this.options.b4Append && await this.options.b4Append.call(this, data);
                this.statusEl.setAttribute('status', 'loaded');
                this.tipsEl.innerHTML = this.options.lang.loaded;
                let fragment = document.createDocumentFragment();
                for (let k of data) {
                    k.classList.add(`${orca.prefix}infinite-item`);
                    fragment.appendChild(k);
                }
                this.targetEl.insertBefore(fragment, this.statusEl);
                this.listSpyIns && this.listSpyIns.add(data);
                super.listen({ name: 'append', params: [data] });
                this.index++;
                (this.index >= this.content.length) && this.finish();
            });
        }
        getStatusEl() {
            this.statusEl = this.targetEl.querySelector(`.${orca.prefix}infinite-status`) || createEl('div', { class: `${orca.prefix}infinite-status`, status: 'preload' });
            this.spinEl = createEl('div', { [orca.alias]: 'spin' }, this.options.spin);
            this.statusEl.appendChild(this.spinEl);
            let nextTmp = this.targetEl.querySelector(`[${orca.alias}="next"]`);
            if (nextTmp) {
                this.nextEl = nextTmp;
            }
            else {
                this.nextEl = createEl('div', { [orca.alias]: 'next' }, this.options.lang.next);
                ['click', 'clicks'].includes(this.options.trigger) && this.statusEl.appendChild(this.nextEl);
            }
            this.nextBtn = this.nextEl.firstElementChild;
            let tipsTmp = this.targetEl.querySelector(`[${orca.alias}="tips"]`);
            if (tipsTmp) {
                this.tipsEl = tipsTmp;
            }
            else {
                this.tipsEl = createEl('div', { [orca.alias]: 'tips' }, this.options.lang.preload);
                this.statusEl.appendChild(this.tipsEl);
            }
        }
        async getInitContent() {
            let result = [];
            if (this.options.content) {
                let contType = getDataType(this.options.content);
                if (contType === 'String') {
                    result = parseUrlArr(this.options.content, { max: this.options.max });
                }
                else if (contType === 'Array' && this.options.content.length) {
                    let firstType = getDataType(this.options.content[0]);
                    if (firstType === 'Object') {
                        for (let k of this.options.content) {
                            let tmp = extend({ target: deepClone(this.contReq), source: k });
                            result.push(await getContent.call(this, tmp));
                        }
                    }
                    else if (firstType === 'Array') {
                        for (let k of this.options.content) {
                            if (!k.length)
                                continue;
                            let sonType = getDataType(k[0]);
                            if (sonType.includes('HTML')) {
                                result = [...this.options.content];
                            }
                            else if (sonType === 'Object') {
                                let tmp = k.map((k) => tplToEl(super.getTplcont(k)));
                                result.push(tmp);
                            }
                        }
                    }
                    else {
                        result = this.options.content;
                    }
                }
            }
            else {
                let pages = getEls(`[${orca.alias}="page"]`, this.statusEl);
                result = pages.map((k) => k.href).filter(Boolean);
            }
            this.content = result.filter((k) => !isEmpty(k));
        }
        async getPageData(data, cb) {
            if (this.destroyed)
                return;
            let dataType = getDataType(data), result = [], contReq = deepClone(this.contReq);
            if (dataType === 'String') {
                result = this.options.contType === 'text' ? tplToEls(data) : await getContent.call(this, { content: data, ...contReq });
            }
            if (dataType.includes('HTML')) {
                result = [...data.children];
            }
            else if (dataType === 'Object') {
                let params = extend({
                    target: contReq,
                    source: data
                }), tmp;
                tmp = await getContent.call(this, params);
                if (isEmpty(tmp)) {
                    if (typeof tmp === 'string') {
                        result = tplToEls(data);
                    }
                    else if (Array.isArray(tmp) && getDataType(tmp[0].include('HTML'))) {
                        result = tmp;
                    }
                }
            }
            else if (dataType === 'Array') {
                result = this.arr2Nodes(data);
            }
            let resultType = getDataType(result);
            if (resultType === 'String') {
                result = tplToEls(result);
            }
            else if (resultType === 'Array') {
                result = this.arr2Nodes(result);
            }
            result = result.filter(Boolean);
            cb && cb(result);
            return result;
        }
        arr2Nodes(data) {
            let result = [];
            if (!data.length)
                return result;
            let itemType = getDataType(data[0]);
            if (itemType.includes('HTML')) {
                result = data;
            }
            else if (itemType === 'Object') {
                result = data.map((k) => tplToEl(super.getTplcont(k)));
            }
            return result;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.nextBtn && (this.nextBtn.onclick = null);
            this.listSpyIns && this.listSpyIns.destroy();
            this.statusSpyIns && this.statusSpyIns.destroy();
            this.contXhr && this.contXhr.abort();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optVirtualize = [
        {
            attr: 'axis',
            prop: 'axis',
            value: 'y',
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'size',
            prop: 'size',
            value: 0,
        },
        {
            attr: 'spill',
            prop: 'spill',
            value: 2,
        },
        {
            attr: 'names',
            prop: 'names',
            value: {
                wrap: 'div',
                list: 'div',
                cont: 'div',
                item: 'section'
            },
        },
        {
            attr: 'index',
            prop: 'index',
            value: 0,
        },
        {
            attr: 'dynamic',
            prop: 'dynamic',
            value: true,
        },
        {
            attr: 'content',
            prop: 'content',
            value: ''
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'tpl-str',
            prop: 'tplStr',
            value: '',
        },
        {
            attr: 'tpl-eng',
            prop: 'tplEng',
            value: null,
        },
        {
            attr: 'b4-append',
            prop: 'b4Append',
            value: null,
        },
        {
            attr: 'b4-updateitem',
            prop: 'b4UpdateItem',
            value: null,
        },
        {
            attr: 'b4-clear',
            prop: 'b4Clear',
            value: null,
        },
        {
            attr: 'on-append',
            prop: 'onAppend',
            value: null,
        },
        {
            attr: 'on-getcont',
            prop: 'onGetCont',
            value: null,
        },
        {
            attr: 'on-exhausted',
            prop: 'onExhausted',
            value: null,
        },
        {
            attr: 'on-tostart',
            prop: 'onToStart',
            value: null,
        },
        {
            attr: 'on-toend',
            prop: 'onToEnd',
            value: null,
        },
        {
            attr: 'on-updateItem',
            prop: 'onUpdatedItem',
            value: null,
        },
        {
            attr: 'on-rendered',
            prop: 'onRendered',
            value: null,
        },
        {
            attr: 'on-error',
            prop: 'onError',
            value: null,
        },
        ...optBase
    ];

    class Virtualize extends ModBaseListenCache {
        options = {};
        propsMap;
        contReq;
        autoRenderEvt;
        obsRenderEvt;
        avgSize;
        targetSize;
        wrapEl;
        contEl;
        listEl;
        startSpaceEl;
        endSpaceEl;
        sizesObs;
        itemSizes;
        startSpyIns;
        endSpyIns;
        itemObs;
        targetObs;
        listSize;
        paddingStart;
        startIdx;
        endIdx;
        offsetVal;
        scrollVal;
        nodes;
        paddingEnd;
        wrapSize;
        contXhr;
        content;
        static hostType = 'node';
        static optMaps = optVirtualize;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: Virtualize.optMaps,
                host: elem,
                component: false,
                spread: []
            });
            this.propsMap = propsMap[this.options.axis];
            this.contReq = {
                content: this.options.content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: {
                    spinSel: this.targetEl,
                    error: (resp) => {
                        super.listen({ name: 'error', params: [resp] });
                    },
                    xhrName: 'contXhr',
                    ...this.options.ajax,
                },
            };
            this.autoRenderEvt = () => {
                this.renderFromStart();
            };
            this.obsRenderEvt = debounce(() => {
                this.initialized && this.renderFromStart();
            });
            this.avgSize = Math.max(parseInt(style(document.body).lineHeight), toPixel(this.options.size));
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setAttrs();
            this.getDirRtl();
            this.targetSize = this.targetEl[this.propsMap.inner];
            this.useTpl();
            this.getNodesTree();
            await this.getInitData();
            this.setSizesObs();
            this.setSpy();
            this.targetEl.addEventListener("scroll", this.autoRenderEvt, false);
            this.itemObs = new MutationObserver(this.obsRenderEvt);
            this.targetObs = new ResizeObserver(this.obsRenderEvt);
            this.targetObs.observe(this.targetEl);
            this.renderFromStart(this.options.index);
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}virt`);
            this.targetEl.setAttribute('axis', this.options.axis);
            classes(this.targetEl).add(this.options.classes);
        }
        getAvgArr(len) {
            return Array(len).fill(null).map(() => { return { size: this.avgSize, rendered: false }; });
        }
        setSizesObs() {
            this.sizesObs = new Observe(this.getAvgArr(this.content.length), {
                deep: true,
                onCompleted: () => {
                    if (this.itemSizes.findIndex((k) => !k.rendered) < 0) {
                        super.listen({ name: 'exhausted', params: [this.content] });
                    }
                }
            });
            this.itemSizes = this.sizesObs.proxy;
        }
        setSpy() {
            this.startSpyIns = new Spy(this.startSpaceEl, {
                onIn: () => {
                    super.listen({ name: 'toStart' });
                },
            });
            this.endSpyIns = new Spy(this.endSpaceEl, {
                onIn: () => {
                    super.listen({ name: 'toEnd' });
                },
            });
        }
        setNodeMutation(el) {
            this.itemObs.observe(el, {
                childList: true,
                subtree: true,
                attributes: true,
            });
        }
        getNodesTree() {
            let tmpWrap = this.targetEl.querySelector(`.${orca.prefix}virt-wrap`);
            if (tmpWrap) {
                this.wrapEl = tmpWrap;
            }
            else {
                this.wrapEl = createEl(this.options.names.wrap, { class: `${orca.prefix}virt-wrap` });
                this.targetEl.appendChild(this.wrapEl);
            }
            let tmpCont = this.wrapEl.querySelector(`.${orca.prefix}virt-cont`);
            if (tmpCont) {
                this.contEl = tmpWrap;
            }
            else {
                this.contEl = createEl(this.options.names.cont, { class: `${orca.prefix}virt-cont` });
                this.wrapEl.appendChild(this.contEl);
            }
            let tmpList = this.contEl.querySelector(`.${orca.prefix}virt-list`);
            if (tmpList) {
                this.wrapEl = tmpList;
            }
            else {
                this.listEl = createEl(this.options.names.list, { class: `${orca.prefix}virt-list` });
                this.contEl.appendChild(this.listEl);
            }
            this.startSpaceEl = createEl('div', { class: `${orca.prefix}virt-space` }, `${this.options.lang.preload}`);
            this.endSpaceEl = createEl('div', { class: `${orca.prefix}virt-space` }, `${this.options.lang.preload}`);
            this.contEl.insertAdjacentElement('afterbegin', this.startSpaceEl);
            this.contEl.appendChild(this.endSpaceEl);
        }
        getWrapSize() {
            return this.options.dynamic ? this.itemSizes.reduce((sum, cur) => sum + cur.size, 0) : this.avgSize * this.itemSizes.length;
        }
        get2SetWrapSize() {
            this.wrapSize = this.getWrapSize();
            this.wrapEl.style[this.propsMap.size] = this.wrapSize + "px";
        }
        async getInitData() {
            let resp = await this.getData();
            this.content = resp.content;
        }
        async getData(data, cb) {
            let resp = await getContent.call(this, data ? Object.assign(this.contReq, data) : this.contReq), respType = getDataType(resp), result = { content: [], source: resp };
            this.respSource = resp;
            if (respType === 'Array') {
                result.content = resp;
            }
            else if (respType === 'Object' && resp.hasOwnProperty('data')) {
                result.content = (Array.isArray(resp.data)) ? resp.data : (resp?.data?.list || []);
            }
            else if (respType === 'String') {
                result.content = tplToEls(resp);
            }
            super.listen({ name: 'getCont', cb, params: [result] });
            return result;
        }
        getItemNode(data) {
            let dataType = getDataType(data), result;
            if (dataType.includes('HTML')) {
                result = data;
            }
            else {
                result = createEl(this.options.names.item, {});
                result.innerHTML = dataType === 'Object' ? super.getTplcont(data) : data.toString();
            }
            this.setNodeMutation(result);
            return result;
        }
        getDirScrollVal() {
            if (this.options.axis !== 'x') {
                return this.targetEl[this.propsMap.scroll];
            }
            else {
                let scrollLeft = this.targetEl[this.propsMap.scroll]; this.targetEl.getAttribute('dir');
                return scrollLeft * super.getRtlCoef();
            }
        }
        setDirScrollVal(val = 0) {
            if (this.options.axis !== 'x') {
                this.targetEl[this.propsMap.scroll] = val;
            }
            else {
                this.targetEl[this.propsMap.scroll] = val * super.getRtlCoef();
            }
        }
        renderFromStart(start) {
            if (this.destroyed)
                return;
            this.listEl.innerHTML = '';
            this.listSize = 0;
            this.paddingStart = 0;
            this.startIdx = 0;
            this.endIdx = this.itemSizes.length - 1;
            this.offsetVal = 0;
            this.scrollVal = this.getDirScrollVal();
            this.nodes = [];
            if (start) {
                this.startIdx = start - 1;
            }
            else {
                if (this.scrollVal) {
                    for (let i = 0; i < this.itemSizes.length; i++) {
                        this.paddingStart += this.itemSizes[i].size;
                        if (this.paddingStart > this.scrollVal) {
                            this.startIdx = i;
                            break;
                        }
                        else if (i === this.itemSizes.length - 1 && this.paddingStart <= this.scrollVal) {
                            return;
                        }
                    }
                }
            }
            this.paddingEnd = 0;
            for (let i = this.startIdx; i < this.itemSizes.length; i++) {
                this.paddingEnd += this.itemSizes[i].size;
                if (this.paddingEnd > this.targetSize) {
                    this.endIdx = i;
                    break;
                }
            }
            this.compensate();
            for (let i = this.startIdx; i <= this.endIdx; i++) {
                this.appendUpdateSize(i, 'beforeend', (size) => {
                    this.listSize += size;
                });
            }
            let fillObj = {};
            this.fillBlank(this.listSize, (val) => {
                fillObj = val;
            });
            this.get2SetWrapSize();
            if (start) {
                this.updateScrollVal(start + (fillObj?.indexDiff || 0));
            }
            else {
                fillObj?.padding && (this.paddingStart -= fillObj.padding);
            }
            this.get2SetContOffset();
            super.listen({ name: 'rendered', params: [{ startIdx: this.startIdx, endIdx: this.endIdx, nodes: this.nodes, scrollVal: this.scrollVal, offsetVal: this.offsetVal, wrapSize: this.wrapSize, listSize: this.listSize }] });
        }
        fillBlank(total = this.listSize, cb) {
            let obj = { startIdx: 0, indexDiff: 0, padding: 0 };
            if (total < this.targetSize) {
                for (let i = 1; i < this.content.length; i++) {
                    let index = this.startIdx - i;
                    if (index < 0)
                        break;
                    this.appendUpdateSize(index, 'afterbegin', (size) => {
                        total += size;
                        obj.padding += size;
                    });
                    if (total >= this.targetSize) {
                        obj.startIdx = index;
                        obj.indexDiff = index - this.startIdx;
                        this.startIdx = index;
                        this.listSize = total;
                        break;
                    }
                }
                cb && cb(obj);
            }
        }
        appendUpdateSize(index, dir = 'afterbegin', cb) {
            if (index < 0 || index >= this.content.length)
                return;
            let itemEl = this.getItemNode(this.content[index]);
            this.nodes.push({ el: itemEl, index });
            this.listEl.insertAdjacentElement(dir, itemEl);
            this.options.dynamic && (this.itemSizes[index].size = getElSpace((itemEl), this.options.axis));
            this.itemSizes[index].rendered = true;
            cb && cb(this.itemSizes[index].size);
        }
        updateSizeOnly(index) {
            let itemEl = this.getItemNode(this.content[index]);
            this.listEl.insertAdjacentElement('beforeend', itemEl);
            this.options.dynamic && (this.itemSizes[index].size = getElSpace((itemEl), this.options.axis));
        }
        renderFromEnd() {
            this.listSize = 0;
            this.listEl.innerHTML = '';
            this.nodes = [];
            this.endIdx = this.content.length - 1;
            for (let i = this.endIdx; i >= 0; i--) {
                this.appendUpdateSize(i, 'afterbegin', (size) => {
                    this.listSize += size;
                });
                if (this.listSize > this.targetSize) {
                    for (let k = 1; k <= this.options.spill; k++) {
                        this.appendUpdateSize(i - k, 'afterbegin', (size) => {
                            this.listSize += size;
                        });
                    }
                    this.startIdx = i - this.options.spill;
                    break;
                }
            }
            this.get2SetWrapSize();
            this.offsetVal = this.wrapSize - this.listSize;
            this.setContOffset();
            this.setScrollVal(this.wrapSize);
            super.listen({ name: 'rendered', params: [{ startIdx: this.startIdx, endIdx: this.endIdx, nodes: this.nodes, scrollVal: this.scrollVal, offsetVal: this.offsetVal, wrapSize: this.wrapSize }] });
        }
        getPadStartFromIdx(index) {
            if (!this.options.dynamic) {
                return this.avgSize * index;
            }
            else {
                let result = 0;
                for (let i = 0; i < index; i++) {
                    result += this.itemSizes[i].size;
                }
                return result;
            }
        }
        setScrollVal(val = this.paddingStart) {
            this.targetEl.removeEventListener('scroll', this.autoRenderEvt);
            this.setDirScrollVal(val);
            this.scrollVal = val;
            setTimeout(() => {
                this.targetEl.addEventListener('scroll', this.autoRenderEvt, false);
            }, 0);
        }
        updateScrollVal(start) {
            this.paddingStart = this.getPadStartFromIdx(start);
            this.setScrollVal();
        }
        compensate() {
            this.endIdx = clampVal({ val: this.endIdx + this.options.spill, min: 0, max: this.itemSizes.length - 1 });
            this.startIdx = clampVal({ val: this.startIdx - this.options.spill, min: 0, max: this.itemSizes.length - 1 });
        }
        get2SetContOffset() {
            if (!this.startIdx) {
                this.offsetVal = 0;
            }
            else {
                this.offsetVal = this.paddingStart;
                if (!this.options.dynamic) {
                    this.offsetVal -= this.avgSize * (this.options.spill + 1);
                }
                else {
                    for (let i = 0; i <= this.options.spill; i++) {
                        this.offsetVal -= this.itemSizes[this.startIdx + i].size;
                    }
                }
            }
            this.setContOffset();
        }
        getContOffset(val) {
            return this.isRtl && this.options.axis === 'x' ? { x: Math.min(0, val * -1) } : { [this.options.axis]: Math.max(0, val) };
        }
        setContOffset(val = this.offsetVal) {
            transformTools.set({
                el: this.contEl,
                data: {
                    translate: this.getContOffset(val),
                }
            });
        }
        scrollTo(index = 0, cb) {
            if (!index) {
                this.setDirScrollVal();
            }
            else {
                this.renderFromStart(index);
            }
            cb && cb.call(this, index);
        }
        toStart() {
            this.scrollTo();
        }
        toEnd() {
            this.renderFromEnd();
        }
        async append(data, cb) {
            if (this.destroyed)
                return;
            let resp = await this.getData(data);
            if (resp.content.length) {
                if (this.options.b4Append) {
                    let tmp = await this.options.b4Append.call(this, resp.content);
                    tmp && (resp.content = tmp);
                }
                this.content.push(...resp.content);
                this.itemSizes.push(...this.getAvgArr(resp.content.length));
                this.renderFromStart();
                super.listen({ name: 'append', cb, params: [resp] });
            }
            return this;
        }
        async updateItem(data = { index: 0, override: true }) {
            if (this.destroyed)
                return;
            let item = this.content[data.index], itemType = getDataType(item), contType = getDataType(data.content);
            if (itemType.includes('HTML')) {
                data.override && (item.innerHTML = '');
                if (contType.includes('HTML')) {
                    item.appendChild(data.content);
                }
                else {
                    item.insertAdjacentHTML('beforeend', data.content.toString());
                }
            }
            else if (['String', 'Number'].includes(itemType) && ['String', 'Number'].includes(contType)) {
                data.override && (this.content[data.index] = '');
                this.content[data.index] += (data.content + '');
            }
            else if (itemType === 'Object' && contType === 'Object') {
                data.override && (this.content[data.index] = {});
                Object.assign(this.content[data.index], data.content);
            }
            if (this.options.b4UpdateItem) {
                let resp = await this.options.b4UpdateItem.call(this, this.content[data.index]);
                resp && (this.content[data.index] = resp);
            }
            if (itemType.includes('HTML') && !isEmpty(data.attrs)) {
                for (let k in data.attrs) {
                    item.setAttribute(k, data.attrs[k]);
                }
            }
            this.updateSizeOnly(data.index);
            this.obsRenderEvt.cancel();
            this.obsRenderEvt();
            super.listen({ name: 'updateItem', cb: data.cb, params: [this.content[data.index]] });
        }
        async clear(cb) {
            if (this.destroyed)
                return;
            this.options.b4Clear && await this.options.b4Clear.call(this);
            this.content = [];
            this.itemSizes = [];
            this.renderFromStart();
            super.listen({ name: 'cleared', cb });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return;
            this.targetEl.removeEventListener("scroll", this.autoRenderEvt);
            this.startSpyIns.destroy();
            this.endSpyIns.destroy();
            this.itemObs.disconnect();
            this.targetObs.unobserve(this.targetEl);
            this.contXhr && this.contXhr.abort();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optPagination = [
        {
            attr: 'list-sel',
            prop: 'listSel',
            value: ''
        },
        {
            attr: 'count',
            prop: 'count',
            value: 10
        },
        {
            attr: 'counts',
            prop: 'counts',
            value: ''
        },
        {
            attr: 'dropdown',
            prop: 'dropdown',
            value: {}
        },
        {
            attr: 'current',
            prop: 'current',
            value: 1,
        },
        {
            attr: 'size',
            prop: 'size',
            value: 'md',
        },
        {
            attr: 'expanded',
            prop: 'expanded',
            value: false,
        },
        {
            attr: 'visible',
            prop: 'visible',
            value: {
                edge: 2,
                center: 2,
            },
        },
        {
            attr: 'align',
            prop: 'align',
            value: '',
        },
        {
            attr: 'type',
            prop: 'type',
            value: '',
        },
        {
            attr: 'flexible',
            prop: 'flexible',
            value: false,
        },
        {
            attr: 'layout',
            prop: 'layout',
            value: 'first|prev|pages|next|last',
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'delay',
            prop: 'delay',
            value: 100,
        },
        {
            attr: 'names',
            prop: 'names',
            value: {
                main: 'div',
                total: 'span',
                count: 'span',
                locate: 'span',
                pages: 'span',
                tips: 'span',
                ellipsis: 'span',
                prev: 'a',
                next: 'a',
                first: 'a',
                last: 'a',
                item: 'a',
                section: 'section',
            },
        },
        {
            attr: 'content',
            prop: 'content',
            value: 1000,
            type: 'ignore',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: '',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'tpl-str',
            prop: 'tplStr',
            value: '',
        },
        {
            attr: 'tpl-eng',
            prop: 'tplEng',
            value: null,
        },
        {
            attr: 'b4-locate',
            prop: 'b4Locate',
            value: null,
        },
        {
            attr: 'b4-renderlist',
            prop: 'b4RenderList',
            value: null,
        },
        {
            attr: 'on-located',
            prop: 'onLocated',
            value: null,
        },
        {
            attr: 'on-gotcont',
            prop: 'onGotCont',
            value: null,
        },
        {
            attr: 'on-tofirst',
            prop: 'onToFirst',
            value: null,
        },
        {
            attr: 'on-tolast',
            prop: 'onToLast',
            value: null,
        },
        {
            attr: 'on-exceeded',
            prop: 'onExceeded',
            value: null,
        },
        {
            attr: 'on-renderedlist',
            prop: 'onRenderedList',
            value: null,
        },
        {
            attr: 'on-renderedpages',
            prop: 'onRenderedPages',
            value: null,
        },
        ...optBase
    ];

    class Pagination extends ModBaseListenCache {
        options = {};
        listEl;
        mainEl;
        pagesEl;
        firstEl;
        lastEl;
        prevEl;
        nextEl;
        totalEl;
        tipsEl;
        locateEl;
        countEl;
        ellEl;
        locateInput;
        locateBtn;
        countInput;
        countBtn;
        items;
        outputObs;
        output;
        content;
        data;
        nodes;
        spyIns;
        dropdwonIns;
        altIns;
        static hostType = 'node';
        static optMaps = optPagination;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: Pagination.optMaps,
                host: elem,
                component: true,
            });
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.setOutputObs();
            this.listEl = getEl(this.options.listSel);
            this.setAttrs();
            this.useTpl();
            this.getNodesTree();
            await this.getInitData();
            this.renderLocateEl();
            this.renderCountEl();
            this.altIns && this.altIns.on('located', (data) => {
                this.locate(data.current);
            });
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setOutputObs() {
            this.outputObs = new Observe({ current: -1, count: this.options.count, total: 0, pages: -1, }, {
                lenient: false,
                onSet: (data) => {
                    if (['total', 'count'].includes(data.key)) {
                        if (data.key === 'total') {
                            data.proxy.pages = Math.ceil(data.value / (data.proxy.count || 1)) || 1;
                        }
                        else if (data.key === 'count') {
                            data.proxy.pages = Math.ceil(data.proxy.total / (data.value || 1)) || 1;
                        }
                        data.proxy.current = Math.min(data.proxy.current, data.proxy.pages);
                    }
                    else if (data.key === 'current') {
                        data.proxy.current = clampVal({ val: data.value, min: 1, max: data.proxy.pages });
                    }
                    this.renderTotalEl();
                    this.renderTipsEl();
                },
                onCompleted: (data) => {
                    if (!data.keys.set.includes('pages') && !data.keys.set.includes('current'))
                        return;
                    if (isEmpty(this.items) || data.keys.set.includes('pages')) {
                        this.renderPagesEl();
                        this.rerenderListEl();
                    }
                    else if (data.keys.set.includes('current')) {
                        if (this.hasEll()) {
                            this.renderPagesEl();
                            this.rerenderListEl();
                        }
                        else {
                            this.toggleSelected();
                        }
                    }
                    if (data.proxy.pages <= 1) {
                        this.setDisabled();
                    }
                    else {
                        if (data.proxy.current <= 1) {
                            this.setDisabled('start');
                            this.setEnabled('end');
                        }
                        else if (data.proxy.current >= data.proxy.pages) {
                            this.setDisabled('end');
                            this.setEnabled('start');
                        }
                        else {
                            this.setEnabled();
                        }
                    }
                    this.altIns && this.altIns.locate(data.proxy.current);
                }
            });
            this.output = this.outputObs.proxy;
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}pagination`);
            this.options.align ? this.targetEl.setAttribute('align', this.options.align) : this.targetEl.removeAttribute('align');
            this.options.type ? this.targetEl.setAttribute('type', this.options.type) : this.targetEl.removeAttribute('type');
            this.options.classes && classes(this.targetEl).add(this.options.classes);
            this.targetEl.toggleAttribute('flexible', this.options.flexible);
            this.options.size ? this.targetEl.setAttribute('size', this.options.size) : this.targetEl.removeAttribute('size');
        }
        getNodesTree() {
            this.targetEl.innerHTML = '';
            this.mainEl = createEl(this.options.names.main, { [orca.alias]: 'main' }, this.pagesEl);
            this.pagesEl = createEl(this.options.names.pages, { [orca.alias]: 'pages' });
            this.firstEl = createEl(this.options.names.first, { [orca.alias]: 'first' }, this.options.lang?.first);
            this.lastEl = createEl(this.options.names.last, { [orca.alias]: 'last' }, this.options.lang?.last);
            this.prevEl = createEl(this.options.names.prev, { [orca.alias]: 'prev' }, this.options.lang?.prev);
            this.nextEl = createEl(this.options.names.next, { [orca.alias]: 'next' }, this.options.lang?.next);
            this.totalEl = createEl(this.options.names.total, { [orca.alias]: 'total' });
            this.tipsEl = createEl(this.options.names.tips, { [orca.alias]: 'tips' });
            this.locateEl = createEl(this.options.names.lacate, { [orca.alias]: 'locate' });
            this.countEl = createEl(this.options.names.count, { [orca.alias]: 'count' });
            this.ellEl = createEl(this.options.names.ellipsis, { [orca.alias]: 'ell' }, this.options.lang?.ellipsis);
            super.parseLayout(this.targetEl, this.options.layout, {
                prev: this.prevEl,
                next: this.nextEl,
                first: this.firstEl,
                last: this.lastEl,
                total: this.totalEl,
                count: this.countEl,
                tips: this.tipsEl,
                locate: this.locateEl,
                pages: this.pagesEl,
                group: this.mainEl,
            });
            this.prevEl.onclick = () => {
                this.prev();
            };
            this.nextEl.onclick = () => {
                this.next();
            };
            this.firstEl.onclick = () => {
                this.first();
            };
            this.lastEl.onclick = () => {
                this.last();
            };
        }
        async getInitData() {
            if (typeof this.options.content === 'number' || this.options.contType === 'total') {
                this.respSource = Array(~~this.options.content).fill(null).map((k, i) => { return { index: i }; });
                this.content = this.respSource;
                this.output.total = this.options.content;
            }
            else if (this.options.content.moduleName === 'pagination') {
                this.altIns = this.options.content;
                this.content = [...this.altIns.content];
                this.output.total = this.content.length;
            }
            else if ((typeof this.options.content === 'string') && this.options.contType === 'ins') {
                this.altIns = instance.find(this.options.content, 'pagination');
                this.content = this.altIns ? [...this.altIns.content] : [];
                this.output.total = this.content.length;
            }
            else {
                let resp = await this.getData();
                this.content = resp.content;
            }
            if (this.options.current < 1 || this.options.current > this.output.pages) {
                console.warn('The value is out of range,it has been fixed!');
                super.listen({ name: 'exceeded', params: [{ val: this.options.current, min: 1, max: this.output.pages }] });
            }
            this.updateCur(this.options.current);
            if (this.isSqlReq()) {
                this.data = this.content;
            }
            else {
                this.data = this.sliceData(this.content);
            }
            if (this.output.current === 1) {
                super.listen({ name: 'toFirst' });
            }
            else if (this.output.current === this.output.pages) {
                super.listen({ name: 'toLast' });
            }
            super.listen({ name: 'located', params: [{ current: this.output.current, data: this.data }] });
        }
        async getData(data, cb) {
            let result = { content: [], source: null };
            let contReq = {
                content: this.options.content,
                contType: this.options.contType,
                contData: Object.assign({ current: this.options.current, count: this.options.count }, this.options.contData),
                ajax: {
                    spinSel: this.listEl,
                    error: (resp) => {
                        super.listen({ name: 'error', params: [resp] });
                    },
                    xhrName: 'contXhr',
                    ...this.options.ajax,
                },
            }, resp = await getContent.call(this, data ? extend({ target: contReq, source: data }) : contReq), respType = getDataType(resp);
            result.source = resp;
            if (respType === 'Array') {
                result.content = resp;
                this.output.total = result.content.length;
            }
            else if (respType === 'Object' && resp.hasOwnProperty('data')) {
                if (Array.isArray(resp.data)) {
                    result.content = resp.data;
                    this.output.total = result.content.length;
                }
                else {
                    result.content = resp?.data?.list || [];
                    this.output.total = resp?.data?.total || result.content.length;
                }
            }
            else if (respType === 'String') {
                result.content = tplToEls(resp);
                this.output.total = result.content.length;
            }
            this.respSource = result.source;
            super.listen({ name: 'gotCont', cb, params: [result] });
            return result;
        }
        isSqlReq(resp = this.respSource) {
            return resp?.data?.hasOwnProperty('list') && resp?.data?.hasOwnProperty('total');
        }
        sliceData(data = this.content, current = this.output.current) {
            let start = (current - 1) * this.output.count;
            return data.slice(start, start + this.output.count);
        }
        async getCurCont(current = this.output.current) {
            current = this.correctCur(current);
            let result;
            if (this.isSqlReq()) {
                let resp = await this.getData({ contData: { current, count: this.output.count } });
                this.content = resp.content;
                result = resp.content;
            }
            else {
                result = this.sliceData(this.content, current);
            }
            return result;
        }
        getItemNode(data) {
            let dataType = getDataType(data), result;
            if (dataType.includes('HTML')) {
                result = data;
            }
            else {
                result = createEl(this.options.names.section, {});
                result.innerHTML = dataType === 'Object' ? super.getTplcont(data) : data.toString();
            }
            return result;
        }
        renderTotalEl() {
            this.totalEl.innerHTML = renderTpl(this.options.lang?.total, this.output);
        }
        renderTipsEl() {
            this.tipsEl.innerHTML = renderTpl(this.options.lang?.tips, this.output);
        }
        renderLocateEl() {
            let tmp = { size: 'sm', feature: 'plain', label: this.options.lang?.locate, unit: this.options.lang?.page, value: this.output.current, btn: `<i class='_icon-arrow-right'></i>` };
            this.locateInput = createEl('oc-input', tmp);
            this.locateInput.on('connected', () => {
                this.locateInput.btnEl.onclick = debounce(() => {
                    let val = ~~this.locateInput.value;
                    (val < 1 || val > this.output.pages) && console.warn('The value is out of range,it has been fixed!');
                    val = this.correctCur(val);
                    this.locateInput.value = val;
                    this.locate(val);
                }, this.options.delay);
                this.locateInput.onkeyup = (e) => (e.code === 'Enter') && this.locateInput.btnEl.click();
            });
            this.locateEl.appendChild(this.locateInput);
        }
        renderCountEl() {
            let tmp = { size: 'sm', feature: 'plain', label: this.options.lang?.count, unit: this.options.lang?.unit, value: this.output.count, btn: `<i class='_icon-arrow-right'></i>` };
            this.countInput = createEl('oc-input', tmp);
            this.countInput.on('connected', () => {
                this.countInput.btnEl.onclick = debounce(() => {
                    this.output.count = ~~this.countInput.value;
                }, this.options.delay);
                this.countInput.onkeyup = (e) => (e.code === 'Enter') && this.countInput.btnEl.click();
                if (this.options.counts) {
                    this.dropdwonIns = new orca.Dropdown(this.countInput, {
                        content: this.options.counts,
                        feature: 'select',
                        popup: {
                            canClick: (target) => {
                                return this.countInput.inputEl.contains(target);
                            },
                            onTargetSet: (val) => {
                                this.countInput.btnEl.click();
                            }
                        }
                    });
                }
            });
            this.countEl.appendChild(this.countInput);
        }
        renderPagesEl(current = this.output.current) {
            this.pagesEl.innerHTML = '';
            this.items = [];
            for (let i = 1; i <= this.output.pages; i++) {
                if (this.options.expanded) {
                    this.items.push(this.createItem(i));
                }
                else {
                    let condL = i > this.options.visible?.edge && i < current - this.options.visible?.center, condR = i > current + this.options.visible?.center && i <= this.output.pages - this.options.visible?.edge;
                    if (condL || condR) {
                        if (this.items.at(-1) && this.items.at(-1).getAttribute(orca.alias) === 'ell') {
                            continue;
                        }
                        else {
                            let tmp = this.ellEl.cloneNode(false);
                            tmp.innerHTML = renderTpl(this.options.lang?.ellipsis, this.output);
                            this.items.push(tmp);
                        }
                    }
                    else {
                        this.items.push(this.createItem(i));
                    }
                }
            }
            this.pagesEl.append(...this.items);
            super.listen({ name: 'renderedPages', params: [{ nodes: this.items, ...this.output }] });
        }
        createItem(current) {
            let tmp = createEl(this.options.names.item, { [orca.alias]: 'page', page: current }, current);
            this.output.current == current && tmp.setAttribute('selected', '');
            tmp.onclick = debounce(() => {
                this.locate(current);
            }, this.options.delay);
            return tmp;
        }
        hasEll() {
            return this.items.find((k) => k.getAttribute(orca.alias, 'ell'));
        }
        correctCur(current) {
            return clampVal({ val: current, min: 1, max: this.output.pages });
        }
        updateCur(current = this.output.current) {
            this.output.current = ~~current;
        }
        async rerenderListEl() {
            if (this.destroyed || !this.listEl)
                return;
            if (this.options.b4RenderList) {
                let resp = await this.options.b4RenderList.call(this, this.data);
                resp && (this.data = resp);
            }
            this.nodes = [];
            for (let k of this.data) {
                let tmp = this.getItemNode(k);
                tmp && this.nodes.push(tmp);
            }
            this.listEl.innerHTML = '';
            this.listEl.append(...this.nodes);
            super.listen({ name: 'renderedList', params: [{ nodes: this.nodes, data: this.data, wrap: this.listEl, ...this.output }] });
        }
        toggleSelected(current = this.output.current) {
            let item = this.items.find((k) => k.getAttribute('page') == current);
            if (item) {
                item.setAttribute('selected', '');
                let tmp = this.items.find((k) => k !== item && k.hasAttribute('selected'));
                tmp && tmp.removeAttribute('selected');
            }
        }
        render({ content = [], tplStr = this.tplStr, tplEng = this.tplEng, nodeName = this.options.names.section, wrapSel }) {
            if (this.destroyed)
                return;
            if (isEmpty(content))
                return;
            this.nodes = [];
            let wrapEl = getEl(wrapSel);
            for (let k of content) {
                let str = super.getTplcont(k, tplStr, tplEng), node = createEl(nodeName, {}, str);
                this.nodes.push(node);
            }
            if (wrapEl) {
                wrapEl.innerHTML = '';
                wrapEl.append(...this.nodes);
            }
            super.listen({ name: 'renderedList', params: [{ nodes: this.nodes, data: content, wrap: wrapEl, ...this.output }] });
        }
        async locate(current, cb) {
            if (this.destroyed)
                return;
            current = ~~current;
            if (this.options.b4Locate) {
                let resp = await this.options.b4Locate.call(this, { to: current, ...this.output });
                if (!isNull(resp)) {
                    typeof resp === 'number' ? (current = resp) : (current = ~~resp);
                }
            }
            if (current < 1 || current > this.output.pages) {
                console.warn('The value is out of range,it has been fixed!');
                super.listen({ name: 'exceeded', params: [{ val: current, min: 1, max: this.output.pages }] });
            }
            current = this.correctCur(current);
            this.data = await this.getCurCont(current);
            this.updateCur(current);
            if (this.output.current === 1) {
                super.listen({ name: 'toFirst' });
            }
            else if (this.output.current === this.output.pages) {
                super.listen({ name: 'toLast' });
            }
            super.listen({ name: 'located', cb, params: [{ current, data: this.data }] });
        }
        prev() {
            this.locate(this.output.current - 1);
        }
        next() {
            this.locate(this.output.current + 1);
        }
        first() {
            this.locate(1);
        }
        last() {
            this.locate(this.output.pages);
        }
        setDisabled(type = 'both') {
            if (type === 'start') {
                this.prevEl.setAttribute('disabled', '');
                this.firstEl.setAttribute('disabled', '');
            }
            else if (type === 'end') {
                this.nextEl.setAttribute('disabled', '');
                this.lastEl.setAttribute('disabled', '');
            }
            else {
                this.prevEl.setAttribute('disabled', '');
                this.firstEl.setAttribute('disabled', '');
                this.nextEl.setAttribute('disabled', '');
                this.lastEl.setAttribute('disabled', '');
            }
        }
        setEnabled(type = 'both') {
            if (type === 'start') {
                this.prevEl.removeAttribute('disabled');
                this.firstEl.removeAttribute('disabled');
            }
            else if (type === 'end') {
                this.nextEl.removeAttribute('disabled');
                this.lastEl.removeAttribute('disabled');
            }
            else {
                this.prevEl.removeAttribute('disabled');
                this.firstEl.removeAttribute('disabled');
                this.nextEl.removeAttribute('disabled');
                this.lastEl.removeAttribute('disabled');
            }
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.spyIns.destroy();
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    let OCTMP_separator$2 = config.rangeHyphen, OCTMP_hyphen = config.rangeHyphen;
    const optRange = [
        {
            attr: 'name',
            prop: 'name',
            value: ''
        },
        {
            attr: 'step',
            prop: 'step',
            value: 1,
        },
        {
            attr: 'max',
            prop: 'max',
            value: 100,
        },
        {
            attr: 'min',
            prop: 'min',
            value: 0,
        },
        {
            attr: 'value',
            prop: 'value',
            value: 0,
        },
        {
            attr: 'multiple',
            prop: 'multiple',
            value: false,
        },
        {
            attr: 'full',
            prop: 'full',
            value: false,
        },
        {
            attr: 'rtl',
            prop: 'rtl',
            value: false,
        },
        {
            attr: 'locked',
            prop: 'locked',
            value: false,
        },
        {
            attr: 'limit-show',
            prop: 'limitShow',
            value: true,
        },
        {
            attr: 'tip-show',
            prop: 'tipShow',
            value: true,
        },
        {
            attr: 'size',
            prop: 'size',
            value: 'md',
        },
        {
            attr: 'fence',
            prop: 'fence',
            value: {
                enable: false,
                min: 0,
                max: 100,
            },
        },
        {
            attr: 'button',
            prop: 'button',
            value: {
                enable: false,
                decrease: `<i class="${orca.prefix}icon-minus-o-f"></i>`,
                increase: `<i class="${orca.prefix}icon-plus-o-f"></i>`,
            }
        },
        {
            attr: 'ruler',
            prop: 'ruler',
            value: {
                enable: false,
                majorEqual: 4,
                minorEqual: 'auto',
                labels: [],
            }
        },
        {
            attr: 'result',
            prop: 'result',
            value: {
                enable: false,
                target: null,
            }
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'keyboard',
            prop: 'keyboard',
            value: false,
        },
        {
            attr: 'separator',
            prop: 'separator',
            value: OCTMP_separator$2,
        },
        {
            attr: 'hyphen',
            prop: 'hyphen',
            value: OCTMP_hyphen,
        },
        {
            attr: 'axis',
            prop: 'axis',
            value: 'x',
        },
        {
            attr: 'disabled',
            prop: 'disabled',
            value: false,
        },
        {
            attr: 'on-set',
            prop: 'onSet',
            value: null,
        },
        {
            attr: 'on-tostart',
            prop: 'onToStart',
            value: null,
        },
        {
            attr: 'on-toend',
            prop: 'onToEnd',
            value: null,
        },
        {
            attr: 'on-enabled',
            prop: 'onEnabled',
            value: null,
        },
        {
            attr: 'on-disabled',
            prop: 'onDisabled',
            value: null,
        },
        {
            attr: 'on-restored',
            prop: 'onRestored',
            value: null,
        },
        ...optBase
    ];

    class Range extends ModBaseListenCache {
        options = {};
        inputEl;
        axisCoef;
        resizeObs;
        sizes;
        keyEvt;
        focusEvt;
        focusHandle;
        handles;
        gestures;
        fence;
        resultParent;
        initVal;
        rawVal;
        places;
        output;
        decrEl;
        incrEl;
        resultEl;
        wrapEl;
        mainEl;
        trackEl;
        thumbEl;
        baseEl;
        bubbleEl;
        bubbles;
        handleEl;
        rulerEl;
        tickEl;
        tmpRatios;
        offset;
        ceilValue;
        ticks;
        fenceEl;
        propsMap;
        static hostType = 'node';
        static optMaps = optRange;
        constructor(elem, options = {}, initial = true) {
            super();
            let tmp = getEl(elem), host;
            if (!tmp)
                return this;
            if (tmp.nodeName === 'INPUT') {
                this.inputEl = tmp;
                this.inputEl.type = 'hidden';
                host = createEl('div', { class: `${orca.prefix}range` });
                tmp.insertAdjacentElement('beforebegin', host);
                host.appendChild(tmp);
            }
            else {
                host = tmp;
                host.classList.add(`${orca.prefix}range`);
                this.inputEl = createEl('input', { type: 'hidden', value: tmp.textContent.trim() });
                tmp.innerHTML = '';
                host.appendChild(this.inputEl);
            }
            super.ready({
                options,
                maps: Range.optMaps,
                host,
                component: true,
                spread: ['button', 'ruler', 'result', 'fence']
            });
            if (this.options.axis === 'x') {
                this.propsMap = propsMap[this.options.axis];
            }
            else {
                this.propsMap = propsMap[this.options.axis];
                this.propsMap.position = 'bottom';
                this.propsMap.start = 'insetBlockEnd';
                this.propsMap.startAlt = 'inset-block-end';
            }
            this.axisCoef = this.options.axis === 'y' ? -1 : 1;
            this.resizeObs = new ResizeObserver(debounce(() => {
                this.updateSizes();
            }));
            this.sizes = {
                handle: 0,
                track: 0,
                ruler: 0,
                thumb: 0,
                bubble: { min: 0, max: 0, from: 0, to: 0, single: 0 },
                ratio: { radius: 0, min: 0, max: 0, full: 0 },
                offset: {
                    from: { min: 0, max: 0 },
                    to: { min: 0, max: 0 },
                    single: { min: 0, max: 0 },
                }
            };
            let _this = this;
            this.keyEvt = function (e) {
                if (!['ArrowLeft', 'ArrowDown', 'ArrowRight', 'ArrowUp'].includes(e.code))
                    return;
                preventDft(e, true);
                _this.focusHandle = this;
                if ([_this.isRtl ? 'ArrowRight' : 'ArrowLeft', 'ArrowDown'].includes(e.code)) {
                    _this.decrease();
                }
                else {
                    _this.increase();
                }
            };
            this.focusEvt = function () {
                this.focus();
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.handles = { from: null, to: null, single: null };
            this.gestures = { from: null, to: null, single: null, thumb: null };
            this.correctOpts();
            this.resultParent = getEl(this.options.result.target);
            this.getInitVal();
            this.rawVal = Array.isArray(this.options.value) ? [...this.initVal] : this.initVal;
            this.getPlaces();
            this.output = { multiple: this.options.multiple, raw: '', value: '', range: [0, 0], ratio: [0, 0] };
            this.initRender();
            this.getDirRtl();
            this.setAttrs();
            this.resizeObs.observe(this.trackEl);
            this.updateSizes();
            this.setVals(this.initVal);
            this.ticks = [];
            this.setTicks();
            this.setFence();
            if (!this.options.disabled) {
                if (this.options.button.enable) {
                    this.decrEl.onclick = () => this.decrease();
                    this.incrEl.onclick = () => this.increase();
                }
                if (this.options.multiple) {
                    this.setHandleIns('from');
                    this.setHandleIns('to');
                    this.tmpRatios = [...this.output.ratio];
                    this.gestures.thumb = new Gesture(this.thumbEl, {
                        onTranslating: (e) => {
                            this.slideSet(this.thumbEl, e.translate.diff[this.options.axis] * this.axisCoef);
                        },
                        onTranslated: () => {
                            this.tmpRatios = [...this.output.ratio];
                        }
                    });
                }
                else {
                    this.setHandleIns('single');
                }
                this.baseEl.onclick = (e) => {
                    let clientObj = getClientObj(e), offset;
                    if (!clientObj) {
                        return false;
                    }
                    offset = (clientObj[this.options.axis] - this.baseEl.getBoundingClientRect()[this.propsMap.position]) * this.axisCoef;
                    if (this.options.multiple) {
                        let fromOffset = this.output.ratio[0] * this.sizes.track, toOffset = this.output.ratio[1] * this.sizes.track;
                        if (offset > toOffset) {
                            this.slideSet(this.thumbEl, offset - toOffset - this.sizes.handle / 2);
                        }
                        else if (offset < toOffset) {
                            this.slideSet(this.thumbEl, offset - fromOffset - this.sizes.handle / 2);
                        }
                        this.tmpRatios = [...this.output.ratio];
                    }
                    else {
                        this.slideSet(this.handles.single, offset - this.sizes.handle / 2);
                    }
                };
                if (!this.options.multiple) {
                    this.thumbEl.onclick = (e) => {
                        let clientObj = getClientObj(e), offset;
                        if (clientObj) {
                            offset = (clientObj[this.options.axis] - this.baseEl.getBoundingClientRect()[this.propsMap.position]) * this.axisCoef;
                            this.slideSet(this.handles.single, offset - this.sizes.handle / 2);
                        }
                    };
                }
                if (this.bubbles.min) {
                    this.bubbles.min.onclick = () => {
                        this.toStart();
                    };
                }
                if (this.bubbles.max) {
                    this.bubbles.max.onclick = () => {
                        this.toEnd();
                    };
                }
                if (this.options.keyboard) {
                    for (let k in this.handles) {
                        let tmp = this.handles[k];
                        if (tmp) {
                            tmp.removeEventListener('keydown', this.keyEvt);
                            tmp.addEventListener('keydown', this.keyEvt, false);
                            tmp.removeEventListener('pointerup', this.focusEvt);
                            tmp.addEventListener('pointerup', this.focusEvt, false);
                        }
                    }
                }
            }
            super.listen({ name: 'initiated', cb });
            return this;
        }
        correctOpts() {
            this.options.max = parseFloat(this.options.max);
            this.options.min = parseFloat(this.options.min);
            this.options.step = parseFloat(this.options.step);
            if (this.options.fence.enable) {
                this.fence = {
                    min: clampVal({ val: this.options.fence.min, min: this.options.min, max: this.options.max }),
                    max: clampVal({ val: this.options.fence.max, min: this.options.min, max: this.options.max })
                };
            }
            else {
                this.fence = { min: this.options.min, max: this.options.max };
            }
        }
        updateSizes() {
            let handle = (this.handles.single || this.handles.from).getBoundingClientRect()[this.propsMap.size], track = this.trackEl.getBoundingClientRect()[this.propsMap.size], min = this.bubbles.min ? this.bubbles.min.getBoundingClientRect()[this.propsMap.size] : 0, max = this.bubbles.max ? this.bubbles.max.getBoundingClientRect()[this.propsMap.size] : 0, from = this.bubbles.from ? this.bubbles.from.getBoundingClientRect()[this.propsMap.size] : 0, to = this.bubbles.to ? this.bubbles.to.getBoundingClientRect()[this.propsMap.size] : 0, single = this.bubbles.single ? this.bubbles.single.getBoundingClientRect()[this.propsMap.size] : 0, fullRatio = (track - handle) / track, radiusRadio = (handle / 2) / track, minRatio = ((this.fence.min - this.options.min) / (this.options.max - this.options.min)) * fullRatio, maxRatio = ((this.fence.max - this.options.min) / (this.options.max - this.options.min)) * fullRatio;
            extend({
                target: this.sizes,
                source: {
                    handle, track,
                    bubble: { min, max, from, to, single },
                    ratio: { radius: radiusRadio, min: minRatio, max: maxRatio, full: fullRatio },
                }
            });
        }
        setHandleIns(type) {
            this.gestures[type] = new Gesture(this.handles[type], {
                onTranslate: () => {
                    this.offset = style(this.handles[type])[this.propsMap.start];
                },
                onTranslating: (e) => {
                    let diff = e.translate.diff[this.options.axis] * this.axisCoef * super.getRtlCoef(), value = parseFloat(this.offset) + diff;
                    this.slideSet(this.handles[type], value);
                },
                onTranslated: () => {
                    type !== 'single' && (this.tmpRatios = [...this.output.ratio]);
                }
            });
        }
        setHandleActive(el) {
            el.setAttribute('active', '');
            for (let k in this.handles) {
                this.handles[k] !== el && (this.handles[k].removeAttribute('active'));
            }
        }
        getRatioFromVal(value) {
            return ((value - this.options.min) / (this.options.max - this.options.min)) * this.sizes.ratio.full;
        }
        getValFromRatio(ratio) {
            return ratio * (this.options.max - this.options.min) / this.sizes.ratio.full + this.options.min;
        }
        decrease(step = this.options.step) {
            let isToFocus = this.handles.to && this.focusHandle === this.handles.to, min = isToFocus ? this.output.range[0] : this.fence.min, value = (this.output.range[isToFocus ? 1 : 0] - step), handleDiff = (this.output.range[1] - this.output.range[0]);
            if (this.options.multiple) {
                value < min && (value = min);
                if (this.options.locked) {
                    this.setVals([value, value + handleDiff]);
                }
                else {
                    this.setVals(isToFocus ? [this.output.range[0], value] : [value, this.output.range[1]]);
                }
            }
            else {
                this.setVals(this.output.range[0] - step);
            }
            this.options.multiple && (this.tmpRatios = [...this.output.ratio]);
        }
        increase(step = this.options.step) {
            let isFromFocus = this.handles.from && this.focusHandle === this.handles.from, max = isFromFocus ? this.output.range[1] : this.fence.max, value = (this.output.range[isFromFocus ? 0 : 1] + step), handleDiff = (this.output.range[1] - this.output.range[0]);
            if (this.options.multiple) {
                value > max && (value = max);
                if (this.options.locked) {
                    this.setVals([value - handleDiff, value]);
                }
                else {
                    this.setVals(isFromFocus ? [value, this.output.range[1]] : [this.output.range[0], value]);
                }
            }
            else {
                this.setVals(this.output.range[0] + step);
            }
            this.options.multiple && (this.tmpRatios = [...this.output.ratio]);
        }
        setAttrs() {
            this.targetEl.setAttribute('axis', this.options.axis);
            classes(this.targetEl).add(this.options.classes);
            this.targetEl.toggleAttribute('multiple', this.options.multiple);
            this.targetEl.toggleAttribute('full', this.options.full);
            this.targetEl.toggleAttribute('inert', this.options.disabled);
            this.targetEl.setAttribute('size', this.options.size);
            this.options.rtl ? this.targetEl.setAttribute('dir', 'rtl') : this.targetEl.removeAttribute('dir');
        }
        getInitVal() {
            if (this.inputEl.value) {
                if (this.inputEl.value.includes(this.options.separator)) {
                    this.options.multiple = true;
                    this.initVal = this.inputEl.value.split(this.options.separator).map((k) => parseFloat(k)).sort((a, b) => a - b);
                }
                else {
                    this.initVal = this.options.multiple ? [parseFloat(this.inputEl.value), this.options.max] : parseFloat(this.inputEl.value);
                }
            }
            else {
                if (this.options.multiple && !Array.isArray(this.options.value)) {
                    let tmp = typeof this.options.value === 'number' ? [this.options.value] :
                        (this.options.value.split(this.options.separator).slice(0, 2).map((k) => parseFloat(k)).sort((a, b) => a - b));
                    this.initVal = [isNull(tmp[0]) ? this.options.min : tmp[0], isNull(tmp[1]) ? this.options.max : tmp[1]];
                }
                else if (!this.options.multiple && Array.isArray(this.options.value)) {
                    this.initVal = this.options.value[0];
                }
                else if (typeof this.options.value === 'string' && this.options.value.includes(this.options.separator)) {
                    this.options.multiple = true;
                    this.initVal = this.options.value.split(this.options.separator).map((k) => parseFloat(k)).sort((a, b) => a - b);
                }
                else {
                    this.initVal = Array.isArray(this.options.value) ? [...this.options.value].sort((a, b) => a - b) : this.options.value;
                }
            }
        }
        getPlaces() {
            let stepPlaces = this.options.step.toString().split('.')[1] ? this.options.step.toString().split('.')[1].length : 0, endsPlaces = Math.max(getPlaces(this.options.min), getPlaces(this.options.max));
            this.places = stepPlaces > 0 ? stepPlaces : endsPlaces;
        }
        correctVal(value) {
            let obj = { min: this.fence.min, max: this.fence.max };
            if (Array.isArray(value)) {
                let tmp = value.map((k) => toNumber(clampVal({ val: k, ...obj }), { places: this.places }));
                this.options.multiple && tmp.sort((a, b) => a - b);
                return tmp;
            }
            else if (value === '' || isNull(value)) {
                return [this.fence.min, this.fence.max];
            }
            else {
                let tmp;
                if (typeof value === 'string' && value.includes(this.options.separator)) {
                    tmp = value.split(this.options.separator).map((k) => parseFloat(k)).sort((a, b) => a - b);
                }
                else {
                    tmp = [toNumber(clampVal({ val: value, ...obj }), { places: this.places }), this.output.range[1]];
                }
                return this.options.multiple ? tmp.sort((a, b) => a - b) : tmp;
            }
        }
        initRender() {
            if (this.wrapEl) {
                this.wrapEl.innerHTML = '';
                this.options.name && (this.inputEl.name = this.options.name);
                this.inputEl.value = '';
            }
            else {
                this.wrapEl = createEl('div', { class: `${orca.prefix}range-wrap` });
                this.targetEl.appendChild(this.wrapEl);
                !this.inputEl.name && (this.inputEl.name = this.options.name);
            }
            this.bubbles = {};
            this.wrapEl.innerHTML = `
        <div class="${orca.prefix}range-main">
            <div class="${orca.prefix}range-track">
                <div ${orca.alias}="base"></div>
                <div ${orca.alias}="thumb"></div>
            </div>
            <div class="${orca.prefix}range-bubble">
                ${this.options.limitShow ? '<span ' + orca.alias + '="min">' + this.options.min + '</span><span ' + orca.alias + '="max">' + this.options.max + '</span>' : ''}
            </div>
            <div class="${orca.prefix}range-handle"></div>
            <div class="${orca.prefix}range-ruler"><ul></ul></div>
        </div>
        `;
            this.mainEl = this.wrapEl.querySelector(`.${orca.prefix}range-main`);
            this.trackEl = this.wrapEl.querySelector(`.${orca.prefix}range-track`);
            this.thumbEl = this.wrapEl.querySelector(`[${orca.alias}="thumb"]`);
            this.baseEl = this.wrapEl.querySelector(`[${orca.alias}="base"]`);
            this.bubbleEl = this.wrapEl.querySelector(`.${orca.prefix}range-bubble`);
            this.bubbles.min = this.bubbleEl.querySelector(`[${orca.alias}="min"]`);
            this.bubbles.max = this.bubbleEl.querySelector(`[${orca.alias}="max"]`);
            this.handleEl = this.wrapEl.querySelector(`.${orca.prefix}range-handle`);
            this.rulerEl = this.wrapEl.querySelector(`.${orca.prefix}range-ruler`);
            this.tickEl = this.rulerEl.querySelector('ul');
            this.decrEl = createEl('span', { class: `${orca.prefix}range-btn`, [orca.alias]: 'decrease' }, this.options.button.decrease);
            this.incrEl = createEl('span', { class: `${orca.prefix}range-btn`, [orca.alias]: 'increase' }, this.options.button.increase);
            if (this.options.button.enable) {
                this.mainEl.insertAdjacentElement('beforebegin', this.decrEl);
                this.mainEl.insertAdjacentElement('afterend', this.incrEl);
            }
            this.resultEl = createEl('span', { class: `${orca.prefix}range-result` });
            if (this.options.result.enable) {
                this.resultParent ? this.resultParent.appendChild(this.resultEl) : this.wrapEl.appendChild(this.resultEl);
            }
            if (this.options.multiple) {
                this.handles.from = createEl('span', { [orca.alias]: 'from', tabindex: 0 });
                this.handles.to = createEl('span', { [orca.alias]: 'to', tabindex: 0 });
                this.handleEl.append(this.handles.from, this.handles.to);
                if (this.options.tipShow) {
                    this.bubbles.from = createEl('span', { [orca.alias]: 'from' });
                    this.bubbles.to = createEl('span', { [orca.alias]: 'to' });
                    this.bubbles.merge = createEl('span', { [orca.alias]: 'merge' });
                    this.bubbleEl.append(this.bubbles.from, this.bubbles.to, this.bubbles.merge);
                }
            }
            else {
                this.handles.single = createEl('span', { [orca.alias]: 'single', tabindex: 0 });
                this.handleEl.append(this.handles.single);
                if (this.options.tipShow) {
                    this.bubbles.single = createEl('span', { [orca.alias]: 'single' });
                    this.bubbleEl.append(this.bubbles.single);
                }
            }
        }
        setVals(value, cb) {
            if (this.destroyed)
                return;
            this.output.range = this.correctVal(value);
            let radiusPercent = this.sizes.ratio.radius * 100, getTipHTML = (val) => toNumber(val, { places: this.places });
            if (this.options.multiple) {
                this.output.ratio = [this.getRatioFromVal(this.output.range[0]), this.getRatioFromVal(this.output.range[1])];
                let fromPercent = this.output.ratio[0] * 100, toPercent = this.output.ratio[1] * 100;
                this.handles.from.style[this.propsMap.start] = `${fromPercent}%`;
                this.handles.to.style[this.propsMap.start] = `${toPercent}%`;
                this.sizes.ratio.center = this.output.ratio[1];
                this.thumbEl.style[this.propsMap.size] = `${toPercent - fromPercent}%`;
                this.thumbEl.style[this.propsMap.start] = `${fromPercent + radiusPercent}%`;
                this.sizes.thumb = this.thumbEl.getBoundingClientRect()[this.propsMap.size];
                if (this.options.tipShow) {
                    this.bubbles.from.style[this.propsMap.start] = `${fromPercent}%`;
                    this.bubbles.from.innerHTML = getTipHTML(this.output.range[0]);
                    this.bubbles.to.style[this.propsMap.start] = `${toPercent}%`;
                    this.bubbles.to.innerHTML = getTipHTML(this.output.range[1]);
                    this.bubbles.merge.style[this.propsMap.start] = `${fromPercent + (toPercent - fromPercent) / 2}%`;
                    this.bubbles.merge.innerHTML = `${getTipHTML(this.output.range[0])}<i>${this.options.hyphen}</i>${getTipHTML(this.output.range[1])}`;
                    this.sizes.bubble.from = this.bubbles.from.getBoundingClientRect()[this.propsMap.size];
                    this.sizes.bubble.to = this.bubbles.to.getBoundingClientRect()[this.propsMap.size];
                    this.mergeTips();
                }
            }
            else {
                this.output.ratio[0] = this.getRatioFromVal(this.output.range[0]);
                let singlePercent = this.output.ratio[0] * 100;
                this.handles.single.style[this.propsMap.start] = `${singlePercent}%`;
                this.thumbEl.style[this.propsMap.size] = `${singlePercent + radiusPercent}%`;
                this.sizes.thumb = this.thumbEl.getBoundingClientRect()[this.propsMap.size];
                if (this.options.tipShow) {
                    this.bubbles.single.style[this.propsMap.start] = `${singlePercent}%`;
                    this.bubbles.single.innerHTML = getTipHTML(this.output.range[0]);
                    this.sizes.bubble.single = this.bubbles.single.getBoundingClientRect()[this.propsMap.size];
                }
            }
            this.output.value = (this.options.multiple ? this.output.range.join(this.options.separator) : this.output.range[0]).toString();
            this.output.raw = this.inputEl.value;
            this.options.limitShow && this.hideEnds();
            this.inputEl.value = this.output.value;
            this.options.result.enable && (this.resultEl.innerHTML = renderTpl(this.options.lang.result, this.output));
            super.listen({ name: 'output', params: [this.output] });
            super.listen({ name: 'set', cb, params: [this.output] });
            this.endsListen(cb);
            return this;
        }
        endsListen(cb) {
            if (this.options.multiple) {
                if (this.output.range[0] <= this.fence.min) {
                    this.decrEl.toggleAttribute('inert', true);
                    super.listen({ name: 'toStart', cb, params: [this.fence] });
                }
                else {
                    this.decrEl.removeAttribute('inert');
                }
                if (this.output.range[1] >= this.fence.max) {
                    this.incrEl.toggleAttribute('inert', true);
                    super.listen({ name: 'toEnd', cb, params: [this.fence] });
                }
                else {
                    this.incrEl.removeAttribute('inert');
                }
            }
            else {
                if (this.output.range[0] <= this.fence.min) {
                    this.decrEl.toggleAttribute('inert', true);
                    super.listen({ name: 'toStart', cb, params: [this.fence] });
                }
                else if (this.output.range[0] >= this.fence.max) {
                    this.incrEl.toggleAttribute('inert', true);
                    super.listen({ name: 'toEnd', cb, params: [this.fence] });
                }
                else {
                    this.decrEl.removeAttribute('inert');
                    this.incrEl.removeAttribute('inert');
                }
            }
        }
        getVals() {
            return this.output;
        }
        toEnd(cb) {
            if (this.destroyed)
                return;
            let value, diff;
            if (this.options.multiple) {
                diff = this.fence.max - this.output.range[1];
                value = [this.output.range[0] + diff, this.output.range[1] + diff];
            }
            else {
                value = this.fence.max;
            }
            this.setVals(value);
            cb && cb.call(this, value);
            return this;
        }
        toStart(cb) {
            if (this.destroyed)
                return;
            let value, diff;
            if (this.options.multiple) {
                diff = this.fence.min - this.output.range[0];
                value = [this.output.range[0] + diff, this.output.range[1] + diff];
            }
            else {
                value = this.fence.min;
            }
            this.setVals(value);
            cb && cb.call(this, value);
            return this;
        }
        slideSet(dom, value) {
            if (this.destroyed)
                return;
            let result;
            if (dom === this.thumbEl && this.options.multiple) {
                let fromRatio = this.tmpRatios[0] + value / this.sizes.track, diffRatio = this.tmpRatios[1] - this.tmpRatios[0], toRatio = fromRatio + diffRatio, from = this.getValFromRatio(fromRatio), to = this.getValFromRatio(toRatio), diff = this.getValFromRatio(toRatio) - this.getValFromRatio(fromRatio);
                if (this.options.locked) {
                    if (from < this.fence.min) {
                        result = [this.fence.min, this.fence.min + diff];
                    }
                    else if (to > this.fence.max) {
                        result = [this.fence.max - diff, this.fence.max];
                    }
                    else {
                        result = [from, to];
                    }
                }
                else {
                    result = [from, to];
                }
            }
            else {
                let ratio = (value / this.sizes.track);
                if (dom === this.handles.from) {
                    if (ratio > this.output.ratio[1]) {
                        ratio = this.output.ratio[1];
                    }
                    else if (ratio < this.sizes.ratio.min) {
                        ratio = this.sizes.ratio.min;
                    }
                    result = [this.getValFromRatio(ratio), this.output.range[1]];
                }
                else if (dom === this.handles.to) {
                    if (ratio > this.sizes.ratio.max) {
                        ratio = this.sizes.ratio.max;
                    }
                    else if (ratio < this.output.ratio[0]) {
                        ratio = this.output.ratio[0];
                    }
                    result = [this.output.range[0], this.getValFromRatio(ratio)];
                }
                else if (dom === this.handles.single) {
                    if (ratio > this.sizes.ratio.max) {
                        ratio = this.sizes.ratio.max;
                    }
                    else if (ratio < this.sizes.ratio.min) {
                        ratio = this.sizes.ratio.min;
                    }
                    result = this.getValFromRatio(ratio);
                }
            }
            this.setVals(result);
        }
        mergeTips() {
            if (this.sizes.thumb < (this.sizes.bubble.from + this.sizes.bubble.to) / 2) {
                this.targetEl.setAttribute('merged', '');
            }
            else {
                this.targetEl.removeAttribute('merged');
            }
        }
        hideEnds() {
            if (this.options.multiple) {
                let offsetFrom = this.output.ratio[0] * this.sizes.track, offsetTo = this.output.ratio[1] * this.sizes.track;
                if (offsetFrom < this.sizes.bubble.min + this.sizes.bubble.from / 2 - this.sizes.handle / 2) {
                    this.targetEl.setAttribute('hidemin', '');
                }
                else {
                    this.targetEl.removeAttribute('hidemin');
                }
                if (this.sizes.track - offsetTo < this.sizes.bubble.max + this.sizes.bubble.from / 2 + this.sizes.handle / 2) {
                    this.targetEl.setAttribute('hidemax', '');
                }
                else {
                    this.targetEl.removeAttribute('hidemax');
                }
            }
            else {
                let offsetSingle = this.output.ratio[0] * this.sizes.track;
                if (offsetSingle < this.sizes.bubble.min + this.sizes.bubble.single / 2 - this.sizes.handle / 2) {
                    this.targetEl.setAttribute('hidemin', '');
                }
                else {
                    this.targetEl.removeAttribute('hidemin');
                }
                if (this.sizes.track - offsetSingle < this.sizes.bubble.max + this.sizes.bubble.single / 2 + this.sizes.handle / 2) {
                    this.targetEl.setAttribute('hidemax', '');
                }
                else {
                    this.targetEl.removeAttribute('hidemax');
                }
            }
        }
        setTicks() {
            if (!this.options.ruler.enable)
                return;
            this.ceilValue = (this.options.max - this.options.min) / this.options.ruler.majorEqual;
            this.sizes.ruler = this.rulerEl.getBoundingClientRect()[this.propsMap.size];
            for (let k = 0; k <= this.options.ruler.majorEqual; k++) {
                let value = toNumber((this.options.min + this.ceilValue * k), { places: this.places }), content = this.options.ruler.labels.length > 0 ? this.options.ruler.labels[k] : value, offsetRatio = k / this.options.ruler.majorEqual, majorEl = createEl('li', { style: `${this.propsMap.startAlt}:${offsetRatio * 100}%`, 'data-content': content });
                this.tickEl.appendChild(majorEl);
                majorEl.onclick = () => {
                    this.setVals(value);
                };
                this.ticks.push({
                    index: k,
                    dom: majorEl,
                    ratio: offsetRatio,
                    content: content,
                    value,
                });
                if (k !== this.options.ruler.majorEqual) {
                    this.setMinorTicks(offsetRatio);
                }
            }
        }
        setFence() {
            if (!this.options.fence.enable)
                return;
            let fullSize = (this.options.max - this.options.min), sizeRatio = (this.fence.max - this.fence.min) / fullSize, offsetRatio = (this.fence.min - this.options.min) / fullSize;
            this.fenceEl = createEl('div', { [orca.alias]: 'fence', style: `${this.propsMap.size}:${sizeRatio * 100}%;${this.propsMap.startAlt}:${offsetRatio * 100}%` });
            this.rulerEl.appendChild(this.fenceEl);
        }
        setMinorTicks(offsetRatio) {
            let count = 0, unitRatio = 0, ceilSize = this.sizes.ruler / this.options.ruler.majorEqual;
            if (this.options.ruler.minorEqual === 'auto') {
                count = ceilSize < 40 ? 5 :
                    (ceilSize >= 40 && ceilSize < 80) ? 6 :
                        (ceilSize >= 80 && ceilSize < 160) ? 7 :
                            (ceilSize >= 160 && ceilSize < 320) ? 8 :
                                (ceilSize >= 320 && ceilSize >= 640) ? 9 : 10;
            }
            else if (this.options.ruler.minorEqual > 0) {
                count = this.options.ruler.minorEqual;
            }
            unitRatio = 1 / (count * this.options.ruler.majorEqual);
            for (let k = 0; k < count; k++) {
                this.tickEl.insertAdjacentHTML('beforeend', `<li style="${this.propsMap.startAlt}:${(offsetRatio + unitRatio * k) * 100}%"></li>`);
            }
        }
        disable(cb) {
            this.targetEl.toggleAttribute('inert', true);
            this.inputEl.disabled = true;
            super.listen({ name: 'disabled', cb });
            return this;
        }
        enable(cb) {
            this.targetEl.removeAttribute('inert');
            this.inputEl.disabled = false;
            super.listen({ name: 'enabled', cb });
            return this;
        }
        clear(cb) {
            if (this.destroyed)
                return this;
            this.options.multiple ? this.setVals([this.fence.min, this.fence.max]) : this.setVals(this.fence.min);
            super.listen({ name: 'cleared', cb });
            return this;
        }
        restore(cb) {
            if (this.destroyed)
                return this;
            this.setVals(this.rawVal);
            super.listen({ name: 'restored', cb, params: [this.rawVal] });
            return this;
        }
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.resizeObs.disconnect();
            for (let k in this.gestures)
                this.gestures[k]?.destroy();
            if (this.options.keyboard) {
                for (let k in this.handles) {
                    let tmp = this.handles[k];
                    if (tmp) {
                        tmp.removeEventListener('keydown', this.keyEvt);
                        tmp.removeEventListener('pointerup', this.focusEvt);
                    }
                }
            }
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    let OCTMP_placeholder = config.lang.form.placeholder;
    const optDatetime = [
        {
            attr: 'name',
            prop: 'name',
            value: ''
        },
        {
            attr: 'value',
            prop: 'value',
            value: ''
        },
        {
            attr: 'disabled',
            prop: 'disabled',
            value: false
        }, {
            attr: 'size',
            prop: 'size',
            value: ''
        },
        {
            attr: 'format',
            prop: 'format',
            value: '',
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'mode',
            prop: 'mode',
            value: 'single',
        },
        {
            attr: 'feature',
            prop: 'feature',
            value: 'single',
        },
        {
            attr: 'multiline',
            prop: 'multiline',
            value: false,
        }, {
            attr: 'placeholder',
            prop: 'placeholder',
            value: OCTMP_placeholder,
        },
        {
            attr: 'label',
            prop: 'label',
            value: '',
        },
        {
            attr: 'tools',
            prop: 'tools',
            value: {
                enable: false,
                children: ['close'],
            },
        },
        {
            attr: 'moc-selection',
            prop: 'maxSelection',
            value: 100,
        },
        {
            attr: 'rows',
            prop: 'rows',
            value: 1,
        },
        {
            attr: 'cols',
            prop: 'cols',
            value: 1,
        },
        {
            attr: 'min-date',
            prop: 'minDate',
            value: '',
        },
        {
            attr: 'moc-date',
            prop: 'maxDate',
            value: '',
        },
        {
            attr: 'datespan',
            prop: 'datespan',
            value: [],
        },
        {
            attr: 'timespan',
            prop: 'timespan',
            value: [],
        },
        {
            attr: 'full',
            prop: 'full',
            value: false,
        },
        {
            attr: 'footer',
            prop: 'footer',
            value: {
                enable: true,
                layout: 'plain',
                children: ['clear', 'confirm'],
            },
        },
        {
            attr: 'now-hide',
            prop: 'nowHide',
            value: false,
        },
        {
            attr: 'now-show',
            prop: 'nowShow',
            value: false,
        },
        {
            attr: 'clear-show',
            prop: 'clearShow',
            value: true,
        },
        {
            attr: 'close-show',
            prop: 'closeShow',
            value: true,
        },
        {
            attr: 'cancel-show',
            prop: 'cancelShow',
            value: false,
        },
        {
            attr: 'result-Show',
            prop: 'resultShow',
            value: false,
        },
        {
            attr: 'confirm-hide',
            prop: 'confirmHide',
            value: true,
        },
        {
            attr: 'auto-fill',
            prop: 'autoFill',
            value: false,
        },
        {
            attr: 'manual',
            prop: 'manual',
            value: false,
        },
        {
            attr: 'auto-correct',
            prop: 'autoCorrect',
            value: true,
        },
        {
            attr: 'required',
            prop: 'required',
            value: false,
        },
        {
            attr: 'week-start',
            prop: 'weekStart',
            value: 'monday',
        },
        {
            attr: 'separator',
            prop: 'separator',
            value: ',',
        },
        {
            attr: 'btn-sel',
            prop: 'btnSel',
            value: '',
        },
        {
            attr: 'pos-sel',
            prop: 'posSel',
            value: '',
        },
        {
            attr: 'input-sel',
            prop: 'inputSel',
            value: '',
        },
        {
            attr: 'child-sel',
            prop: 'childSel',
            value: '',
        },
        {
            attr: 'display',
            prop: 'display',
            value: 'popup',
        },
        {
            attr: 'toDrawer',
            prop: 'toDrawer',
            value: true,
        },
        {
            attr: 'bubble',
            prop: 'bubble',
            value: {},
        },
        {
            attr: 'fill-now',
            prop: 'fillNow',
            value: false,
        },
        {
            attr: 'next',
            prop: 'next',
            value: '',
        },
        {
            attr: 'lunar',
            prop: 'lunar',
            value: {
                enable: false,
                handler: '',
                map: {},
                tplStr: `<div>农历：{{this.animal}}年 {{this.month}}{{this.date}}</div>
                    <div>干支：{{this.gzYear}}年 {{this.gzMonth}}月 {{this.gzDate}}日</div>
                    <div>节日/节气：{{this.term}} {{this.lunarFestival}} {{this.solarFestival}}</div>
                    `,
                tplEng: null,
                arrange: ['solarFestival', 'lunarFestival', 'term', 'date'],
                tags: [],
            }
        },
        {
            attr: 'events',
            prop: 'events',
            value: {
                enable: false,
                display: 'popup',
                tplStr: `<div ${orca.alias}="label">{{this.label}}</div><div ${orca.alias}="content">{{this.content}}</div>`,
                tplEng: null,
                heading: `YYYY年MM月DD日 WW`,
                list: [],
            },
        },
        {
            attr: 'menu',
            prop: 'menu',
            value: [],
        },
        {
            attr: 'b4-fill',
            prop: 'b4fill',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'b4-set',
            prop: 'b4Set',
            value: null,
        },
        {
            attr: 'b4-clear',
            prop: 'b4Clear',
            value: null,
        },
        {
            attr: 'b4-cancel',
            prop: 'b4Cancel',
            value: null,
        },
        {
            attr: 'b4-confirm',
            prop: 'b4Confirm',
            value: null,
        },
        {
            attr: 'on-filled',
            prop: 'onFilled',
            value: null,
        },
        {
            attr: 'on-removed',
            prop: 'onRemoved',
            value: null,
        },
        {
            attr: 'on-set',
            prop: 'onSet',
            value: null,
        },
        {
            attr: 'on-setrange',
            prop: 'onSetRange',
            value: null,
        },
        {
            attr: 'on-createdpanels',
            prop: 'onCreatedPanels',
            value: null,
        },
        {
            attr: 'on-canceled',
            prop: 'onCanceled',
            value: null,
        },
        {
            attr: 'on-confirmed',
            prop: 'onConfirmed',
            value: null,
        }, {
            attr: 'on-cleareded',
            prop: 'onCleared',
            value: null,
        },
        {
            attr: 'on-opened',
            prop: 'onOpened',
            value: null,
        },
        {
            attr: 'on-closed',
            prop: 'onClosed',
            value: null,
        },
        {
            attr: 'on-transferred',
            prop: 'onTransferred',
            value: null,
        },
        {
            attr: 'on-updatedtime',
            prop: 'onUpdatedTime',
            value: null,
        },
        ...optBase
    ];

    class Datetime extends ModBaseListenCache {
        options = {};
        value;
        raw;
        client;
        output;
        data;
        format;
        spreadFooter;
        separator;
        selectedsProxy;
        selecteds;
        resultIns;
        bubbleEl;
        bubbleIns;
        canClick;
        inputEl;
        positionEl;
        childEl;
        monthStr;
        panelIdx;
        datespan;
        timespan;
        wrapEl;
        menuEl;
        resultEl;
        outerEl;
        prevEl;
        nextEl;
        mainEl;
        panelsEl;
        footEl;
        bubbleFootEl;
        footBtnsEl;
        footTipsEl;
        confirmEl;
        clearEl;
        closeEl;
        cancelEl;
        nowEl;
        daytimeBtnEl;
        yearSearchEl;
        rangeChkEl;
        detailEl;
        headingEl;
        eventEl;
        lunarEl;
        detailIns;
        timePanelsEl;
        prevYearEl;
        prevMonthEl;
        nextYearEl;
        nextMonthEl;
        static hostType = 'node';
        static optMaps = optDatetime;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: Datetime.optMaps,
                host: elem,
                component: true,
                spread: ['lunar', 'events', 'footer', 'manual', 'tools']
            });
            
            this.value = [];
            this.raw = [];
            this.monthStr = repeatStr(`<li><span ${orca.alias}="content"><i ${orca.alias}="label">{{this.data[this.index-1]}}</i></span></li>`, 12, this.options.lang.month);
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            super.getDirRtl();
            this.output = { value: '', raw: '', items: [] };
            this.data = {
                startDate: '',
                selecteds: [],
                type: '',
                panels: [
                
                ],
                menu: [],
                year: {
                    panelEl: '',
                    listEl: '',
                    list: []
                },
                
                month: {
                    panelEl: '',
                    listEl: '',
                    list: []
                },
                
                daytime: [],
                
            };
            this.setFeature();
            this.format = trim(this.options.format || 'YYYY/MM/DD');
            this.data.type = dateTools.getDateType(this.format);
            this.getDateTimeSpan();
            this.options.mode === 'range' && this.options.cols === 1 && (this.options.cols = 2);
            if (orca.screen === 'xxs') {
                this.options.display !== 'inline' && this.options.toDrawer && (this.options.display = 'drawer');
                if (this.options.lunar.enable) {
                    this.options.cols = 1;
                    this.options.rows = 1;
                }
                else {
                    if (this.options.cols > 1) {
                        this.options.cols = 1;
                        this.options.rows = 2;
                    }
                }
                this.spreadFooter = false;
            }
            else {
                this.spreadFooter = (this.data.type !== 'daytime' && this.options.cols > 1) || (this.data.type === 'daytime' && this.options.mode === 'range');
            }
            this.separator = this.options.mode === 'range' ? (this.options.lang.range.hyphen || this.options.separator) : this.options.separator;
            this.getTargets();
            this.selectedsProxy = new Observe(this.data.selecteds, {
                deep: true,
            });
            this.selecteds = this.selectedsProxy.proxy;
            this.selectedsProxy.on('completed', (data) => {
                if (this.resultEl) {
                    let newContent = data.proxy.map((k) => {
                        return { label: dateTools.fillFormat(k, this.format, this.options.lang), source: k };
                    });
                    this.resultIns.update({
                        content: newContent,
                    });
                }
                this.options.autoFill && this.confirm(false);
            });
            (this.data.type !== 'daytime') && this.handleDayCont();
            this.createSkeleton();
            (this.data.type !== 'daytime') ? this.createPanels() : this.handleTimeCont();
            if (this.options.display === 'inline') {
                if (this.targetEl) {
                    
                    this.targetEl.insertAdjacentElement(this.targetEl.classList.contains(`${orca.prefix}datetime-wrap`) ? 'beforeend' : 'afterend', this.bubbleEl);
                    this.bubbleEl.insertAdjacentHTML('beforebegin', `<div class="${orca.prefix}datetime-br"></div>`);
                    this.bubbleEl.insertAdjacentHTML('afterend', `<div class="${orca.prefix}datetime-br"></div>`);
                }
            }
            else {
                if (this.options.display === 'dialog') {
                    this.bubbleIns = this.bubbleIns || new Dialog(this.targetEl, extend({
                        target: {
                            content: this.bubbleEl,
                            size: '',
                            padding: false,
                            tools: true,
                            multiple: false,
                            footer: { enable: false },
                            wing: { selector: this.options.btnSel },
                            canClick: this.canClick,
                        },
                        source: this.options.bubble
                    }));
                }
                else if (this.options.display === 'drawer') {
                    this.options.full = true;
                    this.bubbleIns = this.bubbleIns || new Drawer(this.targetEl, extend({
                        target: {
                            content: this.bubbleEl,
                            size: '',
                            padding: false,
                            tools: true,
                            multiple: false,
                            footer: { enable: false },
                            placement: 'bottom',
                            wing: { selector: this.options.btnSel },
                            canClick: this.canClick,
                        },
                        source: this.options.bubble,
                    }));
                }
                else {
                    this.bubbleIns = this.bubbleIns || new Popup(this.positionEl, extend({
                        target: {
                            content: this.bubbleEl,
                            trigger: 'click',
                            tools: { enable: true, placement: 'outside' },
                            size: '',
                            padding: false,
                            placement: this.isRtl ? 'bottom-end' : 'bottom-start',
                            footer: { enable: false },
                            wing: { selector: this.options.btnSel },
                            canClick: this.canClick,
                        },
                        source: this.options.bubble
                    }));
                }
            }
            if (this.bubbleIns) {
                this.bubbleIns.on('show', () => {
                    this.options.autoCorrect && this.checkB4Show();
                });
                this.bubbleIns.on('shown', () => {
                    super.listen({ name: 'shown' });
                });
            }
            this.setAttrs();
            this.renderFinish();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        setFeature() {
            if (this.options.feature === 'static') {
                this.options.footer = false;
            }
            else if (this.options.feature === 'flat') {
                this.options.footer = false;
                this.options.autoFill = true;
                this.options.display = 'inline';
            }
        }
        getTargets() {
            if (this.targetEl && this.targetEl.classList.contains(`${orca.prefix}datetime-wrap`)) {
                this.targetEl.innerHTML = '';
                this.inputEl = createEl('oc-textarea', { mean: `${orca.prefix}icon-calendar`, placeholder: this.options.placeholder || config.lang.form.placeholder });
                this.options.name && this.inputEl.setAttribute('name', this.options.name);
                this.options.label && this.inputEl.setAttribute('label', this.options.label);
                if (this.options.tools.enable && !isEmpty(this.options.tools.children)) {
                    this.inputEl.propsProxy.tools = this.options.tools.children;
                    this.inputEl.changedTools();
                    this.canClick = (el) => (this.inputEl.toolsEl && this.inputEl.toolsEl.contains(el)) || (this.inputEl.labelEl && this.inputEl.labelEl.contains(el)) ? false : true;
                }
                this.inputEl.toggleAttribute('single', !this.options.multiline);
                this.rawHtml.trim() && this.inputEl.setAttribute('value', this.rawHtml.trim());
                this.options.size ? this.inputEl.setAttribute('size', this.options.size) : this.inputEl.removeAttribute('size');
                this.targetEl.appendChild(this.inputEl);
                this.positionEl = this.targetEl;
            }
            else {
                this.positionEl = getEl(this.options.posSel) || this.targetEl;
                this.inputEl = getEl(this.options.inputSel) || this.targetEl;
                this.inputEl && this.inputEl.classList.add(`${orca.prefix}bind-datetime`);
                this.childEl = getEl(this.options.childSel, this.inputEl);
            }
        }
        setAttrs() {
            this.options.classes && this.targetEl && classes(this.targetEl).add(this.options.classes);
            this.bubbleEl.setAttribute('mode', this.options.mode);
            this.data.type ? this.bubbleEl.setAttribute('type', this.data.type) : this.bubbleEl.removeAttribute('type');
            this.bubbleEl.setAttribute('display', this.options.display);
            this.options.feature ? this.bubbleEl.setAttribute('feature', this.options.feature) : this.bubbleEl.removeAttribute('feature');
            if (this.inputEl) {
                this.inputEl.toggleAttribute('readonly', true);
                this.inputEl.toggleAttribute('disabled', this.options.disabled);
            }
            this.bubbleEl.toggleAttribute('disabled', this.options.disabled);
            this.bubbleEl.toggleAttribute('full', this.options.full);
            this.bubbleEl.setAttribute('footer', this.options.footer.enable);
            this.bubbleEl.toggleAttribute('lunar', this.options.lunar.enable);
        }
        createPanel(index, dateObj) {
            let curDate = dateTools.getDate(dateObj, this.data.type, this.options.lang), panelObj = {}, getWeek = () => {
                let tpl = (this.options.weekStart === 'monday') ? `<li>{{this.data[this.index-1]}}</li>` : `<li>{{this.data[this.index===1?6:this.index-2]}}</li>`;
                return repeatStr(tpl, 7, this.options.lang.week);
            };
            if (this.data.type.includes('date')) {
                curDate.setMonth(curDate.getMonth() + index);
                panelObj.month = curDate.getMonth();
                panelObj.year = curDate.getFullYear();
                panelObj.panelEl = tplToEl(`
                        <li panel='${this.options.lunar.enable ? 'lunar' : 'date'}'>
                            <div ${orca.alias}="head">
                                <span ${orca.alias}="year"><i>${panelObj.year}</i>${this.options.lang.unit.Y}</span><span ${orca.alias}="month"><i>${panelObj.month + 1}</i>${this.options.lang.unit.M}</span>
                            </div>
                            <div ${orca.alias}="body" days>
                                <ul ${orca.alias}="column" class="${orca.prefix}reset  ${orca.prefix}grid ${orca.prefix}avg-7">
                                    ${getWeek()}
                                </ul>
                                <ul ${orca.alias}="list" class="${orca.prefix}reset ${orca.prefix}grid ${orca.prefix}avg-7"></ul>
                            </div>
                        </li>
                        `);
                panelObj.type = 'date';
                panelObj.headEl = panelObj.panelEl.querySelector(`[${orca.alias}="head"]`);
                panelObj.yearEl = panelObj.headEl.querySelector(`[${orca.alias}="year"]`);
                panelObj.monthEl = panelObj.headEl.querySelector(`[${orca.alias}="month"]`);
                panelObj.listEl = panelObj.panelEl.querySelector(`[${orca.alias}="list"]`);
                panelObj.list = this.createPanelDayList(panelObj.listEl, curDate);
            }
            else if (this.data.type === 'month') {
                curDate.setFullYear(curDate.getFullYear() + index);
                panelObj.year = curDate.getFullYear();
                panelObj.panelEl = tplToEl(`
                    <li panel='month'>
                        <div ${orca.alias}="head">
                            <span ${orca.alias}="year"><i>${panelObj.year}</i>${this.options.lang.unit.Y}</span>
                        </div>
                        <div body>
                            <ul ${orca.alias}="list" class="${orca.prefix}reset ${orca.prefix}grid ${orca.prefix}avg-3">${this.monthStr}</ul>
                        </div>
                    </li>
                    `);
                panelObj.type = 'month';
                panelObj.headEl = panelObj.panelEl.querySelector(`[${orca.alias}="head"]`);
                panelObj.yearEl = panelObj.headEl.querySelector(`[${orca.alias}="year"]`);
                panelObj.listEl = panelObj.panelEl.querySelector(`[${orca.alias}="list"]`);
                panelObj.list = this.createPanelMonthList(panelObj.listEl, curDate);
            }
            else if (this.data.type === 'year') {
                curDate.setFullYear(curDate.getFullYear() + 18 * index - 7);
                panelObj.year = curDate.getFullYear();
                panelObj.panelEl = tplToEl(`
                <li panel='year'>
                    <div ${orca.alias}="head">
                        <span ${orca.alias}="year"><i>${panelObj.year}</i>${this.options.lang.unit.Y}~<i>${panelObj.year + 17}</i>${this.options.lang.unit.Y}</span>
                    </div>
                    <div ${orca.alias}="body">
                        <ul ${orca.alias}="list" class="${orca.prefix}reset ${orca.prefix}grid ${orca.prefix}avg-3"></ul>
                    </div>
                </li>
                `);
                panelObj.type = 'year';
                panelObj.headEl = panelObj.panelEl.querySelector(`[${orca.alias}="head"]`);
                panelObj.listEl = panelObj.panelEl.querySelector(`[${orca.alias}="list"]`);
                panelObj.list = this.createPanelYearList(panelObj.listEl, curDate);
            }
            panelObj.bodyEl = panelObj.panelEl.querySelector(`[${orca.alias}="body"]`);
            this.data.panels.push(panelObj);
            this.panelsEl.appendChild(panelObj.panelEl);
        }
        createPanels(dateObj, force = false, cb) {
            if (this.destroyed)
                return;
            let index = this.options.rows * this.options.cols, startDate = dateTools.getDate(dateObj || this.data.startDate, this.data.type, this.options.lang);
            if (!force && this.inCurPanels(startDate))
                return;
            this.data.panels = [];
            this.panelsEl.innerHTML = '';
            for (let k = 0; k < index; k++) {
                this.createPanel(k, startDate);
            }
            this.data.startDate = startDate;
            let curItems = this.getCurGrids();
            curItems.forEach((k) => {
                this.inSelectedDate(k) && !k.selected && this.selectedAttrToggle(k, true);
            });
            this.options.mode === 'range' && this.setRangeAttr(curItems);
            let nowObj = dateTools.getDateObj(new Date(), this.data.type), nowItem = curItems.find((k) => JSON.stringify(k.value) == JSON.stringify(nowObj));
            nowItem && nowItem.wrapEl.setAttribute('now', '');
            this.afterCreatePanels();
            super.listen({ name: 'createPanels', cb });
            return this;
        }
        inSelectedDate(data) {
            let value = this.getDateVal(data, this.data.type);
            return this.selecteds.some((k) => {
                let { hh, mm, ss, ...rest } = k;
                return JSON.stringify(rest) == JSON.stringify(value);
            });
        }
        showEvent(obj) {
            this.headingEl.innerHTML = dateTools.fillFormat(obj.value, this.options.events.heading, this.options.lang);
            if (this.options.lunar.enable && this.options.lunar.handler) {
                let lunarObj = { ...this.options.lunar.map }, lunarVal = this.options.lunar.handler(obj.value.YYYY, obj.value.MM + 1, obj.value.DD);
                for (let k in lunarObj) {
                    if (lunarObj.hasOwnProperty(k)) {
                        lunarObj[k] = lunarVal[lunarObj[k]];
                    }
                }
                this.lunarEl.innerHTML = super.getTplcont(lunarObj, this.options.lunar.tplStr, this.options.lunar.tplEng);
            }
            let item = this.options.events.list.find((k) => dateTools.isSameDay(dateTools.getDateObj(k.date, 'date'), dateTools.getDateObj(obj.value, 'date')));
            this.eventEl.innerHTML = item && item.content ? super.getTplcont(item, this.options.events.tplStr, this.options.events.tplEng) : this.options.lang.noEvent;
        }
        inCurPanels(dateObj, curGrids) {
            let type = this.data.type === 'datetime' ? 'date' : this.data.type, date = getDataType(dateObj) === 'Object' ? { ...dateObj } : dateObj, obj = dateTools.getDateObj(date, type), grids = curGrids || this.getCurGrids(), result;
            result = grids.some((k) => JSON.stringify(k.value) == JSON.stringify(obj));
            return result;
        }
        inputVal2Dates(toDate = true) {
            let str = this.getValFromTgt();
            return this.str2Dates(str, toDate);
        }
        str2Dates(str, toDate = true) {
            if (str) {
                return str.split(this.separator).map((k) => toDate ? dateTools.getDate(k, this.data.type, this.options.lang) : k);
            }
            else {
                return [];
            }
        }
        getValFromTgt() {
            if (!this.inputEl)
                return '';
            return ('value' in this.inputEl ? this.inputEl.value : this.childEl ? this.childEl.textContent : this.inputEl.textContent).trim();
        }
        setValFromTgt(value) {
            value = value || '';
            if ('value' in this.inputEl) {
                ['INPUT', 'TEXTAREA'].includes(this.inputEl.nodeName) ? this.inputEl.value = value : this.inputEl.setAttribute('value', value);
            }
            else {
                this.childEl ? this.childEl.innerHTML = value : this.inputEl.innerHTML = value;
            }
        }
        vals2Arr() {
            let type = getDataType(this.options.value), result = [];
            if (!isEmpty(this.options.value)) {
                if (type === 'Array') {
                    result = this.options.value.map((k) => dateTools.getDate(k, this.data.type, this.options.lang));
                }
                else if (type === 'String') {
                    result = this.str2Dates(this.options.value, true);
                }
                else {
                    result = [dateTools.getDate(this.options.value, this.data.type, this.options.lang)];
                }
            }
            else {
                if (this.options.autoCorrect) {
                    let value = this.getValFromTgt();
                    if (value) {
                        result = this.inputVal2Dates();
                    }
                    else {
                        result = this.options.fillNow ? [dateTools.getDate(new Date(), this.data.type, this.options.lang)] : [];
                    }
                }
                else {
                    result = [];
                }
            }
            return result;
        }
        handleDayCont() {
            this.value = this.vals2Arr();
            if (this.value.length > 1 && this.options.mode === 'range') {
                dateTools.sort(this.value);
                this.value.length > 2 && (this.value = this.value.slice(0, 2));
            }
            this.data.startDate = this.value.length === 0 ? dateTools.getDate(new Date(), this.data.type, this.options.lang) : this.value[0];
            let selectedContent = this.dates2Objs(this.value);
            this.selecteds.splice(0, this.data.selecteds.length, ...selectedContent);
            this.raw = [...selectedContent];
            if (this.inputEl) {
                let value = this.selecteds.map((k) => dateTools.fillFormat(k, this.format, this.options.lang)).join(this.separator);
                this.handleVal(value);
            }
        }
        stdTimeStr(data, type = 'object') {
            let objArr = [], dataFn = (obj) => dateTools.getDateObj(obj, 'daytime');
            if (Array.isArray(data)) {
                for (let k of data)
                    objArr.push(dataFn(k));
            }
            else {
                objArr.push(dataFn(data));
            }
            return (type === 'string') ? objArr.map((k) => `${dateTools.fillZero(k.hh)}:${dateTools.fillZero(k.mm)}:${dateTools.fillZero(k.ss)}`) : objArr;
        }
        handleTimeCont() {
            this.value = this.stdTimeStr(this.vals2Arr());
            if (this.options.mode === 'range') {
                if (this.value.length === 0) {
                    this.setDaytime([{ hh: 0, mm: 0, ss: 0 }, { hh: 0, mm: 0, ss: 0 }]);
                }
                else if (this.value.length === 1) {
                    this.setDaytime([this.value[0], { hh: 0, mm: 0, ss: 0 }]);
                }
                else {
                    this.setDaytime(this.value);
                }
            }
            else {
                if (this.value.length === 0) {
                    this.setDaytime({ hh: 0, mm: 0, ss: 0 });
                }
                else {
                    this.setDaytime(this.value[0]);
                }
            }
            this.raw = [...this.value];
            if (this.inputEl && !isEmpty(this.options.value)) {
                let value = this.stdTimeStr(this.value, 'string').join(this.separator);
                this.fillVals(value);
            }
        }
        dates2Objs(dates) {
            let selectedContent = [];
            if (this.data.type === 'year') {
                selectedContent = dates.map((k) => {
                    return { YYYY: k.getFullYear() };
                });
            }
            else if (this.data.type === 'month') {
                selectedContent = dates.map((k) => {
                    return { YYYY: k.getFullYear(), MM: k.getMonth() };
                });
            }
            else if (this.data.type === 'daytime') {
                selectedContent = dates.map((k) => {
                    return { hh: k.getHours(), mm: k.getMinutes(), ss: k.getSeconds() };
                });
            }
            else if (this.data.type === 'date') {
                selectedContent = dates.map((k) => {
                    return { YYYY: k.getFullYear(), MM: k.getMonth(), DD: k.getDate() };
                });
            }
            else if (this.data.type === 'datetime') {
                selectedContent = dates.map((k) => {
                    return { YYYY: k.getFullYear(), MM: k.getMonth(), DD: k.getDate(), hh: k.getHours(), mm: k.getMinutes(), ss: k.getSeconds() };
                });
            }
            return selectedContent;
        }
        checkB4Show() {
            if (this.data.type !== 'daytime') {
                let value = this.inputVal2Dates(), selecteds = this.dates2Objs(value), isSame = JSON.stringify(selecteds) == JSON.stringify(this.data.selecteds);
                if (!isSame) {
                    this.data.startDate = value.length > 0 ? value[0] : dateTools.getDate(this.data.selecteds[0], this.data.type, this.options.lang);
                    this.createPanels();
                    this.clear();
                    this.setVals(selecteds);
                }
            }
            else {
                let timeObj = this.stdTimeStr(this.inputVal2Dates());
                this.setDaytime(timeObj);
            }
        }
        createSkeleton() {
            let outerHTML = '', footHTML = '';
            if (this.data.type !== 'daytime') {
                outerHTML = `
            <div ${orca.alias}="outer">
                        <div ${orca.alias}="prev"></div>
                            <div ${orca.alias}="next"></div>
                            <ul ${orca.alias}="panels" class="${orca.prefix}reset ${orca.prefix}grid ${orca.screen === 'xxs' ? orca.prefix + 'avg-1' : this.spreadFooter ? orca.prefix + 'fence ' + orca.prefix + 'avg-' + this.options.cols : orca.prefix + 'avg-1'}" ></ul>
                        </div>`;
            }
            if (this.options.footer.enable) {
                footHTML = `<div ${orca.alias}="foot"></div>`;
            }
            this.bubbleEl = tplToEl(`
                <div class="${orca.prefix}datetime">
                    <div ${orca.alias}="wrap">
                        ${this.options.menu.length > 0 ? '<ul ' + orca.alias + '="menu"  class="' + orca.prefix + 'reset"></ul>' : ''}
                        <div ${orca.alias}="main">
                            ${this.options.resultShow && this.data.type !== 'daytime' ? '<div ' + orca.alias + '="result"></div>' : ''}
                            ${outerHTML}
                            ${footHTML}
                        </div>
                    </div>
                </div>
            `);
            this.wrapEl = this.bubbleEl.querySelector(`[${orca.alias}="wrap"]`);
            this.menuEl = this.bubbleEl.querySelector(`[${orca.alias}="menu"]`);
            this.resultEl = this.bubbleEl.querySelector(`[${orca.alias}="result"]`);
            this.outerEl = this.bubbleEl.querySelector(`[${orca.alias}="outer"]`);
            this.prevEl = this.bubbleEl.querySelector(`[${orca.alias}="prev"]`);
            this.nextEl = this.bubbleEl.querySelector(`[${orca.alias}="next"]`);
            this.mainEl = this.bubbleEl.querySelector(`[${orca.alias}="main"]`);
            this.panelsEl = this.mainEl.querySelector(`[${orca.alias}="panels"]`);
            if (this.options.footer.enable) {
                this.footEl = this.bubbleEl.querySelector(`[${orca.alias}="foot"]`);
                if (this.spreadFooter) {
                    this.bubbleFootEl = createFooter(Object.assign(this.options.footer, { layout: 'right' }), this.footEl, this);
                    this.footBtnsEl = this.bubbleFootEl.querySelector(`.${orca.prefix}box-btns`);
                    let tmp = this.bubbleFootEl.querySelector(`[${orca.alias}="tips"]`);
                    if (tmp) {
                        this.footTipsEl = tmp;
                    }
                    else {
                        this.footTipsEl = createEl('div', { [orca.alias]: 'tips' });
                        this.footBtnsEl.insertAdjacentElement('afterend', this.footTipsEl);
                    }
                }
                else {
                    this.bubbleFootEl = createFooter(Object.assign(this.options.footer, { layout: 'plain' }), this.footEl, this);
                    this.footBtnsEl = this.bubbleFootEl.querySelector(`.${orca.prefix}box-btns`);
                    this.footTipsEl = this.footBtnsEl;
                }
                this.confirmEl = this.bubbleFootEl.querySelector(`[${orca.alias}="confirm"]`);
                this.clearEl = this.bubbleFootEl.querySelector(`[${orca.alias}="clear"]`);
                this.closeEl = this.bubbleFootEl.querySelector(`[${orca.alias}="close"]`);
                this.cancelEl = this.bubbleFootEl.querySelector(`[${orca.alias}="cancel"]`);
                this.nowEl = this.bubbleFootEl.querySelector(`[${orca.alias}="now"]`);
                this.daytimeBtnEl = this.data.type.includes('time') ? createEl('oc-btn', { type: 'plain', [orca.alias]: 'daytime', label: this.options.lang.daytime.select }) : null;
                this.yearSearchEl = this.data.type === 'year' ? createEl('oc-input', { [orca.alias]: 'search', placeholder: this.options.lang.year.placeholder, btn: `<i class="${orca.prefix}icon-arrow-right"></i>` }) : null;
                this.rangeChkEl = this.options.mode === 'range' && this.data.type === 'datetime' ? createEl('oc-checkbox', { disabled: '', [orca.alias]: 'checkbox', label: this.options.lang.range.checkbox }) : null;
                this.daytimeBtnEl && this.footTipsEl.insertAdjacentElement('afterbegin', this.daytimeBtnEl);
                this.yearSearchEl && this.footTipsEl.insertAdjacentElement('afterbegin', this.yearSearchEl);
                if (this.rangeChkEl) {
                    this.footTipsEl.insertAdjacentElement('afterbegin', this.rangeChkEl);
                    this.rangeChkEl.on('check', (data) => {
                        if (data.checked) {
                            if (this.selecteds.length === 1) {
                                this.selecteds.push({ ...this.selecteds[0] });
                                this.setRange(this.selecteds);
                            }
                        }
                        else {
                            if (this.selecteds.length === 2 && dateTools.isSameDay(this.selecteds[0], this.selecteds[1])) {
                                let tmp = { ...this.selecteds[0] };
                                this.clear(false);
                                this.select(tmp);
                            }
                        }
                    });
                }
            }
            if (this.options.events.enable) {
                this.detailEl = createEl('div', { [orca.alias]: 'detail' });
                this.headingEl = createEl('div', { [orca.alias]: 'heading' });
                this.eventEl = createEl('div', { [orca.alias]: 'event' }, this.options.lang.noEvent);
                this.detailEl.appendChild(this.headingEl);
                this.detailEl.appendChild(this.eventEl);
                if (this.options.lunar.enable && this.options.lunar.handler) {
                    this.lunarEl = createEl('div', { [orca.alias]: 'lunar' });
                    this.headingEl.insertAdjacentElement('afterend', this.lunarEl);
                }
                if (this.options.events.display === 'inline') {
                    this.wrapEl.appendChild(this.detailEl);
                }
                else if (this.options.events.display === 'popup') {
                    this.detailIns = this.detailIns || new Popup(this.panelsEl, {
                        content: this.detailEl,
                        trigger: 'click',
                        placement: 'bottom',
                        size: 'md',
                        footer: false,
                    });
                }
            }
            this.data.type.includes('time') && this.options.footer.enable && this.createTimeSelectPanel();
            this.createMenu();
            if (this.data.type !== 'daytime') {
                if (this.resultEl) {
                    this.resultIns = this.resultIns || new Tags(this.resultEl, {
                        content: '',
                        removable: true,
                        empty: { enable: true, content: this.options.lang.empty },
                    });
                }
                if (this.data.type === 'year' || this.data.type === 'month') {
                    this.prevEl.innerHTML = `<i ${orca.alias}="prevYear" class= "${orca.prefix}icon-left-double"></i> `;
                    this.nextEl.innerHTML = `<i ${orca.alias}="nextYear" class= "${orca.prefix}icon-right-double"></i> `;
                }
                else if (this.data.type.includes('date')) {
                    this.prevEl.innerHTML = `<i ${orca.alias}="prevYear" class= "${orca.prefix}icon-left-double"></i> <i ${orca.alias}="prevMonth" class="${orca.prefix}icon-left"></i>`;
                    this.nextEl.innerHTML = `<i ${orca.alias}="nextYear" class= "${orca.prefix}icon-right-double"></i> <i ${orca.alias}="nextMonth" class="${orca.prefix}icon-right"></i>`;
                }
                this.prevYearEl = this.prevEl.querySelector(`[${orca.alias}="prevYear"]`);
                this.prevMonthEl = this.prevEl.querySelector(`[${orca.alias}="prevMonth"]`);
                this.nextYearEl = this.mainEl.querySelector(`[${orca.alias}="nextYear"]`);
                this.nextMonthEl = this.mainEl.querySelector(`[${orca.alias}="nextMonth"]`);
                if (this.data.type === 'month' || this.data.type.includes('date')) {
                    this.createYearPanel();
                }
                if (this.data.type.includes('date')) {
                    this.createMonthPanel();
                }
            }
        }
        createMenu() {
            if (this.options.menu.length > 0) {
                this.data.menu = this.options.menu;
                let fragment = document.createDocumentFragment();
                this.data.menu.forEach((k) => {
                    k.el = createEl('li', '', k.label);
                    fragment.appendChild(k.el);
                });
                this.menuEl.appendChild(fragment);
                this.data.menu.forEach((k) => {
                    k.el.onclick = () => {
                        k.action && k.action.call(this, k);
                        k.el.setAttribute('selected', '');
                        k.selected = true;
                        this.data.menu.filter((i) => i !== k).forEach((o) => {
                            Reflect.deleteProperty(o, 'selected');
                            o.el.removeAttribute('selected');
                        });
                    };
                });
            }
        }
        createMonthPanel(cb) {
            this.data.month.panelEl = createEl('div', { panel: 'month' }, `<div ${orca.alias}="body"><ul ${orca.alias}="list" class="${orca.prefix}reset ${orca.prefix}grid ${orca.prefix}avg-3">${this.monthStr}</ul></div>`);
            this.data.month.listEl = this.data.month.panelEl.querySelector(`[${orca.alias}="list"]`);
            [...this.data.month.listEl.children].forEach((k, i) => {
                let obj = {
                    wrapEl: k,
                    contEl: k.querySelector(`[${orca.alias}="content"]`),
                    value: i,
                };
                this.data.month.list.push(obj);
            });
            this.panelsEl.insertAdjacentElement('afterend', this.data.month.panelEl);
            cb && cb();
        }
        createYearPanel(cb) {
            this.data.year.panelEl = createEl('div', { panel: 'year' }, `
            <div ${orca.alias}="body">
                                <ul ${orca.alias}="list" class="${orca.prefix}reset ${orca.prefix}grid ${orca.prefix}avg-3"></ul>
                                <ul ${orca.alias}="pages"  class="${orca.prefix}reset ${orca.prefix}grid ${orca.prefix}avg-3">
                                    <li><i ${orca.alias}="prev">${this.options.lang.year.prev}</i></li>
                                    <li><oc-input placeholder="${this.options.lang.year.placeholder}" size="sm" btn="<i class='${orca.prefix}icon-arrow-right'></i>"></oc-input></li>
                                    <li><i ${orca.alias}="next">${this.options.lang.year.next}</i></li>
                                </ul>
                            </div>
            `);
            this.data.year.listEl = this.data.year.panelEl.querySelector(`[${orca.alias}="list"]`);
            this.data.year.prevEl = this.data.year.panelEl.querySelector(`[${orca.alias}="prev"]`);
            this.data.year.nextEl = this.data.year.panelEl.querySelector(`[${orca.alias}="next"]`);
            this.data.year.searchEl = this.data.year.panelEl.querySelector('oc-input');
            this.data.year.inputEl = this.data.year.searchEl.inputEl;
            this.data.year.btnEl = this.data.year.searchEl.btnEl;
            console.dir(this.data.year.searchEl);
            this.panelsEl.insertAdjacentElement('afterend', this.data.year.panelEl);
            cb && cb();
        }
        createYearList(panel, start, index) {
            if (!panel)
                return;
            this.data.year.listEl.innerHTML = '';
            this.data.year.list = [];
            this.panelIdx = index || 0;
            for (let k = 0; k < 15; k++) {
                let year = start || start === 0 ? start + k : panel.year - 7 + k, obj = {
                    wrapEl: createEl('li', '', `<span ${orca.alias}="content"> <i ${orca.alias}="label">${year}${this.options.lang.unit.Y}</i></span> `),
                    value: year,
                };
                obj.contEl = obj.wrapEl.querySelector(`[${orca.alias}="content"]`);
                obj.labelEl = obj.wrapEl.querySelector(`[${orca.alias}="label"]`);
                this.data.year.listEl.appendChild(obj.wrapEl);
                this.data.year.list.push(obj);
            }
            this.data.year.list.forEach((k) => {
                if (panel.year === k.value) {
                    this.selectedAttrToggle(k, true);
                }
                else {
                    this.selectedAttrToggle(k, false);
                }
                k.contEl.onclick = () => {
                    if (k.disabled)
                        return;
                    if (panel.year !== k.value) {
                        let startValue = k.value;
                        if (this.data.type === 'month') {
                            startValue = k.value - this.panelIdx;
                        }
                        else if (this.data.type.includes('date')) {
                            startValue = k.value - (this.data.panels[this.panelIdx].year - this.data.panels[0].year);
                        }
                        this.data.startDate.setFullYear(startValue);
                        this.createPanels(null, true);
                        hide({ el: this.data.year.panelEl });
                    }
                };
            });
        }
        goto(dateObj, select = false, cb) {
            if (this.destroyed)
                return;
            let date = dateTools.getDate(dateObj, this.data.type, this.options.lang);
            if (select) {
                this.setVals(date);
            }
            else {
                this.createPanels(date);
            }
            cb && cb.call(this);
        }
        offset(dateObj, cb) {
            if (this.destroyed)
                return;
            if (this.data.selecteds.length > 0) {
                let dates = this.data.selecteds.map((k) => dateTools.getDateObj(dateTools.getOffsetDate(k, dateObj), this.data.type));
                this.setVals(dates);
            }
            else {
                this.data.startDate = dateTools.getOffsetDate(dateTools.getDateObj(new Date(), this.data.type), dateObj);
                this.setVals(this.data.startDate);
            }
            cb && cb.call(this);
        }
        selectedAttrToggle(obj, state) {
            if (state) {
                if (!obj.selected) {
                    Reflect.set(obj, 'selected', true);
                    obj.wrapEl.setAttribute('selected', '');
                }
            }
            else {
                if (obj.selected) {
                    Reflect.deleteProperty(obj, 'selected');
                    obj.wrapEl.removeAttribute('selected');
                }
            }
        }
        select(data, curGrid, curGrids) {
            let curObj = this.findFromPanels(data, curGrid, curGrids), curItems = curObj.list, curItem = curObj.target, fillTime = (dateObj) => {
                let obj = {};
                if (this.options.mode === 'range') {
                    obj = this.data.type.includes('time') ? { ...dateObj, ...this.data.daytime[this.selecteds.length === 1 ? 1 : 0].value } : dateObj;
                }
                else {
                    obj = this.data.daytime.length > 0 && this.data.type.includes('time') ? { ...dateObj, ...this.data.daytime[0].value } : dateObj;
                }
                return obj;
            }, selectedFun = (obj) => {
                if (obj.disabled)
                    return;
                let value;
                if (this.data.type.includes('time')) {
                    value = (data.hasOwnProperty('hh') && data.hasOwnProperty('mm') && data.hasOwnProperty('ss')) ? data : fillTime(obj.value);
                }
                else {
                    value = data.value || data;
                }
                if (this.options.mode === 'range') {
                    let length = this.selecteds.length;
                    if (length < 2) {
                        this.selecteds.push(value);
                        if (length === 1) {
                            let rangeStart = { ...this.data.selecteds[0] }, rangeEnd = { ...this.data.selecteds[1] };
                            if (dateTools.getDate(rangeStart, this.data.type, this.options.lang) > dateTools.getDate(rangeEnd, this.data.type, this.options.lang)) {
                                this.selecteds.sort((a, b) => dateTools.getDate(a, this.data.type, this.options.lang) - dateTools.getDate(b, this.data.type, this.options.lang));
                                this.assignDaytime();
                            }
                            this.rangeChkEl && this.rangeChkEl.setAttribute('disabled', '');
                            this.rangeChkEl && this.rangeChkEl.setAttribute('check', '');
                            this.setRange(this.selecteds);
                        }
                        else {
                            this.rangeChkEl && this.rangeChkEl.removeAttribute('disabled');
                        }
                    }
                    else {
                        this.clear(false);
                        this.selecteds.splice(0, this.selecteds.length, value);
                        this.rangeChkEl && this.rangeChkEl.removeAttribute('disabled');
                        this.rangeChkEl && this.rangeChkEl.setAttribute('check', '');
                    }
                }
                else {
                    if (this.options.mode === 'multiple') {
                        !this.inSelectedDate(value) && this.selecteds.push(value);
                    }
                    else {
                        if (this.inSelectedDate(value))
                            return;
                        this.clear(false);
                        this.selecteds.splice(0, this.selecteds.length, value);
                    }
                }
                this.selectedAttrToggle(obj, true);
            };
            if (!curItems.includes(data) && !curItem) {
                this.createPanels(data.hasOwnProperty('value') ? data.value : data);
                curItem = this.findFromPanels(data).target;
            }
            if (curItem.disabled)
                return;
            !curItem?.selected && selectedFun(curItem);
            this.options.events.enable && curItem && this.showEvent(curItem);
        }
        deselect(dateObj, curGrid, curGrids) {
            if (isEmpty(dateObj))
                return;
            let curItems = curGrids || this.getCurGrids(), curItem = this.findFromPanels(dateObj, curGrid, curItems).target, selecteds = [];
            curItem && this.selectedAttrToggle(curItem, false);
            selecteds = this.data.selecteds.filter((k) => !dateTools.isSameDay(k, dateObj.hasOwnProperty('value') ? dateObj.value : dateObj));
            this.selecteds.splice(0, this.data.selecteds.length, ...selecteds);
            if (this.options.mode === 'range' && this.data.selecteds.length < 2) {
                curItems.forEach((k) => {
                    this.removeRangeAttr(k);
                });
            }
        }
        setRangeAttr(grids) {
            if (this.data.selecteds.length !== 2)
                return;
            let curGrids = grids || this.getCurGrids(), type = this.data.type === 'datetime' ? 'date' : this.data.type;
            curGrids.forEach((k) => {
                this.removeRangeAttr(k);
                this.selectedAttrToggle(k, false);
                if (dateTools.getDate(k.value, type, this.options.lang) > dateTools.getDate(this.data.selecteds[0], type, this.options.lang) && dateTools.getDate(k.value, type, this.options.lang) < dateTools.getDate(this.data.selecteds[1], type, this.options.lang)) {
                    k.wrapEl.setAttribute('contain', '');
                }
            });
            let gridStart = this.findFromPanels(this.data.selecteds[0], null, curGrids).target, gridEnd = this.findFromPanels(this.data.selecteds[1], null, curGrids).target;
            if (gridStart) {
                gridStart.wrapEl.setAttribute('start', '');
                this.selectedAttrToggle(gridStart, true);
            }
            if (gridEnd) {
                gridEnd.wrapEl.setAttribute('end', '');
                this.selectedAttrToggle(gridEnd, true);
            }
        }
        removeRangeAttr(dateObj) {
            if (dateObj.wrapEl.hasAttribute('start')) {
                dateObj.wrapEl.removeAttribute('start');
            }
            if (dateObj.wrapEl.hasAttribute('end')) {
                dateObj.wrapEl.removeAttribute('end');
            }
            if (dateObj.wrapEl.hasAttribute('contain')) {
                dateObj.wrapEl.removeAttribute('contain');
            }
        }
        getDatespan() {
            this.datespan = [];
            if (isEmpty(this.options.datespan))
                return;
            let spanType = getDataType(this.options.datespan), getVal = (obj) => {
                let objType = getDataType(obj), result = {};
                if (objType !== 'Object') {
                    return result;
                }
                if (obj.hasOwnProperty('min')) {
                    result.min = {
                        Date: dateTools.getDate(obj.min, this.data.type, this.options.lang),
                        Object: dateTools.getDateObj(obj.min, this.data.type, this.options.lang)
                    };
                }
                obj.hasOwnProperty('min') && (result.min = dateTools.getDate(obj.min, this.data.type, this.options.lang));
                obj.hasOwnProperty('max') && (result.max = dateTools.getDate(obj.max, this.data.type, this.options.lang));
                if (obj.hasOwnProperty('max')) {
                    result.max = {
                        Date: dateTools.getDate(obj.max, this.data.type, this.options.lang),
                        Object: dateTools.getDateObj(obj.max, this.data.type, this.options.lang)
                    };
                }
                return result;
            };
            if (spanType === 'Object') {
                this.datespan.push(getVal(this.options.datespan));
            }
            else if (spanType === 'Array') {
                this.datespan = this.options.datespan.map((k) => getVal(k)).filter((k) => !isEmpty(k));
            }
        }
        getTimespan() {
            this.timespan = [];
            if (isEmpty(this.options.timespan))
                return;
            let spanType = getDataType(this.options.timespan), getVal = (obj) => {
                let objType = getDataType(obj), result = {};
                if (objType !== 'Object') {
                    return result;
                }
                obj.hasOwnProperty('min') && (result.min = dateTools.getDateObj(obj.min, this.data.type, this.options.lang));
                obj.hasOwnProperty('max') && (result.max = dateTools.getDateObj(obj.max, this.data.type, this.options.lang));
                return result;
            };
            if (spanType === 'Object') {
                this.timespan.push(getVal(this.options.timespan));
            }
            else if (spanType === 'Array') {
                this.timespan = this.options.timespan.map((k) => getVal(k)).filter((k) => !isEmpty(k));
            }
        }
        getDateTimeSpan() {
            let hander = (type = 'timespan') => {
                if (isEmpty(this.options[type]))
                    return [];
                let spanType = getDataType(this.options[type]), dateProp = type === 'datespan' ? 'getDate' : 'getDateObj', getVal = (obj) => {
                    let objType = getDataType(obj), result = {};
                    if (objType !== 'Object')
                        return result;
                    obj.hasOwnProperty('min') && (result.min = dateTools[dateProp](obj.min, this.data.type, this.options.lang));
                    obj.hasOwnProperty('max') && (result.max = dateTools[dateProp](obj.max, this.data.type, this.options.lang));
                    return result;
                };
                if (spanType === 'Object') {
                    return [getVal(this.options[type])];
                }
                else if (spanType === 'Array') {
                    return this.options[type].map((k) => getVal(k)).filter((k) => !isEmpty(k));
                }
            };
            this.datespan = hander('datespan');
            this.timespan = hander('timespan');
        }
        setWrapDisabled(obj) {
            obj.disabled = true;
            obj.wrapEl.setAttribute('disabled', '');
        }
        compareVal(data, range, prop) {
            let min = range.hasOwnProperty('min') ? prop ? range.min[prop] : range.min : null, max = range.hasOwnProperty('max') ? prop ? range.max[prop] : range.max : null, result;
            if (isNull(min) && isNull(max)) {
                result = false;
            }
            else if (isNull(min)) {
                result = data <= max;
            }
            else if (isNull(max)) {
                result = data >= min;
            }
            else {
                result = data >= min && data <= max;
            }
            return result;
        }
        setDatespanDisabled(dateObj) {
            if (!this.datespan.length || dateObj.disabled)
                return;
            let condition;
            let valDate = dateTools.getDate(dateObj.value, this.data.type, this.options.lang);
            let tmp = this.datespan.find((k) => {
                
                return this.compareVal(valDate, k);
            });
            condition = tmp ? false : true;
            condition && this.setWrapDisabled(dateObj);
        }
        setTimespanDisabled(timeObj, prop) {
            if (!this.timespan.length || timeObj.disabled)
                return;
            let condition;
            let tmp = this.timespan.find((k) => {
                
                return this.compareVal(timeObj.value, k, prop);
            });
            condition = tmp ? false : true;
            condition && this.setWrapDisabled(timeObj);
        }
        getDateVal(dateObj, type) {
            let objType = getDataType(dateObj), value = {}, result;
            if (objType === 'String' || objType === 'Date') {
                result = dateTools.getDateObj(dateObj, 'date');
            }
            else {
                if (objType === 'Object') {
                    if (dateObj.hasOwnProperty('value')) {
                        value = dateObj.value;
                    }
                    else {
                        value = dateObj;
                    }
                }
                else if (objType === 'Number') {
                    value = this.data.selecteds[dateObj];
                }
                result = dateTools.getDateObj(value, 'date');
            }
            if (type === 'year') {
                Reflect.deleteProperty(result, 'DD');
                Reflect.deleteProperty(result, 'MM');
            }
            else if (type === 'month') {
                Reflect.deleteProperty(result, 'DD');
            }
            return result;
        }
        getCurGrids() {
            return this.data.panels.map((k) => k.list).flat(Infinity).filter((k) => !k.exceed);
        }
        findFromPanels(dateObj, grid, grids) {
            let value = this.getDateVal(dateObj, this.data.type), curItems = grids || this.getCurGrids(), curItem = grid || curItems.find((k) => JSON.stringify(k.value) == JSON.stringify(value));
            return { target: curItem, list: curItems };
        }
        afterCreatePanels() {
            if (this.data.type !== 'daytime') {
                let curGrids = this.getCurGrids();
                this.data.panels.forEach((o) => {
                    o.list.forEach((k) => {
                        k.contEl.onclick = () => {
                            if (k.disabled)
                                return;
                            if (this.data.selecteds.length > this.options.maxSelection) {
                                console.warn(`The selected items have exceeded the ${this.options.maxSelection} limit!`);
                                return;
                            }
                            let curItem = curGrids.find((i) => JSON.stringify(i.value) == JSON.stringify(k.value));
                            if (this.options.mode === 'multiple') {
                                if (curItem) {
                                    curItem.selected ? this.deselect(k, curItem, curGrids) : this.select(k, curItem, curGrids);
                                }
                                else {
                                    this.select(k, curItem, curGrids);
                                }
                            }
                            else {
                                this.select(k, curItem, curGrids);
                            }
                            super.listen({ name: 'set', params: [k] });
                        };
                        if (this.detailIns) {
                            k.contEl.onmouseenter = () => {
                                this.showEvent(k);
                                this.detailIns.transfer(k.contEl, () => {
                                    this.detailIns.show();
                                });
                            };
                        }
                    });
                });
                this.data.panels.forEach((k, i) => {
                    if (k.yearEl) {
                        k.yearEl.onclick = () => {
                            this.data.year.panelEl.style.top = k.panelEl.offsetTop + k.headEl.clientHeight + 'px';
                            this.data.year.panelEl.style.left = k.panelEl.offsetLeft + 'px';
                            this.data.month.panelEl && elState(this.data.month.panelEl).isVisible && hide({ el: this.data.month.panelEl });
                            this.createYearList(k, null, i);
                            toggle({
                                el: this.data.year.panelEl,
                                done: {
                                    show: () => {
                                        k.yearEl.classList.add(`${orca.prefix}opened`);
                                    },
                                    hide: () => {
                                        k.yearEl.classList.remove(`${orca.prefix}opened`);
                                    }
                                }
                            });
                        };
                        this.data.year.prevEl.onclick = () => {
                            this.createYearList(k, this.data.year.list[0].value - 15, i);
                        };
                        this.data.year.nextEl.onclick = () => {
                            this.createYearList(k, this.data.year.list[14].value + 1, i);
                        };
                        this.data.year.btnEl.onclick = () => {
                            this.searchYear2Update(this.data.year.inputEl);
                        };
                        this.data.year.inputEl.onkeyup = (e) => {
                            (e.code === 'Enter') && this.searchYear2Update(this.data.year.inputEl);
                        };
                    }
                    if (k.monthEl) {
                        k.monthEl.onclick = () => {
                            this.data.month.panelEl.style.top = k.panelEl.offsetTop + k.headEl.clientHeight + 'px';
                            this.data.month.panelEl.style.left = k.panelEl.offsetLeft + 'px';
                            if (elState(this.data.year.panelEl).isVisible) {
                                hide({ el: this.data.year.panelEl });
                            }
                            this.data.month.list.forEach((o) => {
                                if (k.month === o.value) {
                                    this.selectedAttrToggle(o, true);
                                }
                                else {
                                    this.selectedAttrToggle(o, false);
                                }
                                o.contEl.onclick = () => {
                                    if (k.month !== o.value) {
                                        this.data.startDate.setMonth(o.value - i);
                                        this.createPanels('', true);
                                        hide({ el: this.data.month.panelEl });
                                    }
                                };
                            });
                            toggle({
                                el: this.data.month.panelEl,
                                done: {
                                    show: () => {
                                        k.monthEl.classList.add(`${orca.prefix}opened`);
                                    },
                                    hide: () => {
                                        k.monthEl.classList.remove(`${orca.prefix}opened`);
                                    }
                                }
                            });
                        };
                    }
                });
                this.data.selecteds.forEach((k, i) => {
                    let item = this.findFromPanels(k, null, curGrids).target;
                    if (item) {
                        this.selectedAttrToggle(item, true);
                        (i === 0 && this.options.events.enable) && this.showEvent(item);
                    }
                });
            }
        }
        renderFinish() {
            if (this.data.type !== 'daytime') {
                if (this.resultIns) {
                    this.resultIns.on('removed', (items) => {
                        for (let k of items) {
                            this.deselect(k.source);
                        }
                    });
                    this.resultIns.on('updated', () => {
                        this.resultIns.data.forEach((k) => {
                            k.wrapEl.onclick = (e) => {
                                e.target.getAttribute(orca.alias) !== 'remove' && !this.findFromPanels(k.label).target && this.createPanels(k.label);
                            };
                        });
                    });
                }
                if (this.prevYearEl) {
                    this.prevYearEl.onclick = () => {
                        let years = (this.data.type === 'year') ? -18 * this.options.cols * this.options.rows :
                            (this.data.type === 'month') ? -this.options.cols * this.options.rows : -1;
                        this.createPanels(dateTools.getOffsetDate(this.data.startDate, { YYYY: years }), true);
                        this.data.year.panelEl && this.createYearList(this.data.panels[this.panelIdx], null, this.panelIdx);
                    };
                }
                if (this.nextYearEl) {
                    this.nextYearEl.onclick = () => {
                        let years = (this.data.type === 'year') ? 18 * this.options.cols * this.options.rows :
                            (this.data.type === 'month') ? this.options.cols * this.options.rows : 1;
                        this.createPanels(dateTools.getOffsetDate(this.data.startDate, { YYYY: years }), true);
                        this.data.year.panelEl && this.createYearList(this.data.panels[this.panelIdx], null, this.panelIdx);
                    };
                }
                if (this.data.type.includes('date')) {
                    this.prevMonthEl.onclick = () => {
                        this.createPanels(dateTools.getOffsetDate(this.data.startDate, { MM: -1 }), true);
                    };
                    this.nextMonthEl.onclick = () => {
                        this.createPanels(dateTools.getOffsetDate(this.data.startDate, { MM: 1 }), true);
                    };
                }
                if (this.yearSearchEl) {
                    this.yearSearchEl.btnEl.onclick = () => {
                        this.searchYear2Update(this.yearSearchEl.inputEl, false);
                    };
                    this.yearSearchEl.inputEl.onkeyup = (e) => {
                        (e.code === 'Enter') && this.searchYear2Update(this.yearSearchEl.inputEl, false);
                    };
                }
                if (this.timePanelsEl) {
                    if (this.options.mode === 'range') {
                        if (this.data.selecteds.length === 0) {
                            this.setDaytime([{ hh: 0, mm: 0, ss: 0 }, { hh: 0, mm: 0, ss: 0 }]);
                        }
                        else if (this.data.selecteds.length === 1) {
                            this.setDaytime([this.data.selecteds[0], { hh: 0, mm: 0, ss: 0 }]);
                        }
                        else {
                            this.setDaytime(this.data.selecteds);
                        }
                    }
                    else {
                        if (this.data.selecteds.length === 0) {
                            this.setDaytime({ hh: 0, mm: 0, ss: 0 });
                        }
                        else {
                            this.setDaytime(this.data.selecteds[0]);
                        }
                    }
                    if (this.daytimeBtnEl) {
                        this.daytimeBtnEl.onclick = () => {
                            slideToggle({
                                el: this.timePanelsEl,
                                display: 'grid',
                                before: (e) => {
                                    e.for === 'show' && this.openTime2Scroll();
                                }
                            });
                        };
                    }
                }
            }
            if (this.options.footer.enable) {
                if (this.confirmEl) {
                    this.confirmEl.onclick = () => this.confirm();
                }
                if (this.nowEl) {
                    this.nowEl.onclick = () => this.setNow();
                }
                if (this.clearEl) {
                    this.clearEl.onclick = () => this.clear(true);
                }
                if (this.cancelEl) {
                    this.cancelEl.onclick = () => this.cancel();
                }
                if (this.closeEl) {
                    this.closeEl.onclick = () => this.hide();
                }
            }
            if (this.data.type.includes('time') && this.data.daytime.length > 0) {
                let timeCols = this.data.daytime.map((k) => k.colsEl).flat(Infinity);
                if (this.options.display === 'inline') {
                    this.openTime2Scroll(timeCols);
                }
                else {
                    if (this.bubbleIns) {
                        this.bubbleIns.on('show', () => {
                            this.openTime2Scroll(timeCols);
                        });
                    }
                }
            }
            if (this.bubbleIns) {
                this.bubbleIns.on('show', () => {
                    this.setResultWidth();
                });
            }
            else {
                this.setResultWidth();
            }
        }
        setResultWidth() {
            this.resultEl && (this.resultEl.style.maxWidth = this.panelsEl.getBoundingClientRect().width + 'px');
        }
        openTime2Scroll(cols) {
            let timeCols = cols || this.data.daytime.map((k) => k.colsEl).flat(Infinity);
            timeCols.forEach((k) => {
                this.showForemost(k);
            });
        }
        searchYear2Update(input, isHide = true) {
            let value = input.value;
            if (value && !isNaN(value)) {
                this.data.startDate.setFullYear(~~value);
                this.createPanels();
                isHide && hide({ el: this.data.year.panelEl });
                this.data.type === 'year' && this.select({ YYYY: ~~value });
            }
            else {
                new Message({
                    status: 'error',
                    iconShow: true,
                    content: this.options.lang.message.requireYearFormat,
                }).show();
            }
        }
        createPanelDayList(elem, dateObj) {
            elem.innerHTML = '';
            let curDate = dateTools.getDate(dateObj, this.data.type, this.options.lang);
            curDate.setDate(1);
            let list = [], startIndex, curMonth = curDate.getMonth(), curYear = curDate.getFullYear(), monthDays = dateTools.getCurDays(curDate), preDate = dateTools.getOffsetDate(curDate, { MM: -1 }), prevMonth = preDate.getMonth(), prevYear = preDate.getFullYear(), nextDate = dateTools.getOffsetDate(curDate, { MM: 1 }), nextMonth = nextDate.getMonth(), nextYear = nextDate.getFullYear(), fragment = document.createDocumentFragment();
            if (this.options.weekStart === 'monday') {
                startIndex = (curDate.getDay() === 0) ? 7 : curDate.getDay();
            }
            else {
                startIndex = (curDate.getDay() === 0) ? 1 : curDate.getDay() + 1;
            }
            let day = 1;
            for (let gridIndex = 1; gridIndex <= 42;) {
                let dayObj = {
                    wrapEl: createEl('li'),
                    contEl: createEl('span', { [orca.alias]: 'content' }),
                    labelEl: createEl('i', { [orca.alias]: 'label' }),
                }, label;
                dayObj.wrapEl.appendChild(dayObj.contEl);
                dayObj.contEl.appendChild(dayObj.labelEl);
                if (gridIndex < startIndex) {
                    label = dateTools.getCurDays({ YYYY: prevYear, MM: prevMonth }) - startIndex + gridIndex + 1;
                    dayObj.value = { YYYY: prevYear, MM: prevMonth, DD: label };
                    dayObj.exceed = true;
                    dayObj.wrapEl.setAttribute('exceed', '');
                }
                else if (gridIndex >= startIndex + monthDays) {
                    label = gridIndex - startIndex - monthDays + 1;
                    dayObj.value = { YYYY: nextYear, MM: nextMonth, DD: label };
                    dayObj.exceed = true;
                    dayObj.wrapEl.setAttribute('exceed', '');
                }
                else {
                    label = day;
                    dayObj.value = { YYYY: curYear, MM: curMonth, DD: label };
                    day++;
                }
                dayObj.label = label;
                dayObj.labelEl.textContent = label;
                this.setDatespanDisabled(dayObj);
                if (this.options.lunar && this.options.lunar.handler) {
                    let lunarObj = this.options.lunar.handler(dayObj.value.YYYY, dayObj.value.MM + 1, dayObj.value.DD);
                    if (lunarObj && lunarObj != -1) {
                        let lunarContent = '', attr = '';
                        for (let v of this.options.lunar.arrange) {
                            if (this.options.lunar.map.hasOwnProperty(v) && lunarObj[this.options.lunar.map[v]]) {
                                lunarContent = lunarObj[this.options.lunar.map[v]];
                                if (v.includes('Festival')) {
                                    attr = 'festival';
                                }
                                else if (v === 'term') {
                                    attr = v;
                                }
                                break;
                            }
                        }
                        dayObj.lunarEl = createEl('u', '', lunarContent);
                        attr ? dayObj.lunarEl.setAttribute(orca.alias, attr) : null;
                        dayObj.labelEl.insertAdjacentElement('afterend', dayObj.lunarEl);
                    }
                    if (this.options.lunar.tags.length > 0) {
                        for (let v of this.options.lunar.tags) {
                            let date = dateTools.getDateObj(v.date, this.data.type), tagEl = createEl('s', v.attr ? { [orca.alias]: v.attr } : {}, v.content);
                            if (dateTools.isSameDay(date, dayObj.value)) {
                                dayObj.contEl.appendChild(tagEl);
                                break;
                            }
                        }
                    }
                }
                if (this.options.events.enable) {
                    for (let v of this.options.events.list) {
                        let date = dateTools.getDateObj(v.date, this.data.type);
                        if (dateTools.isSameDay(date, dayObj.value)) {
                            dayObj.busy = true;
                            dayObj.wrapEl.setAttribute('busy', '');
                            break;
                        }
                    }
                }
                gridIndex++;
                fragment.appendChild(dayObj.wrapEl);
                list.push(dayObj);
            }
            elem.appendChild(fragment);
            return list;
        }
        createPanelMonthList(elem, dateObj) {
            let list = [];
            [...elem.children].forEach((k, i) => {
                let obj = {
                    wrapEl: k,
                    contEl: k.querySelector(`[${orca.alias}="content"]`),
                    value: { YYYY: dateObj.getFullYear(), MM: i }
                };
                this.setDatespanDisabled(obj);
                list.push(obj);
            });
            return list;
        }
        createPanelYearList(elem, dateObj) {
            let list = [], fragment = document.createDocumentFragment();
            for (let k = 0; k < 18; k++) {
                let year = dateObj.getFullYear() + k, wrap = createEl('li', '', `<span ${orca.alias}="content"><i ${orca.alias}="label">${year}${this.options.lang.unit.Y}</i></span>`), obj = {
                    wrapEl: wrap,
                    value: { YYYY: year },
                };
                obj.contEl = obj.wrapEl.querySelector(`[${orca.alias}="content"]`);
                this.setDatespanDisabled(obj);
                list.push(obj);
                fragment.appendChild(wrap);
            }
            elem.appendChild(fragment);
            return list;
        }
        createLoopStr(max) {
            let str = '<li>';
            for (let n = 0; n < max; n++) {
                str += `<div> <span ${orca.alias}="content"><i ${orca.alias}="label">${dateTools.fillZero(n)}</i></span></div> `;
            }
            str += '</li>';
            return str;
        }
        createTimeList(label) {
            return `
        <li panel="daytime">
                            <span ${orca.alias}="tools"><i ${orca.alias}="restore" title='${this.options.lang.toolTip.restore}'></i><i ${orca.alias}="reset" title='${this.options.lang.toolTip.reset}'></i><i ${orca.alias}="now" title='${this.options.lang.toolTip.now}'></i><i ${orca.alias}="close" title='${this.options.lang.toolTip.close}'></i></span>
                            <div ${orca.alias}="head">
                                <span ${orca.alias}="time">${label}</span>
                            </div>
                            <div ${orca.alias}="body">
                                <ul ${orca.alias}="column" class="${orca.prefix}reset ${orca.prefix}grid ${orca.prefix}avg-3">
                                    <li>${this.options.lang.unit.h}</li>
                                    <li>${this.options.lang.unit.m}</li>
                                    <li>${this.options.lang.unit.s}</li>
                                </ul>
                                <ul ${orca.alias}="list" class="${orca.prefix}reset ${orca.prefix}grid ${orca.prefix}avg-3">
                                ${this.createLoopStr(24)}
                                ${this.createLoopStr(60)}
                                ${this.createLoopStr(60)}
                                </ul>
                            </div>
                        </li>
        `;
        }
        toggleTimeList(item, list) {
            this.selectedAttrToggle(item, true);
            let selectedItem = list.find((k) => k != item && k.selected);
            selectedItem && this.selectedAttrToggle(selectedItem, false);
        }
        getTimeListArr(parent, type) {
            let children = parent.children, arr = [];
            [...children].forEach((k, i) => {
                let obj = {
                    wrapEl: k,
                    contEl: k.querySelector(`[${orca.alias}="content"]`),
                    value: i
                };
                if (!this.format.includes(type)) {
                    obj.disabled = true;
                    obj.wrapEl.setAttribute('disabled', '');
                }
                else {
                    this.setTimespanDisabled(obj, type);
                }
                arr.push(obj);
            });
            return arr;
        }
        showForemost(parent) {
            let fun = (elem) => {
                let selectedItem = elem.querySelector('[selected]'), toTop = selectedItem.getBoundingClientRect().height * Math.floor((~~selectedItem.textContent) / 2);
                selectedItem && (elem.scrollTop = toTop);
            };
            if (Array.isArray(parent)) {
                parent.forEach((k) => {
                    fun(k);
                });
            }
            else {
                fun(parent);
            }
        }
        createTimeSelectPanel() {
            this.timePanelsEl = createEl('UL', { class: `${orca.prefix}reset ${orca.prefix}grid ${orca.prefix}fence ${orca.screen === 'xxs' ? orca.prefix + 'avg-1' : orca.prefix + 'avg-' + this.options.cols}`, panels: 'hms' });
            if (this.options.mode === 'range') {
                this.timePanelsEl.innerHTML = this.createTimeList(this.options.lang.daytime.start) + this.createTimeList(this.options.lang.daytime.end);
            }
            else {
                this.timePanelsEl.innerHTML = this.createTimeList(this.options.lang.daytime.select);
            }
            [...this.timePanelsEl.querySelectorAll(`[panel]`)].forEach((k) => {
                let liArr = [...k.querySelectorAll(`[${orca.alias}="list"] li`)], panelObj = {
                    panelEl: k,
                    colsEl: liArr,
                    restoreEl: k.querySelector(`[${orca.alias}="restore"]`),
                    resetEl: k.querySelector(`[${orca.alias}="reset"]`),
                    nowEl: k.querySelector(`[${orca.alias}="now"]`),
                    closeEl: k.querySelector(`[${orca.alias}="close"]`),
                    value: {},
                    hh: this.getTimeListArr(liArr[0], 'hh'),
                    mm: this.getTimeListArr(liArr[1], 'mm'),
                    ss: this.getTimeListArr(liArr[2], 'ss'),
                };
                this.data.daytime.push(panelObj);
            });
            this.footEl.insertAdjacentElement('beforebegin', this.timePanelsEl);
            this.data.daytime.forEach((k, n) => {
                k.closeEl.onclick = () => {
                    slideUp({ el: this.timePanelsEl, display: 'inline-grid' });
                };
                k.restoreEl.onclick = () => {
                    this.raw[n] && this.setDaytime(this.raw[n], n, true);
                };
                k.resetEl.onclick = () => {
                    this.setDaytime({ hh: 0, mm: 0, ss: 0 }, n, true);
                };
                k.nowEl.onclick = () => {
                    let time = dateTools.getDateObj(new Date(), this.data.type);
                    this.setDaytime({ hh: time.hh, mm: time.mm, ss: time.ss }, n, true);
                };
                k.hh.forEach((i) => {
                    i.contEl.onclick = () => {
                        if (i.selected || i.disabled)
                            return;
                        this.toggleTimeList(i, k.hh);
                        k.value.hh = i.value;
                        this.timeToUpdate(k, n, true);
                        super.listen({ name: 'updatedTime', params: [i] });
                    };
                });
                k.mm.forEach((i) => {
                    i.contEl.onclick = () => {
                        if (i.selected || i.disabled)
                            return;
                        this.toggleTimeList(i, k.mm);
                        k.value.mm = i.value;
                        this.timeToUpdate(k, n, true);
                        super.listen({ name: 'updatedTime', params: [i] });
                    };
                });
                k.ss.forEach((i) => {
                    i.contEl.onclick = () => {
                        if (i.selected || i.disabled)
                            return;
                        this.toggleTimeList(i, k.ss);
                        k.value.ss = i.value;
                        this.timeToUpdate(k, n, true);
                        super.listen({ name: 'updatedTime', params: [i] });
                    };
                });
            });
        }
        timeToUpdate(parent, index = 0, updateHTML = false) {
            updateHTML ? this.setTimeBtnHTML() : null;
            if (this.data.type !== 'daytime' && (this.options.mode === 'single' || this.options.mode === 'range')) {
                (this.data.selecteds.length >= index + 1) && Object.assign(this.selecteds[index], parent.value);
            }
            this.data.type === 'daytime' && this.options.autoFill && this.confirm(false);
        }
        setTimeBtnHTML() {
            if (!this.data.type.includes('time') || !this.daytimeBtnEl)
                return;
            let timeStr = this.data.daytime.map((k) => {
                return isEmpty(k.value) ? this.options.lang.daytime.select : `${dateTools.fillZero(k.value.hh)}:${dateTools.fillZero(k.value.mm)}:${dateTools.fillZero(k.value.ss)}`;
            });
            this.daytimeBtnEl.setAttribute('label', timeStr.join('~'));
        }
        setDaytime(timeObj, index = 0, update = false, cb) {
            if (isEmpty(timeObj) || !this.data.type.includes('time') || this.destroyed)
                return;
            let type = getDataType(timeObj);
            let setFun = (k, i) => {
                let time = (typeof k === 'string') ? dateTools.getTimeObj(timeObj) : k;
                this.data.daytime[i].value.hh = time.hh;
                this.toggleTimeList(this.data.daytime[i].hh[time.hh], this.data.daytime[i].hh);
                this.data.daytime[i].value.mm = time.mm;
                this.toggleTimeList(this.data.daytime[i].mm[time.mm], this.data.daytime[i].mm);
                this.data.daytime[i].value.ss = time.ss;
                this.toggleTimeList(this.data.daytime[i].ss[time.ss], this.data.daytime[i].ss);
                update && this.data.type === 'datetime' ? this.timeToUpdate(this.data.daytime[i], i) : null;
            };
            if (type === 'Array') {
                timeObj.forEach((k, i) => {
                    (this.data.daytime.length > i) && setFun(k, i);
                });
            }
            else {
                setFun(timeObj, index);
            }
            this.setTimeBtnHTML();
            super.listen({ name: 'updatedTime', cb, params: [timeObj] });
        }
        assignDaytime() {
            this.selecteds.forEach((k, i) => {
                this.data.daytime[i] && Object.assign(k, this.data.daytime[i].value);
            });
        }
        async cancel(cb) {
            this.options.b4Cancel && await this.options.b4Cancel.call(this);
            this.hide();
            this.clear(true);
            this.handleVal('');
            super.listen({ name: 'canceled', cb });
        }
        hide(cb) {
            this.bubbleIns && this.bubbleIns.hide(() => {
                super.listen({ name: 'hidden', cb });
            });
        }
        show(cb) {
            this.bubbleIns && this.bubbleIns.show(() => {
                super.listen({ name: 'shown', cb });
            });
        }
        async confirm(hide = this.options.confirmHide, cb) {
            if (this.destroyed)
                return;
            this.options.b4Confirm && await this.options.b4Confirm.call(this);
            let result = '';
            if (this.data.type !== 'daytime') {
                if (this.options.mode === 'range') {
                    if (this.data.selecteds.length === 0) {
                        result = '';
                    }
                    else if (this.data.selecteds.length === 2) {
                        let startStr = dateTools.fillFormat(this.data.selecteds[0], this.format, this.options.lang), endStr = dateTools.fillFormat(this.data.selecteds[1], this.format, this.options.lang);
                        result = `${startStr}${this.options.lang.range.hyphen}${endStr} `;
                    }
                    else {
                        new Message({
                            status: 'error',
                            iconShow: true,
                            content: this.options.lang.message.requireTwoValue,
                        }).show();
                        return false;
                    }
                }
                else {
                    result = this.data.selecteds.map((k) => dateTools.fillFormat(k, this.format, this.options.lang)).join(this.options.separator);
                    if (this.options.required && !result) {
                        new Message({
                            status: 'error',
                            iconShow: true,
                            content: this.options.lang.message.requireOneSelected,
                        }).show();
                        return false;
                    }
                }
            }
            else {
                result = this.data.daytime.map((k) => dateTools.fillFormat(k.value, this.format, this.options.lang)).join(this.separator);
            }
            await this.handleVal(result);
            if (hide && this.bubbleIns) {
                this.hide();
                let nextIns = this.options.next && instance.find(this.options.next, 'datetime');
                nextIns?.bubbleIns && nextIns.show();
            }
            super.listen({ name: 'confirmed', cb, params: [result] });
        }
        fillVals(value) {
            if (!this.inputEl || this.options.feature === 'static')
                return;
            let oldVal = this.inputEl.value;
            this.setValFromTgt(value);
            super.listen({ name: 'filled', params: [value] });
            this.output = { value, raw: oldVal, items: this.data.selecteds };
            super.listen({ name: 'output', params: [this.output] });
            super.updateCache({ content: value });
        }
        async handleVal(value) {
            if (this.options.b4Fill) {
                let resp = await this.options.b4Fill.call(this, value, this.separator);
                resp && (value = resp);
            }
            this.value = value;
            !this.options.manual && this.fillVals(value);
        }
        setNow(hide = this.options.nowHide) {
            if (this.destroyed)
                return;
            let date = dateTools.getDateObj(new Date(), this.data.type);
            if (this.data.type === 'daytime') {
                this.setDaytime(date);
            }
            else {
                this.timePanelsEl && this.options.mode !== 'range' && this.setDaytime(date);
                this.select(date);
            }
            if (hide) {
                this.confirm();
                this.hide();
            }
        }
        removeIns() {
            this.bubbleEl.remove();
            this.bubbleIns && (this.bubbleIns.destroy(), this.bubbleIns = null);
            this.detailIns && (this.detailIns.destroy(), this.detailIns = null);
            this.resultIns && (this.resultIns.destroy(), this.resultIns = null);
        }
        async update(settings, cb) {
            if (this.destroyed)
                return;
            this.removeIns();
            if (!isEmpty(settings)) {
                this.updateCache && this.updateCache(settings);
                extend({ target: this.options, source: settings });
                await this.init();
            }
            super.listen({ name: 'updated', cb, params: [this.options] });
            return this;
        }
        setVals2Objs(data) {
            let dataType = getDataType(data), arr = [];
            if (dataType === 'Array') {
                arr = data;
            }
            if (dataType === 'Date') {
                arr = [data];
            }
            else if (dataType === 'Object') {
                arr = [data];
            }
            else if (dataType === 'String') {
                let separator;
                if (data.includes(this.options.separator)) {
                    separator = this.options.separator;
                }
                else {
                    separator = this.separator;
                }
                arr = data.split(separator);
            }
            if (arr.length === 0) {
                return [];
            }
            else {
                return arr.map((k) => dateTools.getDateObj(k, this.data.type));
            }
        }
        getVals() {
            return { value: this.value, separator: this.separator };
        }
        async setVals(data, cb) {
            if (isEmpty(data) || this.destroyed)
                return;
            let objArr = this.setVals2Objs(data);
            if (objArr.length === 0)
                return;
            if (this.options.b4Set) {
                let resp = await this.options.b4Set.call(this, objArr);
                !isEmpty(resp) && (objArr = resp);
            }
            super.listen({ name: 'set', cb, params: [objArr] });
            if (this.options.mode === 'range') {
                if (objArr.length >= 2) {
                    objArr.splice(2, objArr.length - 2);
                    this.setRange(objArr);
                }
                else {
                    this.select(objArr[0]);
                }
                this.setDaytime(objArr, 0, true);
            }
            else {
                if (this.options.mode === 'single') {
                    this.select(objArr[0]);
                    this.setDaytime(objArr[0], 0, true);
                }
                else if (this.options.mode === 'multiple') {
                    objArr.forEach((k) => {
                        this.select(k);
                    });
                }
            }
            super.listen({ name: 'set', cb, params: [objArr] });
            return this;
        }
        setRange(data, cb) {
            if (isEmpty(data) || data.length !== 2 || this.destroyed)
                return;
            let objArr = data.map((k) => dateTools.getDateObj(k, this.data.type)), curGrids = this.getCurGrids();
            dateTools.sort(objArr);
            this.selecteds.splice(0, this.selecteds.length, ...objArr);
            if (!this.inCurPanels(objArr[0], curGrids) && !this.inCurPanels(objArr[1], curGrids)) {
                this.createPanels(objArr[0]);
            }
            else {
                this.setDaytime(objArr);
            }
            this.setRangeAttr();
            super.listen({ name: 'ranged', cb, params: [objArr] });
            return this;
        }
        
        async removeVals(data, cb) {
            if (isEmpty(data) || this.destroyed)
                return;
            let objArr = this.setVals2Objs(data);
            if (objArr.length === 0)
                return;
            this.options.b4Remove && await this.options.b4Remove.call(this, objArr);
            objArr.forEach((k) => {
                this.deselect(k);
            });
            super.listen({ name: 'removed', cb, params: [objArr] });
            return this;
        }
        async clear(resetTime = true, cb) {
            if (this.destroyed)
                return;
            this.options.b4Clear && await this.options.b4Clear.call(this);
            if (this.data.type !== 'daytime') {
                this.selecteds.splice(0);
                this.resultIns && this.resultIns.clear();
                let curGrids = this.getCurGrids();
                curGrids.forEach((k) => {
                    if (k.selected) {
                        this.selectedAttrToggle(k, false);
                    }
                    this.removeRangeAttr(k);
                });
            }
            if (resetTime && this.timePanelsEl) {
                for (let k in this.data.daytime) {
                    this.setDaytime({ hh: 0, mm: 0, ss: 0 }, k);
                }
            }
            super.listen({ name: 'cleared', cb, });
            return this;
        }
        async transfer(input, pos, cb) {
            if (this.destroyed)
                return;
            let tmpPos = getEl(pos), tmpInput = getEl(input);
            if (this.options.display === 'popup' && tmpPos) {
                this.positionEl = tmpPos;
                await this.bubbleIns.transfer(pos);
            }
            if (tmpInput) {
                this.inputEl = tmpInput;
                this.inputEl.readOnly = true;
                this.options.autoCorrect && this.checkB4Show();
            }
            super.listen({ name: 'transferred', cb, params: [tmpInput, tmpPos] });
        }
        disable() {
            if (this.destroyed)
                return;
            this.inputEl && this.inputEl.toggleAttribute('inert', true);
            this.bubbleEl.toggleAttribute('inert', true);
            super.listen({ name: 'disabled' });
        }
        enable() {
            if (this.destroyed)
                return;
            this.inputEl && this.inputEl.removeAttribute('inert');
            this.bubbleEl.removeAttribute('inert');
            super.listen({ name: 'enabled' });
        }
        
        destroy(cb) {
            if (this.destroyed)
                return;
            this.removeIns();
            this.confirmEl && (this.confirmEl.onclick = null);
            this.nowEl && (this.nowEl.onclick = null);
            this.clearEl && (this.clearEl.onclick = null);
            this.cancelEl && (this.cancelEl.onclick = null);
            this.closeEl && (this.closeEl.onclick = null);
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    let OCTMP_tipTpl = config.lang.rate.template.tooltip, OCTMP_resultTpl = config.lang.rate.template.result;
    const optRate = [
        {
            attr: 'name',
            prop: 'name',
            value: ''
        },
        {
            attr: 'value',
            prop: 'value',
            value: 0,
        },
        {
            attr: 'fill',
            prop: 'fill',
            value: 'value',
        },
        {
            attr: 'heading',
            prop: 'heading',
            value: ''
        },
        {
            attr: 'half',
            prop: 'half',
            value: false,
        },
        {
            attr: 'count',
            prop: 'count',
            value: 5,
        },
        {
            attr: 'increment',
            prop: 'increment',
            value: 1,
        },
        {
            attr: 'tooltip',
            prop: 'tooltip',
            value: {
                enable: false,
                format: OCTMP_tipTpl,
            },
        },
        {
            attr: 'result',
            prop: 'result',
            value: {
                enable: false,
                format: OCTMP_resultTpl,
            },
        },
        {
            attr: 'label',
            prop: 'label',
            value: {
                enable: false,
                format: '',
            },
        },
        {
            attr: 'clearable',
            prop: 'clearable',
            value: false,
        },
        {
            attr: 'size',
            prop: 'size',
            value: 'md',
        },
        {
            attr: 'star',
            prop: 'star',
            value: `${orca.prefix}icon-star-f`,
        },
        {
            attr: 'type',
            prop: 'type',
            value: 'icon',
        },
        {
            attr: 'map',
            prop: 'map',
            value: [],
        },
        {
            attr: 'highlight',
            prop: 'highlight',
            value: false,
        },
        {
            attr: 'omitted',
            prop: 'omitted',
            value: false,
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'disabled',
            prop: 'disabled',
            value: false,
        },
        {
            attr: 'readonly',
            prop: 'readonly',
            value: false,
        },
        {
            attr: 'on-set',
            prop: 'onSet',
            value: null,
        },
        {
            attr: 'on-changed',
            prop: 'onChanged',
            value: null,
        },
        {
            attr: 'on-restored',
            prop: 'onRestored',
            value: null,
        },
        {
            attr: 'on-cleared',
            prop: 'onCleared',
            value: null,
        },
        ...optBase
    ];

    class Rate extends ModBaseListenCache {
        options = {};
        inputEl;
        current;
        evtMap;
        useMap;
        outputIns;
        output;
        rawVal;
        wrapEl;
        tooltipIns;
        tooltipEl;
        clearEl;
        items;
        legends;
        headEl;
        resultEl;
        static hostType = 'node';
        static optMaps = optRate;
        constructor(elem, options = {}, initial = true) {
            super();
            let tmp = getEl(elem), host;
            if (!tmp)
                return this;
            if (tmp.nodeName === 'INPUT') {
                this.inputEl = tmp;
                this.inputEl.type = 'range';
                host = createEl('div', { class: `${orca.prefix}rate` });
                tmp.insertAdjacentElement('beforebegin', host);
            }
            else {
                host = tmp;
                host.classList.add(`${orca.prefix}rate`);
                this.inputEl = createEl('input', { type: 'range' });
            }
            super.ready({
                options,
                maps: Rate.optMaps,
                host,
                component: true,
                spread: ['tooltip', 'result', 'lable']
            });
            this.current = { place: 'full', legend: null, value: 0, stars: 0 };
            this.evtMap = orca.isTouchScr ? { move: 'ontouchmove', end: 'ontouchend' } : { move: 'onmousemove', end: 'onmouseleave' };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            this.useMap = !isEmpty(this.options.map) && Array.isArray(this.options.map);
            this.options.count = this.useMap ? this.options.map.length : ~~this.options.count;
            this.createOutputIns();
            this.legends = [];
            this.renderMain();
            this.renderFormat();
            this.getDirRtl();
            this.setAttrs();
            this.options.value = parseFloat(this.options.value || this.rawHtml || this.inputEl.value);
            this.rawVal = this.options.value;
            this.setVals(this.options.value);
            this.createTooltip();
            this.renderFinish();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        createOutputIns() {
            this.outputIns = new Observe({ stars: 0, value: 0, title: this.options.lang.title.dft, count: this.options.count, total: this.options.count * this.options.increment }, {
                onSet: (data) => {
                    if (data.key === 'value') {
                        let oldVal = parseFloat(this.inputEl.value), newVal = this.output[this.options.fill || 'value'];
                        this.inputEl.value = newVal;
                        oldVal !== newVal && super.listen({ name: 'changed', params: [newVal, oldVal] });
                    }
                },
                onCompleted: () => {
                    this.renderFormat();
                }
            });
            this.output = this.outputIns.proxy;
        }
        renderFinish() {
            if (this.options.readonly || this.options.disabled)
                return;
            this.wrapEl[this.evtMap.move] = (e) => {
                let legend = this.findLegend(e);
                if (!legend)
                    return;
                let place = this.getStarPoint(e, legend), { stars, value } = this.updateStarsState({ legend, place });
                if (this.tooltipIns) {
                    this.tooltipIns.transfer(legend, () => this.tooltipIns.show());
                    this.renderFormat('tooltip', { ...this.output, stars, value });
                }
                this.current = { place, legend, stars, value };
            };
            this.wrapEl.onclick = (e) => {
                let legend = this.findLegend(e);
                if (!legend)
                    return;
                this.setVals({ legend, place: this.getStarPoint(e, legend) });
            };
            this.wrapEl[this.evtMap.end] = (e) => {
                this.tooltipIns && this.tooltipIns.hide();
                if (orca.isTouchScr) {
                    this.setVals(this.current);
                }
                else {
                    this.updateStarsState(this.output.value);
                }
            };
            this.clearEl.onclick = () => {
                this.clear();
            };
        }
        renderFormat(type, data = { ...this.output }) {
            let el = type === 'result' ? this.resultEl : type === 'tooltip' ? this.tooltipEl : null;
            if (el) {
                this.options[type].enable && (el.innerHTML = renderTpl(this.options[type].format, data));
            }
            else {
                this.options.result.enable && (this.resultEl.innerHTML = renderTpl(this.options.result.format, data));
                this.options.tooltip.enable && (this.tooltipEl.innerHTML = renderTpl(this.options.tooltip.format, data));
            }
        }
        findLegend(e) {
            return this.legends.find((k) => contains(getEvtTarget(e), k));
        }
        getStarPoint(e, node) {
            if (!this.options.half)
                return 'full';
            let tmp = getRectPoints(e, node), dir = this.isRtl ? 'r' : 'l';
            return tmp.length <= 1 ? '' : tmp.includes(`${dir}/3`) || tmp.includes(`${dir}/2`) ? 'half' : 'full';
        }
        createTooltip() {
            if (!this.options.tooltip.enable)
                return;
            this.tooltipIns = new Tooltip(this.wrapEl, extend({
                target: {
                    content: this.tooltipEl,
                    size: '',
                    theme: 'text-lt',
                    keepShow: true,
                },
                source: this.options.tooltip,
            }));
        }
        getStarsHtml() {
            let getStar = (val) => this.options.type === 'image' ? `<i><img src="${val}"/></i>` : `<i class="${val}"></i>`, result = '', tpl = '', data, getHtml = (cont) => this.options.label.enable ? `<span ${orca.alias}="label">${cont}</span>` : '';
            if (this.useMap) {
                for (let [i, k] of this.options.map.entries()) {
                    data = { id: i + 1, title: k.title, count: this.options.map.length };
                    tpl = this.options.label.format ? renderTpl(this.options.label.format, data) : data.title;
                    result += `<li ${k.title ? 'title="' + k.title + '"' : ''}>
                <span ${orca.alias}="legend">${getStar(k.on)}${getStar(k.off || k.on)}</span>
                ${getHtml(tpl)}
                </li>`;
                }
            }
            else {
                for (let i = 0; i < this.options.count; i++) {
                    data = { id: i + 1, title: '', count: this.options.count };
                    tpl = this.options.label.format ? renderTpl(this.options.label.format, data) : data.id + this.options.lang.star;
                    result += `<li>
                <span ${orca.alias}="legend">${getStar(this.options.star).repeat(2)}</span>
                ${getHtml(tpl)}
                </li>`;
                }
            }
            return result;
        }
        renderMain() {
            this.targetEl.innerHTML = '';
            let fragment = document.createDocumentFragment();
            fragment.appendChild(this.inputEl);
            this.wrapEl = createEl('ul', { class: `${orca.prefix}reset` }, this.getStarsHtml());
            this.resultEl = createEl('div', { [orca.alias]: 'result' });
            this.tooltipEl = createEl('div', { [orca.alias]: 'tooltip' });
            this.clearEl = createEl('i', { class: `${orca.prefix}icon-close-o-f`, [orca.alias]: 'clear', title: this.options.lang.title.clear });
            this.items = [...this.wrapEl.children];
            this.legends = this.items.map((k) => getEl(`[${orca.alias}="legend"]`, k));
            this.headEl = createEl('i', { [orca.alias]: 'head' }, this.options.heading);
            this.options.heading && fragment.appendChild(this.headEl);
            this.options.clearable && fragment.appendChild(this.clearEl);
            fragment.appendChild(this.wrapEl);
            this.options.result.enable && fragment.appendChild(this.resultEl);
            this.targetEl.appendChild(fragment);
            super.listen({ name: 'rendered', params: [{ targetEl: this.targetEl, headEl: this.headEl, wrapEl: this.wrapEl, resultEl: this.resultEl, clearEl: this.clearEl, items: this.items, legends: this.legends }] });
        }
        setAttrs() {
            this.options.size ? this.targetEl.setAttribute('size', this.options.size) : this.targetEl.removeAttribute('size');
            this.options.classes && classes(this.targetEl).add(this.options.classes);
            this.targetEl.setAttribute('type', this.options.type);
            this.targetEl.toggleAttribute('disabled', this.options.disabled);
            this.targetEl.toggleAttribute('readonly', this.options.readonly);
            this.targetEl.toggleAttribute('omitted', this.options.omitted);
            this.inputEl.step = (this.options.half ? 0.5 : 1) * (this.options.fill === 'value' ? this.options.increment : 1);
            this.inputEl.max = this.options.count * (this.options.fill === 'value' ? this.options.increment : 1);
            this.inputEl.min = 0;
            this.inputEl.disabled = true;
            this.inputEl.name = this.options.name;
            !this.inputEl.hasAttribute('value') && (this.inputEl.value = 0);
            this.options.rtl ? this.targetEl.setAttribute('dir', 'rtl') : this.targetEl.removeAttribute('dir');
        }
        getVals() {
            return { ...this.output };
        }
        correctVal(val) {
            let valType = getDataType(val), value = 0;
            if (valType === 'Object') {
                let idx = this.legends.findIndex((k) => k === val.legend);
                if (idx === -1) {
                    value = 0;
                }
                else {
                    let tmp = val.place === 'half' ? 0.5 : val.place === 'full' ? 1 : 0;
                    value = (idx + tmp) * this.options.increment;
                }
            }
            else {
                let tmp = clampVal({ min: 0, max: this.options.increment * this.options.count, val: parseFloat(val) }), stars = tmp / this.options.increment, integer = Math.floor(stars), float = stars - integer, rest = this.getFloatStar(float);
                value = (integer + rest) * this.options.increment;
            }
            return value;
        }
        getFloatStar(float) {
            if (this.options.half) {
                return !float ? 0 : float > 0 && float <= 0.5 ? 0.5 : 1;
            }
            else {
                return !float ? 0 : 1;
            }
        }
        toggleSelected(li) {
            let other = [...this.wrapEl.children].find((k) => k !== li && k.hasAttribute('selected'));
            other && other.toggleAttribute('selected', false);
            li.toggleAttribute('selected', true);
        }
        updateStarsState(val = 0) {
            let value = this.correctVal(val), stars = value / this.options.increment, b4Stars = Math.floor(stars), curStar = stars - b4Stars, item, map = [`${orca.prefix}half`, `${orca.prefix}full`];
            curStar = this.getFloatStar(curStar);
            for (let i = 0; i < this.legends.length; i++) {
                let el = this.legends[i].firstElementChild, li = el.closest('li');
                if (!value) {
                    classes(el).remove(map.join());
                }
                else {
                    if (i < b4Stars) {
                        if (this.options.highlight) {
                            
                            if (!curStar && i === b4Stars - 1) {
                                classes(el).replace(...map);
                                this.toggleSelected(li);
                                item = li;
                            }
                            else {
                                classes(el).remove(map.join());
                            }
                        }
                        else {
                            classes(el).replace(...map);
                            if (!curStar && i === b4Stars - 1) {
                                this.toggleSelected(li);
                                item = li;
                            }
                        }
                    }
                    else if (i === b4Stars) {
                        if (curStar === 0) {
                            classes(el).remove(map.join());
                        }
                        else {
                            if (curStar === 0.5) {
                                classes(el).replace(...[...map].reverse());
                            }
                            else {
                                classes(el).replace(...map);
                            }
                            this.toggleSelected(li);
                            item = li;
                        }
                    }
                    else {
                        classes(el).remove(map.join());
                    }
                }
            }
            return { stars: b4Stars + curStar, value, item };
        }
        setVals(val, cb) {
            let { stars, value, item } = this.updateStarsState(val);
            if (value === this.output.value)
                return;
            this.output.stars = stars;
            this.output.value = value;
            this.output.item = item;
            this.useMap && (this.output.title = this.options.map[Math.ceil(stars) - 1].title);
            super.updateCache({ value });
            super.listen({ name: 'set', cb, params: [{ ...this.output }] });
        }
        restore(cb) {
            if (this.destroyed)
                return this;
            this.setVals(this.rawVal);
            super.listen({ name: 'restored', cb, params: [this.rawVal] });
            return this;
        }
        clear(cb) {
            if (this.destroyed)
                return this;
            this.setVals(0);
            super.listen({ name: 'cleared', cb });
            return this;
        }
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.wrapEl[this.evtMap.move] = null;
            this.wrapEl.onclick = null;
            this.wrapEl[this.evtMap.end] = null;
            this.clearEl.onclick = null;
            this.tooltipIns && this.tooltipIns.destroy();
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    let OCTMP_separator$1 = config.splitHyphen;
    const optAccordion = [
        {
            attr: 'name',
            prop: 'name',
            value: '',
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'passive',
            prop: 'passive',
            value: false,
        },
        {
            attr: 'disable',
            prop: 'disable',
            value: '',
        },
        {
            attr: 'readonly',
            prop: 'readonly',
            value: '',
        },
        {
            attr: 'expand',
            prop: 'expand',
            value: {
                value: '',
                all: false,
                only: true,
                linkage: false,
            },
        },
        {
            attr: 'arrow',
            prop: 'arrow',
            value: {
                enable: true,
                show: `${orca.prefix}icon-down`,
                hide: `${orca.prefix}icon-down`,
                anim: `${orca.prefix}rotate180`,
                type: 'icon',
                trigger: 'click',
            },
        },
        {
            attr: 'check',
            prop: 'check',
            value: {
                enable: false,
                type: 'checkbox',
                value: '',
            },
        },
        {
            attr: 'tools',
            prop: 'tools',
            value: {
                enable: false,
                trigger: 'hover',
                children: ['add', 'edit', 'remove'],
            },
        },
        {
            attr: 'output',
            prop: 'output',
            value: {
                enable: true,
                target: '',
                separator: OCTMP_separator$1,
                prop: 'label',
            },
        },
        {
            attr: 'click-line',
            prop: 'clickLine',
            value: 'none',
        },
        {
            attr: 'deferred',
            prop: 'deferred',
            value: false,
        },
        {
            attr: 'delay',
            prop: 'delay',
            value: 100,
        },
        {
            attr: 'drag',
            prop: 'drag',
            value: {
                enable: false,
                exclude: '',
            },
        },
        {
            attr: 'drop',
            prop: 'drop',
            value: {
                attr: 'dropnode',
                global: false,
            },
        },
        {
            attr: 'lamp',
            prop: 'lamp',
            value: {
                enable: false,
                placement: 'bottom',
            },
        },
        {
            attr: 'duration',
            prop: 'duration',
            value: 0,
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'layout',
            prop: 'layout',
            value: 'check(icon|disk|cube|label|tips)custom|tools|badge|arrow',
        },
        {
            attr: 'appear',
            prop: 'appear',
            value: {
                rounded: true,
                bordered: true,
                divided: true,
                gapped: false,
            },
        },
        {
            attr: 'b4-expand',
            prop: 'b4Expand',
            value: null,
        },
        {
            attr: 'b4-collapse',
            prop: 'b4Collapse',
            value: null,
        },
        {
            attr: 'b4-add',
            prop: 'b4Add',
            value: null,
        },
        {
            attr: 'b4-edit',
            prop: 'b4Edit',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'b4-graft',
            prop: 'b4Graft',
            value: null,
        },
        {
            attr: 'on-rendered',
            prop: 'onRendered',
            value: null,
        },
        {
            attr: 'on-trigger',
            prop: 'onTrigger',
            value: null
        },
        {
            attr: 'on-added',
            prop: 'onAdded',
            value: null
        },
        {
            attr: 'on-edited',
            prop: 'onEdited',
            value: null
        },
        {
            attr: 'on-removed',
            prop: 'onRemoved',
            value: null
        },
        {
            attr: 'on-disabled',
            prop: 'onDisabled',
            value: null
        },
        {
            attr: 'on-enabled',
            prop: 'onEnabled',
            value: null
        },
        {
            attr: 'on-disabledall',
            prop: 'onDisabledAll',
            value: null
        },
        {
            attr: 'on-enabledall',
            prop: 'onEnabledAll',
            value: null
        },
        {
            attr: 'on-readonly',
            prop: 'onReadonly',
            value: null
        },
        {
            attr: 'on-readonlyall',
            prop: 'onReadonlyAll',
            value: null
        },
        {
            attr: 'on-expand',
            prop: 'onExpand',
            value: null
        },
        {
            attr: 'on-expanded',
            prop: 'onExpanded',
            value: null
        },
        {
            attr: 'on-collapse',
            prop: 'onCollapse',
            value: null
        },
        {
            attr: 'on-collapsed',
            prop: 'onCollapsed',
            value: null
        },
        {
            attr: 'on-expandall',
            prop: 'onExpandAll',
            value: null
        },
        {
            attr: 'on-expandedAll',
            prop: 'onExpandedAll',
            value: null
        },
        {
            attr: 'on-collapsedall',
            prop: 'onCollapsedAll',
            value: null
        },
        {
            attr: 'on-selected',
            prop: 'onSelected',
            value: null
        },
        {
            attr: 'on-deselected',
            prop: 'onDeselected',
            value: null
        },
        {
            attr: 'on-selectedall',
            prop: 'onSelectedAll',
            value: null
        },
        {
            attr: 'on-checked',
            prop: 'onChecked',
            value: null
        },
        {
            attr: 'on-unchecked',
            prop: 'onUnchecked',
            value: null
        },
        {
            attr: 'on-checkedall',
            prop: 'onCheckedAll',
            value: null
        },
        {
            attr: 'on-filled',
            prop: 'onFilled',
            value: null
        },
        {
            attr: 'on-turned',
            prop: 'onTurned',
            value: null
        },
        {
            attr: 'on-got',
            prop: 'onGot',
            value: null
        },
        {
            attr: 'on-set',
            prop: 'onSet',
            value: null
        },
        {
            attr: 'on-cleared',
            prop: 'onCleared',
            value: null
        },
        {
            attr: 'on-grafted',
            prop: 'onGrafted',
            value: null
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null
        },
        {
            attr: 'on-request',
            prop: 'onRequest',
            value: null
        },
        {
            attr: 'on-toofew',
            prop: 'onTooFew',
            value: null
        },
        {
            attr: 'on-toomany',
            prop: 'onTooMany',
            value: null
        },
        {
            attr: 'on-locked',
            prop: 'onLocked',
            value: null
        },
        {
            attr: 'on-unlocked',
            prop: 'onUnlocked',
            value: null
        },
        ...optBase
    ];

    class Accordion extends ModBaseListenCacheNest {
        expandEvt;
        lineEvt;
        treeDataOrig;
        receiver;
        rawData;
        observeIns;
        chainChecking;
        hoverIns;
        inputEl;
        value;
        contXhr;
        static hostType = 'node';
        static optMaps = optAccordion;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Accordion.optMaps,
                component: true,
                spread: ['output', 'arrow', 'check', 'lamp', 'tools', 'drag']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            
            let _this = this;
            this.expandEvt = debounce(function () {
                let attr = this.getAttribute(orca.alias) === 'arrow' ? 'arrowEl' : 'headEl', item = findItem(this, _this.flatData, attr);
                _this.toggleExpanded(item);
            }, this.options.delay);
            this.lineEvt = debounce(function (e) {
                let item = findItem(this, _this.flatData, 'headEl');
                if (!item)
                    return;
                if ((['group', 'gap', 'holder'].includes(e.target.getAttribute(orca.alias)) || e.target === item.headEl)) {
                    if (_this.options.clickLine === 'expanded') {
                        _this.toggleExpanded(item);
                    }
                    else if (_this.options.clickLine === 'checked') {
                        _this.toggleCheck(item);
                    }
                }
            }, this.options.delay);
            this.treeDataOrig = [];
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch (err) {
                err ? console.error(err) : console.warn(config.warn.init);
                return this;
            }
            this.receiver = getEl(this.options.output.target);
            super.useTpl();
            await this.getDataToRender();
            this.setAttrs();
            this.renderFinish();
            super.initCheckeds();
            this.initExpandeds();
            super.initDisableds();
            super.initReadonlys();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        async getDataToRender() {
            let base = {
                nodeType: 'accordion',
            }, promise;
            if (this.options.content) {
                promise = treeTools.allToTree({
                    content: this.options.content,
                    contType: this.options.contType,
                    contData: this.options.contData,
                    ajax: { spinSel: this.targetEl, xhrName: 'contXhr' },
                    ins: this,
                    ...base
                });
            }
            else {
                promise = treeTools.allToTree({
                    content: this.targetEl.innerHTML,
                    ...base
                });
            }
            await promise.then((res) => {
                
                this.treeDataOrig = res.data && Array.isArray(res.data) ? res.data : res;
                this.rawData = res;
            });
            this.targetEl.innerHTML = '';
            this.renderData(this.treeDataOrig);
            this.getTreeFlat();
            super.listen({ name: 'rendered', params: [this.treeData, this.flatData] });
            return this;
        }
        getTreeFlat() {
            this.treeData = this.getObserver(this.treeDataOrig).proxy;
            this.flatData = this.treeData;
        }
        getObserver(data) {
            this.observeIns = new Observe(data, {
                deep: {
                    enable: true,
                    exclude: ['tools'],
                },
                onSet: (obj) => {
                    if (obj.key === 'icon' && obj.proxy.iconEl) {
                        classes(obj.proxy.iconEl).replace(obj.raw, obj.value);
                    }
                    else if (obj.key === 'cube' && obj.proxy.cubeEl) {
                        obj.proxy.cubeEl.src = obj.value;
                    }
                    else if (obj.key === 'disk' && obj.proxy.diskEl) {
                        obj.proxy.diskEl.src = obj.value;
                    }
                    else if (obj.key === 'label') {
                        obj.proxy.labelEl.innerHTML = obj.value;
                    }
                    else if (obj.key === 'tips' && obj.proxy.tipsEl) {
                        obj.proxy.tipsEl.innerHTML = obj.value;
                    }
                    else if (obj.key === 'content') {
                        super.updateElCont(obj.proxy, obj.value, 'content');
                    }
                    else if (obj.key === 'extra') {
                        super.updateElCont(obj.proxy, obj.value, 'extra');
                    }
                    else if (obj.key === 'custom' && obj.proxy.customEl) {
                        super.updateElCont(obj.proxy, obj.value, 'custom');
                    }
                    else if (obj.key === 'badge' && obj.proxy.badgeEl) {
                        obj.proxy.badgeEl.setAttribute('label', obj.value);
                    }
                    else if (obj.key === 'href' && obj.proxy.labelEl.nodeName === 'A') {
                        obj.proxy.labelEl.href = obj.value;
                    }
                    else if (obj.key === 'rel' && obj.proxy.labelEl.nodeName === 'A') {
                        obj.proxy.labelEl.rel = obj.value;
                    }
                    else if (obj.key === 'target' && obj.proxy.labelEl.nodeName === 'A') {
                        obj.proxy.labelEl.target = obj.value;
                    }
                    else if (obj.key === 'expanded') {
                        super.toggleArrow(obj.value, obj.proxy);
                    }
                    else if (obj.key === 'disabled') {
                        obj.proxy.wrapEl.toggleAttribute('disabled', obj.value);
                    }
                    else if (obj.key === 'readonly') {
                        obj.proxy.headEl.toggleAttribute('readonly', obj.value);
                    }
                    else if (obj.key === 'checked') {
                        obj.proxy.headEl.toggleAttribute('checked', obj.value);
                        obj.proxy.checkEl.setAttribute('check', obj.value ? 'ed' : '');
                    }
                    else if (obj.key === 'children') {
                        if (!obj.raw && obj.value) ;
                        else if (obj.raw && !obj.value) ;
                    }
                },
                onDeleted: (obj) => {
                    if (obj.key === 'children') {
                        treeTools.parentToChild(obj.proxy);
                    }
                },
                onCompleted: (data) => {
                    data.keys.set.includes('checked') && this.updateVals();
                    if (this.options.storName) {
                        let tmp = {
                            check: { value: treeTools.getBoolItems(this.flatData, 'checked').map((k) => k.id) },
                            expand: treeTools.getBoolItems(this.flatData, 'expanded').map((k) => k.id),
                            disable: treeTools.getBoolItems(this.flatData, 'disabled').map((k) => k.id),
                            readonly: treeTools.getBoolItems(this.flatData, 'readonly').map((k) => k.id),
                            content: !isEmpty(this.options.content) ? deepClone(this.treeDataOrig) : '',
                        };
                        super.updateCache(tmp);
                    }
                }
            });
            return this.observeIns;
        }
        initExpandeds() {
            let vals = valToArr(this.options.expand.value).map((k) => findItem(k, this.flatData)).filter(Boolean), items = this.flatData.filter((k) => k.expanded), tmp = [...items, ...vals];
            for (let k of items)
                k.expanded = false;
            if (this.options.expand.all) {
                this.expandAll();
            }
            else {
                super.expand(tmp);
            }
        }
        renderData(data) {
            for (let k of data) {
                this.createHeadEl(k);
                this.createBodyEl(k);
                k.wrapEl.append(k.headEl, k.bodyEl);
                this.targetEl.appendChild(k.wrapEl);
            }
            this.inputEl = createEl('input', { type: 'hidden', name: this.options.name });
            this.options.name && this.targetEl.insertAdjacentElement('afterbegin', this.inputEl);
        }
        updateArrowEl(item) {
            if (!item.arrowEl)
                return;
            item.arrowEl.setAttribute('type', this.options.arrow.type);
            this.options.lang.title.arrow && item.arrowEl.setAttribute('title', this.options.lang.title.arrow);
            if (this.options.arrow.type === 'image') {
                this.options.arrow.hide && (item.arrowEl.style.backgroundImage = `url("${this.options.arrow.hide}")`);
            }
            else {
                item.arrowEl.classList.remove(`${orca.prefix}none`);
                this.options.arrow.hide && item.arrowEl.classList.add(this.options.arrow.hide);
            }
        }
        
        createHeadEl(item) {
            if (item.wrapEl)
                return;
            item.wrapEl = createEl('section', { class: `${orca.prefix}accordion-wrap` });
            if (item.headEl) {
                if (!item.labelEl) {
                    item.labelEl = createEl(item.hasOwnProperty('href') ? 'a' : 'i', { [orca.alias]: 'label' }, item.label);
                    item.headEl.appendChild(item.labelEl);
                }
            }
            else {
                item.headEl = createEl('div', { class: `${orca.prefix}accordion-head` });
                !item.labelEl && (item.labelEl = createEl(item.hasOwnProperty('href') ? 'a' : 'i', { [orca.alias]: 'label' }, item.label));
                item.headEl.appendChild(item.labelEl);
            }
            item.wrapEl.appendChild(item.headEl);
            item.href && (item.labelEl.href = item.href);
            item.target && (item.labelEl.target = item.target);
            item.groupEl = createEl('div', { [orca.alias]: 'group' });
            super.getArrowEl(item);
            if (!item.iconEl) {
                item.iconEl = item.hasOwnProperty('icon') ? createEl('i', { [orca.alias]: 'icon', class: item.icon }) : null;
            }
            if (!item.diskEl) {
                item.diskEl = item.hasOwnProperty('disk') ? createEl('img', { [orca.alias]: 'disk', src: item.disk || orca.images.none }) : null;
            }
            if (!item.cubeEl) {
                item.cubeEl = item.hasOwnProperty('cube') ? createEl('img', { [orca.alias]: 'cube', src: item.cube || orca.images.none }) : null;
            }
            if (!item.imageEl) {
                item.imageEl = item.hasOwnProperty('image') ? createEl('img', { [orca.alias]: 'image', src: item.image || orca.images.none }) : null;
            }
            if (!item.badgeEl) {
                item.badgeEl = item.badge ? createEl('oc-badge', { [orca.alias]: 'badge', label: item.badge.toString().trim() }) : null;
            }
            if (!item.tipsEl) {
                item.tipsEl = item.tips ? createEl('i', { [orca.alias]: 'tips' }, item.tips) : null;
            }
            if (!item.customEl) {
                item.customEl = item.custom ? createEl('div', { [orca.alias]: 'custom' }, item.custom) : null;
            }
            item.expanded && item.headEl.toggleAttribute('expanded', true);
            item.disabled && item.headEl.toggleAttribute('disabled', true);
            item.readonly && item.headEl.toggleAttribute('readonly', true);
            item.checked && item.headEl.toggleAttribute('checked', true);
            if (this.options.check.enable) {
                item.checkEl = createEl(`oc-${this.options.check.type}`, { [orca.alias]: 'check' });
            }
            if (this.options.tools.enable) {
                item.toolsEl = createTools(this.options.tools.children, item.headEl);
                item.toolsEl.setAttribute(orca.alias, 'tools');
                item.tools = deepClone(this.options.tools.children);
                for (let k of item.tools) {
                    this.options.lang.title[k.name] && k.wrapEl.setAttribute('title', this.options.lang.title[k.name]);
                    if (k.name === 'add') {
                        item.addEl = k.wrapEl;
                    }
                    else if (k.name === 'remove') {
                        item.removeEl = k.wrapEl;
                    }
                    else if (k.name === 'edit') {
                        item.editEl = k.wrapEl;
                    }
                }
            }
            super.parseLayout(item.headEl, this.options.layout, {
                arrow: item.arrowEl,
                label: item.labelEl,
                check: item.checkEl,
                icon: item.iconEl,
                disk: item.diskEl,
                cube: item.cubeEl,
                badge: item.badgeEl,
                tips: item.tipsEl,
                custom: item.customEl,
                tools: item.toolsEl,
                group: item.groupEl
            });
        }
        createBodyEl(item) {
            item.bodyEl = createEl('div', { class: `${orca.prefix}accordion-body` });
            !item.contEl && (item.contEl = createEl('div', { class: `${orca.prefix}accordion-cont` }));
            item.bodyEl.appendChild(item.contEl);
            if (!item.extraEl && item.hasOwnProperty('extra')) {
                item.extraEl = createEl('div', { class: `${orca.prefix}accordion-extra` });
            }
            item.extraEl && item.bodyEl.appendChild(item.extraEl);
            !this.options.deferred && this.setContExtra(item, true);
            item.headEl.insertAdjacentElement('afterend', item.bodyEl);
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}accordion`);
            this.options.classes && classes(this.targetEl).add(this.options.classes);
            this.targetEl.toggleAttribute('inert', this.options.passive);
            this.targetEl.setAttribute('tools-trigger', this.options.tools.trigger);
            this.options.lamp.enable ? this.targetEl.setAttribute('lamp', this.options.lamp.placement) : this.targetEl.removeAttribute('lamp');
            for (let k in this.options.appear) {
                let val = this.options.appear[k];
                this.targetEl.toggleAttribute(k, val);
            }
        }
        updateExpandEvt(k) {
            if (!this.options.arrow.enable)
                return;
            if (this.options.arrow.trigger === 'click') {
                k.arrowEl.removeEventListener('click', this.expandEvt);
                k.arrowEl.addEventListener('click', this.expandEvt, false);
            }
            else if (this.options.arrow.trigger === 'hover') {
                k.hoverIns && k.hoverIns.destroy();
                k.hoverIns = new Hover(k.arrowEl, {
                    onMove: (isIn) => {
                        !isIn && this.options.expand.only ? super.collapse(k) : null;
                    },
                    onEnter: () => {
                        super.expand(k);
                    },
                    onLeave: () => {
                        super.collapse(k);
                    }
                });
            }
        }
        updateEvt(k) {
            this.updateExpandEvt(k);
            if (k.toolsEl) {
                if (k.removeEl) {
                    k.removeEl.onclick = () => {
                        if (k.readonly)
                            return;
                        this.remove(k);
                    };
                }
                if (k.editEl) {
                    k.editEl.onclick = () => {
                        if (k.readonly)
                            return;
                        this.inputLabelCont(k);
                    };
                }
                if (k.addEl) {
                    k.addEl.onclick = () => {
                        if (k.readonly)
                            return;
                        this.add({ target: k });
                    };
                }
                for (let [i, o] of this.options.tools.children.entries()) {
                    let tool = k.tools[i], refer = { ins: this, item: k };
                    o.action && o.action.call(refer, tool);
                    tool.action && tool.action.call(refer, tool);
                }
            }
            if (['expanded', 'checked'].includes(this.options.clickLine)) {
                k.headEl.removeEventListener('click', this.lineEvt);
                k.headEl.addEventListener('click', this.lineEvt, false);
            }
            k.disabled && k.headEl.toggleAttribute('disabled', true);
            k.readonly && k.headEl.toggleAttribute('readonly', true);
            if (this.options.check.enable) {
                k.checkEl.on('check', (val) => {
                    !this.chainChecking && val.checked !== k.checked && this.check(k, val.checked);
                });
            }
            if (this.options.drag.enable) ;
            k.action && k.action.call(this, k);
        }
        renderFinish() {
            for (let k of this.flatData) {
                this.updateEvt(k);
            }
        }
        getTriggerEl(item) {
            return (item.href && item.arrowEl ? item.arrowEl : item.headEl);
        }
        addTrigger(item, target) {
            if (item.disabled)
                return;
            let triggerEl = target || this.getTriggerEl(item);
            if (this.options.arrow.trigger === 'click') {
                triggerEl.removeEventListener('click', this.expandEvt);
                triggerEl.addEventListener('click', this.expandEvt, false);
            }
            else if (this.options.arrow.trigger === 'hover') {
                this.hoverIns ? this.hoverIns.destroy() : null;
                this.hoverIns = new Hover(item.wrapEl, {
                    onEnter: () => {
                        super.expand(item);
                        super.listen({ name: 'trigger', params: [item] });
                    },
                    onLeave: () => {
                        super.collapse(item);
                    }
                });
            }
        }
        removeTrigger(item, target) {
            if (item.disabled)
                return;
            let triggerEl = target || this.getTriggerEl(item);
            if (this.options.arrow.trigger === 'click') {
                triggerEl.removeEventListener('click', this.expandEvt);
            }
            else if (this.options.arrow.trigger === 'hover') {
                this.hoverIns ? this.hoverIns.destroy() : null;
            }
        }
        toggleExpanded(data) {
            if (this.destroyed)
                return;
            let item = findItem(data, this.flatData);
            if (!item)
                return;
            item.expanded ? super.collapse(item) : super.expand(item);
            super.listen({ name: 'trigger', params: [item] });
        }
        async setContExtra(item, force = false) {
            await super.getElCont({
                target: item,
                data: item.content,
                prop: 'content',
                cb: (cont) => {
                    if (cont !== item.content) {
                        item.content = cont;
                        force && super.updateElCont(item, cont, 'content');
                    }
                    else {
                        super.updateElCont(item, cont, 'content');
                    }
                }
            });
            if (item.extraEl) {
                await super.getElCont({
                    target: item,
                    data: item.extra,
                    prop: 'extra',
                    cb: (cont) => {
                        if (cont !== item.extra) {
                            item.extra = cont;
                            force && super.updateElCont(item, cont, 'extra');
                        }
                        else {
                            super.updateElCont(item, cont, 'extra');
                        }
                    }
                });
            }
        }
        async eachCollapse(data, cb) {
            if (isNull(data))
                return;
            try {
                if (this.options.b4Collapse) {
                    let resp = await this.options.b4Collapse.call(this, data);
                    resp && (data = resp);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('Branch collapsing has been prevented!');
                return;
            }
            let item = findItem(data, this.flatData);
            if (!item)
                return;
            super.listen({ name: 'collapse', cb, params: [item] });
            item.expanded = false;
            slideUp({
                el: item.bodyEl,
                duration: this.options.duration,
                done: () => {
                    super.listen({ name: 'collapsed', cb, params: [item] });
                }
            });
        }
        async eachExpand(data, cb) {
            if (isNull(data))
                return;
            try {
                if (this.options.b4Expand) {
                    let resp = await this.options.b4Expand.call(this, data);
                    resp && (data = resp);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('Branch expansion has been prevented!');
                return;
            }
            let item = findItem(data, this.flatData);
            if (!item)
                return;
            super.listen({ name: 'expand', cb, params: [item] });
            if (this.options.deferred && !item.contEl.innerHTML) {
                item.arrowEl && item.arrowEl.toggleAttribute('spinning', true);
                await this.setContExtra(item);
                item.arrowEl && item.arrowEl.removeAttribute('spinning');
            }
            item.expanded = true;
            slideDown({
                el: item.bodyEl,
                duration: this.options.duration,
                done: () => {
                    super.listen({ name: 'expanded', cb, params: [item] });
                }
            });
            if (this.options.expand.only) {
                let others = this.flatData.filter((k) => k !== item && k.expanded);
                for (let k of others)
                    super.collapse(k);
            }
        }
        uncheckSibings(item) {
            this.chainChecking = true;
            let siblings = super.getSiblings(item).filter((k) => k.checked);
            for (let k of siblings)
                k.checked = false;
            this.chainChecking = false;
        }
        check(data, flag = true, cb) {
            if (this.destroyed)
                return;
            let tmp = Array.isArray(data) ? data : [data], filters = tmp.map((k) => findItem(k, this.flatData)), items = filters.filter((k) => k && !k.checked === flag), fn = (obj) => {
                obj.checked = flag;
                flag && this.options.check.type === 'radio' && this.uncheckSibings(obj);
            };
            if (!items.length)
                return;
            for (let k of items)
                fn(k);
            super.listen({ name: flag ? 'checked' : 'unchecked', cb, params: [items] });
            return this;
        }
        checkAll(cb) {
            if (this.destroyed || !this.options.check.enable || this.options.check.type !== 'checkbox')
                return;
            if (this.options.check.type === 'checkbox') {
                this.check(this.flatData, true);
            }
            else {
                let checkedItem = this.flatData.find((k) => k.checked);
                !checkedItem && this.check(this.flatData[0], true);
            }
            super.listen({ name: 'checkedAll', cb });
            return this;
        }
        async add(options) {
            if (this.destroyed)
                return;
            let opts = Object.assign({ repeat: true, autoFill: true, isFront: false }, options), type = getDataType(opts.data), target = findItem(opts.target, this.flatData), tmp = [], items = [], appendFun = (data) => {
                let obj = treeTools.createBranchObj({
                    source: data,
                    flatData: this.flatData,
                    target,
                    isLeaf: true,
                    isChild: false
                });
                this.createHeadEl(obj);
                this.createBodyEl(obj);
                treeTools.addBranch({
                    source: obj,
                    rootEl: this.targetEl,
                    flatData: this.flatData,
                    treeData: this.treeData,
                    brother: target,
                    isFront: opts.isFront,
                    repeat: opts.repeat,
                    autoFill: opts.autoFill,
                    cb: (item) => {
                        items.push(item);
                        this.updateEvt(item);
                    }
                });
            };
            tmp = isNull(opts.data) ? [null] : ((type === 'Array' && opts.data.length > 0) ? opts.data : [opts.data]);
            for (let k of tmp) {
                try {
                    if (this.options.b4Add) {
                        let resp = await this.options.b4Add.call(this, k);
                        resp && (k = resp);
                    }
                }
                catch (err) {
                    err ? console.error(err) : console.warn(`Adding new branche (${JSON.stringify(k)}) has been prevented!`);
                    continue;
                }
                appendFun(k);
            }
            super.listen({ name: 'added', cb: opts.cb, params: [items] });
            return this;
        }
        async remove(data, cb) {
            if (this.destroyed || isNull(data))
                return;
            if (this.flatData.length === 0) {
                console.warn('The source data is already empty!');
                return;
            }
            let tmp = [], items = [], removeItem = (child) => {
                treeTools.removeBranch({
                    source: child,
                    flatData: this.flatData,
                    treeData: this.treeData,
                    remove: false,
                    cb: (obj) => {
                        items.push(obj);
                    }
                });
            };
            tmp = Array.isArray(data) ? data : [data];
            for (let k of tmp) {
                try {
                    if (this.options.b4Remove) {
                        let resp = await this.options.b4Remove.call(this, k);
                        resp && (k = resp);
                    }
                }
                catch (err) {
                    err ? console.error(err) : console.warn(`Removing old branch (${JSON.stringify(k)}) has been prevented!`);
                    continue;
                }
                removeItem(k);
            }
            super.listen({ name: 'removed', cb, params: [items] });
            return this;
        }
        inputLabelCont(item) {
        }
        async edit(item, data, cb) {
            if (this.destroyed || isNull(item) || isEmpty(data)) {
                return this;
            }
            let source = findItem(item, this.flatData);
            if (!source)
                return this;
            for (let k in data) {
                let val = data[k];
                try {
                    if (this.options.b4Edit) {
                        let resp = await this.options.b4Edit.call(this, { key: k, value: val }, source);
                        resp && (val = resp);
                    }
                    if (k === 'action') {
                        source[k] = val.call({ ins: this, item: k }, source);
                    }
                    else if (['icon', 'disk', 'cube', 'href', 'target', 'rel', 'label', 'content', 'tips', 'badge'].includes(k)) {
                        source[k] = val;
                    }
                }
                catch (err) {
                    err ? console.error(err) : console.warn(`No changes have been made to the ${k} property!`);
                    return this;
                }
            }
            super.listen({ name: 'edited', cb, params: [source] });
            return this;
        }
        async graft({ source, target, isFront = true, isChild = true, cb }) {
            if (this.destroyed || isNull(source))
                return;
            try {
                if (this.options.b4Graft) {
                    let resp = await this.options.b4Graft.call(this, source, target);
                    resp && resp.source && (source = resp.source);
                    resp && resp.target && (source = resp.target);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn(`The branch relationship between source and target in the tree remains unchanged!`);
                return this;
            }
            let sourceObj = findItem(source, this.flatData, '', { node: 'wrapEl' }), targetObj = findItem(target, this.flatData);
            if (!sourceObj)
                return;
            treeTools.graftBranch({
                source: sourceObj,
                target: targetObj,
                isFront,
                isChild,
                flatData: this.flatData,
                treeData: this.treeData,
                rootEl: this.targetEl,
                cb: (obj) => {
                    super.listen({ name: 'grafted', cb, params: [obj] });
                    return this;
                }
            });
            return this;
        }
        updateVals() {
            if (!this.options.output.enable)
                return;
            let val = this.getVals();
            this.options.name && (this.inputEl.value = val);
            fieldTools.setVals({ target: this.receiver, value: val });
        }
        setVals(target = this.receiver, cb) {
            if (this.destroyed)
                return;
            let receiver = getEl(target), val = this.getVals();
            fieldTools.setVals({ target: receiver, value: val });
            super.listen({ name: 'set', cb, params: [val] });
            return this;
        }
        clearVals(cb) {
            if (this.destroyed)
                return this;
            super.uncheckAll();
            this.value = '';
            fieldTools.setVals({ target: this.receiver, value: '' });
            this.options.name && (this.inputEl.value = '');
            super.listen({ name: 'cleared', cb });
            return this;
        }
        getVals(opt = {}, cb) {
            if (this.destroyed)
                return this;
            let options = Object.assign({ ...this.options.output, isStr: true }, opt), items = super.getCheckeds(), result = items.map((k) => k[options.prop]);
            let val = options.isStr ? result.join(options.separator) : result;
            super.listen({ name: 'got', cb, params: [val] });
            return val;
        }
        async setContent(item, data = {}, cb) {
            if (this.destroyed)
                return;
            await super.setElCont({
                item,
                data,
                prop: 'content',
                cb: (cont, target) => {
                    super.listen({ name: 'filled', cb, params: [cont, target] });
                }
            });
            return this;
        }
        
        async updateCont(content, cb) {
            if (this.destroyed)
                return this;
            await getContent.call(this, {
                content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: {
                    xhrName: 'contXhr',
                    ...this.options.ajax
                },
                request: (data) => {
                    this.listen({ name: 'request', params: [data] });
                },
                cb: (data) => {
                    if (Array.isArray(data)) {
                        this.treeDataOrig = deepClone(data);
                        treeTools.addIdPath({ source: this.treeDataOrig });
                        this.targetEl.innerHTML = '';
                        this.renderData(this.treeDataOrig);
                        this.getTreeFlat();
                        this.renderFinish();
                        super.updateCache({ content });
                        super.listen({ name: 'updatedCont', cb, params: [this.treeDataOrig] });
                    }
                }
            });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            for (let k of this.flatData) {
                if (this.options.arrow.trigger === 'click') {
                    let triggerEl = k.hasOwnProperty('href') && k.arrowEl ? k.arrowEl : k.headEl;
                    triggerEl.removeEventListener('click', this.expandEvt);
                }
                else if (this.options.arrow.trigger === 'hover') {
                    this.hoverIns.destroy();
                }
                ['expanded', 'checked'].includes(this.options.clickLine) && k.headEl.removeEventListener('click', this.lineEvt);
                this.options.drag.enable && k.dragIns.destroy();
            }
            this.contXhr && this.contXhr.abort();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optEditor = [
        {
            attr: 'name',
            prop: 'name',
            value: '',
        },
        {
            attr: 'value',
            prop: 'value',
            value: '',
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'disabled',
            prop: 'disabled',
            value: false,
        },
        {
            attr: 'readonly',
            prop: 'readonly',
            value: false,
        },
        {
            attr: 'deferred',
            prop: 'deferred',
            value: false,
        },
        {
            attr: 'delay',
            prop: 'delay',
            value: 200,
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'appear',
            prop: 'appear',
            value: {
                rounded: true,
                bordered: true,
            },
        },
        {
            attr: 'mode',
            prop: 'mode',
            value: 'editor',
        },
        {
            attr: 'header',
            prop: 'header',
            value: {
                enable: true,
                children: [],
            },
        },
        {
            attr: 'footer',
            prop: 'footer',
            value: {
                enable: true,
            },
        },
        {
            attr: 'min-height',
            prop: 'minHeight',
            value: '',
        },
        {
            attr: 'moc-height',
            prop: 'maxHeight',
            value: '',
        },
        {
            attr: 'feature',
            prop: 'feature',
            value: 'simple',
        },
        {
            attr: 'b4-paste',
            prop: 'b4Paste',
            value: null,
        },
        {
            attr: 'on-edited',
            prop: 'onEdited',
            value: null
        },
        {
            attr: 'on-disabled',
            prop: 'onDisabled',
            value: null
        },
        {
            attr: 'on-enabled',
            prop: 'onEnabled',
            value: null
        },
        {
            attr: 'on-readonly',
            prop: 'onReadonly',
            value: null
        },
        {
            attr: 'on-filled',
            prop: 'onFilled',
            value: null
        },
        {
            attr: 'on-set',
            prop: 'onSet',
            value: null
        },
        {
            attr: 'on-cleared',
            prop: 'onCleared',
            value: null
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null
        },
        {
            attr: 'on-request',
            prop: 'onRequest',
            value: null
        },
        {
            attr: 'on-output',
            prop: 'onOutput',
            value: null
        },
        ...optBase
    ];

    class Editor extends ModBaseListenCache {
        options = {};
        flatData;
        treeData;
        inputEl;
        headEl;
        bodyEl;
        contEl;
        footEl;
        pathEl;
        stateEl;
        maskEl;
        toolsEl;
        output;
        tmpRaw;
        contXhr;
        keyupEvt;
        pointerEvt;
        inputEvt;
        pasteEvt;
        readonlyEvt;
        tools;
        static hostType = 'node';
        static optMaps = optEditor;
        constructor(elem, options = {}, initial = true) {
            super();
            let tmp = getEl(elem), host;
            if (!tmp)
                return this;
            if (['TEXTAREA'].includes(tmp.nodeName)) {
                this.inputEl = tmp;
                this.inputEl.classList.add(`${orca.prefix}editor-source`);
                host = createEl('div', { class: `${orca.prefix}editor` });
                tmp.insertAdjacentElement('afterend', host);
            }
            else {
                host = tmp;
                host.classList.add(`${orca.prefix}editor`);
                this.inputEl = createEl('textarea', { class: `${orca.prefix}editor-source` });
            }
            super.ready({
                options,
                host,
                maps: Editor.optMaps,
                component: true,
                spread: ['header', 'footer']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            
            this.rawHtml = this.inputEl.value || this.targetEl.innerHTML;
            this.contEl = createEl('div', { class: `${orca.prefix}editor-cont`, placeholder: this.options.lang.placeholder, contenteditable: true });
            let _this = this;
            this.keyupEvt = debounce((e) => {
                let code = e.key;
                if (code === 'Backspace') {
                    
                    ([`<br>`, `<p><br></p>`, `<div><br></div>`].includes(trim(this.contEl.innerHTML, 'global'))) && (this.contEl.innerHTML = '');
                    this.updateInputVal();
                }
            }, this.options.delay);
            this.pointerEvt = () => {
                this.setPathInfo();
            };
            this.inputEvt = debounce(function (e) {
                if (this === _this.contEl) {
                    _this.inputEl.value = _this.contEl.innerHTML;
                }
                else if (this === _this.inputEl) {
                    _this.contEl.innerHTML = _this.inputEl.value;
                }
                _this.output.value = _this.inputEl.value;
                _this.updateInfo();
            }, {
                delay: this.options.delay,
                
            });
            this.pasteEvt = async function (e) {
                let text = '';
                if (_this.options.b4Paste) {
                    e.preventDefault();
                    text = await _this.options.b4Paste.call(_this, await navigator.clipboard.readText());
                    if (text) {
                        let selection = window.getSelection();
                        if (selection.rangeCount > 0) {
                            let range = selection.getRangeAt(0), textNode = document.createTextNode(text);
                            range.insertNode(textNode);
                            range.setStartAfter(textNode);
                            range.collapse(true);
                            selection.removeAllRanges();
                            selection.addRange(range);
                        }
                    }
                }
                else {
                    text = await navigator.clipboard.readText();
                }
                _this.listen({ name: 'pasted', params: [text] });
                if (this === _this.contEl) {
                    _this.inputEl.value = _this.contEl.innerHTML;
                }
                else if (this === _this.inputEl) {
                    _this.contEl.innerHTML = _this.inputEl.value;
                }
                _this.output.value = _this.inputEl.value;
                _this.updateInfo();
            };
            this.readonlyEvt = (e) => {
                e.preventDefault();
            };
            this.tools = [
                ...this.createToggleItems([
                    { name: 'bold', icon: `${orca.prefix}icon-bold`, key: 'fontWeight', value: 'bold', tips: this.options.lang.tips.bold },
                    { name: 'italic', icon: `${orca.prefix}icon-italic`, key: 'fontStyle', value: 'italic', tips: this.options.lang.tips.italic },
                    { name: 'underline', icon: `${orca.prefix}icon-underline`, key: 'textDecorationLine', value: 'underline', tips: this.options.lang.tips.underline },
                    { name: 'through', icon: `${orca.prefix}icon-through`, key: 'textDecorationLine', value: 'line-through', tips: this.options.lang.tips.through },
                ]),
                ...this.createFontsizeItems([
                    { name: 'fontsize-dft', label: this.options.lang.fontsizeDft, value: '' },
                    { name: '1.2rem', label: '12px/1.2rem', value: '1.2rem' },
                    { name: '1.4rem', label: '14px/1.4rem', value: '1.4rem' },
                    { name: '1.6rem', label: '16px/1.6rem', value: '1.6rem' },
                    { name: '1.8rem', label: '18px/1.8rem', value: '1.8rem' },
                    { name: '2.2rem', label: '22px/2.2rem', value: '2.2rem' },
                    { name: '2.8rem', label: '2.8px/2.8rem', value: '2.8rem' },
                    { name: '3.2rem', label: '32px/3.2rem', value: '3.2rem' },
                    { name: '3.8rem', label: '38px/3.8rem', value: '3.8rem' },
                    { name: '4.2rem', label: '42px/4.2rem', value: '4.2rem' },
                    { name: '4.8rem', label: '48px/4.8rem', value: '4.8rem' },
                ]),
                ...this.createAlignItems([
                    { name: 'align-dft', label: this.options.lang.alignDft, value: '' },
                    { name: 'align-left', icon: `${orca.prefix}icon-align-left`, value: 'left', tips: this.options.lang.tips.alignLeft },
                    { name: 'align-center', icon: `${orca.prefix}icon-align-center`, value: 'center', tips: this.options.lang.tips.alignCenter },
                    { name: 'align-right', icon: `${orca.prefix}icon-align-right`, value: 'right', tips: this.options.lang.tips.alignRight },
                    { name: 'align-justify', icon: `${orca.prefix}icon-align-justify`, value: 'justify', tips: this.options.lang.tips.alignJustify },
                ]),
                ...this.createSpanTags([
                    { name: 'sup', icon: `${orca.prefix}icon-superscript`, value: 'sup', tips: this.options.lang.tips.sup },
                    { name: 'sub', icon: `${orca.prefix}icon-subscript`, value: 'sub', tips: this.options.lang.tips.sub },
                    { name: 'highlight', icon: `${orca.prefix}icon-highlight`, value: 'mark', tips: this.options.lang.tips.highlight },
                    { name: 'cite', icon: `${orca.prefix}icon-quote-left`, value: 'cite', tips: this.options.lang.tips.cite },
                    { name: 'code-inline', icon: `${orca.prefix}icon-code-inline`, value: 'code', tips: this.options.lang.tips.codeInline },
                    { name: 'em', label: this.options.lang.tips.em, value: 'em', },
                    { name: 'address', label: this.options.lang.tips.address, value: 'address', },
                    { name: 'time', label: this.options.lang.tips.time, value: 'time', },
                    { name: 'ruby', label: this.options.lang.tips.ruby, value: 'ruby', },
                    { name: 'rt', label: this.options.lang.tips.rt, value: 'rt', },
                ]),
                ...this.createLineTags([
                    { name: 'p', icon: `${orca.prefix}icon-article`, value: 'p', tips: this.options.lang.tips.text, },
                    { name: 'h1', icon: `${orca.prefix}icon-heading-1`, value: 'h1', tips: this.options.lang.tips.h1 },
                    { name: 'h2', icon: `${orca.prefix}icon-heading-2`, value: 'h2', tips: this.options.lang.tips.h2 },
                    { name: 'h3', icon: `${orca.prefix}icon-heading-3`, value: 'h3', tips: this.options.lang.tips.h3 },
                    { name: 'h4', icon: `${orca.prefix}icon-heading-4`, value: 'h4', tips: this.options.lang.tips.h4 },
                    { name: 'h5', icon: `${orca.prefix}icon-heading-5`, value: 'h5', tips: this.options.lang.tips.h5 },
                    { name: 'h6', icon: `${orca.prefix}icon-heading-6`, value: 'h6', tips: this.options.lang.tips.h6 },
                    { name: 'blockquote', icon: `${orca.prefix}icon-quote-left-f`, value: 'blockquote', tips: this.options.lang.tips.blockquote },
                ]),
                ...this.createCloseTags([
                    { name: 'hr', icon: `${orca.prefix}icon-line-h`, value: 'hr', tips: this.options.lang.tips.hr },
                    { name: 'br', icon: `${orca.prefix}icon-br`, value: 'br', tips: this.options.lang.tips.br },
                ]),
                ...this.createNestTags([
                    { name: 'code-block', icon: `${orca.prefix}icon-code-block`, value: ['pre', 'code'], tips: this.options.lang.tips.codeBlock, },
                    { name: 'list-ul', icon: `${orca.prefix}icon-list-ul`, value: ['ul', 'li', 'br'], tips: this.options.lang.tips.listUl },
                    { name: 'list-ol', icon: `${orca.prefix}icon-list-ol`, value: ['ol', 'li', 'br'], tips: this.options.lang.tips.listOl },
                    { name: 'paragraph', icon: `${orca.prefix}icon-paragraph`, value: ['div', 'br'], tips: this.options.lang.tips.paragraph, isRoot: true },
                ]),
                {
                    name: 'indent-more',
                    icon: `${orca.prefix}icon-indent-more`,
                    tips: this.options.lang.tips.indentMore,
                    action: (resp) => {
                        resp.wrapEl.onpointerdown = (e) => {
                            e.preventDefault();
                            this.setLineStyles('', '', (el) => {
                                let now = style(el).textIndent;
                                el.style.textIndent = `${toPixel(now) + toPixel('2.8rem')}px`;
                            });
                        };
                    }
                },
                {
                    name: 'indent-less',
                    icon: `${orca.prefix}icon-indent-less`,
                    tips: this.options.lang.tips.indentLess,
                    action: (resp) => {
                        resp.wrapEl.onpointerdown = (e) => {
                            e.preventDefault();
                            this.setLineStyles('', '', (el) => {
                                let now = style(el).textIndent, val = Math.max(0, toPixel(now) - toPixel('2.8rem'));
                                el.style.textIndent = `${val}px`;
                            });
                        };
                    }
                },
                {
                    name: 'dropdown-fontsize',
                    label: this.options.lang.fontsizeDft,
                    extendable: true,
                    action: (resp) => {
                        let content = [
                            { label: this.options.lang.fontsizeDft, value: '' },
                            { label: '12px/1.2rem', value: '1.2rem' },
                            { label: '14px/1.4rem', value: '1.4rem' },
                            { label: '16px/1.6rem', value: '1.6rem' },
                            { label: '18px1.8rem', value: '1.8rem' },
                            { label: '22px/2.2rem', value: '2.2rem' },
                            { label: '28px/2.8rem', value: '2.8rem' },
                            { label: '32px/3.2rem', value: '3.2rem' },
                            { label: '38px/3.8rem', value: '3.8rem' },
                            { label: '42px/4.2rem', value: '4.2rem' },
                            { label: '48px/4.8rem', value: '4.8rem' },
                        ];
                        new Dropdown(resp.wrapEl, {
                            content: content.map((k) => k.label),
                            feature: 'select',
                            popup: {
                                onTargetSet: (value) => {
                                    this.setStyles('fontSize', content.find((k) => k.label === value).value);
                                }
                            }
                        });
                    }
                },
                {
                    name: 'dropdown-align',
                    label: this.options.lang.alignDft,
                    extendable: true,
                    action: (resp) => {
                        let content = [
                            { label: this.options.lang.alignDft, value: '' },
                            { label: this.options.lang.tips.alignLeft, icon: `${orca.prefix}icon-align-left`, value: 'left' },
                            { label: this.options.lang.tips.alignCenter, icon: `${orca.prefix}icon-align-center`, value: 'center' },
                            { label: this.options.lang.tips.alignRight, icon: `${orca.prefix}icon-align-right`, value: 'right' },
                            { label: this.options.lang.tips.alignJustify, icon: `${orca.prefix}icon-align-justify`, value: 'justify' },
                        ];
                        new Dropdown(resp.wrapEl, {
                            content: content.map((k) => k.label),
                            feature: 'select',
                            popup: {
                                onTargetSet: (value) => {
                                    this.setLineStyles('textAlign', content.find((k) => k.label === value).value);
                                }
                            }
                        });
                    }
                },
                {
                    name: 'dropdown-heading',
                    label: this.options.lang.tips.text,
                    extendable: true,
                    action: (resp) => {
                        let content = [
                            { label: this.options.lang.tips.text, value: 'p' },
                            { label: this.options.lang.tips.h1, icon: `${orca.prefix}icon-heading-1`, value: 'h1' },
                            { label: this.options.lang.tips.h2, icon: `${orca.prefix}icon-heading-2`, value: 'h2' },
                            { label: this.options.lang.tips.h3, icon: `${orca.prefix}icon-heading-3`, value: 'h3' },
                            { label: this.options.lang.tips.h4, icon: `${orca.prefix}icon-heading-1`, value: 'h4' },
                            { label: this.options.lang.tips.h5, icon: `${orca.prefix}icon-heading-5`, value: 'h5' },
                            { label: this.options.lang.tips.h6, icon: `${orca.prefix}icon-heading-6`, value: 'h6' },
                        ];
                        new Dropdown(resp.wrapEl, {
                            content: content.map((k) => k.label),
                            feature: 'select',
                            popup: {
                                onTargetSet: (value) => {
                                    this.replaceLineTag(content.find((k) => k.label === value).value);
                                }
                            }
                        });
                    }
                },
                {
                    name: 'dropdown-tags',
                    label: this.options.lang.tagsDft,
                    extendable: true,
                    action: (resp) => {
                        let content = [
                            { label: this.options.lang.tips.em, value: 'em' },
                            { label: this.options.lang.tips.address, value: 'address' },
                            { label: this.options.lang.tips.time, value: 'time' },
                            { label: this.options.lang.tips.ruby, value: 'ruby' },
                            { label: this.options.lang.tips.rt, value: 'rt' },
                        ];
                        new Dropdown(resp.wrapEl, {
                            content: content.map((k) => k.label),
                            feature: 'button',
                            popup: { trigger: 'hover' },
                            action: (resp) => {
                                resp.el.onclick = (e) => {
                                    e.preventDefault();
                                    this.addWraps(content.find((k) => k.label === resp.data.label).value);
                                };
                            }
                        });
                    }
                },
                {
                    name: 'source',
                    icon: `${orca.prefix}icon-code-box`,
                    swap: `${orca.prefix}icon-html-box`,
                    tips: this.options.lang.tips.source,
                    action: (resp) => {
                        resp.wrapEl.onpointerdown = (e) => {
                            e.preventDefault();
                            if (this.targetEl.getAttribute('mode') === 'source') {
                                this.targetEl.setAttribute('mode', 'editor');
                                resp.wrapEl.toggleAttribute('focused', false);
                                classes(resp.iconEl).replace(resp.icon, resp.swap);
                            }
                            else {
                                this.targetEl.setAttribute('mode', 'source');
                                resp.wrapEl.toggleAttribute('focused', true);
                                classes(resp.iconEl).replace(resp.swap, resp.icon);
                            }
                        };
                    }
                },
            ];
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch (err) {
                err ? console.error(err) : console.warn(config.warn.init);
                return this;
            }
            this.output = { value: '', raw: '' };
            this.tmpRaw = '';
            super.useTpl();
            this.renderMain();
            this.setAttrs();
            !this.options.deferred && await this.fillCont(this.options.content || this.options.value || this.rawHtml);
            this.renderFinish();
            this.contEl.addEventListener("input", this.inputEvt, false);
            this.inputEl.addEventListener("input", this.inputEvt, false);
            this.contEl.addEventListener("paste", this.pasteEvt, false);
            this.inputEl.addEventListener("paste", this.pasteEvt, false);
            this.contEl.addEventListener("keyup", this.keyupEvt, false);
            this.contEl.addEventListener("pointerdown", this.pointerEvt, false);
            super.listen({ name: 'initiated', cb });
            return this;
        }
        insertNewPara(parentEl, newPara, startNode) {
            if (parentEl === this.contEl) {
                this.contEl.insertBefore(newPara, startNode === this.contEl || !startNode ? null : startNode.nextSibling);
            }
            else {
                parentEl.parentNode.insertBefore(newPara, parentEl.nextSibling);
            }
        }
        getTools() {
            if (!isEmpty(this.options.header.children)) {
                return this.options.header.children.map((k) => {
                    let tmp = this.tools.find((i) => i.name === k);
                    return tmp || k;
                });
            }
            else {
                if (this.options.feature === 'simple') {
                    return ['bold', 'align-left', 'align-center', 'align-right', 'highlight', 'p', 'h1', 'h2', 'h3', 'hr', 'br', 'paragraph', 'indent-more', 'indent-less', 'source']
                        .map((k) => this.tools.find((i) => i.name === k));
                }
                else if (this.options.feature === 'comm') {
                    return ['bold', 'italic', 'underline', 'through', 'align-left', 'align-center', 'align-right', 'highlight', 'cite', 'blockquote',
                        'code-inline', 'code-block', 'p', 'h1', 'h2', 'h3', 'hr', 'br', 'list-ul', 'list-ol', 'paragraph', 'indent-more', 'indent-less', 'source']
                        .map((k) => this.tools.find((i) => i.name === k));
                }
                else if (this.options.feature === 'flat') {
                    return this.tools.filter((k) => !k.name.includes('dropdown-') && !k.name.includes('group-'));
                }
                else if (this.options.feature === 'group') {
                    return this.tools.filter((k) => k.name.includes('dropdown-') || k.name.includes('group-'));
                }
                else {
                    return this.tools;
                }
            }
        }
        renderMain() {
            this.targetEl.innerHTML = '';
            this.headEl = createEl('div', { class: `${orca.prefix}editor-head` });
            this.inputEl.placeholder = this.options.lang.placeholder;
            this.options.name && (this.inputEl.name = this.options.name);
            this.bodyEl = createEl('div', { class: `${orca.prefix}editor-body` });
            this.bodyEl.append(this.contEl, this.inputEl);
            this.pathEl = createEl('div', { class: `${orca.prefix}editor-path` });
            this.stateEl = createEl('div', { class: `${orca.prefix}editor-state` });
            this.footEl = createEl('div', { class: `${orca.prefix}editor-foot` });
            this.footEl.append(this.pathEl, this.stateEl);
            this.maskEl = createEl('div', { class: `${orca.prefix}editor-mask` }, this.options.lang.defer);
            if (this.options.header.enable) {
                this.toolsEl = createTools(this.getTools(), this.headEl);
                this.targetEl.appendChild(this.headEl);
            }
            this.targetEl.appendChild(this.bodyEl);
            this.options.footer.enable && this.targetEl.appendChild(this.footEl);
            this.options.deferred && this.bodyEl.appendChild(this.maskEl);
            this.updateInfo();
        }
        updateInfo() {
            this.setPathInfo();
            this.setStateInfo();
            this.output = { value: this.inputEl.value, raw: this.tmpRaw };
            super.listen({ name: 'output', params: [this.output] });
            this.tmpRaw = this.inputEl.value;
        }
        setPathInfo(selection = document.getSelection()) {
            if (!selection.rangeCount) {
                this.pathEl.innerHTML = this.options.lang.path + ' -';
                return;
            }
            let range = selection.getRangeAt(0), startNode = range.startContainer, parNames = [];
            if (!this.isValidRange(startNode))
                return;
            while (startNode && this.isValidRange(startNode)) {
                parNames.unshift(startNode.nodeName.toLowerCase());
                startNode = startNode.parentNode;
            }
            this.pathEl.innerHTML = this.options.lang.path + ' ' + parNames.join(' › ');
        }
        setStateInfo() {
            let charCount = this.contEl.textContent.replace(/\s/g, '').length, paraCount = this.contEl.childNodes.length, html = this.contEl.innerHTML;
            this.stateEl.innerHTML = this.options.lang.chars + ' ' + +charCount + ' , ' + this.options.lang.paras + ' ' + +paraCount;
            super.updateCache({ content: html });
            super.listen({ name: 'edited', params: [html] });
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}editor`);
            this.options.classes && classes(this.targetEl).add(this.options.classes);
            this.options.readonly ? this.readonly() : this.enable();
            this.targetEl.toggleAttribute('inert', this.options.disabled);
            this.targetEl.setAttribute('mode', this.options.mode);
            this.options.minHeight ? addStyle(this.contEl, 'moc-height', this.options.minHeight) : removeStyle(this.contEl, 'moc-height');
            for (let k in this.options.appear) {
                let val = this.options.appear[k];
                this.targetEl.toggleAttribute(k, val);
            }
            this.targetEl.toggleAttribute('deferred', this.options.deferred);
        }
        readonly() {
            this.headEl.toggleAttribute('inert', true);
            this.contEl.addEventListener('keydown', this.readonlyEvt);
            this.contEl.addEventListener('paste', this.readonlyEvt);
            this.contEl.addEventListener('drop', this.readonlyEvt, false);
            this.inputEl.addEventListener('keydown', this.readonlyEvt, false);
            this.inputEl.addEventListener('paste', this.readonlyEvt, false);
            this.inputEl.addEventListener('drop', this.readonlyEvt, false);
            this.inputEl.readOnly = true;
            super.listen({ name: 'readonly' });
        }
        disable() {
            this.headEl.toggleAttribute('inert', true);
            this.targetEl.toggleAttribute('inert', true);
            this.contEl.addEventListener('keydown', this.readonlyEvt, false);
            this.contEl.addEventListener('paste', this.readonlyEvt, false);
            this.contEl.addEventListener('drop', this.readonlyEvt, false);
            this.inputEl.addEventListener('keydown', this.readonlyEvt, false);
            this.inputEl.addEventListener('paste', this.readonlyEvt, false);
            this.inputEl.addEventListener('drop', this.readonlyEvt, false);
            this.inputEl.readOnly = true;
            super.listen({ name: 'disabled' });
        }
        enable() {
            this.headEl.toggleAttribute('inert', false);
            this.targetEl.toggleAttribute('inert', false);
            this.contEl.removeEventListener('keydown', this.readonlyEvt);
            this.contEl.removeEventListener('paste', this.readonlyEvt);
            this.contEl.removeEventListener('drop', this.readonlyEvt);
            this.inputEl.removeEventListener('keydown', this.readonlyEvt);
            this.inputEl.removeEventListener('paste', this.readonlyEvt);
            this.inputEl.removeEventListener('drop', this.readonlyEvt);
            this.inputEl.readOnly = false;
            super.listen({ name: 'enabled' });
        }
        renderFinish() {
            if (this.options.deferred) {
                this.maskEl.onclick = async () => {
                    await this.fillCont(this.options.content || this.options.value);
                    this.targetEl.removeAttribute('deferred');
                    this.maskEl.remove();
                };
            }
        }
        fullTextNode(range) {
            let startNode = range.startContainer, endNode = range.endContainer;
            if (startNode === endNode) {
                if (startNode.nodeType === 3) {
                    const text = startNode.textContent;
                    return range.startOffset === 0 && range.endOffset === text.length;
                }
                else if (startNode.nodeType === 1) {
                    return range.startOffset === 0 && range.endOffset === 1;
                }
                else {
                    return false;
                }
            }
            else {
                return false;
            }
        }
        setChildRange(wrap, selection = document.getSelection()) {
            let newRange = document.createRange();
            if (!wrap.firstChild || !wrap.lastChild)
                return;
            newRange.setStartBefore(wrap.firstChild);
            newRange.setEndAfter(wrap.lastChild);
            selection.removeAllRanges();
            selection.addRange(newRange);
        }
        setStyles(key, value, selection = document.getSelection()) {
            if (selection.rangeCount > 0) {
                for (let i = 0; i < selection.rangeCount; i++) {
                    let range = selection.getRangeAt(i), startNode = range.startContainer;
                    if (!this.isValidRange(startNode))
                        continue;
                    let wrap = this.fullTextNode(range) ? (startNode.nodeType === 1 ? startNode : startNode.parentNode) : this.addOneWrap('i', range);
                    wrap.style[key] = value;
                    this.setChildRange(wrap, selection);
                }
                this.updateInputVal();
            }
        }
        getParentNode(range) {
            let parent = range.commonAncestorContainer;
            return (parent.nodeType !== 1) ? parent.parentNode : parent;
        }
        removeStyles(key, selection = document.getSelection()) {
            if (selection.rangeCount > 0) {
                for (let i = 0; i < selection.rangeCount; i++) {
                    let range = selection.getRangeAt(i), startNode = range.startContainer;
                    if (!this.isValidRange(startNode))
                        continue;
                    let parent = this.getParentNode(range);
                    if (parent) {
                        parent.style[key] = null;
                    }
                }
            }
        }
        toggleStyles(key, value, selection = document.getSelection()) {
            if (selection.rangeCount > 0) {
                for (let i = 0; i < selection.rangeCount; i++) {
                    let range = selection.getRangeAt(i), startNode = range.startContainer;
                    if (!this.isValidRange(startNode))
                        continue;
                    let parent = this.getParentNode(range);
                    if (parent && parent.style[key]) {
                        parent.style[key] = null;
                    }
                    else {
                        let wrap = this.fullTextNode(range) ? (startNode.nodeType === 1 ? startNode : startNode.parentNode) : this.addOneWrap('i', range);
                        wrap.style[key] = value;
                        this.setChildRange(wrap, selection);
                    }
                }
                this.updateInputVal();
            }
        }
        addOneWrap(tagName, range) {
            let text = range.extractContents(), wrap = document.createElement(tagName);
            wrap.appendChild(text);
            range.insertNode(wrap);
            return wrap;
        }
        addWraps(tagName, selection = document.getSelection()) {
            if (!selection.rangeCount)
                return;
            let last;
            for (let i = 0; i < selection.rangeCount; i++) {
                let range = selection.getRangeAt(i), startNode = range.startContainer;
                if (!this.isValidRange(startNode))
                    continue;
                let parent = this.getParentNode(range);
                if (parent && parent.nodeName === tagName.toUpperCase()) {
                    continue;
                }
                let wrap = this.addOneWrap(tagName, range);
                if (i === selection.rangeCount - 1) {
                    last = wrap;
                }
            }
            last && this.setChildRange(last, selection);
            this.updateInputVal();
        }
        replaceLineTag(tagName, selection = document.getSelection()) {
            if (!selection.rangeCount)
                return;
            let range = selection.getRangeAt(0), startNode = range.startContainer, newTag = document.createElement(tagName), startOffset = range.startOffset, newRange = document.createRange();
            if (!this.isValidRange(startNode))
                return;
            while (startNode && startNode.nodeType === 3 && startNode.parentNode !== this.contEl)
                startNode = startNode.parentNode;
            if (startNode?.tagName?.toLowerCase() === tagName)
                return;
            newTag.innerHTML = startNode.innerHTML || startNode.textContent;
            startNode.parentNode.replaceChild(newTag, startNode);
            let start = newTag.firstChild || newTag;
            try {
                newRange.setStart(start, startOffset);
            }
            catch {
                newRange.setStart(start, 0);
            }
            newRange.collapse(true);
            selection.removeAllRanges();
            selection.addRange(newRange);
            this.updateInputVal();
        }
        setLineStyles(key, value, cb) {
            let selection = document.getSelection(), range = selection.getRangeAt(0), startNode = range.startContainer, parEl = startNode?.parentNode;
            if (!selection.rangeCount || !this.isValidRange(startNode) || parEl === this.contEl)
                return;
            key && (parEl.style[key] = value);
            this.updateInputVal();
            cb && cb(parEl);
        }
        createNestWrap(tags) {
            let root = document.createElement(tags[0]), leaf;
            tags.slice(1).reduce((parent, tag, idx) => {
                let newNode = document.createElement(tag);
                if (idx === tags.length - 2)
                    leaf = newNode;
                parent.appendChild(newNode);
                return newNode;
            }, root);
            return { root, leaf };
        }
        insertNestNodes(tags, isRoot = false) {
            if (!Array.isArray(tags) || !tags.length)
                return;
            let selection = document.getSelection();
            if (!selection)
                return;
            let range = selection.getRangeAt(0), startNode = range.startContainer, { root, leaf } = this.createNestWrap(tags), newRange = document.createRange();
            if (!selection.rangeCount || !this.isValidRange(startNode, false))
                return;
            if (isRoot) {
                let parNode = startNode, curNode = startNode;
                while (parNode !== this.contEl) {
                    curNode = parNode;
                    parNode = parNode.parentNode;
                }
                this.contEl.insertBefore(root, curNode === this.contEl ? null : curNode.nextSibling);
            }
            else {
                range.insertNode(root);
            }
            newRange.setStart(leaf, 0);
            newRange.collapse(true);
            selection.removeAllRanges();
            selection.addRange(newRange);
            this.updateInputVal();
        }
        insertTag(tag) {
            let selection = document.getSelection();
            if (!selection.rangeCount || !this.isValidRange(null, false))
                return;
            let range = selection.getRangeAt(0), node = document.createElement(tag);
            this.clearRanges(selection);
            range.insertNode(node);
            range.setStartAfter(node);
            range.setEndAfter(node);
            selection.removeAllRanges();
            selection.addRange(range);
            this.updateInputVal();
        }
        clearRanges(selection = document.getSelection()) {
            if (selection.rangeCount > 0) {
                for (let i = 0; i < selection.rangeCount; i++) {
                    let range = selection.getRangeAt(i);
                    range.deleteContents();
                }
            }
        }
        isValidRange(node, exact = true) {
            let startNode;
            if (!node) {
                let selection = document.getSelection(), range = selection.getRangeAt(0);
                startNode = range.startContainer;
            }
            else {
                startNode = node;
            }
            return this.contEl.contains(startNode) && (exact ? this.contEl !== startNode : true);
        }
        createFontsizeItems(arr) {
            return arr.map((k) => {
                return {
                    name: k.name,
                    label: k.label,
                    tips: k.tips,
                    icon: k.icon,
                    action: (resp) => {
                        resp.wrapEl.onpointerdown = (e) => {
                            e.preventDefault();
                            this.setStyles('fontSize', k.value);
                        };
                    }
                };
            });
        }
        createToggleItems(arr) {
            return arr.map((k) => {
                return {
                    name: k.name,
                    label: k.label,
                    tips: k.tips,
                    icon: k.icon,
                    action: (resp) => {
                        resp.wrapEl.onpointerdown = (e) => {
                            e.preventDefault();
                            this.toggleStyles(k.key, k.value);
                        };
                    }
                };
            });
        }
        createAlignItems(arr) {
            return arr.map((k) => {
                return {
                    name: k.name,
                    label: k.label,
                    tips: k.tips,
                    icon: k.icon,
                    action: (resp) => {
                        resp.wrapEl.onpointerdown = (e) => {
                            e.preventDefault();
                            this.setLineStyles('textAlign', k.value);
                        };
                    }
                };
            });
        }
        createLineTags(arr) {
            return arr.map((k) => {
                return {
                    name: k.name,
                    label: k.label,
                    tips: k.tips,
                    icon: k.icon,
                    action: (resp) => {
                        resp.wrapEl.onpointerdown = (e) => {
                            e.preventDefault();
                            this.replaceLineTag(k.value);
                        };
                    }
                };
            });
        }
        createSpanTags(arr) {
            return arr.map((k) => {
                return {
                    name: k.name,
                    label: k.label,
                    tips: k.tips,
                    icon: k.icon,
                    action: (resp) => {
                        resp.wrapEl.onpointerdown = (e) => {
                            e.preventDefault();
                            this.addWraps(k.value);
                        };
                    }
                };
            });
        }
        createCloseTags(arr) {
            return arr.map((k) => {
                return {
                    name: k.name,
                    label: k.label,
                    tips: k.tips,
                    icon: k.icon,
                    action: (resp) => {
                        resp.wrapEl.onpointerdown = (e) => {
                            e.preventDefault();
                            this.insertTag(k.value);
                        };
                    }
                };
            });
        }
        createNestTags(arr) {
            return arr.map((k) => {
                return {
                    name: k.name,
                    label: k.label,
                    tips: k.tips,
                    icon: k.icon,
                    action: (resp) => {
                        resp.wrapEl.onpointerdown = (e) => {
                            e.preventDefault();
                            this.insertNestNodes(k.value, k.isRoot);
                        };
                    }
                };
            });
        }
        async fillCont(content = this.options.content, cb) {
            if (isEmpty(content))
                return;
            let result, spinProp = elState(this.maskEl).isVisible ? { target: this.maskEl } : { spinSel: this.bodyEl };
            await getContent.call(this, {
                content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: {
                    xhrName: 'contXhr',
                    ...spinProp,
                    ...this.options.ajax
                },
                request: (data) => {
                    super.listen({ name: 'request', params: [data] });
                },
                cb: async (resp) => {
                    result = resp;
                    setContent({
                        content: resp,
                        template: content?.tplStr || this.tplStr,
                        engine: content?.tplEng || this.tplEng,
                        target: this.contEl,
                        prevent: (result) => {
                            if (getDataType(result).includes('HTML')) {
                                this.contEl.appendChild(result);
                            }
                            else {
                                this.contEl.innerHTML = result;
                            }
                            this.inputEl.value = this.output.value = this.contEl.innerHTML;
                            this.updateInfo();
                        }
                    });
                }
            });
            super.listen({ name: 'filled', cb, params: [result] });
        }
        updateInputVal() {
            this.inputEl.value = this.output.value = this.contEl.innerHTML;
            this.updateInfo();
        }
        setVals(value, cb) {
            if (this.destroyed)
                return this;
            this.inputEl.value = this.contEl.innerHTML = value;
            this.updateInfo();
            super.listen({ name: 'set', cb, params: [value] });
            return this;
        }
        getVals() {
            if (this.destroyed)
                return;
            return this.contEl.innerHTML;
        }
        clearVals(cb) {
            if (this.destroyed)
                return;
            this.inputEl.value = this.contEl.innerHTML = '';
            this.updateInfo();
            super.listen({ name: 'cleared', cb });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.contEl.removeEventListener("input", this.inputEvt);
            this.inputEl.removeEventListener("input", this.inputEvt);
            this.contEl.removeEventListener("keyup", this.keyupEvt);
            this.enable();
            this.contXhr && this.contXhr.abort();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optSelect = [
        {
            attr: 'name',
            prop: 'name',
            value: '',
        },
        {
            attr: 'value',
            prop: 'value',
            value: '',
        },
        {
            attr: 'field',
            prop: 'field',
            value: 'label',
        },
        {
            attr: 'type',
            prop: 'type',
            value: 'dropdown',
        },
        {
            attr: 'manual',
            prop: 'manual',
            value: false,
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'disabled',
            prop: 'disabled',
            value: false,
        },
        {
            attr: 'multiple',
            prop: 'multiple',
            value: false,
        },
        {
            attr: 'exclude',
            prop: 'exclude',
            value: '',
        },
        {
            attr: 'readonly',
            prop: 'readonly',
            value: false,
        },
        {
            attr: 'full',
            prop: 'full',
            value: false,
        },
        {
            attr: 'min',
            prop: 'min',
            value: 0,
        },
        {
            attr: 'max',
            prop: 'max',
            value: 0,
        },
        {
            attr: 'sliced',
            prop: 'sliced',
            value: true,
        },
        {
            attr: 'removable',
            prop: 'removable',
            value: true,
        },
        {
            attr: 'moc-height',
            prop: 'maxHeight',
            value: '',
        },
        {
            attr: 'span',
            prop: 'span',
            value: 'leaf',
        },
        {
            attr: 'unique',
            prop: 'unique',
            value: true,
        },
        {
            attr: 'collapse',
            prop: 'collapse',
            value: false,
        },
        {
            attr: 'size',
            prop: 'size',
            value: 'md',
        },
        {
            attr: 'search',
            prop: 'search',
            value: {
                enable: false,
                value: '',
                fuzzy: true,
                ignore: true,
                result: true,
            },
        },
        {
            attr: 'tools',
            prop: 'tools',
            value: {
                enable: false,
                children: ['close']
            },
        },
        {
            attr: 'auto-width',
            prop: 'autoWidth',
            value: true,
        },
        {
            attr: 'status',
            prop: 'status',
            value: false,
        },
        {
            attr: 'tags',
            prop: 'tags',
            value: {},
        },
        {
            attr: 'popup',
            prop: 'popup',
            value: {
                enable: true,
            },
        },
        {
            attr: 'tree',
            prop: 'tree',
            value: {},
        },
        {
            attr: 'b4-expand',
            prop: 'b4Expand',
            value: null,
        },
        {
            attr: 'b4-collapse',
            prop: 'b4Collapse',
            value: null,
        },
        {
            attr: 'b4-add',
            prop: 'b4Add',
            value: null,
        },
        {
            attr: 'b4-edit',
            prop: 'b4Edit',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'b4-graft',
            prop: 'b4Graft',
            value: null,
        },
        {
            attr: 'on-rendered',
            prop: 'onRendered',
            value: null,
        },
        {
            attr: 'on-trigger',
            prop: 'onTrigger',
            value: null
        },
        {
            attr: 'on-added',
            prop: 'onAdded',
            value: null
        },
        {
            attr: 'on-edited',
            prop: 'onEdited',
            value: null
        },
        {
            attr: 'on-removed',
            prop: 'onRemoved',
            value: null
        },
        {
            attr: 'on-disabled',
            prop: 'onDisabled',
            value: null
        },
        {
            attr: 'on-enabled',
            prop: 'onEnabled',
            value: null
        },
        {
            attr: 'on-disabledall',
            prop: 'onDisabledAll',
            value: null
        },
        {
            attr: 'on-enabledall',
            prop: 'onEnabledAll',
            value: null
        },
        {
            attr: 'on-readonly',
            prop: 'onReadonly',
            value: null
        },
        {
            attr: 'on-readonlyall',
            prop: 'onReadonlyAll',
            value: null
        },
        {
            attr: 'on-expand',
            prop: 'onExpand',
            value: null
        },
        {
            attr: 'on-expanded',
            prop: 'onExpanded',
            value: null
        },
        {
            attr: 'on-collapse',
            prop: 'onCollapse',
            value: null
        },
        {
            attr: 'on-collapsed',
            prop: 'onCollapsed',
            value: null
        },
        {
            attr: 'on-expandall',
            prop: 'onExpandAll',
            value: null
        },
        {
            attr: 'on-expandedAll',
            prop: 'onExpandedAll',
            value: null
        },
        {
            attr: 'on-collapsedall',
            prop: 'onCollapsedAll',
            value: null
        },
        {
            attr: 'on-selected',
            prop: 'onSelected',
            value: null
        },
        {
            attr: 'on-deselected',
            prop: 'onDeselected',
            value: null
        },
        {
            attr: 'on-selectedall',
            prop: 'onSelectedAll',
            value: null
        },
        {
            attr: 'on-checked',
            prop: 'onChecked',
            value: null
        },
        {
            attr: 'on-unchecked',
            prop: 'onUnchecked',
            value: null
        },
        {
            attr: 'on-checkedall',
            prop: 'onCheckedAll',
            value: null
        },
        {
            attr: 'on-filled',
            prop: 'onFilled',
            value: null
        },
        {
            attr: 'on-turned',
            prop: 'onTurned',
            value: null
        },
        {
            attr: 'on-got',
            prop: 'onGot',
            value: null
        },
        {
            attr: 'on-set',
            prop: 'onSet',
            value: null
        },
        {
            attr: 'on-cleared',
            prop: 'onCleared',
            value: null
        },
        {
            attr: 'on-grafted',
            prop: 'onGrafted',
            value: null
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null
        },
        {
            attr: 'on-request',
            prop: 'onRequest',
            value: null
        },
        {
            attr: 'on-toofew',
            prop: 'onTooFew',
            value: null
        },
        {
            attr: 'on-toomany',
            prop: 'onTooMany',
            value: null
        },
        {
            attr: 'on-locked',
            prop: 'onLocked',
            value: null
        },
        {
            attr: 'on-unlocked',
            prop: 'onUnlocked',
            value: null
        },
        {
            attr: 'on-output',
            prop: 'onOutput',
            value: null
        },
        ...optBase
    ];

    class Select extends ModBaseListenCache {
        options = {};
        flatData;
        selectData;
        inputEl;
        tagsEl;
        arrowEl;
        toolsEl;
        listEl;
        wrapEl;
        searchEl;
        resultEl;
        keysEl;
        checkEl;
        statsEl;
        statusEl;
        statusHolderEl;
        popupIns;
        tagsIns;
        treeIns;
        output;
        rawHmtl;
        clearVals;
        static hostType = 'node';
        static optMaps = optSelect;
        constructor(elem, options = {}, initial = true) {
            super();
            let tmp = getEl(elem), host;
            if (!tmp)
                return this;
            if (['SELECT', 'INPUT'].includes(tmp.nodeName)) {
                this.inputEl = tmp;
                host = createEl('div', { class: `${orca.prefix}select` });
                tmp.insertAdjacentElement('afterend', host);
                host.appendChild(this.inputEl);
            }
            else {
                host = tmp;
                host.classList.add(`${orca.prefix}select`);
                this.inputEl = createEl('input', { type: 'hidden' });
            }
            super.ready({
                options,
                host,
                maps: Select.optMaps,
                component: true,
                spread: ['popup', 'search', 'tools']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch (err) {
                err ? console.error(err) : console.warn(config.warn.init);
                return this;
            }
            this.correctOpts();
            super.useTpl();
            this.renderMain();
            this.setAttrs();
            this.output = { value: '', raw: '', items: [] };
            if (this.options.popup.enable && !this.options.readonly) {
                this.setPopup();
                await this.popupIns.init();
            }
            else {
                this.popupIns && this.popupIns.destroy();
            }
            this.setTags();
            await this.tagsIns.init();
            this.setTree();
            await this.treeIns.init();
            this.renderFinish();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        renderMain() {
            this.targetEl.innerHTML = '';
            this.inputEl.setAttribute(orca.alias, 'input');
            let nameTmp = this.options.name;
            if (this.inputEl.nodeName === 'SELECT' && this.options.multiple)
                nameTmp += `[]`;
            this.options.name && (this.inputEl.name = nameTmp);
            this.targetEl.appendChild(this.inputEl);
            this.tagsEl = createEl('div', { [orca.alias]: 'tags' });
            this.arrowEl = createEl('i', { [orca.alias]: 'arrow' });
            this.targetEl.appendChild(this.tagsEl);
            if (this.options.tools.enable) {
                this.toolsEl = createTools(this.options.tools.children, null, this);
                this.tagsEl.insertAdjacentElement('afterend', this.toolsEl);
                this.toolsEl.setAttribute(orca.alias, 'tools');
                for (let k of this.options.tools.children) {
                    !k.tips && !k.title && this.options.lang.title[k.name] && k.wrapEl.setAttribute('title', this.options.lang.title[k.name]);
                    if (k.name === 'close') {
                        k.wrapEl.onclick = () => {
                            this.clearVals();
                        };
                    }
                }
            }
            this.options.popup.enable && this.targetEl.appendChild(this.arrowEl);
            this.listEl = createEl('div', { class: `${orca.prefix}select-list` });
            this.wrapEl = createEl('div', { class: `${orca.prefix}select-wrap` }, this.listEl);
            if (this.options.popup.enable && this.options.search.enable) {
                this.searchEl = createEl('div', { class: `${orca.prefix}select-search` });
                this.resultEl = createEl('div', { [orca.alias]: 'result' }, this.options.lang.search.start);
                if (!this.options.manual) {
                    this.keysEl = createEl('oc-input', { tools: true, placeholder: this.options.lang.search.placeholder, [orca.alias]: 'keys' });
                    this.searchEl.appendChild(this.keysEl);
                }
                this.options.search.result && this.searchEl.appendChild(this.resultEl);
                this.wrapEl.insertAdjacentElement('afterbegin', this.searchEl);
            }
            if (this.options.popup.enable && this.options.status) {
                this.checkEl = createEl('oc-checkbox', { label: this.options.lang.check.all, [orca.alias]: 'check' });
                !this.options.multiple && this.checkEl.toggleAttribute('disabled', true);
                this.statsEl = createEl('span', { [orca.alias]: 'stats' });
                this.statusEl = createEl('div', { class: `${orca.prefix}select-status` });
                this.statusEl.append(this.checkEl, this.statsEl);
                this.wrapEl.appendChild(this.statusEl);
                this.checkEl.on('check', (data) => {
                    if (data.value === 'ed') {
                        this.treeIns.checkAll();
                        this.checkEl.setAttribute('label', this.options.lang.check.none);
                    }
                    else if (data.value === 'ing') {
                        this.checkEl.setAttribute('label', this.options.lang.check.ing);
                    }
                    else {
                        this.treeIns.uncheckAll();
                        this.checkEl.setAttribute('label', this.options.lang.check.ed);
                    }
                });
                this.statusHolderEl = createEl('div', { class: `${orca.prefix}select-holder` });
                this.wrapEl.appendChild(this.statusHolderEl);
            }
        }
        updateResult(value, keys) {
            if (!this.options.popup.enable || !this.options.search.enable)
                return;
            this.resultEl.innerHTML = renderTpl(value ? this.options.lang.search.succ : (keys.length ? this.options.lang.search.fail : this.options.lang.search.start), { value, keys: keys.toString() });
        }
        updateStatus() {
            if (!this.options.popup.enable || !this.options.status)
                return;
            let total = this.treeIns.flatData.length, value = this.treeIns.getCheckeds().length;
            this.statsEl.innerHTML = renderTpl(this.options.lang.stats, { value, total });
            this.checkEl.setAttribute('check', !value ? '' : (total === value ? 'ed' : 'ing'));
        }
        setPopup() {
            let footer = this.options.multiple && !this.options.manual ? {
                children: [
                    {
                        name: 'clear',
                        action: (resp) => {
                            resp.el.onclick = () => {
                                this.treeIns.clearVals();
                            };
                        },
                    },
                    'confirm',
                    
                ]
            } : false, targetObj = {
                trigger: 'click',
                content: this.wrapEl,
                contType: 'node',
                placement: 'bottom-start',
                padding: false,
                arrow: false,
                tools: false,
                footer,
                canClick: (el) => {
                    let arr = [];
                    if (this.options.manual) {
                        arr = [this.arrowEl, this.targetEl, this.tagsEl];
                    }
                    else {
                        let dft = [this.arrowEl, this.targetEl, this.tagsEl, this.tagsEl.emptyEl], tmp = this.tagsIns.data.map((k) => [k.wralEl, k.labelEl, k.iconEl, k.diskEl, k.cubeEl, k.imageEl]).flat().filter(Boolean);
                        arr = !this.options.multiple ? [...tmp, ...dft] : dft;
                    }
                    return arr.includes(el) ? true : false;
                },
                onInitiated: () => {
                    this.popupIns.mainEl.classList.add(`${orca.prefix}select-popup`);
                    if (this.options.autoWidth && !(this.popupIns.options.adaptive && orca.screen === 'xxs')) {
                        this.popupIns.positionIns.on('changed', () => {
                            this.popupIns.mainEl.style.width = this.popupIns.positionIns.targetData.width + 'px';
                        });
                    }
                }
            }, params = extend({ target: targetObj, source: this.options.popup });
            this.popupIns && this.popupIns.destroy();
            this.popupIns = new Popup(this.targetEl, params, false);
        }
        setTags() {
            let content = this.options.popup.enable ?
                { content: '' } :
                {
                    content: this.rawHmtl || this.options.content,
                    contType: this.options.contType,
                    contData: this.options.contData,
                    ajx: this.options.ajax,
                }, opts = {
                ...content,
                field: this.options.field,
                min: this.options.multiple ? this.options.min : 0,
                max: this.options.multiple ? this.options.max : 1,
                sliced: this.options.sliced,
                compact: true,
                size: this.options.size,
                unique: { enable: this.options.manual ? this.options.unique : true },
                editor: !this.options.manual || this.options.readonly ? false : true,
                removable: this.options.readonly || !this.options.removable ? false : true,
                empty: { enable: !this.options.manual ? true : false, content: this.options.lang.placeholder },
                onRemoved: (items) => {
                    for (let k of items) {
                        this.treeIns.check(k[this.options.field], false);
                    }
                },
                onOutput: (data) => {
                    super.updateCache({ value: data.value });
                    this.output = data;
                    super.listen({ name: 'output', params: [this.output] });
                }
            };
            if (this.options.manual) {
                opts.b4Add = (data) => {
                    return new Promise(async (resolve, reject) => {
                        let rest = [];
                        for (let k of data) {
                            let tmp = this.treeIns.flatData.find((i) => k[this.options.field] === i[this.options.field]);
                            if (tmp) {
                                if (tmp.checked) {
                                    rest.push(k);
                                }
                                else {
                                    await this.treeIns.check(tmp, true);
                                }
                            }
                            else {
                                rest.push(k);
                            }
                        }
                        resolve(rest);
                    });
                };
                opts.onAdded = () => {
                    this.tagsIns.editEl.focus();
                };
            }
            this.tagsIns && this.tagsIns.initiated && this.tagsIns.destroy();
            this.tagsIns = new Tags(this.tagsEl, extend({
                target: opts,
                source: this.options.tags,
            }), false);
        }
        setTree() {
            this.listEl.innerHTML = this.rawHtml;
            let targetObj = {
                content: this.options.content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: this.options.ajax,
                passive: this.options.disabled,
                lang: {
                    empty: this.options.lang.empty,
                },
                search: {
                    target: this.options.search.enable ? (this.options.manual ? this.tagsIns.editEl : this.keysEl) : null,
                    trigger: this.options.manual ? 'input' : 'changed',
                    ignore: this.options.search.ignore,
                    fuzzy: this.options.search.fuzzy,
                    value: this.options.search.value,
                },
                disable: this.options.exclude,
                check: {
                    type: this.options.multiple ? 'checkbox' : 'radio',
                    value: this.options.value,
                    sliced: this.options.sliced,
                },
                feature: {
                    type: this.options.type,
                    check: {
                        linkage: false,
                        span: this.options.span,
                        only: this.options.multiple ? false : true,
                    },
                    expand: {
                        all: !this.options.collapse,
                    }
                },
                output: {
                    field: this.options.field,
                },
                onInitiated: () => {
                    this.updateStatus();
                },
                onChecked: (items) => {
                    if (!this.options.manual)
                        return;
                    this.tagsIns.add(items.map((k) => k[this.options.field]));
                    if (this.tagsIns.editEl.value) {
                        this.treeIns.search();
                        this.tagsIns.editEl.value = '';
                    }
                },
                onUnchecked: (items) => {
                    if (!this.options.manual)
                        return;
                    this.tagsIns.remove(items.map((k) => k[this.options.field]));
                },
                onCheckedAll: () => {
                    if (!this.options.manual)
                        return;
                    let tmp = this.treeIns.getCheckeds();
                    this.tagsIns.add(filterPrims(tmp));
                },
                onOutput: (data) => {
                    if (!this.options.manual) {
                        let vals = filterPrims(data.items);
                        this.popupIns && this.popupIns.state === 'shown' && !this.options.multiple && this.popupIns.hide();
                        this.tagsIns.updateCont(vals);
                        this.updateStatus();
                    }
                    fieldTools.setVals({
                        target: this.inputEl,
                        value: data.value.split(this.treeIns.options.output.separator),
                        separator: this.treeIns.options.output.separator
                    });
                },
                onSearched: (searchs, keys) => {
                    this.options.manual && this.popupIns && this.popupIns.show();
                    this.updateResult(searchs.length, keys);
                },
            }, params = extend({ target: targetObj, source: this.options.tree, });
            this.treeIns && this.treeIns.initiated && this.treeIns.destroy();
            this.treeIns = new Tree(this.listEl, params, false);
        }
        correctOpts() {
            if (this.inputEl.nodeName === 'SELECT') {
                this.options.manual = false;
                this.options.multiple = this.inputEl.multiple;
                this.options.span = 'leaf';
            }
            this.inputEl.disabled && (this.options.disabled = true);
            this.options.autoWidth && (this.options.popup.size = '');
            this.options.manual === false && (this.options.popup.enable = true);
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}select`);
            this.targetEl.setAttribute('tabindex', 0);
            this.options.classes && classes(this.targetEl).add(this.options.classes);
            this.targetEl.toggleAttribute('inert', this.options.disabled);
            this.inputEl.disabled = this.options.disabled;
            this.targetEl.setAttribute('size', this.options.size);
            this.targetEl.toggleAttribute('readonly', this.options.readonly);
            this.targetEl.toggleAttribute('full', this.options.full);
            this.targetEl.toggleAttribute('manual', this.options.manual);
            this.targetEl.toggleAttribute('multiple', this.options.multiple);
            this.options.maxHeight ? addStyle(this.listEl, 'moc-height', this.options.maxHeight) : removeStyle(this.listEl, 'moc-height');
        }
        renderFinish() {
        }
        getVals(cb) {
            if (this.destroyed)
                return this;
            return this.tagsIns.getVals((data) => {
                super.listen({ name: 'got', cb, params: [data] });
            });
        }
        async select(vals, cb) {
            if (this.destroyed)
                return this;
            let resp;
            if (this.options.manual) {
                await this.tagsIns.add(vals, (data) => {
                    resp = data;
                });
            }
            else {
                await this.treeIns.check(vals, true, (data) => {
                    resp = data;
                });
            }
            super.listen({ name: 'selected', cb, params: [resp] });
            return this;
        }
        async deselect(vals, cb) {
            if (this.destroyed || !this.tagsIns.data.length)
                return this;
            await this.tagsIns.remove(vals, (data) => {
                super.listen({ name: 'deselected', cb, params: [data] });
            });
            return this;
        }
        clear(cb) {
            if (this.destroyed)
                return this;
            this.treeIns.uncheckAll();
            this.options.manual && this.tagsIns.clear();
            super.listen({ name: 'cleared', cb });
            return this;
        }
        selectAll(cb) {
            if (this.destroyed)
                return this;
            this.treeIns.checkAll();
            super.listen({ name: 'selectedAll', cb });
            return this;
        }
        disable(cb) {
            this.treeIns.lock();
            this.targetEl.toggleAttribute('inert', true);
            this.inputEl.disabled = true;
            super.listen({ name: 'disabled', cb });
            return this;
        }
        enable(cb) {
            this.treeIns.unlock();
            this.targetEl.toggleAttribute('inert', false);
            this.inputEl.disabled = false;
            super.listen({ name: 'enabled', cb });
            return this;
        }
        destroy(cb) {
            if (this.destroyed)
                return this;
            if (this.options.popup.enable && !this.options.readonly) {
                this.popupIns.destroy();
            }
            this.treeIns.destroy();
            this.tagsIns.destroy();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    let OCTMP_separator = config.splitHyphen;
    const optUpload = [
        {
            attr: 'name',
            prop: 'name',
            value: '',
        },
        {
            attr: 'value',
            prop: 'value',
            value: '',
        },
        {
            attr: 'url',
            prop: 'url',
            value: '',
        },
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'disabled',
            prop: 'disabled',
            value: false,
        },
        {
            attr: 'readonly',
            prop: 'readonly',
            value: false,
        },
        {
            attr: 'multiple',
            prop: 'multiple',
            value: true,
        },
        {
            attr: 'manual',
            prop: 'manual',
            value: false,
        },
        {
            attr: 'type',
            prop: 'type',
            value: 'text',
        },
        {
            attr: 'icons',
            prop: 'icons',
            value: {},
        },
        {
            attr: 'cols',
            prop: 'cols',
            value: 4,
        },
        {
            attr: 'type-getter',
            prop: 'typeGetter',
            value: null,
        },
        {
            attr: 'feature',
            prop: 'feature',
            value: '',
        },
        {
            attr: 'limit',
            prop: 'limit',
            value: {
                min: 0,
                max: 0,
                size: 0,
                suffix: '',
            },
        },
        {
            attr: 'accept',
            prop: 'accept',
            value: '',
        },
        {
            attr: 'size',
            prop: 'size',
            value: 'md',
        },
        {
            attr: 'table',
            prop: 'table',
            value: {
                header: true,
            },
        },
        {
            attr: 'pastable',
            prop: 'pastable',
            value: true,
        },
        {
            attr: 'choose-btn',
            prop: 'chooseBtn',
            value: {
                target: '',
                icon: `${orca.prefix}icon-plus`,
                attrs: {},
            },
        },
        {
            attr: 'upload-btn',
            prop: 'uploadBtn',
            value: {
                enable: false,
                target: '',
                icon: `${orca.prefix}icon-upload`,
                attrs: {},
            },
        },
        {
            attr: 'clear-btn',
            prop: 'clearBtn',
            value: {
                enable: false,
                target: '',
                icon: `${orca.prefix}icon-trash`,
                attrs: {},
            },
        },
        {
            attr: 'picture-btn',
            prop: 'pictureBtn',
            value: {
                icon: `${orca.prefix}icon-plus`,
                attrs: {},
            },
        },
        {
            attr: 'gallery-btn',
            prop: 'galleryBtn',
            value: {
                icon: `${orca.prefix}icon-addpic`,
                attrs: {},
            },
        },
        {
            attr: 'separator',
            prop: 'separator',
            value: OCTMP_separator,
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'status',
            prop: 'status',
            value: '',
        },
        {
            attr: 'success',
            prop: 'success',
            value: (data) => data.code == 200,
        },
        {
            attr: 'cloud',
            prop: 'cloud',
            value: {
                enable: false,
                field: '',
                server: '',
                domain: '',
                map: { name: '', url: '', size: '', time: '' }
            },
        },
        {
            attr: 'b4-clear',
            prop: 'b4Clear',
            value: null,
        },
        {
            attr: 'b4-remove',
            prop: 'b4Remove',
            value: null,
        },
        {
            attr: 'b4-upload',
            prop: 'b4Upload',
            value: null,
        },
        {
            attr: 'b4-uploadall',
            prop: 'b4UploadAll',
            value: null,
        },
        {
            attr: 'on-output',
            prop: 'onOutput',
            value: null,
        }, {
            attr: 'on-rendered',
            prop: 'onRendered',
            value: null,
        },
        {
            attr: 'on-added',
            prop: 'onAdded',
            value: null
        },
        {
            attr: 'on-removed',
            prop: 'onRemoved',
            value: null
        },
        {
            attr: 'on-cleared',
            prop: 'onCleared',
            value: null
        },
        {
            attr: 'on-pasted',
            prop: 'onPasted',
            value: null
        },
        {
            attr: 'on-dropped',
            prop: 'onDropped',
            value: null
        },
        {
            attr: 'on-uploading',
            prop: 'onUploading',
            value: null
        },
        {
            attr: 'on-uploaded',
            prop: 'onUploaded',
            value: null
        },
        {
            attr: 'on-received',
            prop: 'onReceived',
            value: null
        },
        {
            attr: 'on-receivedAll',
            prop: 'onReceivedAll',
            value: null
        },
        {
            attr: 'on-uploadAll',
            prop: 'onUploadAll',
            value: null
        },
        {
            attr: 'on-uploadedAll',
            prop: 'onUploadedAll',
            value: null
        }, {
            attr: 'on-failed',
            prop: 'onFailed',
            value: null
        },
        {
            attr: 'on-error',
            prop: 'onError',
            value: null
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null
        },
        {
            attr: 'on-request',
            prop: 'onRequest',
            value: null
        },
        {
            attr: 'on-locked',
            prop: 'onLocked',
            value: null
        },
        {
            attr: 'on-unlocked',
            prop: 'onUnlocked',
            value: null
        },
        ...optBase
    ];

    class Upload extends ModBaseListenCache {
        options = {};
        flatData;
        treeData;
        dftTypes;
        fileChangeEvt;
        chooseEvt;
        clearEvt;
        uploadEvt;
        dragLeaveEvt;
        dragOverEvt;
        dragEnterEvt;
        dropEvt;
        tipsEl;
        summaryEl;
        infoEl;
        listEl;
        tableEl;
        theadEl;
        fileEl;
        inputEl;
        footEl;
        headEl;
        chooseBtn;
        uploadBtn;
        clearBtn;
        ctrlvEl;
        tipsText;
        name;
        singleSizeLimit;
        fileTypes;
        passedItems;
        allItems;
        output;
        files;
        value;
        validItems;
        static hostType = 'node';
        static optMaps = optUpload;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Upload.optMaps,
                component: true,
                spread: ['cloud', 'uploadBtn', 'clearBtn']
            });
            
            
            
            
            
            
            
            
            
            
            
            
            
            this.dftTypes = {
                'image': `${orca.prefix}icon-image`,
                'video': `${orca.prefix}icon-video`,
                'audio': `${orca.prefix}icon-music`,
                'file': `${orca.prefix}icon-file-text`,
            };
            let _this = this;
            this.fileChangeEvt = function () {
                let files = [...this.files];
                _this.renderList(files);
                this.value = '';
                _this.listen({ name: 'changed', params: [files] });
            };
            this.chooseEvt = () => {
                let globalValid = this.globalValid();
                if (!globalValid.passed) {
                    new Message({
                        content: globalValid.msg,
                        status: 'error',
                    }).show();
                    return;
                }
                this.fileEl.click();
            };
            this.clearEvt = () => {
                this.clear.call(this);
            };
            this.uploadEvt = () => {
                this.uploadAll();
            };
            this.dragLeaveEvt = (e) => {
                e.preventDefault();
                this.targetEl.removeAttribute('dragging');
            };
            this.dragOverEvt = (e) => {
                e.preventDefault();
                this.targetEl.toggleAttribute('dragging', true);
            };
            this.dragEnterEvt = (e) => {
                e.preventDefault();
            };
            this.dropEvt = async (e) => {
                e.preventDefault();
                this.targetEl.removeAttribute('dragging');
                let items = e.dataTransfer.items;
                for (let k of items) {
                    if (k.kind === "file") {
                        let entry = k.webkitGetAsEntry();
                        this.getEntries(entry);
                    }
                }
                super.listen({ name: 'dropped', params: [items] });
            };
            this.tipsEl = createEl('div', { [orca.alias]: 'tips' });
            this.summaryEl = createEl('div', { [orca.alias]: 'summary' });
            this.infoEl = createEl('div', { class: `${orca.prefix}upload-info` });
            this.createSetList();
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        createSetList() {
            let classes = orca.prefix + 'reset';
            if (this.options.type === 'card') {
                classes += ` ${orca.prefix}grid ${orca.prefix}g-xs`;
                this.options.cols && (classes += ` ${orca.prefix}avg-${this.options.cols}`);
            }
            this.listEl = createEl(this.options.type === 'table' ? 'table' : 'ul', { class: `${this.options.type !== 'table' ? classes : ''} ${orca.prefix}upload-list` });
            if (this.options.type === 'table') {
                this.tableEl = createEl('table');
                this.listEl = createEl('tbody', { class: `${orca.prefix}upload-list` });
                if (this.options.table.header) {
                    this.theadEl = createEl('thead', {}, this.options.lang.thead.map((k) => `<th>${k}</th>`).join(''));
                    this.tableEl.appendChild(this.theadEl);
                }
                this.tableEl.appendChild(this.listEl);
            }
            else {
                this.listEl = createEl('ul', { class: `${classes} ${orca.prefix}upload-list` });
            }
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch (err) {
                err ? console.error(err) : console.warn(config.warn.init);
                return this;
            }
            this.passedItems = [];
            this.allItems = [];
            this.output = { value: '', raw: '', items: [] };
            this.singleSizeLimit = this.options.limit.size * 1024 * 1024;
            this.setFeature();
            this.getFileTypes();
            this.name = this.targetEl.name || this.options.name;
            this.createSkeleton();
            this.setAttrs();
            this.renderFinish();
            this.initShow();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        initShow() {
            if (!isEmpty(this.options.value)) {
                this.add(this.options.value);
            }
            else {
                let tmp = this.rawHtml.trim();
                tmp && this.add(tmp);
            }
        }
        setFeature() {
            if (this.options.feature === 'picture') {
                this.options.type = 'cube';
            }
        }
        getFileTypes() {
            this.fileTypes = { ...this.dftTypes, ...this.options.icons };
        }
        getTips() {
            this.tipsText = [this.options.lang.tips.free];
            this.options.limit.suffix && this.tipsText.push(renderTpl(this.options.lang.tips.suffix, { value: this.options.limit.suffix }));
            this.options.limit.size && this.tipsText.push(renderTpl(this.options.lang.tips.size, { value: this.options.limit.size }));
            this.options.limit.min && this.tipsText.push(renderTpl(this.options.lang.tips.min, { value: this.options.limit.min }));
            this.options.limit.max && this.tipsText.push(renderTpl(this.options.lang.tips.max, { value: this.options.limit.max }));
            return this.tipsText.join(',');
        }
        createStart() {
            if (this.options.feature === 'gallery') {
                this.chooseBtn = this.createBox(this.options.feature, 'div');
            }
            else if (this.options.feature === 'picture') {
                this.chooseBtn = this.createBox(this.options.feature, 'li');
            }
            else {
                this.chooseBtn = getEl(this.options.chooseBtn.target) || this.createBtn('choose');
            }
        }
        createBox(type, node = 'li') {
            let iconStr = this.options[type + 'Btn'].icon ? `<i ${orca.alias}="icon" class="${this.options[type + 'Btn'].icon}"></i>` : '', textStr = this.options.lang.button[type] ? `<div ${orca.alias}="text">${this.options.lang.button[type]}</div>` : '';
            return createEl(node, Object.assign({ [orca.alias]: ['picture', 'gallery'].includes(type) ? 'choose' : type }, type !== 'gallery' ? { tabindex: 0 } : {}, this.options[type + 'Btn'].attrs), `${iconStr}${textStr}`);
        }
        createBtn(type) {
            return createEl('oc-btn', Object.assign({ [orca.alias]: type, size: this.options.size, tabindex: 0, icon: this.options[type + 'Btn'].icon, label: this.options.lang.button[type] }, this.options[type + 'Btn'].attrs));
        }
        createInput(hasText = true, hasFile = true) {
            if (hasText) {
                this.inputEl = createEl('input', { type: 'hidden', readonly: '', name: this.name });
            }
            if (hasFile) {
                this.fileEl = createEl('input', { type: 'file', readonly: '' });
            }
        }
        createSkeleton() {
            if (this.targetEl) {
                if (this.targetEl.nodeName === 'INPUT') {
                    let tmp = this.targetEl;
                    if (tmp.type === 'file') {
                        this.fileEl = tmp;
                        this.fileEl.readOnly = true;
                        this.createInput(true, false);
                    }
                    else {
                        this.inputEl = tmp;
                        this.inputEl.type = 'hidden';
                        this.inputEl.name = this.name;
                        this.inputEl.readOnly = true;
                        this.createInput(false, true);
                    }
                    this.targetEl = createEl('div');
                    tmp.insertAdjacentElement('beforeBegin', this.targetEl);
                }
                else {
                    this.createInput(true, true);
                }
            }
            else {
                this.targetEl = createEl('div');
                this.createInput(true, true);
            }
            this.inputEl.toggleAttribute(orca.embedSign, true);
            this.fileEl.toggleAttribute(orca.embedSign, true);
            this.targetEl.innerHTML = this.listEl.innerHTML = '';
            this.options.accept && this.fileEl.setAttribute('accept', this.options.accept);
            if (this.fileEl.multiple) {
                this.options.multiple = true;
            }
            else {
                this.options.multiple && (this.fileEl.toggleAttribute('multiple', true));
            }
            !this.fileEl.multiple && (this.options.limit.min = 0, this.options.limit.max = 1);
            this.targetEl.append(this.inputEl, this.fileEl);
            this.targetEl.appendChild(this.options.type === 'table' ? this.tableEl : this.listEl);
            this.footEl = createEl('div', { class: `${orca.prefix}upload-foot` }, this.infoEl);
            if (this.options.status) {
                this.targetEl.setAttribute('status', this.options.status);
                if (this.options.status.includes('tips')) {
                    this.tipsEl.innerHTML = this.getTips();
                    this.infoEl.appendChild(this.tipsEl);
                }
                if (this.options.status.includes('summary')) {
                    this.summaryEl.innerHTML = this.getSummary();
                    this.infoEl.appendChild(this.summaryEl);
                }
            }
            if (this.options.feature === 'gallery') {
                this.createCtrlv();
                this.targetEl.appendChild(this.footEl);
                this.chooseBtn = this.createBox(this.options.feature, 'div');
                this.targetEl.insertAdjacentElement('afterBegin', this.chooseBtn);
                this.targetEl.setAttribute('tabindex', 0);
                if (this.options.clearBtn.enable) {
                    this.clearBtn = this.createBtn('clear');
                    this.footEl.appendChild(this.clearBtn);
                }
                if (this.options.uploadBtn.enable) {
                    this.uploadBtn = this.createBtn('upload');
                    this.footEl.appendChild(this.uploadBtn);
                }
            }
            else if (this.options.feature === 'picture') {
                this.targetEl.appendChild(this.footEl);
                this.chooseBtn = this.createBox(this.options.feature, 'li');
                this.listEl.appendChild(this.chooseBtn);
                if (this.options.clearBtn.enable) {
                    this.clearBtn = this.createBox('clear', 'li');
                    this.chooseBtn.insertAdjacentElement('afterEnd', this.clearBtn);
                }
                if (this.options.uploadBtn.enable) {
                    this.uploadBtn = this.createBox('upload', 'li');
                    this.chooseBtn.insertAdjacentElement('afterEnd', this.uploadBtn);
                }
            }
            else {
                this.headEl = createEl('div', { class: `${orca.prefix}upload-head` });
                this.listEl.insertAdjacentElement('beforeBegin', this.footEl);
                let btn = getEl(this.options.chooseBtn.target);
                if (btn) {
                    this.chooseBtn = btn;
                }
                else {
                    this.chooseBtn = this.createBtn('choose');
                    this.headEl.appendChild(this.chooseBtn);
                }
                if (this.options.uploadBtn.enable) {
                    let tmp = getEl(this.options.uploadBtn.target);
                    if (tmp) {
                        this.uploadBtn = tmp;
                    }
                    else {
                        this.uploadBtn = this.createBtn('upload');
                        this.headEl.appendChild(this.uploadBtn);
                    }
                }
                if (this.options.clearBtn.enable) {
                    let tmp = getEl(this.options.clearBtn.target);
                    if (tmp) {
                        this.clearBtn = tmp;
                    }
                    else {
                        this.clearBtn = this.createBtn('clear');
                        this.headEl.appendChild(this.clearBtn);
                    }
                }
                this.targetEl.insertAdjacentElement('afterBegin', this.headEl);
            }
        }
        addEvts() {
            this.chooseBtn.addEventListener('click', this.chooseEvt, false);
            this.uploadBtn && this.uploadBtn.addEventListener('click', this.uploadEvt, false);
            this.clearBtn && this.clearBtn.addEventListener('click', this.clearEvt, false);
            this.fileEl.addEventListener('change', this.fileChangeEvt, false);
            this.targetEl.addEventListener("dragleave", this.dragLeaveEvt, false);
            this.targetEl.addEventListener("dragover", this.dragOverEvt, false);
            this.targetEl.addEventListener("dragenter", this.dragEnterEvt, false);
            this.targetEl.addEventListener("drop", this.dropEvt, false);
        }
        removeEvts() {
            this.chooseBtn.removeEventListener('click', this.chooseEvt);
            this.uploadBtn && this.uploadBtn.removeEventListener('click', this.uploadEvt);
            this.clearBtn && this.clearBtn.removeEventListener('click', this.clearEvt);
            this.fileEl.removeEventListener('change', this.fileChangeEvt);
            this.targetEl.removeEventListener("dragleave", this.dragLeaveEvt);
            this.targetEl.removeEventListener("dragover", this.dragOverEvt);
            this.targetEl.removeEventListener("dragenter", this.dragEnterEvt);
            this.targetEl.removeEventListener("drop", this.dropEvt);
        }
        renderFinish() {
            this.removeEvts();
            this.addEvts();
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}upload`);
            this.options.type ? this.targetEl.setAttribute('type', this.options.type) : this.targetEl.removeAttribute('type');
            this.targetEl.toggleAttribute('pastable', this.options.pastable);
            this.targetEl.toggleAttribute('inert', this.options.disabled);
            this.options.feature ? this.targetEl.setAttribute('feature', this.options.feature) : this.targetEl.removeAttribute('feature');
            this.targetEl.setAttribute('size', this.options.size);
            this.updateInsProg('ready');
        }
        createCtrlv() {
            if (this.options.pastable) {
                this.ctrlvEl = createEl('i', { [orca.alias]: 'ctrlv' }, this.options.lang.paste.before);
                this.targetEl.appendChild(this.ctrlvEl);
                this.ctrlvEl.onclick = () => {
                    this.ctrlvEl.innerHTML = this.options.lang.paste.ing;
                    this.ctrlvEl.toggleAttribute('contenteditable', true);
                    this.ctrlvEl.focus();
                };
                this.ctrlvEl.onpaste = (e) => {
                    e.preventDefault();
                    this.ctrlvEl.toggleAttribute('contenteditable', false);
                    let data = e.clipboardData;
                    if (data) {
                        let item = data.items[0];
                        if (item && item.kind === 'file' && item.type.includes('image')) {
                            this.renderList([item.getAsFile()]);
                            this.ctrlvEl && (this.ctrlvEl.innerHTML = this.options.lang.paste.after);
                        }
                        super.listen({ name: 'pasted', params: [item] });
                    }
                };
                this.targetEl.onmouseleave = () => {
                    this.ctrlvEl.innerHTML = this.options.lang.paste.before;
                };
            }
        }
        getSummary() {
            let originalSize = 0, realSize, totalNum = this.passedItems.length, receivedItems = this.passedItems.filter((i) => i.progress == 'received'), okNum = receivedItems.length;
            for (let k of receivedItems) {
                originalSize += k.file.size;
            }
            realSize = convertByte({ val: originalSize }).str;
            return renderTpl(this.options.lang.summary, { total: totalNum, count: okNum, size: realSize });
        }
        createItem(item) {
            let name = item.file.name, size = item.file.size, passed = item.valid.passed, msg = item.valid.msg, tpl = '', part1 = `
        <div class="${orca.prefix}upload-mask">
            ${this.options.manual ? '<i ' + orca.alias + '="upload" class="' + orca.prefix + 'icon-upload"></i>' : ''}
            <i ${orca.alias}="view" class="${orca.prefix}icon-zoomin"></i>
            <a ${orca.alias}="download" href="###" class="${orca.prefix}icon-download"></a>
            <i ${orca.alias}="remove" class="${orca.prefix}icon-trash"></i>
        </div>
        <oc-progress ${orca.alias}="progress" thk="xs" size="sm" type="circle"></oc-progress>
        <i ${orca.alias}="state"></i>
        <i ${orca.alias}="sign" class="${orca.prefix}icon-check"></i>
        <div ${orca.alias}="message">${passed ? msg : ''}</div>
        `, part2 = `
                <div class="${orca.prefix}upload-info">
                    <a href="###" ${orca.alias}="title">${name}</a>
                    ${this.options.type === 'bullet' ? '<div ' + orca.alias + '="size">' + convertByte({ val: size }).str + '</div>' : ''}
                </div>
                <oc-progress ${orca.alias}="progress" label="false" thk="xs"></oc-progress>
                <i ${orca.alias}="message">${passed ? msg : ''}</i>
                <i ${orca.alias}="percent"></i>
                <i ${orca.alias}="state"></i>
                <i ${orca.alias}="sign" class="${orca.prefix}icon-check"></i>
                ${this.options.manual ? '<i ' + orca.alias + '="upload" class="' + orca.prefix + 'icon-upload"></i>' : ''}
                <i ${orca.alias}="remove" class="${orca.prefix}icon-trash"></i>
                `;
            if (this.options.type === 'card') {
                tpl = `
                    <li valid=${passed ? 'success' : 'failed'}>
                        <div class="${orca.prefix}upload-file">
                            ${part1}
                        </div>
                        <div class="${orca.prefix}upload-info">
                            <div ${orca.alias}="title">${name}</div>
                            <div ${orca.alias}="size">${convertByte({ val: size }).str}</div>
                            <div ${orca.alias}="url"></div>
                        </div>
                    </li>
                    `;
            }
            else if (this.options.type === 'cube') {
                tpl = `
                    <li valid=${passed ? 'success' : 'failed'}>
                        <div class="${orca.prefix}upload-file"></div>
                        ${part1}
                    </li>
                    `;
            }
            else if (this.options.type == 'bullet') {
                tpl = `
                    <li valid=${passed ? 'success' : 'failed'}>
                        <a href="###" class="${orca.prefix}upload-file"></a>
                        ${part2}
                    </li>
                    `;
            }
            else if (this.options.type === 'table') {
                let btns = `
                ${this.options.manual ? '<i ' + orca.alias + '="upload" class="' + orca.prefix + 'icon-upload"></i>' : ''}
                <i ${orca.alias}="remove" class="${orca.prefix}icon-trash"></i>
            `;
                tpl = `
                    <tr valid=${passed ? 'success' : 'failed'}>
                        <td><div class="${orca.prefix}upload-file"></div></td>
                        <td><div class="${orca.prefix}upload-info"><a href="###" ${orca.alias}="title">${name}</a></div></td>
                        <td>${convertByte({ val: size }).str}</td>
                        <td><oc-progress ${orca.alias}="progress" thk="sm"></oc-progress></td>
                        <td><i ${orca.alias}="message">${passed ? msg : ''}</i></td>
                        <td><span ${orca.alias}="state">${passed ? this.options.lang.progress.passed : this.options.lang.progress.notPassed}</span></td>
                        <td>${btns}</td>
                    </tr>
                    `;
            }
            else {
                tpl = `
                    <li valid=${passed ? 'success' : 'failed'}>
                        <i ${orca.alias}="icon" class="${orca.prefix}icon-attach"></i>
                        ${part2}
                    </li>
                    `;
            }
            item.wrapEl = tplToEl(tpl);
            item.fileEl = item.wrapEl.querySelector(`.${orca.prefix}upload-file`);
            item.fileEl && this.fillHeader(item);
            if (this.options.feature === 'picture') {
                this.chooseBtn.insertAdjacentElement('beforeBegin', item.wrapEl);
            }
            else {
                this.listEl.appendChild(item.wrapEl);
            }
        }
        updateInsProg(prog) {
            this.targetEl.setAttribute('progress', prog);
        }
        updateItemProg(item, prog) {
            item.progress = prog;
            item.wrapEl.setAttribute('progress', prog);
            item.stateEl && (item.stateEl.innerHTML = this.options.lang.progress[prog]);
        }
        updateItemValid(item, valid) {
            item.wrapEl.setAttribute('valid', valid);
        }
        renderItem(file) {
            let fileValid = this.fileValid(file), item = { file, valid: fileValid };
            this.createItem(item);
            item.uploadEl = item.wrapEl.querySelector(`[${orca.alias}="upload"]`);
            item.removeEl = item.wrapEl.querySelector(`[${orca.alias}="remove"]`);
            item.stateEl = item.wrapEl.querySelector(`[${orca.alias}="state"]`);
            item.msgEl = item.wrapEl.querySelector(`[${orca.alias}="message"]`);
            item.progEl = item.wrapEl.querySelector(`oc-progress`);
            if (item.uploadEl) {
                item.uploadEl.onclick = async () => {
                    try {
                        this.options.b4Upload && await this.options.b4Upload.call(this, item);
                    }
                    catch (err) {
                        err ? console.error(err) : console.warn('The "upload" operation has been blocked!');
                        return this;
                    }
                    this.upload(item);
                };
            }
            if (item.removeEl) {
                item.removeEl.onclick = async () => {
                    try {
                        this.options.b4Remove && await this.options.b4Remove.call(this, item);
                    }
                    catch (err) {
                        err ? console.error(err) : console.warn('The "remove" operation has been blocked!');
                        return this;
                    }
                    this.remove(item);
                };
            }
            this.allItems.push(item);
            fileValid.passed && this.passedItems.push(item);
            this.updateItemProg(item, 'rendered');
            super.listen({ name: 'rendered', params: [item] });
            return item;
        }
        getEntries(entry) {
            if (entry.isFile) {
                entry.file((i) => this.renderList([i]));
            }
            else {
                entry.createReader().readEntries((k) => k.forEach((i) => this.getEntries(i)));
            }
        }
        hasSame(file) {
            return this.allItems.length ? this.allItems.some((i) => (i.file.name === file.name && i.file.size === file.size)) : false;
        }
        renderList(files) {
            if (!files.length)
                return;
            for (let k of files) {
                !this.hasSame(k) && this.renderItem(k);
            }
            !this.options.manual && this.uploadAll();
            this.updateInsProg('processing');
        }
        async uploadAll(cb) {
            if (!this.options.url)
                throw new Error('The parameter "url" (the address of the page to send data) is required!');
            let globalValid = this.globalValid();
            if (!globalValid.passed) {
                new Message({
                    content: globalValid.msg,
                    status: 'error',
                }).show();
                return this;
            }
            else {
                if (this.allItems.length < this.options.limit.min) {
                    new Message({
                        content: globalValid.msg,
                        status: 'warn',
                    }).show();
                }
            }
            let items = this.getUploadingItems();
            try {
                this.options.b4UploadAll && await this.options.b4UploadAll.call(this, items);
            }
            catch (err) {
                err ? console.error(err) : console.warn('The "upload all files" operation has been blocked!');
                return this;
            }
            super.listen({ name: 'uploadAll', cb, params: [items] });
            this.saveRaw();
            await Promise.all(items.map((k) => this.upload(k, true)));
            this.setInputVal();
            this.listenReceivedAll();
            return this;
        }
        getUploadingItems() {
            return this.passedItems.filter((i) => this.canUpload(i));
        }
        actOpt(item) {
            let file = item.file, dom = item.wrapEl, url = item.data.url; item.file.name;
            if (this.options.cloud.enable)
                url = url ? this.options.cloud.domain + url : 'javascript:void(0);';
            let downloadBtn = dom.querySelector(`[${orca.alias}="download"]`), viewBtn = dom.querySelector(`[${orca.alias}="view"]`);
            if (downloadBtn) {
                if (this.options.cloud.enable) {
                    downloadBtn.onclick = () => fileTools.download(url, file.name);
                }
                else {
                    downloadBtn.setAttribute('download', '');
                    downloadBtn.setAttribute('href', url);
                }
            }
            if (viewBtn) {
                this.getFileType(file);
            }
            if (['text', 'bullet', 'table'].includes(this.options.type)) {
                let titleEl = dom.querySelector(`[${orca.alias}="title"]`), fileEl = dom.querySelector(`.${orca.prefix}upload-file`);
                titleEl.setAttribute('href', url);
                titleEl.setAttribute('target', '_blank');
                if (fileEl) {
                    fileEl.setAttribute('href', url);
                    fileEl.setAttribute('target', '_blank');
                }
            }
        }
        canUpload(item) {
            return item.valid.passed && !['uploading', 'uploaded', 'received'].includes(item.progress);
        }
        async upload(item, eager = false) {
            let data = new FormData(), file = item.file, dom = item.wrapEl, fixEl = (flag, message) => {
                if (flag) {
                    this.actOpt(item);
                    this.updateItemProg(item, 'received');
                }
                else {
                    this.updateItemProg(item, 'failed');
                    this.updateItemValid(item, 'failed');
                    item.msgEl.innerText = message;
                    this.passedItems = this.allItems.filter((i) => i.valid.passed);
                }
                this.options.status.includes('summary') && (this.summaryEl.innerHTML = this.getSummary());
            };
            if (!this.canUpload(item))
                return this;
            try {
                this.options.b4Upload && await this.options.b4Upload.call(this, item);
            }
            catch (err) {
                err ? console.error(err) : console.warn('The "upload" operation has been blocked!');
                return this;
            }
            data.append(this.name || 'file', file);
            if (this.options.cloud.enable) {
                await ajax({
                    url: this.options.url,
                    before: () => {
                        this.updateItemProg(item, 'getAuth');
                    },
                    success: (resp) => {
                        for (let k in resp.content)
                            data.append(k, resp.content[k]);
                        this.options.cloud.append && this.options.cloud.append(data, file);
                        this.updateItemProg(item, 'authorized');
                    },
                    error: () => {
                        this.updateItemProg(item, 'unauthorized');
                        this.updateItemValid(item, 'failed');
                        this.validItems = this.allItems.filter((i) => i.valid.passed);
                        return;
                    }
                });
            }
            this.updateItemProg(item, 'uploading');
            !eager && this.saveRaw();
            await ajax({
                url: this.options.cloud.enable ? this.options.cloud.server : this.options.url,
                data,
                uploading: (resp) => {
                    item.abort = resp.abort;
                    item.progEl.setAttribute('value', resp.percent);
                    if (['text', 'bullet'].includes(this.options.type)) {
                        dom.querySelector(`[${orca.alias}="percent"]`).innerHTML = resp.result;
                    }
                    if (resp.percent >= 100) {
                        this.updateItemProg(item, 'uploaded');
                        super.listen({ name: 'uploaded', params: [item] });
                        if (this.passedItems.every((i) => i.valid.passed && ['uploaded', 'received'].includes(i.progress))) {
                            super.listen({ name: 'uploadedAll' });
                        }
                    }
                    else {
                        this.updateItemProg(item, 'uploading');
                        super.listen({ name: 'uploading', params: [{ item, content: resp }] });
                    }
                },
                success: async (resp) => {
                    let name = '', msg = '', url = '', size = 0, time = 0, passed, map = this.options.cloud.map, forceMsg = (item, msg, type) => {
                        if (msg) {
                            item.valid.msg = msg;
                        }
                        else {
                            item.valid.msg = this.options.lang.message.single[type];
                        }
                    }, getKeys = (obj, str) => {
                        if (!str)
                            return '';
                        if (!str.includes('.'))
                            return obj[str];
                        let arr = str.split("."), len = arr.length, value = len === 1 ? obj[arr[0]] : len === 2 ? obj[arr[0]][arr[1]] : '';
                        return value;
                    };
                    if (this.options.cloud.enable) {
                        name = getKeys(resp.content, map.name || 'name');
                        url = getKeys(resp.content, map.url || 'url');
                        size = getKeys(resp.content, map.size || 'size');
                        time = getKeys(resp.content, map.time || 'time');
                        msg = getKeys(resp.content, map.msg || 'msg');
                    }
                    else {
                        name = resp.content.name || item.file.name;
                        url = resp.content.url;
                        size = file.size;
                        time = resp.content.time;
                        msg = resp.content.msg;
                    }
                    passed = (this.options.success && this.options.success(resp.content)) || !!url;
                    item.resp = resp.content;
                    item.data = { name, url, size, time };
                    item.valid.passed = passed;
                    if (!passed) {
                        forceMsg(item, msg, 'failed');
                        super.listen({ name: 'failed', params: [{ item, content: resp.content }] });
                    }
                    else {
                        forceMsg(item, msg, 'success');
                        super.listen({ name: 'received', params: [{ item, content: resp.content }] });
                    }
                    fixEl(passed, item.valid.msg);
                },
                error: (resp) => {
                    fixEl(false, this.options.lang.message.single.failed);
                    super.listen({ name: 'error', params: [{ item, content: resp.content }] });
                }
            });
            if (!eager) {
                this.setInputVal();
                this.listenReceivedAll();
            }
        }
        listenReceivedAll() {
            if (this.passedItems.every((i) => i.valid.passed && i.progress == 'received')) {
                super.listen({ name: 'receivedAll' });
            }
        }
        items2Vals(vals = this.passedItems) {
            let items = vals.map((k) => k.data).filter(Boolean), arr = [];
            for (let k of items)
                arr.push(k.url);
            return { value: arr.join(this.options.separator), items };
        }
        saveRaw(items = this.passedItems) {
            this.output.raw = this.items2Vals(items).value;
        }
        setInputVal(value = this.passedItems) {
            Object.assign(this.output, this.items2Vals(value));
            if (this.inputEl) {
                this.inputEl.value = this.output.value;
                this.inputEl.onchange && this.inputEl.onchange();
            }
            super.listen({ name: 'output', params: [this.output] });
        }
        getFileType(file) {
            let type = file.type, sfx = fileTools.getSuffix(file).toLowerCase(), tmp = '';
            if (type.startsWith('image')) {
                tmp = 'image';
            }
            else if (type.startsWith('video')) {
                tmp = 'video';
            }
            else if (type.startsWith('audio')) {
                tmp = 'audio';
            }
            else {
                tmp = this.options.typeGetter ? this.options.typeGetter(file, sfx) : 'file';
            }
            return tmp;
        }
        async fillHeader(item) {
            let file = item.file, type = this.getFileType(file), elem;
            if (type === 'image') {
                await fileTools.getBase64(file, (data) => { elem = createEl('img', { src: data }); });
            }
            else if (['video', 'audio'].includes(type)) {
                await fileTools.getBase64(file, (data) => elem = createEl(type, { src: data, controls: '' }));
            }
            else {
                elem = createEl('i', { class: this.fileTypes[type] || this.fileTypes.file, [orca.alias]: 'icon' });
            }
            item.fileEl.appendChild(elem);
        }
        fileValid(file) {
            let msg = this.options.lang.message.single.passed, passed = true, suffix = fileTools.getSuffix(file);
            if (this.allItems.length > this.options.limit.max && this.options.limit.max) {
                msg = this.options.lang.message.single.max;
                passed = false;
            }
            else if (this.singleSizeLimit && (file.size > this.singleSizeLimit)) {
                msg = this.options.lang.message.single.size;
                passed = false;
            }
            else if (this.options.limit.suffix && !this.options.limit.suffix.includes(suffix)) {
                msg = this.options.lang.message.single.suffix;
                passed = false;
            }
            return { passed, msg };
        }
        globalValid() {
            let msg = this.options.lang.message.global.passed, passed = true;
            if (this.allItems.length < this.options.limit.min) {
                msg = renderTpl(this.options.lang.message.global.min, { value: this.options.limit.min });
                passed = true;
            }
            else if (this.options.limit.max && this.allItems.length > this.options.limit.max) {
                msg = renderTpl(this.options.lang.message.global.max, { value: this.options.limit.max });
                passed = false;
            }
            return { passed, msg };
        }
        findItem(data) {
            let type = getDataType(data), result;
            if (type === 'String') {
                result = this.allItems.find((i) => i.file.name === data);
            }
            else if (type === 'Number') {
                result = this.allItems[data];
            }
            else if (type === 'File') {
                result = this.allItems.find((i) => i.file === data);
            }
            else if (type === 'Object' && data.wrapEl) {
                result = this.allItems.find((i) => i === data);
            }
            return result;
        }
        async remove(data, cb) {
            if (this.destroyed)
                return this;
            let item = this.findItem(data);
            if (!item)
                return this;
            try {
                this.options.b4Remove && await this.options.b4Remove.call(this, item);
            }
            catch (err) {
                err ? console.error(err) : console.warn('The "remove" operation has been blocked!');
                return this;
            }
            this.saveRaw();
            item.abort && item.abort();
            item.wrapEl.remove();
            this.allItems = this.allItems.filter((i) => i !== item);
            this.passedItems = this.passedItems.filter((i) => i !== item);
            if (this.passedItems.length) {
                this.setInputVal();
            }
            else {
                this.updateInsProg('ready');
                this.setInputVal();
            }
            this.options.status.includes('summary') && (this.summaryEl.innerHTML = this.getSummary());
            super.listen({ name: 'removed', cb, params: [item] });
            return this;
        }
        async clear(cb) {
            if (this.destroyed)
                return this;
            try {
                this.options.b4Clear && await this.options.b4Clear.call(this);
            }
            catch (err) {
                err ? console.error(err) : console.warn('The "clear" operation has been blocked!');
                return this;
            }
            this.saveRaw();
            for (let k of this.passedItems) {
                k.abort && k.abort();
                k.wrapEl.remove();
            }
            this.passedItems = [];
            this.allItems = [];
            this.setInputVal();
            this.updateInsProg('ready');
            this.options.status.includes('summary') && (this.summaryEl.innerHTML = this.getSummary());
            super.listen({ name: 'cleared', cb });
            return this;
        }
        getVals() {
            if (this.destroyed)
                return this;
            return this.inputEl.value;
        }
        async add(data, cb) {
            if (this.destroyed)
                return this;
            let newData = valToArr(data).map((k) => { return typeof k === 'string' ? { url: k, name: '' } : k; }).filter(Boolean), result = [];
            if (!newData.length)
                return;
            this.updateInsProg('processing');
            this.saveRaw();
            for (let k of newData) {
                try {
                    await fileTools.urlToFile(k.url, k.name, (file) => {
                        if (this.hasSame(file))
                            return;
                        let item = this.renderItem(file);
                        item.valid = {
                            passed: true,
                            msg: this.options.lang.message.single.success
                        };
                        item.data = {
                            name: file.name,
                            url: k.url,
                            time: k.time || file.lastModified,
                            size: file.size,
                        };
                        this.updateItemProg(item, 'received');
                        this.actOpt(item);
                        result.push(item);
                    });
                }
                catch {
                    console.error(`File address error, or the file may be blocked due to cross-origin restrictions:${k.url}`);
                    continue;
                }
            }
            this.options.status.includes('summary') && (this.summaryEl.innerHTML = this.getSummary());
            this.setInputVal();
            super.listen({ name: 'added', cb, params: [result] });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.removeEvts();
            for (let k of this.passedItems) {
                k.abort && k.abort();
                k.uploadEl && (k.uploadEl.onclick = null);
                k.removeEl && (k.removeEl.onclick = null);
            }
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optPanel = [
        {
            attr: 'content',
            prop: 'content',
            value: '',
        },
        {
            attr: 'cont-type',
            prop: 'contType',
            value: 'text',
        },
        {
            attr: 'cont-data',
            prop: 'contData',
            value: {},
        },
        {
            attr: 'ajax',
            prop: 'ajax',
            value: {},
        },
        {
            attr: 'tpl-str',
            prop: 'tplStr',
            value: '',
        },
        {
            attr: 'tpl-eng',
            prop: 'tplEng',
            value: null,
        },
        {
            attr: 'label',
            prop: 'label',
            value: '',
        },
        {
            attr: 'tips',
            prop: 'tips',
            value: '',
        },
        {
            attr: 'cube',
            prop: 'cube',
            value: '',
        },
        {
            attr: 'disk',
            prop: 'disk',
            value: '',
        },
        {
            attr: 'image',
            prop: 'image',
            value: '',
        },
        {
            attr: 'icon',
            prop: 'icon',
            value: '',
        },
        {
            attr: 'badge',
            prop: 'badge',
            value: null,
        },
        {
            attr: 'annot',
            prop: 'annot',
            value: '',
        },
        {
            attr: 'lamp',
            prop: 'lamp',
            value: '',
        },
        {
            attr: 'custom',
            prop: 'custom',
            value: '',
        },
        {
            attr: 'brief',
            prop: 'brief',
            value: '',
        },
        {
            attr: 'classes',
            prop: 'classes',
            value: '',
        },
        {
            attr: 'arrow',
            prop: 'arrow',
            value: {
                enable: false,
                show: `${orca.prefix}icon-up`,
                hide: `${orca.prefix}icon-up`,
                anim: `${orca.prefix}rotate180`,
                type: 'icon',
                placement: 'end',
            },
        },
        {
            attr: 'tab',
            prop: 'tab',
            value: {
                enable: true,
            },
        },
        {
            attr: 'tools',
            prop: 'tools',
            value: {
                enable: false,
                children: ['toggle']
            },
        },
        {
            attr: 'deferred',
            prop: 'deferred',
            value: false,
        },
        {
            attr: 'feature',
            prop: 'feature',
            value: '',
        },
        {
            attr: 'dividable',
            prop: 'dividable',
            value: false,
        },
        {
            attr: 'collapsed',
            prop: 'collapsed',
            value: false,
        },
        {
            attr: 'head-closable',
            prop: 'headClosable',
            value: false,
        },
        {
            attr: 'padded',
            prop: 'padded',
            value: true,
        },
        {
            attr: 'theme',
            prop: 'theme',
            value: '',
        },
        {
            attr: 'b4-fill',
            prop: 'b4Fill',
            value: null,
        },
        {
            attr: 'b4-expand',
            prop: 'b4Expand',
            value: null,
        },
        {
            attr: 'b4-collapse',
            prop: 'b4Collapse',
            value: null,
        },
        {
            attr: 'on-filled',
            prop: 'onFilled',
            value: null
        },
        {
            attr: 'on-rendered',
            prop: 'onRendered',
            value: null
        },
        {
            attr: 'on-expand',
            prop: 'onExpand',
            value: null
        },
        {
            attr: 'on-expanded',
            prop: 'onExpanded',
            value: null
        },
        {
            attr: 'on-collapse',
            prop: 'onCollapse',
            value: null
        },
        {
            attr: 'on-collapsed',
            prop: 'onCollapsed',
            value: null
        },
        {
            attr: 'on-updatedcont',
            prop: 'onUpdatedCont',
            value: null
        },
        {
            attr: 'on-request',
            prop: 'onRequest',
            value: null
        },
        ...optBase
    ];

    class Panel extends ModBaseListenCache {
        options = {};
        flatData;
        treeData;
        wrapEl;
        headEl;
        innerEl;
        titleEl;
        groupEl;
        labelEl;
        iconEl;
        diskEl;
        cubeEl;
        imageEl;
        briefEl;
        annotEl;
        badgeEl;
        tipsEl;
        customEl;
        toolsEl;
        arrowEl;
        bodyEl;
        contEl;
        closeEl;
        tabIns;
        contXhr;
        transmitioned;
        data;
        closeEvt;
        static hostType = 'node';
        static optMaps = optPanel;
        constructor(elem, options = {}, initial = true) {
            super();
            super.ready({
                options,
                host: elem,
                maps: Panel.optMaps,
                component: true,
                spread: ['arrow', 'tab', 'tools']
            });
            this.transmitioned = true;
            this.closeEvt = () => {
                if (!this.transmitioned)
                    return;
                if (elState(this.bodyEl).isHidden) {
                    this.expand();
                }
                else {
                    this.collapse();
                }
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch (err) {
                err ? console.error(err) : console.warn(config.warn.init);
                return this;
            }
            super.useTpl();
            this.renderMain();
            this.setAttrs();
            await this.getDataToRender();
            this.renderFinish();
            super.listen({ name: 'initiated', cb });
            return this;
        }
        correctOpts() {
            if (this.options.feature === 'window') {
                this.options.dividable = false;
            }
        }
        async fillBody(content, cb) {
            if (this.destroyed)
                return this;
            try {
                if (this.options.b4Fill) {
                    let resp = await this.options.b4Fill.call(this, content);
                    resp && (content = resp);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('Body filling has been prevented!');
                return;
            }
            setContent({
                content,
                target: this.contEl,
                template: this.tplStr,
                engine: this.tplEng
            });
            if ((this.options.deferred || this.options.collapsed) && !this.options.arrow.enable && !this.options.headClosable) {
                await this.expand();
            }
            super.listen({ name: 'filled', cb, params: [content] });
            return this;
        }
        async getDataToRender(force = false) {
            let allow = force || !this.options.deferred;
            if (!allow)
                return;
            if (this.options.content) {
                this.data = await getContent.call(this, {
                    content: this.options.content,
                    contType: this.options.contType,
                    contData: this.options.contData,
                    ajax: {
                        xhrName: 'contXhr',
                        spinSel: this.arrowEl,
                        ...this.options.ajax
                    },
                    request: (data) => {
                        this.listen({ name: 'request', params: [data] });
                    }
                });
            }
            else {
                this.data = this.rawEl || this.rawHtml;
            }
            this.data && await this.fillBody(this.data);
        }
        toggleArrow(val) {
            if (!this.arrowEl)
                return;
            let map = val ? { new: 'show', old: 'hide', action: 'remove' } : { new: 'hide', old: 'show', action: 'add' };
            if (this.options.arrow.type === 'image') {
                this.arrowEl.style.backgroundImage = `url("${this.options.arrow[map.new]}")`;
            }
            else {
                if (this.options.arrow.show === this.options.arrow.hide) {
                    this.arrowEl.classList[map.action](this.options.arrow.anim);
                }
                else {
                    classes(this.arrowEl).replace(this.options.arrow[map.old], this.options.arrow[map.new]);
                }
            }
        }
        setArrow() {
            if (!this.arrowEl)
                return;
            let prop = this.options.collapsed || this.options.deferred ? 'hide' : 'show';
            if (this.options.arrow.type === 'image') {
                this.options.arrow[prop] && (this.arrowEl.style.backgroundImage = `url("${this.options.arrow[prop]}")`);
            }
            else {
                this.options.arrow[prop] && this.arrowEl.classList.add(this.options.arrow[prop]);
                (this.options.arrow.show === this.options.arrow.hide) && prop === 'hide' && this.arrowEl.classList.add(this.options.arrow.anim);
            }
        }
        createHeadEl() {
            let tpl = `
        <div class="_panel-head">
                <div class="_panel-inner">
                    <div class="_panel-title">
                        <div rep="group">
                            <i rep="label">${this.options.label}</i>
                        </div>
                    </div>
                </div>
            </div>
        `;
            this.headEl = tplToEl(tpl);
            this.innerEl = this.headEl.querySelector(`.${orca.prefix}panel-inner`);
            this.titleEl = this.headEl.querySelector(`.${orca.prefix}panel-title`);
            this.groupEl = this.headEl.querySelector(`[${orca.alias}="group"]`);
            this.labelEl = this.headEl.querySelector(`[${orca.alias}="label"]`);
            if (this.options.icon) {
                this.iconEl = createEl('i', { [orca.alias]: `icon`, class: this.options.icon });
                (this.options.feature === 'loose' ? this.innerEl : this.groupEl).insertAdjacentElement('beforebegin', this.iconEl);
            }
            if (this.options.disk) {
                this.diskEl = createEl('img', { [orca.alias]: `disk`, src: this.options.disk });
                (this.options.feature === 'loose' ? this.innerEl : this.groupEl).insertAdjacentElement('beforebegin', this.diskEl);
            }
            if (this.options.cube) {
                this.cubeEl = createEl('img', { [orca.alias]: `cube`, src: this.options.cube });
                (this.options.feature === 'loose' ? this.innerEl : this.groupEl).insertAdjacentElement('beforebegin', this.cubeEl);
            }
            if (this.options.image) {
                this.imageEl = createEl('img', { [orca.alias]: `image`, src: this.options.image });
                (this.options.feature === 'loose' ? this.innerEl : this.groupEl).insertAdjacentElement('beforebegin', this.imageEl);
            }
            if (this.options.brief) {
                this.briefEl = createEl('div', { class: `${orca.prefix}panel-brief` }, this.options.brief);
                this.titleEl.insertAdjacentElement('afterend', this.briefEl);
            }
            if (this.options.annot) {
                this.annotEl = createEl('span', { [orca.alias]: `annot` }, this.options.annot);
                this.labelEl.insertAdjacentElement('afterend', this.annotEl);
            }
            if (!isNull(this.options.badge)) {
                this.badgeEl = createEl('oc-badge', { label: this.options.badge });
                this.groupEl.insertAdjacentElement('afterend', this.badgeEl);
            }
            if (this.options.tips) {
                this.tipsEl = createEl('span', { [orca.alias]: `tips` }, this.options.tips);
                this.groupEl.insertAdjacentElement('afterend', this.tipsEl);
            }
            if (this.options.custom) {
                this.customEl = createEl('div', { [orca.alias]: `custum` }, this.options.custom);
                this.groupEl.insertAdjacentElement('afterend', this.customEl);
            }
            if (this.options.tools.enable) {
                this.toolsEl = createTools(this.options.tools.children, this.titleEl);
                this.toolsEl.setAttribute(orca.alias, 'tools');
            }
            if (this.options.arrow.enable) {
                this.arrowEl = createEl('i', { [orca.alias]: `arrow` });
                this.setArrow();
                if (this.options.arrow.placement === 'end') {
                    this.titleEl.appendChild(this.arrowEl);
                }
                else {
                    (this.options.feature === 'loose' ? this.headEl : this.titleEl).insertAdjacentElement('afterbegin', this.arrowEl);
                }
            }
            this.wrapEl.insertAdjacentElement('afterbegin', this.headEl);
            this.options.dividable && this.headEl.insertAdjacentHTML('afterend', `<oc-line ${this.options.theme ? 'theme="' + this.options.theme + '"' : ''}></oc-line>`);
        }
        createBodyEl() {
            this.bodyEl = createEl('div', { class: `${orca.prefix}panel-body` });
            if (this.options.padded) {
                this.contEl = createEl('div', { class: `${orca.prefix}panel-inner` });
                this.bodyEl.appendChild(this.contEl);
            }
            else {
                this.contEl = this.bodyEl;
            }
            this.wrapEl.appendChild(this.bodyEl);
        }
        renderMain() {
            this.targetEl.innerHTML = '';
            this.wrapEl = createEl('div', { class: `${orca.prefix}panel-wrap` });
            this.targetEl.appendChild(this.wrapEl);
            this.createHeadEl();
            this.createBodyEl();
            super.listen({ name: 'rendered' });
        }
        setAttrs() {
            this.targetEl.classList.add(`${orca.prefix}panel`);
            this.options.classes && classes(this.targetEl).add(this.options.classes);
            (this.options.collapsed || this.options.deferred) && this.targetEl.toggleAttribute('collapsed', true);
            this.options.headClosable && this.targetEl.toggleAttribute('headclosable', true);
            this.options.feature && this.targetEl.setAttribute('feature', this.options.feature);
            this.options.lamp && this.targetEl.setAttribute('lamp', this.options.lamp);
            this.options.theme && this.targetEl.setAttribute('theme', this.options.theme);
        }
        renderFinish() {
            this.closeEl = this.options.headClosable ? this.headEl : this.arrowEl;
            if (this.closeEl) {
                this.closeEl.removeEventListener('click', this.closeEvt);
                this.closeEl.addEventListener('click', this.closeEvt, false);
            }
            for (let k of this.options.tools.children) {
                if (k.name === 'toggle') {
                    k.wrapEl.onclick = () => {
                        if (k.iconEl.classList.contains(k.icon)) {
                            this.targetEl.toggleAttribute('max', true);
                            classes(k.iconEl).replace(k.icon, k.swap);
                        }
                        else {
                            this.targetEl.toggleAttribute('max', false);
                            classes(k.iconEl).replace(k.swap, k.icon);
                        }
                    };
                }
                else {
                    k.action && k.action.call(this, k);
                }
            }
            if (this.options.tab.enable && this.headEl.querySelector(`.${orca.prefix}tab-head`) && this.bodyEl.querySelector(`.${orca.prefix}tab-body`)) {
                this.tabIns = new Tab(this.targetEl, this.options.tab);
            }
        }
        async expand(cb) {
            if (this.destroyed || !this.transmitioned || elState(this.bodyEl).isVisible)
                return this;
            try {
                if (this.options.b4Expand) {
                    await this.options.b4Expand.call(this);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('Body expanding has been prevented!');
                return;
            }
            this.options.deferred && !this.contEl.innerHTML && await this.getDataToRender(true);
            slideDown({
                el: this.bodyEl,
                before: () => {
                    this.transmitioned = false;
                    super.listen({ name: 'expand' });
                },
                doing: () => {
                    this.toggleArrow(true);
                },
                done: () => {
                    this.transmitioned = true;
                    super.listen({ name: 'expanded', cb });
                    super.updateCache({ collapsed: false });
                }
            });
            return this;
        }
        async collapse(cb) {
            if (this.destroyed || !this.transmitioned || elState(this.bodyEl).isHidden)
                return this;
            try {
                if (this.options.b4Collapse) {
                    await this.options.b4Collapse.call(this);
                }
            }
            catch (err) {
                err ? console.error(err) : console.warn('Body collapsing has been prevented!');
                return;
            }
            slideUp({
                el: this.bodyEl,
                before: () => {
                    this.transmitioned = false;
                    super.listen({ name: 'collapse' });
                },
                doing: () => {
                    this.toggleArrow(false);
                },
                done: () => {
                    this.transmitioned = true;
                    super.listen({ name: 'collapsed', cb });
                    super.updateCache({ collapsed: true });
                }
            });
            return this;
        }
        
        destroy(cb) {
            if (this.destroyed)
                return this;
            this.closeEl && this.closeEl.removeEventListener('click', this.closeEvt);
            this.contXhr && this.contXhr.abort();
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    const optRouter = [
        {
            attr: 'routes',
            prop: 'routes',
            value: [],
        },
        {
            attr: 'current',
            prop: 'current',
            value: '',
        },
        {
            attr: 'redirect',
            prop: 'redirect',
            value: [],
        },
        {
            attr: 'before-check',
            prop: 'beforeCheck',
            value: null,
        },
        {
            attr: 'after-check',
            prop: 'afterCheck',
            value: null,
        },
        {
            attr: 'purpose',
            prop: 'purpose',
            value: 'sort',
        },
        {
            attr: 'point',
            prop: 'point',
            value: {
                before: ['t/3'],
                after: ['b/3'],
            },
        },
        {
            attr: 'holder',
            prop: 'holder',
            value: {
                from: false,
                to: false,
            },
        },
        {
            attr: 'arrow',
            prop: 'arrow',
            value: {
                enable: false,
                icon: `${orca.prefix}icon-right`,
                placement: 'left',
                selector: '',
            },
        },
        {
            attr: 'gesture',
            prop: 'gesture',
            value: {},
        },
        {
            attr: 'delay',
            prop: 'delay',
            value: 50,
        },
        {
            attr: 'duration',
            prop: 'duration',
            value: 200,
        },
        {
            attr: 'b4-drop',
            prop: 'b4Drop',
            value: null,
        },
        {
            attr: 'on-dropping',
            prop: 'onDropping',
            value: null,
        },
        {
            attr: 'on-dropped',
            prop: 'onDropped',
            value: null,
        },
        {
            attr: 'on-dragstart',
            prop: 'onDragStart',
            value: null,
        },
        {
            attr: 'on-dragmove',
            prop: 'onDragMove',
            value: null,
        },
        {
            attr: 'on-dragend',
            prop: 'onDragEnd',
            value: null,
        },
        {
            attr: 'on-located',
            prop: 'onLocated',
            value: null,
        },
        ...optBase
    ];

    class Router extends ModBaseListen {
        options = {};
        routes;
        current;
        stateEvt;
        static hostType = 'none';
        constructor(options = {}, initial = true) {
            super();
            super.ready({
                options,
                maps: optRouter,
            });
            this.routes = this.options.routes || [];
            this.current = this.options.current;
            this.stateEvt = (evt) => {
                if (!evt.state) ;
                else {
                    if (this.current !== evt.state.path) {
                        let toRoute = this.getRoute(evt.state.path), fromRoute = this.getRoute();
                        if (this.options.beforeCheck) {
                            let resp = this.options.beforeCheck(toRoute, fromRoute);
                            if (typeof resp === 'string') {
                                let reRoute = this.getRoute(resp);
                                if (reRoute) {
                                    this.push(reRoute);
                                }
                                else {
                                    return;
                                }
                            }
                            else if (!resp) {
                                return;
                            }
                        }
                        this.current = evt.state.path;
                        toRoute.action && toRoute.action.call(this, toRoute);
                        super.listen({ name: 'located', params: [toRoute] });
                    }
                }
            };
            super.listen({ name: 'constructed' });
            initial && this.init();
        }
        async init(cb) {
            super.listen({ name: 'initiate' });
            try {
                this.options.b4Init && await this.options.b4Init.call(this);
            }
            catch {
                console.warn(config.warn.init);
                return this;
            }
            window.addEventListener('popstate', this.stateEvt);
            this.current = this.getUrlPath();
            this.add({ path: this.current, action: null });
            super.listen({ name: 'initiated', cb });
            return this;
        }
        getUrlPath() {
            let pathname = window.location.pathname, search = window.location.search, hash = window.location.hash;
            return pathname + search + hash;
        }
        getRoute(path = this.current) {
            return this.routes.find((k) => k.path === path);
        }
        ;
        add(state) {
            let item = this.routes.find((k) => k.path === state.path);
            item ? Object.assign(item, state) : this.routes.push(state);
        }
        remove(path) {
            this.routes.filter((k) => k.path !== path);
        }
        push(state, cb) {
            if (isNull(state) || this.destroyed)
                return;
            if (this.options.beforeCheck) {
                let resp = this.options.beforeCheck(state, this.getRoute());
                if (typeof resp === 'string') {
                    state = this.getRoute(state.resp);
                    if (!state)
                        window.location.href = resp;
                }
                else if (!resp) {
                    return;
                }
            }
            let route = this.getRoute(state.path);
            if (route) {
                this.replace(state);
                Object.assign(route, state);
                return this;
            }
            this.add(state);
            history.pushState({ path: state.path }, Date.now() + '', state.path);
            this.current = state.path;
            state.action && state.action.call(this, state);
            super.listen({ name: 'located', cb, params: [state] });
            return this;
        }
        replace(state, cb) {
            if (isNull(state) || this.destroyed)
                return;
            let route = this.getRoute(state.path);
            if (!route) {
                this.push(state);
                return this;
            }
            Object.assign(route, state);
            if (this.options.beforeCheck) {
                let resp = this.options.beforeCheck(route, this.getRoute());
                if (typeof resp === 'string') {
                    state = this.getRoute(state.resp);
                    if (!state)
                        return;
                }
                else if (!resp) {
                    return;
                }
            }
            history.replaceState({ path: state.path }, Date.now() + '', state.path);
            this.current = state.path;
            state.action && state.action.call(this, state);
            super.listen({ name: 'located', cb, params: [state] });
            return this;
        }
        back() {
            if (this.destroyed)
                return;
            history.go(-1);
            return this;
        }
        forward() {
            if (this.destroyed)
                return;
            history.go(1);
            return this;
        }
        go(path) {
            if (this.destroyed)
                return;
            if (typeof path === 'string') {
                this.push(this.getRoute(path));
            }
            else {
                history.go(path);
            }
            return this;
        }
        clear() {
            this.routes = [];
            return this;
        }
        routeChange(path) {
            if (!path)
                return;
            let action = this.routes[path];
            if (action) {
                this.current = path;
                action.call(this);
            }
            else {
                console.error(`No route found for path: ${path}`);
            }
        }
        beforeCheck(to, from, next) {
        }
        afterCheck() {
        }
        restore() {
            return this;
        }
        destroy(cb) {
            if (this.destroyed)
                return;
            this.destroyed = true;
            super.listen({ name: 'destroyed', cb });
            return this;
        }
    }

    class CompBaseCommField extends CompBaseComm {
        name;
        value;
        disabled;
        readOnly;
        checked;
        multiple;
        events;
        inputEl;
        zeroEvt;
        evtsArr;
        toolsEl;
        mediaEl;
        constructor() {
            super();
            this.focus = () => {
                this.inputEl.focus();
            };
            this.blur = () => {
                this.inputEl.blur();
            };
            this.zeroEvt = new Event('input');
            this.reset = (cb) => {
                for (let k in this.propsRaw) {
                    (this.propsRaw[k] !== null && this.propsRaw[k] !== false) ? this.setAttribute(k, this.propsRaw[k]) : this.removeAttribute(k);
                }
                this.inputEl && this.inputEl.dispatchEvent(this.zeroEvt);
                this.listen({ name: 'reset', cb });
            };
            this.clear = (cb) => {
                if (this.inputEl) {
                    this.inputEl.value = '';
                    this.inputEl.dispatchEvent(this.zeroEvt);
                }
                this.mediaEl && (this.mediaEl.innerHTML = '');
                this.listen({ name: 'cleared', cb });
            };
            this.on('connected', () => {
                this.setAttribute(orca.compSign, '');
                this.setCache();
            });
            this.on('reset', () => {
                this.clearCache();
            });
        }
        static evtsArr = [...this.baseAttrs, 'on-cleared', 'on-changed',];
        connectedCallback() {
            if (this.inputEl) {
                this.addEvts(['blur', 'focus']);
                for (let k in this.events) {
                    this.inputEl.addEventListener(k, () => {
                        this.dispatchEvent(this.events[k].event);
                    });
                }
            }
            this.connectedRender();
        }
        addEvts(evts) {
            this.events = {};
            if (isEmpty(evts))
                return;
            for (let k of evts) {
                this.events[k] = createEvt({ target: this, name: k });
            }
        }
        getToolsEl(data) {
            if (!isEmpty(data)) {
                this.toolsEl = createTools(data, null, this);
                this.toolsEl.setAttribute(orca.alias, 'tools');
            }
        }
        setFieldProps(props) {
            for (let k of props) {
                k === 'name' ? this.name = this.propsProxy.name || '' :
                    k === 'value' ? this.value = this.propsProxy.value || '' :
                        k === 'disabled' ? this.disabled = this.propsProxy.disabled || false :
                            k === 'readOnly' ? this.readOnly = this.propsProxy.readonly || false :
                                k === 'multiple' ? this.multiple = this.propsProxy.multiple || false :
                                    k === 'check' ? this.checked = (this.propsProxy.check === 'ed' ? true : false) : null;
            }
        }
        getItemsData(data) {
            let arr = super.getAttrHtmlData(data);
            return this.formatData(arr);
        }
        formatData(data) {
            let itemType = typeof data[0];
            if (itemType === 'string') {
                return data.map((k) => {
                    return { label: k, value: k, disabled: false, checked: false };
                });
            }
            else {
                return data;
            }
        }
        addScrollable(input) {
            let scrolled = input.scrollHeight > input.clientHeight;
            this.wrapEl.toggleAttribute('scrollable', scrolled);
        }
        setValAttr(data, el) {
            if (!isNull(data.value)) {
                el.value = data.value;
            }
            else if (isNull(data.value) && data.label) {
                el.value = data.label;
            }
        }
        changedMultiDisable(opt) {
            let tmp = getAttrArr(opt.newVal);
            for (let k of this.inputs) {
                if (tmp.includes(k.propsProxy.value)) {
                    k.setAttribute('disabled', '');
                }
                else {
                    k.removeAttribute('disabled');
                }
            }
        }
        changedMultiDisabled(opt) {
            this.toggleAttribute('disabled', this.propsProxy['disabled']);
            this.disabled = this.propsProxy['disabled'];
        }
        changedMultiName(opt) {
            for (let k of this.inputs)
                opt.newVal ? k.setAttribute(opt.name, opt.newVal) : k.removeAttribute(opt.name);
            if (opt.name === 'name') {
                opt.newVal ? this.name = opt.newVal : this.removeAttribute('name');
            }
        }
        changedMultiCont(opt) {
            this.updateInputs(opt.newVal);
        }
        changedSingleDisabled(opt) {
            this.inputEl.toggleAttribute('disabled', this.propsProxy.disabled);
            this.disabled = this.propsProxy.disabled;
        }
        changedSingleName(opt) {
            opt.newVal ? this.inputEl.name = opt.newVal : this.inputEl.removeAttribute('name');
            this.name = this.inputEl.name;
        }
        changedSingleValue(opt) {
            if (opt.newVal === null && !this.propsProxy.label) {
                this.propsProxy.value = undefined;
                this.value = '';
                this.inputEl.removeAttribute('value');
            }
            else {
                this.propsProxy.value = this.value = opt.newVal;
                this.inputEl.value = this.value;
            }
        }
        changedSingleLabel(opt) {
            this.labelEl.innerHTML = opt.newVal;
            if (opt.newVal && isNull(this.propsProxy.value)) {
                this.propsProxy.value = this.value = opt.newVal;
                this.inputEl.value = this.value;
            }
        }
        changedSingleCheck(opt) {
            let oldChecked = opt.oldVal === 'ed' ? true : false;
            this.checked = opt.newVal === 'ed' ? true : false;
            this.inputEl.checked = this.checked;
            this.listen({ name: 'check', params: [{ value: opt.newVal, checked: this.checked }] });
            oldChecked !== this.checked && this.listen({ name: 'changed', params: [{ newVal: this.checked, oldVal: !this.checked }] });
        }
    }

    class CompBaseCommFieldMixin extends CompBaseCommField {
        modsOpts;
        canListenkeys;
        static custAttrs;
        static boolAttrs;
        constructor() {
            super();
            this.modsOpts = {};
            this.createShadow();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static get observedAttributes() {
            return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.evtsArr];
        }
        connectedCallback() {
            this.addEvts(['blur', 'focus', 'input', 'change']);
            this.connectedRender();
        }
        mapVals(name, newVal, module, opts = []) {
            return module.evtsArr.includes(name) ? newVal :
                module.boolAttrs.includes(name) ? Object.values(attrJoinVal(name, newVal, opts))[0] :
                    isNull(newVal) ? null : Object.values(attrJoinVal(name, newVal, opts))[0];
        }
        saveModsOpts(name, opts = [], module = 'module') {
            if (!name || !module)
                return;
            let tmp = this.propsProxy[name], item = opts.find((k) => k.attr === name);
            if (!item)
                return;
            !this.modsOpts[module] && (this.modsOpts[module] = {});
            if (isNull(tmp)) {
                this.connected && (this.modsOpts[module][item.prop] = item.value);
            }
            else {
                this.modsOpts[module][item.prop] = tmp;
            }
        }
        getRawProps(comp, opts = []) {
            for (let k of [...comp.custAttrs, ...comp.lazyAttrs, ...comp.boolAttrs, ...comp.evtsArr]) {
                this.propsRaw[k] = this.mapVals(k, this.getAttribute(k), comp, opts);
            }
        }
        filterModsOpts(opts = []) {
            for (let k of Object.keys(this.properties).filter(keyCond))
                this.saveModsOpts(k, opts);
        }
        getListenKeys(comp, exclude = []) {
            this.canListenkeys = [...comp.custAttrs, ...comp.boolAttrs].filter((k) => !exclude.includes(k));
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', {}, this.rawHtml);
        }
        updateProxyOpts(comp, opts = [], name, newVal, oldVal) {
            this.propsProxy[name] = name === 'async' ? getAttrBool(newVal) : this.mapVals(name, newVal, comp, opts);
            !comp.evtsArr.includes(name) && this.saveModsOpts(name, opts);
            this.changedMaps[name] && this.changedMaps[name].call(this, { name, newVal, oldVal, proxy: this.propsProxy });
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
        }
        getRawPropsOpts(comp, opts) {
            this.getRawProps(comp, opts);
            this.getProxyProps();
            this.filterModsOpts(opts);
        }
        completedEvt(data) {
            let intArr = getIntArr([this.canListenkeys, data.keys.set]);
            (this.modsOpts['module']);
            intArr.length && this.ins.update(this.modsOpts['module']);
        }
    }

    class MoreElem extends CompBaseComm {
        constructor() {
            super();
            this.createShadow();
            super.createPropsObs();
            this.fillWrap(this.propsProxy);
        }
        static get observedAttributes() {
            return [...optMore.map((k) => k.attr), 'options', 'async'];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            super.updateProxy(name, newVal, optMore);
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'slot-host' }, this.rawHtml);
        }
        createIns() {
            if (this.ins)
                return;
            this.ins = new More(this.wrapEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
        }
    }

    class ResultElem extends CompBaseComm {
        iconEl;
        labelEl;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
            
        }
        static custAttrs = ['to', 'shape', 'type', ...this.baseAttrs];
        static boolAttrs = [];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, ResultElem);
        }
        getRawData() {
            this.getRawProps(ResultElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('span', { [orca.alias]: 'wrap' });
            this.iconEl = createEl('i', { [orca.alias]: 'icon' }, icons.svg.info);
            this.labelEl = createEl('i', { [orca.alias]: 'label' }, data.label || '');
            this.wrapEl.appendChild(this.iconEl);
            data.label && this.wrapEl.appendChild(this.labelEl);
        }
        getIcon(data) {
            let result = '';
            if (!data.to) {
                result = icons.svg.info;
            }
            else {
                if (!data.type || data.type === 'svg') {
                    result = icons.svg[data.to];
                }
                else if (data.type === 'font') {
                    let icon = data.to + (data.shape === 'thick' ? '-t' : data.shape === 'fill' ? '-f' : '');
                    result = icons.font[icon];
                }
            }
            return result;
        }
        render(data) {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            label: this.changedLabel,
            type: this.changedIcon,
            to: this.changedIcon,
            shape: this.changedIcon,
        };
        changedLabel(opt) {
            if (opt.newVal) {
                this.labelEl.innerHTML = opt.newVal || '';
                elState(this.labelEl).isVirtual && this.wrapEl.appendChild(this.labelEl);
            }
            else {
                this.labelEl.remove();
            }
        }
        changedIcon(opt) {
            let content = this.getIcon(this.propsProxy);
            content && (this.iconEl.innerHTML = content);
        }
    }

    class DeformElem extends CompBaseComm {
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['type', 'theme', 'shape', 'size', ...this.baseAttrs];
        static boolAttrs = ['disabled', 'bordered', 'filled', 'dark'];
        static get observedAttributes() {
            return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, DeformElem);
        }
        getRawData() {
            this.getRawProps(DeformElem);
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, '<i></i>'.repeat(3));
        }
        render(data) {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            class: this.changedClass,
        };
        changedClass(opt) {
            let has = opt.newVal.includes(config.actClass), type = this.propsRaw.type;
            if (has) {
                if (type === 'left') {
                    this.setAttribute('type', 'right');
                }
                else if (type === 'right') {
                    this.setAttribute('type', 'left');
                }
                else if (type === 'up') {
                    this.setAttribute('type', 'down');
                }
                else if (type === 'down') {
                    this.setAttribute('type', 'up');
                }
                else {
                    this.setAttribute('type', 'close');
                }
            }
            else {
                this.setAttribute('type', this.propsRaw.type);
            }
        }
    }

    class RadioElem extends CompBaseCommField {
        labelEl;
        legendEl;
        check;
        type;
        constructor() {
            super();
            this.type = 'radio-comp';
            this.getRawData();
            this.fillWrap(this.propsProxy);
            this.clear = () => {
                this.removeAttribute('check');
                this.listen({ name: 'cleared' });
            };
            this.check = (val) => {
                this.setAttribute('check', val);
            };
        }
        static custAttrs = ['size', 'value', 'name', 'type', 'check', ...this.evtsArr];
        static boolAttrs = ['disabled'];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, RadioElem);
        }
        getRawData() {
            this.getRawProps(RadioElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
            this.setFieldProps(['name', 'value', 'disabled', 'check']);
        }
        fillWrap(data) {
            this.wrapEl = createEl('label', { [orca.alias]: 'wrap' });
            this.inputEl = createEl('input', { type: 'radio', [orca.embedSign]: '' });
            this.setValAttr(data, this.inputEl);
            data.name && (this.inputEl.name = data.name || '');
            this.legendEl = createEl('u');
            this.labelEl = createEl('i', '', data.label);
            this.wrapEl.append(this.inputEl, this.legendEl, this.labelEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.inputEl.addEventListener('change', (e) => {
                this.setAttribute('check', 'ed');
                let others = getEls(`oc-radio[name=${this.propsProxy.name}]`, this.closest('form')).filter((k) => k !== this);
                others.forEach((k) => {
                    k.setAttribute('check', '');
                });
            }, false);
        }
        changedMaps = {
            disabled: this.changedSingleDisabled,
            name: this.changedSingleName,
            value: this.changedSingleValue,
            label: this.changedSingleLabel,
            check: this.changedSingleCheck,
        };
    }

    class CheckboxElem extends CompBaseCommField {
        labelEl;
        legendEl;
        check;
        type;
        constructor() {
            super();
            this.type = 'checkbox-comp';
            this.getRawData();
            this.fillWrap(this.propsProxy);
            this.clear = () => {
                this.removeAttribute('check');
                this.listen({ name: 'cleared' });
            };
            this.check = (val) => {
                this.setAttribute('check', val);
            };
        }
        static custAttrs = ['size', 'value', 'type', 'name', 'check', ...this.evtsArr];
        static boolAttrs = ['disabled'];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, CheckboxElem);
        }
        getRawData() {
            [...CheckboxElem.custAttrs, ...CheckboxElem.lazyAttrs].forEach((k) => {
                this.propsRaw[k] = this.getAttribute(k);
            });
            CheckboxElem.boolAttrs.forEach((k) => {
                this.propsRaw[k] = getAttrBool(this.getAttribute(k));
            });
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
            this.setFieldProps(['name', 'value', 'disabled', 'check']);
        }
        fillWrap(data) {
            this.wrapEl = createEl('label', { [orca.alias]: 'wrap' });
            this.inputEl = createEl('input', { type: 'checkbox', [orca.embedSign]: '' });
            this.setValAttr(data, this.inputEl);
            data.name && (this.inputEl.name = data.name || '');
            this.legendEl = createEl('u');
            this.labelEl = createEl('i', '', data.label);
            this.wrapEl.append(this.inputEl, this.legendEl, this.labelEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.inputEl.addEventListener('change', (e) => {
                let val = e.target.checked ? 'ed' : '';
                this.setAttribute('check', val);
            }, false);
        }
        changedMaps = {
            disabled: this.changedSingleDisabled,
            name: this.changedSingleName,
            value: this.changedSingleValue,
            label: this.changedSingleLabel,
            check: this.changedSingleCheck,
            lang: this.changedLang,
        };
        changedLang(opt) {
            if (this.propsProxy.type !== 'switch')
                return;
            let trackEl = getEl(':scope > u', this.wrapEl);
            this.propsProxy.lang.on ? trackEl.setAttribute('on', this.propsProxy.lang.on) : trackEl.removeAttribute('on');
            this.propsProxy.lang.off ? trackEl.setAttribute('off', this.propsProxy.lang.off) : trackEl.removeAttribute('off');
        }
    }

    class BadgeElem extends CompBaseComm {
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['theme', 'type', 'shape', ...this.baseAttrs];
        static boolAttrs = ['glassy'];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, BadgeElem);
        }
        getRawData() {
            this.getRawProps(BadgeElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, data.label);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            label: this.changedLabel,
        };
        changedLabel(opt) {
            if (opt.newVal === null) {
                this.wrapEl.innerHTML = '';
            }
            else {
                this.wrapEl.innerHTML = opt.newVal;
            }
        }
    }

    class BtnElem extends CompBaseComm {
        labelEl;
        iconEl;
        tailEl;
        diskEl;
        cubeEl;
        imageEl;
        badgeEl;
        meanEl;
        tipsIns;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static dependencies = [{ tag: 'oc-badge', comp: BadgeElem }];
        static custAttrs = ['type', 'theme', 'href', 'tab', 'target', 'rel', 'download', 'shape', 'size', 'width', 'check', 'icon', 'tail', 'disk', 'cube', 'image', 'tips', 'badge', 'mean', ...this.baseAttrs];
        static boolAttrs = ['disabled', 'shaded', 'grad'];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, BtnElem);
        }
        getRawData() {
            this.getRawProps(BtnElem);
            this.initLabel();
            this.getProxyProps();
        }
        initLabel() {
            if (this.innerHTML) {
                let child = this.firstElementChild;
                if (child && child.nodeName === 'A') {
                    this.propsRaw.href = child.href;
                    child.hasAttribute('target') && (this.propsRaw.target = child.target);
                    child.hasAttribute('rel') && (this.propsRaw.rel = child.rel);
                    child.hasAttribute('download') && (this.propsRaw.download = child.download);
                    this.propsRaw.label = child.innerHTML;
                }
                else {
                    this.propsRaw.label = this.innerHTML;
                }
            }
            else {
                this.propsRaw.label = this.getAttribute('label');
            }
        }
        getWrap(data) {
            let obj = { [orca.alias]: 'wrap' }, node = '';
            if (!isNull(data.href)) {
                node = 'a';
                obj.href = data.href;
                data.target && (obj.target = data.target);
                data.rel && (obj.rel = data.rel);
            }
            else {
                node = 'span';
            }
            this.wrapEl = createEl(node, obj, this.labelEl);
        }
        insertIcon(val) {
            this.iconEl = createEl('i', { class: val, [orca.alias]: 'icon' });
            this.labelEl.insertAdjacentElement('beforeBegin', this.iconEl);
        }
        insertTail(val) {
            this.tailEl = createEl('i', { class: val, [orca.alias]: 'tail' });
            this.labelEl.insertAdjacentElement('afterEnd', this.tailEl);
        }
        insertMean(val) {
            this.meanEl = createEl('i', { [orca.alias]: val });
            this.wrapEl.appendChild(this.meanEl);
        }
        insertBadge(val) {
            if (!isNull(val) && val !== '0') {
                this.badgeEl = createEl('oc-badge', { [orca.alias]: 'badge' }, val?.trim());
                this.wrapEl.appendChild(this.badgeEl);
            }
        }
        insertDisk(val) {
            if (val) {
                this.diskEl = createEl('img', { [orca.alias]: 'disk', src: val });
                this.labelEl.insertAdjacentElement('beforeBegin', this.diskEl);
            }
        }
        insertCube(val) {
            if (val) {
                this.cubeEl = createEl('img', { [orca.alias]: 'cube', src: val });
                this.labelEl.insertAdjacentElement('beforeBegin', this.cubeEl);
            }
        }
        insertImage(val) {
            if (val) {
                this.imageEl = createEl('img', { [orca.alias]: 'image', src: val });
                this.labelEl.insertAdjacentElement('beforeBegin', this.imageEl);
            }
        }
        insertTips(val) {
            if (val) {
                this.tipsIns = new Tooltip(this, {
                    content: val,
                    trigger: 'sticky',
                    deadShow: true,
                });
            }
        }
        fillWrap(data) {
            this.labelEl = createEl('i', { [orca.alias]: 'label' }, data.label);
            this.getWrap(data);
            data.icon ? this.insertIcon(data.icon) : null;
            data.tail ? this.insertTail(data.tail) : null;
            data.mean ? this.insertMean(data.mean) : null;
            data.cube ? this.insertCube(data.cube) : null;
            data.image ? this.insertImage(data.image) : null;
            data.disk ? this.insertDisk(data.disk) : null;
            data.hasOwnProperty('badge') ? this.insertBadge(data.badge) : null;
        }
        render(data) {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            label: this.changedLabel,
            href: this.changedHref,
            target: this.changedTarget,
            rel: this.changedTarget,
            download: this.changedTarget,
            tab: this.changedTab,
            icon: this.changedIcon,
            disk: this.changedDisk,
            cube: this.changedCube,
            image: this.changedImage,
            tips: this.changedTips,
            tail: this.changedTail,
            mean: this.changedMean,
            badge: this.changedBadge,
        };
        changedLabel(opt) {
            this.labelEl.innerHTML = opt.newVal || '';
        }
        changedHref(opt) {
            if (opt.newVal === null || opt.oldVal === null) {
                this.innerHTML = '';
                this.fillWrap(this.propsProxy);
                this.render();
            }
            else {
                this.wrapEl.href = opt.newVal;
            }
        }
        changedTarget(opt) {
            if (opt.newVal) {
                this.wrapEl.setAttribute(opt.name, opt.newVal);
            }
            else {
                this.wrapEl.removeAttribute(opt.name);
            }
        }
        changedTab(opt) {
            opt.newVal ? this.wrapEl.tabIndex = opt.newVal : this.wrapEl.removeAttribute('tabindex');
        }
        changedIcon(opt) {
            if (this.iconEl) {
                this.iconEl.setAttribute('class', opt.newVal);
            }
            else {
                this.insertIcon(opt.newVal);
            }
        }
        changedTail(opt) {
            if (this.tailEl) {
                this.tailEl.setAttribute('class', opt.newVal);
            }
            else {
                this.insertTail(opt.newVal);
            }
        }
        changedDisk(opt) {
            if (this.diskEl) {
                this.diskEl.setAttribute('src', opt.newVal);
            }
            else {
                this.insertDisk(opt.newVal);
            }
        }
        changedCube(opt) {
            if (this.cubeEl) {
                this.cubeEl.setAttribute('src', opt.newVal);
            }
            else {
                this.insertCube(opt.newVal);
            }
        }
        changedImage(opt) {
            if (this.imageEl) {
                this.imageEl.setAttribute('src', opt.newVal);
            }
            else {
                this.insertImage(opt.newVal);
            }
        }
        changedMean(opt) {
            if (this.meanEl) {
                this.meanEl.setAttribute(orca.alias, opt.newVal);
            }
            else {
                this.insertMean(opt.newVal);
            }
        }
        changedBadge(opt) {
            if (this.badgeEl) {
                isNull(opt.newVal) || opt.newVal === '0' ? this.badgeEl.remove() : this.badgeEl.setAttribute('label', opt.newVal);
            }
            else {
                this.insertBadge(opt.newVal);
            }
        }
        changedTips(opt) {
            if (this.tipsIns) {
                this.tipsIns.updateCont(opt.newVal);
                if (opt.newVal) {
                    this.tipsIns.popupIns.state !== 'shown' && this.tipsIns.popupIns.show();
                }
                else {
                    this.tipsIns.popupIns.hide();
                }
            }
            else {
                opt.newVal ? this.insertTips(this.propsProxy.tips) : null;
            }
        }
    }

    class LineElem extends CompBaseComm {
        labelEl;
        startEl;
        endEl;
        contRaw;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['type', 'theme', 'size', 'align', 'dir', ...this.baseAttrs];
        static boolAttrs = [];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, LineElem);
        }
        getRawData() {
            this.getRawProps(LineElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, this.labelEl);
            this.startEl = createEl('i', { [orca.alias]: 'start' });
            this.endEl = createEl('i', { [orca.alias]: 'end' });
            this.labelEl = createEl('i', { [orca.alias]: 'label' }, data.label);
            this.wrapEl.appendChild(this.startEl);
            data.label ? this.wrapEl.append(this.labelEl, this.endEl) : null;
        }
        render(data) {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            label: this.changedLabel,
        };
        changedLabel(opt) {
            this.labelEl.innerHTML = opt.newVal;
            if (opt.newVal) {
                (elState(this.labelEl).isVirtual) && this.wrapEl.append(this.labelEl, this.endEl);
            }
            else {
                this.labelEl.remove();
                this.endEl.remove();
            }
        }
    }

    class AvatarElem extends CompBaseComm {
        mainEl;
        badgeEl;
        tipsEl;
        contRaw;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static dependencies = [{ tag: 'oc-badge', comp: BadgeElem }];
        static custAttrs = ['type', 'theme', 'tips', 'size', 'src', 'shape', 'badge', 'href', 'target', 'rel', ...this.baseAttrs];
        static boolAttrs = ['disabled'];
        static get observedAttributes() {
            return ['src', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, AvatarElem);
        }
        getMainEl(type, src) {
            return (type === 'text') ? createEl('i', { [orca.alias]: 'main' }, src || 'null') : createEl('img', { [orca.alias]: 'main', src: src || orca.images.avatar });
        }
        getRawData() {
            this.getRawProps(AvatarElem);
            this.propsRaw.src = this.getAttribute('src') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('a', { [orca.alias]: 'wrap' });
            this.badgeEl = createEl('oc-badge', { [orca.alias]: 'badge', shadowed: '', label: data?.badge?.trim() });
            this.tipsEl = createEl('i', { [orca.alias]: 'tips' }, data.tips || '');
            this.mainEl = this.getMainEl(data.type, data.src);
            this.wrapEl.appendChild(this.mainEl);
            this.hasAttribute('badge') && this.wrapEl.appendChild(this.badgeEl);
            this.getAttribute('tips') && this.wrapEl.appendChild(this.tipsEl);
        }
        render(data) {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            badge: this.changedBadge,
            tips: this.changedTips,
            src: this.changedSrc,
            href: this.changedHref,
            target: this.changedHref,
            rel: this.changedHref,
            type: this.changedType,
        };
        changedSrc(opt) {
            (this.propsProxy.type === 'text') ? this.mainEl.innerHTML = opt.newVal : this.mainEl.src = opt.newVal;
        }
        changedHref(opt) {
            if (opt.newVal) {
                this.wrapEl.setAttribute(opt.name, opt.newVal);
            }
            else {
                this.wrapEl.removeAttribute(opt.name);
            }
        }
        changedBadge(opt) {
            if (opt.newVal === null) {
                this.badgeEl.remove();
            }
            else {
                this.badgeEl.setAttribute('label', (opt.newVal === '0' || !opt.newVal) ? '' : opt.newVal);
                (elState(this.badgeEl).isVirtual) ? this.wrapEl.appendChild(this.badgeEl) : null;
            }
        }
        changedTips(opt) {
            if (opt.newVal === null) {
                this.tipsEl.remove();
            }
            else {
                this.tipsEl.innerHTML = opt.newVal;
                (elState(this.tipsEl).isVirtual) ? this.wrapEl.appendChild(this.tipsEl) : null;
            }
        }
        changedType(opt) {
            if ((this.mainEl.nodeName === 'IMG' && opt.newVal === 'text') || (this.mainEl.nodeName === 'I' && (opt.newVal === 'image' || !opt.newVal))) {
                this.mainEl.remove();
                this.mainEl = this.getMainEl(opt.newVal, this.propsProxy.src);
                this.wrapEl.appendChild(this.mainEl);
            }
        }
    }

    class FormatElem extends CompBaseComm {
        tipsIns;
        infoEl;
        separator;
        locale;
        prefixEl;
        suffixEl;
        prefixTips;
        suffixTips;
        labelEl;
        places;
        constructor() {
            super();
            this.getRawData();
            this.locale = navigator.language || 'en-US';
            this.getSeparator();
            this.places = 2;
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['type', 'rts', 'info', 'tips', 'lines', 'size', 'width', 'locale', 'places', ...this.baseAttrs];
        static boolAttrs = [];
        static jsonAttrs = ['lang', 'prefix', 'suffix'];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, FormatElem);
        }
        getRawData() {
            this.getRawProps(FormatElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            let sfxStr = this.getAttribute('suffix')?.trim(), preStr = this.getAttribute('prefix')?.trim();
            this.propsRaw.prefix = { content: !preStr?.startsWith('{') && !preStr?.endsWith('}') ? preStr : '', tips: {} };
            this.propsRaw.suffix = { content: !sfxStr?.startsWith('{') && !sfxStr?.endsWith('}') ? sfxStr : '', tips: {} };
            this.getProxyProps();
        }
        fillWrap(data) {
            this.labelEl = createEl('span', { [orca.alias]: 'label' }, data.label);
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, this.labelEl);
            this.fillCont(data);
        }
        fillCont(data) {
            if (data.type === 'ruby') {
                this.labelEl.innerHTML = `<ruby>${this.getRuby(data.label, data.rts)}</ruby>`;
            }
            else if (data.type === 'latex') {
                try {
                    new Function(`label`, `el`, `"use strict";${data.engin || 'katex.render(label, el)'}`)(data.label, this.labelEl);
                }
                catch {
                    console.error('Please introduce a math formula parsing plugin(katex)!');
                }
            }
            else if (data.type === 'break') {
                this.labelEl.innerHTML = this.getBrText(data.label, data.lines, data.size);
            }
            else if (data.type === 'localenum') {
                this.labelEl.innerHTML = this.getLocaleNum(data.label);
            }
            else if (data.type === 'plainnum') {
                this.labelEl.innerHTML = this.getPlainNum(data.label);
            }
            else if (data.type === 'padstart' || data.type === 'padend') {
                this.labelEl.innerHTML = this.getPadstr(data.label, data.type);
            }
            else {
                this.labelEl.innerHTML = data.label;
            }
        }
        render(data) {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        getRuby(text, rts) {
            let result = '';
            if (!text) {
                return result;
            }
            if (!rts) {
                return text;
            }
            let chars = text.split(''), hyphen = text.includes(config.splitHyphen) ? config.splitHyphen : config.wordHyphen, rtArr = rts.split(hyphen);
            chars = chars.map((k, i) => {
                return `${k}<rt>${rtArr[i] || ''}</rt>`;
            });
            result = chars.join('');
            return result;
        }
        getBrText(text, lines = 2, size) {
            if (!text) {
                return '';
            }
            if (lines === 1 || !lines) {
                return text;
            }
            let points = Math.ceil(text.length / lines), fontSize = size ? 'style="font-size:' + size + '"' : '', result = `<i class="${orca.prefix}t-br" ${fontSize}>`, hasBr = text.includes('<br') ? true : false;
            if (hasBr) {
                result += text;
            }
            else {
                for (let i = 0; i < lines; i++) {
                    if (i === lines - 1) {
                        result += text.substring(i * points);
                    }
                    else {
                        result += text.substring(i * points, (i + 1) * points) + '<br/>';
                    }
                }
            }
            return result + '</i>';
        }
        getLocaleNum(text) {
            let localeObj = new Intl.NumberFormat(this.locale).formatToParts(text.trim()), localeStr = localeObj.map(k => k.value).join('');
            return localeStr;
        }
        getPlainNum(text) {
            return text.trim().replaceAll(this.separator[0], '').replaceAll(this.separator[1], '.');
        }
        getSeparator() {
            this.separator = this.locale == 'de-DE' ? ['.', ','] :
                this.locale == 'fr-FR' ? [' ', ','] :
                    this.locale == 'de-CH' ? [`’`, '.'] :
                        this.locale == 'sv-SE' ? [` `, ','] : [',', '.'];
        }
        getPadstr(text, placement = 'padend') {
            let tmp = text.replaceAll(this.separator[0], ''), split = tmp.split(this.separator[1]), int = split[0], dec = split[1] || '', dot = dec ? this.separator[1] : '';
            if (placement === 'padstart') {
                return int.length > this.places ? tmp : int.padStart(this.places, '0') + dot + dec;
            }
            else {
                return dec.length > this.places ? tmp : int + dot + dec.padEnd(this.places, '0');
            }
        }
        changedMaps = {
            label: this.changedLabel,
            type: this.changedLabel,
            rts: this.changedRts,
            prefix: this.changedEnds,
            suffix: this.changedEnds,
            lines: this.changedLines,
            size: this.changedSize,
            width: this.changedWidth,
            locale: this.changedLocale,
            places: this.changedPlaces,
        };
        changedLabel(opt) {
            this.labelEl.innerHTML = '';
            this.fillCont(this.propsProxy);
        }
        changedRts(opt) {
            if (this.propsProxy.type === 'ruby') {
                this.labelEl.innerHTML = `<ruby>${this.getRuby(this.propsProxy.label, opt.newVal)}</ruby>`;
            }
        }
        changedEnds(opt) {
            if (opt.newVal === null) {
                this[`${opt.name}El`].remove();
                return;
            }
            let el = this[`${opt.name}El`], tips = this[`${opt.name}Tips`], data = this.propsProxy[opt.name], content = isNull(data.content) ? this.propsRaw[opt.name].content : data.content;
            if (content) {
                if (el) {
                    el.innerHTML = content;
                }
                else {
                    this[`${opt.name}El`] = createEl('i', { [orca.alias]: opt.name }, content);
                    el = this[`${opt.name}El`];
                    this.wrapEl.insertAdjacentElement(opt.name === 'suffix' ? 'beforeend' : 'afterbegin', el);
                }
                if (!isEmpty(data.tips)) {
                    if (typeof data.tips === 'string') {
                        this.propsProxy[opt.name].tips = { content: data.tips };
                    }
                    if (tips) {
                        tips.update(this.propsProxy[opt.name].tips);
                    }
                    else {
                        this[`${opt.name}Tips`] = new Tooltip(el, this.propsProxy[opt.name].tips);
                    }
                }
                else {
                    tips && tips.update({ asleep: true });
                }
            }
            else {
                el && el.remove();
            }
        }
        changedLines(opt) {
            if (this.propsProxy.type === 'break') {
                this.labelEl.innerHTML = this.getBrText(this.propsProxy.label, ~~opt.newVal, this.propsProxy.size);
            }
        }
        changedSize(opt) {
            if (this.propsProxy.type === 'break') {
                let tmp = this.labelEl.firstElementChild;
                tmp ? tmp.style.fontSize = opt.newVal : null;
            }
        }
        changedWidth(opt) {
            if (this.propsProxy.type === 'break') {
                let tmp = this.labelEl.firstElementChild;
                tmp ? tmp.style.width = opt.newVal : null;
            }
        }
        changedLocale(opt) {
            this.locale = !opt.newVal ? navigator.language || 'en-US' : opt.newVal;
            this.getSeparator();
            if (['localenum', 'plainnum'].includes(this.propsProxy.type)) {
                this.labelEl.innerHTML = '';
                this.fillCont(this.propsProxy);
            }
        }
        changedPlaces(opt) {
            if (!['padstart', 'padend'].includes(this.propsProxy.type))
                return;
            if (opt.newVal !== null) {
                this.places = ~~opt.newVal;
            }
            this.labelEl.innerHTML = this.getPadstr(this.propsProxy.label, this.propsProxy.type);
        }
    }

    class FlagElem extends CompBaseComm {
        labelEl;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['type', 'theme', 'placement', ...this.baseAttrs];
        static boolAttrs = [];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, FlagElem);
        }
        getRawData() {
            this.getRawProps(FlagElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.labelEl = createEl('i', { [orca.alias]: 'label' }, this.propsProxy.label);
            this.wrapEl = createEl('span', { [orca.alias]: 'wrap' }, this.labelEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            label: this.changedLabel,
        };
        changedLabel(opt) {
            this.labelEl.innerHTML = opt.newVal || '';
        }
    }

    class BuoyElem extends CompBaseComm {
        headEl;
        labelEl;
        iconEl;
        arrowEl;
        valueEl;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['icon', 'label', 'theme', 'size', ...this.baseAttrs];
        static boolAttrs = ['inverted', 'arrow'];
        static get observedAttributes() {
            return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, BuoyElem);
        }
        getRawData() {
            this.getRawProps(BuoyElem);
            this.propsRaw.value = this.getAttribute('value') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('span', { [orca.alias]: 'wrap' });
            this.headEl = createEl('span', { [orca.alias]: 'head' });
            this.labelEl = createEl('i', { [orca.alias]: 'label' }, data.label || '');
            this.iconEl = createEl('i', { class: data.icon || '', [orca.alias]: 'icon' });
            this.arrowEl = createEl('i', { class: `${orca.prefix}icon-down`, [orca.alias]: 'arrow' });
            this.valueEl = createEl('i', { [orca.alias]: 'value' }, data.value || '');
            data.label ? this.headEl.appendChild(this.labelEl) : null;
            data.icon ? this.headEl.insertAdjacentElement('afterBegin', this.iconEl) : null;
            data.arrow ? this.headEl.insertAdjacentElement('beforeEnd', this.arrowEl) : null;
            this.wrapEl.append(this.headEl, this.valueEl);
        }
        render(data) {
            this.insertSource();
            this.append(this.wrapEl);
        }
        changedMaps = {
            value: this.changedValue,
            label: this.changedLabel,
            icon: this.changedIcon,
            arrow: this.changedArrow,
        };
        changedValue(opt) {
            this.valueEl.innerHTML = opt.newVal || '';
        }
        changedLabel(opt) {
            if (opt.newVal === null) {
                this.labelEl.remove();
            }
            else {
                this.labelEl.innerHTML = opt.newVal;
                if (elState(this.labelEl).isVirtual) {
                    if (!elState(this.iconEl).isVirtual) {
                        this.iconEl.insertAdjacentElement('afterEnd', this.labelEl);
                    }
                    else {
                        this.headEl.insertAdjacentElement('afterBegin', this.labelEl);
                    }
                }
            }
        }
        changedIcon(opt) {
            if (opt.newVal === null) {
                this.iconEl.remove();
            }
            else {
                this.iconEl.setAttribute('class', opt.newVal);
                if (elState(this.iconEl).isVirtual) {
                    this.headEl.insertAdjacentElement('afterBegin', this.iconEl);
                }
            }
        }
        changedArrow(opt) {
            if (!attrValBool(opt.newVal)) {
                this.arrowEl.remove();
            }
            else {
                if (elState(this.arrowEl).isVirtual) {
                    this.headEl.appendChild(this.arrowEl);
                }
            }
        }
    }

    class GoodElem extends CompBaseComm {
        labelEl;
        iconEl;
        tipsEl;
        valueEl;
        increase;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
            this.increase = (step = 1, cb) => {
                let value = parseInt(this.properties.value) + step, tips = this.getAttribute('tips');
                this.canListen = false;
                this.setAttribute('value', String(value));
                tips && this.setAttribute('tips', tips);
                this.toggleAttribute('increased', true);
                cb && cb.call(this, value);
                this.canListen = true;
            };
        }
        static custAttrs = ['icon', 'label', 'tips', ...this.baseAttrs];
        static boolAttrs = ['disabled', 'increased'];
        static get observedAttributes() {
            return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, GoodElem);
        }
        getRawData() {
            this.getRawProps(GoodElem);
            this.propsRaw.value = this.getAttribute('value') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('span', { [orca.alias]: 'wrap' });
            this.labelEl = createEl('i', { [orca.alias]: 'label' });
            this.iconEl = createEl('i', { [orca.alias]: 'icon' });
            this.valueEl = createEl('i', { [orca.alias]: 'value' }, data.value || '');
            this.tipsEl = createEl('i', { [orca.alias]: 'tips' });
            this.wrapEl.appendChild(this.valueEl);
        }
        render(data) {
            this.insertSource();
            this.append(this.labelEl, this.wrapEl, this.tipsEl);
        }
        changedMaps = {
            label: this.changedLabel,
            value: this.changedLabel,
            tips: this.changedLabel,
            icon: this.changedIcon,
        };
        changedLabel(opt) {
            this[opt.name + 'El'].innerHTML = opt.newVal || '';
        }
        changedIcon(opt) {
            if (opt.newVal === null) {
                this.iconEl.remove();
            }
            else {
                this.iconEl.setAttribute('class', opt.newVal);
                elState(this.iconEl).isVirtual && this.wrapEl.insertAdjacentElement('afterBegin', this.iconEl);
            }
        }
    }

    class AnchorsElem extends CompBaseComm {
        data;
        smoothEvent;
        interactIns;
        constructor() {
            super();
            this.getRawData();
            this.createInteract();
            this.fillWrap(this.propsProxy);
            this.render(this.propsProxy);
        }
        static custAttrs = ['root', 'active', 'offset', ...this.baseAttrs];
        static boolAttrs = ['smooth'];
        static get observedAttributes() {
            return ['headings', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, AnchorsElem);
        }
        getRawData() {
            this.getRawProps(AnchorsElem);
            this.propsRaw.headings = this.getHeadings(this.getAttribute('headings') || this.rawHtml);
            this.getProxyProps();
        }
        createInteract() {
            this.interactIns = new IntersectionObserver(entries => {
                for (let k of entries) {
                    if (k.isIntersecting) {
                        if (k.intersectionRatio === 1) {
                            this.activate(k.target, true, false);
                        }
                    }
                }
            }, {
                threshold: [1],
            });
        }
        getHeadings(str) {
            return valToArr(str).map((k) => {
                let tmp = k.split('|');
                return { heading: tmp[0], exclude: tmp[1] };
            });
        }
        getData(headings) {
            if (headings.length === 0) {
                headings = [{ heading: 'h2', exclude: '' }];
            }
            let result = [], getChildren = (index, current, arr, pNext) => {
                let els = getEls(current.heading, this.propsProxy.root), excEls = getEls(current.exclude, this.propsProxy.root), keyNext = headings[index + 1]?.heading;
                for (let [y, x] of els.entries()) {
                    let obj = {
                        target: x,
                        label: x.textContent.replace('§', '')
                    };
                    let children = getBetweenEls({
                        selector: keyNext,
                        start: x,
                        end: els[y + 1] || pNext,
                        root: this.propsProxy.root,
                    });
                    if (children.length > 0) {
                        obj.children = [];
                        getChildren(index + 1, headings[index + 1], obj.children, els[y + 1]);
                    }
                    if (excEls.length && excEls.find((i) => i.contains(x)))
                        continue;
                    arr.push(obj);
                }
            };
            getChildren(0, headings[0], result);
            treeTools.addIdPath({ source: result });
            return result;
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
            this.get2FillTreeNodes(data);
        }
        get2FillTreeNodes(data) {
            this.data = this.getData(data.headings);
            let plantTree = (parent, data) => {
                let ul = createEl('ul', { class: `${orca.prefix}reset` });
                for (let k of data) {
                    k.wrapEl = createEl('li', { [orca.alias]: 'wrap' });
                    k.labelEl = createEl('a', { [orca.alias]: 'label', href: `#${k.label}` }, k.label);
                    k.headEl = createEl('div', { [orca.alias]: 'head', id: k.id }, k.labelEl);
                    k.wrapEl.appendChild(k.headEl);
                    k.labelEl.onclick = () => this.smoothToActive(k, false);
                    k.target.id = k.label;
                    k.target.classList.add(`${orca.prefix}anchor`);
                    let tmp = k.target.querySelector(`${orca.prefix}hash`);
                    tmp && tmp.remove();
                    k.hashEl = createEl('a', { href: `#${k.label}`, class: `${orca.prefix}hash` }, '§');
                    k.hashEl.onclick = () => this.smoothToActive(k, false);
                    k.target.appendChild(k.hashEl);
                    this.interactIns.observe(k.target);
                    if (k.hasOwnProperty('children')) {
                        k.bodyEl = plantTree(k.wrapEl, k.children);
                        k.bodyEl.setAttribute(orca.alias, 'body');
                    }
                    ul.appendChild(k.wrapEl);
                }
                parent.appendChild(ul);
                return ul;
            };
            this.wrapEl.innerHTML = '';
            plantTree(this.wrapEl, this.data);
        }
        render(data) {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        activate(data, active = true, smooth = true) {
            if (!data) {
                return this;
            }
            let flat = treeTools.toFlat(this.data), dataType = getDataType(data), tmp = Number(data), value = tmp === 0 || !!tmp ? tmp : data, item = dataType.includes('HTML') ? findItem(data, flat, 'target') : findItem(value, flat);
            if (item) {
                if (!item.active && active) {
                    item.headEl.setAttribute('active', '');
                    item.active = true;
                    let others = flat.filter((k) => k !== item && k.active);
                    for (let k of others) {
                        k.headEl.removeAttribute('active');
                        Reflect.deleteProperty(k, 'active');
                    }
                }
                if (smooth) {
                    if (this.propsProxy.smooth) {
                        scrollTo(item.target, {
                            offset: this.propsProxy.offset,
                        });
                    }
                }
            }
        }
        addSmooth() {
            let flat = treeTools.toFlat(this.data);
            for (let k of flat) {
                k.labelEl.onclick = () => this.smoothToActive(k, false);
                k.hashEl.onclick = () => this.smoothToActive(k, false);
            }
        }
        removeSmooth() {
            let flat = treeTools.toFlat(this.data);
            for (let k of flat) {
                k.labelEl.onclick = null;
                k.hashEl.onclick = null;
            }
        }
        smoothToActive(obj, active = true) {
            this.activate(obj.target, active, this.propsProxy.smooth);
        }
        changedMaps = {
            headings: this.changedRender,
            root: this.changedRender,
            active: this.changedActive,
            offset: this.changedOffset,
            smooth: this.changedSmooth,
        };
        changedRender(opt) {
            this.get2FillTreeNodes(this.propsProxy);
        }
        changedActive(opt) {
            this.activate(opt.newVal);
        }
        changedOffset(opt) {
            for (let k of this.data)
                k.target.style.scrollMarginTop = opt.newVal;
        }
        changedSmooth(opt) {
            let bool = attrValBool(opt.newVal);
            bool ? this.addSmooth() : this.removeSmooth();
        }
    }

    class MenuElem extends CompBaseComm {
        constructor() {
            super();
            this.createShadow();
            super.createPropsObs();
            this.fillWrap(this.propsProxy);
        }
        static get observedAttributes() {
            return [...optMenu$1.map((k) => k.attr), 'options', 'async'];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            if (name === 'active') {
                this.ins && newVal && this.ins.activate(newVal);
            }
            if (name === 'disable') {
                this.ins && newVal && this.ins.treeIns.disable(newVal);
            }
            else {
                super.updateProxy(name, newVal, optMenu$1);
            }
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'slot-host' }, this.rawHtml);
        }
        createIns() {
            if (this.ins)
                return;
            this.ins = new Menu(this.wrapEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
        }
    }

    class FileElem extends CompBaseCommField {
        holderEl;
        meanEl;
        clickEvent;
        changeEvt;
        namesEl;
        type;
        clickEvt;
        labelEl;
        constructor() {
            super();
            this.type = 'file-comp';
            this.getRawData();
            this.fillWrap(this.propsProxy);
            this.clickEvt = (evt) => {
                let target = getEvtTarget(evt);
                if (this.toolsEl && this.toolsEl.contains(target))
                    return;
                this.inputEl.click();
            };
            this.zeroEvt = new Event('change');
        }
        static custAttrs = ['name', 'value', 'accept', 'size', 'label', 'show', 'tools', ...this.evtsArr];
        static boolAttrs = ['disabled', 'readonly', 'multiple', 'full'];
        static get observedAttributes() {
            return ['placeholder', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, FileElem, { tools: getAttrArr(newVal, 'close') });
        }
        getRawData() {
            this.getRawProps(FileElem);
            this.propsRaw.placeholder = this.getAttribute('placeholder') || this.rawHtml || config.lang.form.fileLabel;
            this.propsRaw.value = this.propsRaw.multiple ? [] : '';
            this.getProxyProps();
            this.propsProxy['tools'] = getAttrArr(this.getAttribute('tools'), 'close');
            this.value = this.propsProxy.value;
            this.setFieldProps(['name', 'value', 'disabled', 'readonly', 'multiple']);
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
            this.inputEl = createEl('input', { type: 'file', [orca.embedSign]: '' });
            this.inputEl.multiple = data.multiple;
            this.labelEl = createEl('span', { [orca.alias]: 'label' });
            data.name && (this.inputEl.name = (data.name + (this.inputEl.multiple ? `[]` : '')) || '');
            super.getToolsEl(data.tools);
            this.holderEl = createEl('i', { [orca.alias]: 'placeholder' }, data.placeholder);
            this.namesEl = createEl('i', { [orca.alias]: 'names' });
            this.meanEl = createEl('i', { [orca.alias]: 'mean' }, 'file');
            this.wrapEl.append(this.inputEl, this.namesEl, this.holderEl, this.meanEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.inputEl.addEventListener('change', (e) => {
                let files = [...this.inputEl.files], names = files.map((k) => k.name), oldVal = this.value;
                this.value = this.propsProxy.multiple ? files : files[0] || '';
                files.length > 0 && (this.propsProxy.value = names.join(','));
                this.namesEl.innerHTML = (files.length === 0) ? '' : (files.length === 1) ? this.inputEl.value : renderTpl(this.propsProxy.lang?.multi || config.lang.form.fileMulti, { data: files.length }) + this.propsProxy.value;
                if (this.mediaEl) {
                    this.mediaEl.innerHTML = '';
                    for (let k of Array.from(e.target.files))
                        this.read2Append(k, this.mediaEl);
                }
                this.listen({ name: 'changed', params: [{ oldVal, newVal: this.value }] });
            }, false);
            this.wrapEl.addEventListener('click', this.clickEvt);
        }
        read2Append(file, box) {
            let reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = (evt) => {
                let src = evt.target.result, el;
                if (file.type.startsWith('image/')) {
                    el = orca.createEl('img', { src });
                }
                else if (file.type.startsWith('video/')) {
                    el = orca.createEl('video', { src, controls: true });
                }
                else if (file.type.startsWith('audio/')) {
                    el = orca.createEl('audio', { src, controls: true });
                }
                el && box.appendChild(el);
            };
        }
        changedMaps = {
            disabled: this.changedBool,
            readonly: this.changedBool,
            multiple: this.changedBool,
            full: this.changedBool,
            name: this.changedName,
            value: this.changedValue,
            accept: this.changedName,
            tools: this.changedTools,
            placeholder: this.changedHolder,
            label: this.changedLabel,
            show: this.changedShow,
        };
        changedBool(opt) {
            this.inputEl[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
            this[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
        }
        changedTools(opt) {
            this.toolsEl && this.toolsEl.remove();
            if (this.propsProxy.tools.length > 0) {
                super.getToolsEl(this.propsProxy.tools);
                this.propsProxy.tools.forEach((k) => {
                    if (k.name === 'close') {
                        k.wrapEl.onclick = () => {
                            this.clear();
                        };
                    }
                    else {
                        k.action && k.action.bind(this);
                    }
                });
                this.holderEl.insertAdjacentElement('afterEnd', this.toolsEl);
            }
        }
        changedHolder(opt) {
            this.holderEl.innerHTML = opt.newVal;
        }
        changedName(opt) {
            this.inputEl.setAttribute(opt.name, opt.newVal);
            opt.name === 'name' && (this.name = opt.newVal + (this.propsProxy.multiple ? `[]` : ''));
            if (opt.name === 'name') {
                this.name = opt.newVal || '';
                if (this.name) {
                    this.inputEl.name = this.propsProxy.multiple ? `${this.name}[]` : this.name;
                }
                else {
                    this.inputEl.removeAttribute('name');
                }
            }
        }
        changedValue(opt) {
            this.clear();
            console.warn('The field.files property cannot be changed through scripts,this operation is performed by resetting!');
        }
        changedLabel(opt) {
            if (opt.newVal) {
                this.labelEl.innerHTML = opt.newVal;
                elState(this.labelEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.labelEl);
            }
            else {
                this.labelEl.remove();
            }
        }
        changedShow(opt) {
            this.mediaEl && (this.mediaEl.innerHTML = '');
            if (opt.newVal) {
                this.mediaEl = getEl(opt.newVal);
                let arr = Array.from(this.inputEl.files);
                if (!this.mediaEl || !arr.length)
                    return;
                for (let k of arr)
                    this.read2Append(k, this.mediaEl);
            }
        }
    }

    class InputElem extends CompBaseCommField {
        unitEl;
        customEl;
        imageEl;
        labelEl;
        limitEl;
        diskEl;
        cubeEl;
        iconEl;
        btnEl;
        meanEl;
        type;
        select;
        btnEvt;
        constructor() {
            super();
            this.type = 'text-comp';
            this.getRawData();
            this.fillWrap(this.propsProxy);
            this.select = () => this.inputEl.select();
            this.btnEvt = (evt) => {
                if (evt.code === 'Enter' && elState(this.btnEl).isVisible && this.btnEl.click && !this.propsProxy.blocked) {
                    preventDft(evt);
                    this.btnEl.click();
                }
            };
            this.addEventListener('click', (e) => {
                let target = getEvtTarget(e);
                target === this.wrapEl && this.inputEl.focus();
            }, false);
            this.inputEl.addEventListener('input', (e) => {
                let tmp = this.propsProxy.value;
                this.propsProxy.value = this.value = this.inputEl.value;
                this.updateLimit();
                let data = { oldVal: tmp, newVal: this.inputEl.value };
                this.listen({ name: 'input', params: [data] });
                (tmp !== this.inputEl.value) && this.listen({ name: 'changed', params: [data] });
            }, false);
        }
        static custAttrs = ['name', 'placeholder', 'type', 'size', 'limit', 'tools', 'icon', 'cube', 'disk', 'image', 'btn', 'action', 'label', 'unit', 'custom', 'mean', 'task', ...this.evtsArr];
        static boolAttrs = ['disabled', 'readonly', 'blocked', 'full'];
        static get observedAttributes() {
            return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, InputElem, { tools: getAttrArr(newVal, 'close') });
        }
        getRawData() {
            this.getRawProps(InputElem);
            this.propsRaw.value = this.getAttribute('value') || this.rawHtml;
            this.getProxyProps();
            this.propsProxy['tools'] = getAttrArr(this.getAttribute('tools'), 'close');
            this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
            this.inputEl = createEl('input', { type: data.type || 'text', placeholder: data.placeholder || config.lang.form.placeholder, [orca.embedSign]: '' });
            data.value && (this.inputEl.value = data.value || '');
            data.name && (this.inputEl.name = data.name || '');
            this.wrapEl.appendChild(this.inputEl);
            super.getToolsEl(data.tools);
            this.limitEl = createEl('div', { [orca.alias]: 'limit' });
            this.labelEl = createEl('span', { [orca.alias]: 'label' });
            this.unitEl = createEl('span', { [orca.alias]: 'unit' });
            this.diskEl = createEl('img', { [orca.alias]: 'disk' });
            this.cubeEl = createEl('img', { [orca.alias]: 'cube' });
            this.imageEl = createEl('img', { [orca.alias]: 'image' });
            this.iconEl = createEl('i', { [orca.alias]: 'icon' });
            this.btnEl = createEl('span', { [orca.alias]: 'btn' });
            this.customEl = createEl('span', { [orca.alias]: 'custom' });
            this.meanEl = createEl('i', { [orca.alias]: 'mean' });
        }
        updateLimit() {
            let total = ~~this.propsProxy.limit, value = this.propsProxy.value, len = value.length, tmp = total - len, remaining = tmp <= 0 ? 0 : tmp;
            if (!total) {
                return this;
            }
            this.limitEl.innerHTML = renderTpl(this.propsProxy.lang?.max || config.lang.form.maxLength, { total, value: len, remaining });
            if (tmp <= 0) {
                if (tmp < 0) {
                    this.inputEl.value = value.slice(0, total);
                    this.inputEl.dispatchEvent(this.zeroEvt);
                }
                this.setAttribute('exceeded', '');
            }
            else {
                this.removeAttribute('exceeded');
            }
            elState(this.limitEl).isVirtual && this.appendChild(this.limitEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            ~~this.propsProxy.limit && this.appendChild(this.limitEl);
        }
        changedMaps = {
            disabled: this.changedBool,
            readonly: this.changedBool,
            blocked: this.changedBool,
            full: this.changedBool,
            name: this.changedName,
            type: this.changedName,
            placeholder: this.changedName,
            value: this.changedValue,
            icon: this.changedIcon,
            disk: this.changedImage,
            cube: this.changedImage,
            image: this.changedImage,
            task: this.changedTask,
            label: this.changedLabel,
            unit: this.changedUnit,
            custom: this.changedCustom,
            action: this.changedAction,
            btn: this.changedBtn,
            mean: this.changedMean,
            limit: this.changedLimit,
            tools: this.changedTools,
        };
        changedBool(opt) {
            if (opt.name === 'blocked') {
                if (this.propsProxy['blocked']) {
                    this.btnEl.setAttribute('disabled', '');
                }
                else {
                    this.btnEl.removeAttribute('disabled');
                }
            }
            else {
                this.inputEl[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
                this[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
            }
        }
        changedTools(opt) {
            this.toolsEl && this.toolsEl.remove();
            if (this.propsProxy.tools.length > 0) {
                super.getToolsEl(this.propsProxy.tools);
                this.propsProxy.tools.forEach((k) => {
                    if (k.name === 'close') {
                        k.wrapEl.onclick = () => this.clear();
                    }
                    else {
                        k.action && k.action.bind(this);
                    }
                });
                this.inputEl.insertAdjacentElement('afterend', this.toolsEl);
            }
        }
        changedValue(opt) {
            this.value = opt.newVal || '';
            let tmp = this.inputEl.value;
            this.inputEl.value = opt.newVal;
            (tmp !== this.value) && this.listen({ name: 'changed', params: [{ oldVal: tmp, newVal: this.value }] });
        }
        changedLimit(opt) {
            this.updateLimit();
        }
        changedName(opt) {
            if (opt.name === 'type' && !['text', 'number', 'search', 'email', 'url', 'tel', 'password', 'time', 'week', 'datetime', 'datetime-local', 'month'].includes(opt.newVal))
                return;
            isNull(opt.newVal) ? this.inputEl.removeAttribute(opt.name) : this.inputEl.setAttribute(opt.name, opt.newVal);
            opt.name === 'name' && (this.name = opt.newVal || '');
        }
        changedLabel(opt) {
            if (opt.newVal) {
                this.labelEl.innerHTML = opt.newVal;
                elState(this.labelEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.labelEl);
            }
            else {
                this.labelEl.remove();
            }
        }
        changedUnit(opt) {
            if (opt.newVal) {
                this.unitEl.innerHTML = opt.newVal;
                elState(this.unitEl).isVirtual && this.wrapEl.appendChild(this.unitEl);
            }
            else {
                this.unitEl.remove();
            }
        }
        changedCustom(opt) {
            if (opt.newVal) {
                this.customEl.innerHTML = opt.newVal;
                if (elState(this.customEl).isVirtual) {
                    elState(this.unitEl).isVisible ? this.unitEl.insertAdjacentElement('beforebegin', this.customEl) : this.wrapEl.appendChild(this.customEl);
                }
            }
            else {
                this.customEl.remove();
            }
        }
        changedBtn(opt) {
            if (opt.newVal) {
                this.btnEl.innerHTML = opt.newVal;
                if (elState(this.btnEl).isVirtual) {
                    elState(this.unitEl).isVisible ? this.unitEl.insertAdjacentElement('beforebegin', this.btnEl) : this.wrapEl.appendChild(this.btnEl);
                }
                this.inputEl.addEventListener('keydown', this.btnEvt, false);
            }
            else {
                this.btnEl.remove();
                this.inputEl.removeEventListener('keydown', this.btnEvt);
            }
        }
        changedAction(opt) {
            if (opt.newVal) {
                this.btnEl.onclick = () => {
                    new Function('"use strict";return ' + opt.newVal)().call(this, { btn: this.btnEl, el: this });
                };
            }
            else {
                this.btnEl.onclick = null;
            }
        }
        changedIcon(opt) {
            if (opt.newVal) {
                this.iconEl.classList.add(opt.newVal);
                elState(this.iconEl).isVirtual && this.inputEl.insertAdjacentElement('beforebegin', this.iconEl);
            }
            else {
                this.iconEl.remove();
            }
        }
        changedImage(opt) {
            if (opt.newVal) {
                this[`${opt.name}El`].src = opt.newVal;
                elState(this[`${opt.name}El`]).isVirtual && this.inputEl.insertAdjacentElement('beforebegin', this[`${opt.name}El`]);
            }
            else {
                this[`${opt.name}El`].remove();
            }
        }
        changedMean(opt) {
            if (opt.newVal) {
                this.meanEl.classList.add(opt.newVal);
                if (elState(this.meanEl).isVirtual) {
                    elState(this.unitEl).isVisible ? this.unitEl.insertAdjacentElement('beforebegin', this.meanEl) : this.wrapEl.appendChild(this.meanEl);
                }
            }
            else {
                this.meanEl.remove();
            }
        }
        changedTask(opt) {
            if (opt.newVal) {
                this.meanEl.onclick = () => {
                    new Function('"use strict";return ' + opt.newVal)().call(this, { btn: this.meanEl, el: this });
                };
            }
            else {
                this.meanEl.onclick = null;
            }
        }
    }

    class TextareaElem extends CompBaseCommField {
        labelEl;
        limitEl;
        type;
        select;
        headEl;
        meanEl;
        constructor() {
            super();
            this.type = 'textarea-comp';
            this.getRawData();
            this.fillWrap(this.propsProxy);
            this.select = () => this.inputEl.select();
            this.addEventListener('click', (e) => {
                let target = getEvtTarget(e);
                target === this.wrapEl && this.inputEl.focus();
            }, false);
            this.inputEl.addEventListener('input', (e) => {
                let tmp = this.propsProxy.value;
                this.propsProxy.value = this.inputEl.value;
                this.value = this.inputEl.value;
                this.updateLimit();
                this.addScrollable(this.inputEl);
                let data = { oldVal: tmp, newVal: this.inputEl.value };
                this.listen({ name: 'input', params: [data] });
                (tmp !== this.inputEl.value) && this.listen({ name: 'changed', params: [data] });
            }, false);
        }
        static custAttrs = ['name', 'placeholder', 'size', 'tools', 'limit', 'label', 'mean', 'task', ...this.evtsArr];
        static boolAttrs = ['disabled', 'readonly', 'single', 'full'];
        static get observedAttributes() {
            return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, TextareaElem, { tools: getAttrArr(newVal, 'close') });
        }
        getRawData() {
            this.getRawProps(TextareaElem);
            this.propsRaw.value = this.getAttribute('value') || this.rawHtml;
            this.getProxyProps();
            this.propsProxy['tools'] = getAttrArr(this.getAttribute('tools'), 'close');
            this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
            this.inputEl = createEl('textarea', { placeholder: data.placeholder || config.lang.form.placeholder, [orca.embedSign]: '' });
            data.value && (this.inputEl.value = data.value || '');
            data.name && (this.inputEl.name = data.name || '');
            this.wrapEl.appendChild(this.inputEl);
            this.getToolsEl(data.tools);
            this.limitEl = createEl('div', { [orca.alias]: 'limit' });
            this.labelEl = createEl('span', { [orca.alias]: 'label' });
            this.headEl = createEl('div', { [orca.alias]: 'head' }, this.labelEl);
            this.meanEl = createEl('i', { [orca.alias]: 'mean' });
        }
        updateLimit() {
            let total = ~~this.propsProxy.limit, value = this.propsProxy.value, len = value.length, tmp = total - len, remaining = tmp <= 0 ? 0 : tmp;
            if (!total) {
                return this;
            }
            this.limitEl.innerHTML = renderTpl(this.propsProxy.lang?.max || config.lang.form.maxLength, { total, value: len, remaining });
            if (tmp <= 0) {
                if (tmp < 0) {
                    this.inputEl.value = value.slice(0, total);
                    this.inputEl.dispatchEvent(this.zeroEvt);
                }
                this.setAttribute('exceeded', '');
            }
            else {
                this.removeAttribute('exceeded');
            }
            elState(this.limitEl).isVirtual && this.appendChild(this.limitEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            ~~this.propsProxy.limit && this.appendChild(this.limitEl);
        }
        changedMaps = {
            disabled: this.changedBool,
            readonly: this.changedBool,
            full: this.changedBool,
            name: this.changedName,
            placeholder: this.changedName,
            value: this.changedValue,
            tools: this.changedTools,
            label: this.changedLabel,
            mean: this.changedMean,
            single: this.changedSingle,
            task: this.changedTask,
        };
        changedBool(opt) {
            this.inputEl[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
            this[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
        }
        changedName(opt) {
            isNull(opt.newVal) ? this.inputEl.removeAttribute(opt.name) : this.inputEl.setAttribute(opt.name, opt.newVal);
            opt.name === 'name' && (this.name = opt.newVal || '');
        }
        changedTools(opt) {
            this.toolsEl && this.toolsEl.remove();
            if (this.propsProxy.tools.length > 0) {
                this.getToolsEl(this.propsProxy.tools);
                this.propsProxy.tools.forEach((k) => {
                    if (k.name === 'close') {
                        k.wrapEl.onclick = () => this.clear();
                    }
                    else {
                        k.action && k.action.bind(this);
                    }
                });
                if (!this.propsProxy['single'] && this.propsProxy['label']) {
                    this.headEl.appendChild(this.toolsEl);
                }
                else {
                    this.inputEl.insertAdjacentElement('afterend', this.toolsEl);
                }
            }
        }
        changedValue(opt) {
            this.value = opt.newVal || '';
            let tmp = this.inputEl.value;
            this.inputEl.value = this.value;
            (tmp !== this.value) && this.listen({ name: 'changed', params: [{ oldVal: tmp, newVal: this.value }] });
        }
        changedLabel(opt) {
            if (opt.newVal) {
                this.labelEl.innerHTML = opt.newVal;
                elState(this.headEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.headEl);
                !this.propsProxy.single && this.propsProxy.tools.length > 0 && this.headEl.appendChild(this.toolsEl);
                this.propsProxy.mean && this.headEl.insertAdjacentElement('afterbegin', this.meanEl);
            }
            else {
                this.headEl.remove();
                this.propsProxy.tools.length > 0 && this.wrapEl.appendChild(this.toolsEl);
                this.propsProxy.mean && this.propsProxy.single && this.wrapEl.appendChild(this.meanEl);
            }
        }
        changedSingle(opt) {
            if (this.propsProxy.single) {
                this.propsProxy.tools.length > 0 && this.wrapEl.appendChild(this.toolsEl);
                this.propsProxy.mean && this.wrapEl.appendChild(this.meanEl);
            }
            else {
                if (this.propsProxy.label) {
                    this.propsProxy.mean && this.headEl.insertAdjacentElement('afterbegin', this.meanEl);
                    this.propsProxy.tools.length > 0 && this.headEl.appendChild(this.toolsEl);
                }
                else {
                    this.propsProxy.tools.length > 0 && this.wrapEl.appendChild(this.toolsEl);
                    this.meanEl.remove();
                }
            }
        }
        changedMean(opt) {
            if (opt.newVal) {
                this.meanEl.classList.add(opt.newVal);
                if (elState(this.meanEl).isVirtual) {
                    if (!this.propsProxy.single) {
                        this.headEl.insertAdjacentElement('afterbegin', this.meanEl);
                    }
                    else {
                        this.wrapEl.appendChild(this.meanEl);
                    }
                }
            }
            else {
                this.meanEl.remove();
            }
        }
        changedTask(opt) {
            if (opt.newVal) {
                this.meanEl.onclick = () => {
                    new Function('"use strict";return ' + opt.newVal)().call(this, { btn: this.meanEl, el: this });
                };
            }
            else {
                this.meanEl.onclick = null;
            }
        }
    }

    class RadiosElem extends CompBaseCommField {
        labelEl;
        legendEl;
        inputs;
        setVals;
        setLabels;
        check;
        type;
        valMap;
        constructor() {
            super();
            this.type = 'radios-comp';
            this.getRawData();
            this.fillWrap(this.propsProxy);
            this.reset = () => {
                if (this.propsRaw.content != this.propsRaw.content)
                    this.updateInputs(this.propsRaw.content, this.propsRaw);
                for (let k in this.propsRaw) {
                    if (k === 'content')
                        continue;
                    (this.propsRaw[k] !== null && this.propsRaw[k] !== false) ? this.setAttribute(k, this.propsRaw[k]) : this.removeAttribute(k);
                }
                this.listen({ name: 'reset' });
            };
            this.clear = () => {
                this.removeAttribute('checked');
                this.listen({ name: 'cleared' });
            };
            this.check = (value, type = 'ed', from = 'value') => {
                let val = Array.isArray(value) ? value[0] : value;
                if (!val && val !== 0) {
                    this.setAttribute('checked', '');
                    return;
                }
                let input = this.inputs.find((i) => i.propsProxy[from] == val);
                if (input) {
                    if (type === 'ing') {
                        input.checked && this.setAttribute('checked', '');
                        input.setAttribute('check', type);
                    }
                    else if (type === 'ed') {
                        this.setAttribute('checked', input.propsProxy.value);
                    }
                    else {
                        input.checked && this.setAttribute('checked', '');
                    }
                }
            };
            this.propsObs.on('set', (data) => {
                data.key === 'value' && (this.valMap = { newVal: data.value, oldVal: data.raw || '' });
            });
            this.propsObs.on('completed', (data) => {
                if (data.keys.set.includes('value')) {
                    this.updateCache({ check: data.proxy.value });
                    this.listen({ name: 'changed', params: [this.valMap] });
                }
            });
        }
        static dependencies = [{ tag: 'oc-radio', comp: RadioElem }];
        static custAttrs = ['size', 'name', 'type', 'layout', 'cols', 'checked', 'disable', 'content', 'wrap-classes', 'item-classes', 'input-classes', 'on-checked', ...this.evtsArr];
        static boolAttrs = ['disabled'];
        static get observedAttributes() {
            return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, RadiosElem);
        }
        getRawData() {
            this.getRawProps(RadiosElem);
            !this.propsRaw.name && (this.propsRaw.name = orca.namePfx + Date.now());
            this.propsRaw.content = super.getItemsData();
            this.getProxyProps();
            this.setFieldProps(['name', 'value', 'disabled']);
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
            data['wrap-classes'] && classes(this.wrapEl).add(data['wrap-classes']);
            if (data.layout === 'grid') {
                this.wrapEl.classList.add(`${orca.prefix}grid`);
                data.cols && this.wrapEl.classList.add(`${orca.prefix}avg-${data.cols}`);
            }
            else if (data.layout === 'flex') {
                this.wrapEl.classList.add(`${orca.prefix}row`);
            }
            this.updateInputs(data.content, data);
        }
        updateInputs(data, host = this.propsProxy) {
            this.inputs = [];
            this.wrapEl.innerHTML = '';
            let tmp = super.getItemsData(data);
            for (let k of tmp) {
                let parent = createEl('div'), input = createEl('oc-radio', { label: k.label, value: isNull(k.value) ? k.label : k.value, [orca.embedSign]: '' });
                host.name ? input.setAttribute('name', host.name) : input.removeAttribute('name');
                host.type ? input.setAttribute('type', host.type) : input.removeAttribute('type');
                k.checked ? input.setAttribute('check', 'ed') : input.removeAttribute('check');
                input.toggleAttribute('disabled', !!k.disabled);
                host['input-classes'] && classes(input).add(host['input-classes']);
                this.inputs.push(input);
                if (host.layout) {
                    host.layout === 'flex' && parent.classList.add(`${orca.prefix}flex`);
                    host['item-classes'] && classes(parent).add(host['item-classes']);
                    parent.appendChild(input);
                    this.wrapEl.appendChild(parent);
                }
                else {
                    this.wrapEl.appendChild(input);
                }
                input.on('changed', (data) => {
                    let eds = this.inputs.find((i) => i.propsProxy.check === 'ed');
                    this.propsProxy.value = eds ? eds.propsProxy.value : '';
                    this.value = this.propsProxy.value;
                    data.newVal && this.listen({ name: 'checked', params: [input] });
                });
            }
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            content: this.changedMultiCont,
            disabled: this.changedMultiDisabled,
            name: this.changedMultiName,
            type: this.changedMultiName,
            size: this.changedMultiName,
            checked: this.changedChecked,
            disable: this.changedMultiDisable,
        };
        changedChecked(opt) {
            for (let k of this.inputs) {
                if (opt.newVal === null) {
                    k.check('');
                }
                else {
                    k.check(k.propsProxy.value === opt.newVal ? 'ed' : '');
                }
            }
        }
    }

    class CheckboxesElem extends CompBaseCommField {
        labelEl;
        legendEl;
        inputs;
        checkedAll;
        switch;
        setVals;
        check;
        setLabels;
        switchType;
        switchEvt;
        valMap;
        checkedMore;
        checkedLess;
        type;
        constructor() {
            super();
            this.type = 'checkboxes-comp';
            this.getRawData();
            this.fillWrap(this.propsProxy);
            this.reset = () => {
                if (this.propsRaw.content != this.propsRaw.content)
                    this.updateInputs(this.propsRaw.content, this.propsRaw);
                for (let k in this.propsRaw) {
                    if (k === 'content')
                        continue;
                    (this.propsRaw[k] !== null && this.propsRaw[k] !== false) ? this.setAttribute(k, this.propsRaw[k]) : this.removeAttribute(k);
                }
                this.listen({ name: 'reset' });
            };
            this.clear = () => {
                let tmp = this.inputs.every((k) => !k.propsProxy.check);
                if (tmp)
                    return;
                this.setAttribute('checked', '');
                this.listen({ name: 'cleared' });
            };
            this.checkedAll = () => {
                let vals = this.inputs.
                    filter((k) => !k.propsProxy.checked && k.propsProxy.value).
                    map((k) => k.propsProxy.value);
                if (!vals.length)
                    return;
                this.setAttribute('checked', vals);
                this.listen({ name: 'checkedAll', params: [vals] });
            };
            this.checkedMore = (data) => {
                let vals = valToArr(data), cur = this.value.split(','), value = unique([...cur, ...vals]).filter(Boolean);
                this.setAttribute('checked', value.join(','));
            };
            this.checkedLess = (data) => {
                let vals = valToArr(data), cur = this.value.split(','), value = cur.filter((k) => !vals.includes(k));
                this.setAttribute('checked', value.join(','));
            };
            this.check = (value, type = 'ed', from = 'value') => {
                let vals = valToArr(value);
                if (!vals.length) {
                    this.setAttribute('checked', '');
                    return;
                }
                let inputs = vals.map((k) => this.inputs.find((i) => i.propsProxy[from] == k)).filter(Boolean);
                if (!inputs.length)
                    return;
                let val = inputs.map((k) => k.value), cur = this.propsProxy.value.split(','), diff = !type ? cur.filter((k) => !val.includes(k)) : val;
                if (type === 'ing') {
                    inputs[0].checked && this.setAttribute('checked', cur.shift.join(','));
                    inputs[0].setAttribute('check', type);
                }
                else {
                    this.setAttribute('checked', diff.join(','));
                }
            };
            this.propsObs.on('set', (data) => {
                data.key === 'value' && (this.valMap = { newVal: data.value, oldVal: data.raw || '' });
            });
            this.propsObs.on('completed', (data) => {
                if (data.keys.set.includes('value')) {
                    this.referSwitch(data.proxy.value);
                    this.updateCache({ check: data.proxy.value });
                    this.listen({ name: 'changed', params: [this.valMap] });
                }
            });
            this.switchEvt = (e) => {
                this.switch.value == '1' || this.switch.checked ? this.checkedAll() : this.clear();
            };
        }
        static dependencies = [{ tag: 'oc-checkbox', comp: CheckboxElem }];
        static custAttrs = [
            'size', 'name', 'type', 'layout', 'cols', 'checked', 'disable', 'content', 'switch', 'wrap-classes', 'item-classes', 'input-classes', 'on-checkedall', ...this.evtsArr
        ];
        static boolAttrs = ['disabled'];
        static get observedAttributes() {
            return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, CheckboxesElem);
        }
        getRawData() {
            this.getRawProps(CheckboxesElem);
            !this.propsRaw.name && (this.propsRaw.name = orca.namePfx + Date.now());
            this.propsRaw.content = super.getItemsData();
            this.getProxyProps();
            this.setFieldProps(['name', 'value', 'disabled']);
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
            data['wrap-classes'] && classes(this.wrapEl).add(data['wrap-classes']);
            if (data.layout === 'grid') {
                this.wrapEl.classList.add(`${orca.prefix}grid`);
                data.cols && this.wrapEl.classList.add(`${orca.prefix}avg-${data.cols}`);
            }
            else if (data.layout === 'flex') {
                this.wrapEl.classList.add(`${orca.prefix}row`);
            }
            this.updateInputs(data.content, data);
        }
        updateInputs(data, host = this.propsProxy) {
            this.inputs = [];
            this.wrapEl.innerHTML = '';
            let tmp = super.getItemsData(data);
            for (let k of tmp) {
                let parent = createEl('div'), input = createEl('oc-checkbox', { label: k.label, value: isNull(k.value) ? k.label : k.value, [orca.embedSign]: '' });
                host.name ? input.setAttribute('name', `${host.name}[]`) : input.removeAttribute('name');
                host.type ? input.setAttribute('type', host.type) : input.removeAttribute('type');
                k.checked ? input.setAttribute('check', 'ed') : input.removeAttribute('check');
                input.toggleAttribute('disabled', !!k.disabled);
                host['input-classes'] && classes(input).add(host['input-classes']);
                this.inputs.push(input);
                if (host.layout) {
                    host.layout === 'flex' && parent.classList.add(`${orca.prefix}flex`);
                    host['item-classes'] && classes(parent).add(host['item-classes']);
                    parent.appendChild(input);
                    this.wrapEl.appendChild(parent);
                }
                else {
                    this.wrapEl.appendChild(input);
                }
            }
            this.inputs.forEach((k) => {
                k.on('changed', () => {
                    let eds = this.inputs.filter((i) => i.propsProxy.check === 'ed').map((o) => o.propsProxy.value).join(',');
                    this.propsProxy.value = eds;
                    this.value = this.propsProxy.value;
                });
            });
        }
        referSwitch(val) {
            if (!this.switch)
                return;
            if (!val) {
                ['OC-CHECKBOXES', 'OC-CHECKBOX', 'OC-RADIO'].includes(this.switchType) ? this.switch.clear() : this.switch.check('0');
            }
            else {
                let tmp = val.split(',').length;
                if (tmp > 0 && tmp < this.inputs.length) {
                    this.switch.clear();
                    
                    if (['OC-CHECKBOX', 'OC-RADIO'].includes(this.switchType)) {
                        this.switch.setAttribute('check', 'ing');
                    }
                    else {
                        let tmp = this.switch.inputs.find((k) => k.propsProxy.value == '1');
                        tmp && tmp.setAttribute('check', 'ing');
                    }
                }
                else {
                    
                    if (['OC-CHECKBOX', 'OC-RADIO'].includes(this.switchType)) {
                        this.switch.setAttribute('check', 'ed');
                    }
                    else {
                        this.switch.check('1');
                    }
                }
            }
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            content: this.changedMultiCont,
            disabled: this.changedMultiDisabled,
            name: this.changedMultiName,
            type: this.changedMultiName,
            size: this.changedMultiName,
            checked: this.changedChecked,
            disable: this.changedMultiDisable,
            switch: this.changedSwitch,
        };
        changedChecked(opt) {
            for (let k of this.inputs) {
                if (opt.newVal === null) {
                    k.check('');
                }
                else {
                    let tmp = !opt.newVal ? [''] : getAttrArr(opt.newVal);
                    k.check(tmp.includes(k.propsProxy.value) ? 'ed' : '');
                }
            }
        }
        changedSwitch(opt) {
            this.switch = getEl(`[name="${opt.newVal}"]`);
            if (this.switch) {
                this.switchType = this.switch.nodeName;
                this.switch.removeEventListener('change', this.switchEvt);
                this.switch.addEventListener('change', this.switchEvt, false);
            }
        }
    }

    class NumberElem extends CompBaseCommField {
        labelEl;
        inputEvt;
        tipsEl;
        incrEl;
        decrEl;
        type;
        select;
        constructor() {
            super();
            this.type = 'number-comp';
            this.getRawData();
            this.fillWrap(this.propsProxy);
            this.select = () => this.inputEl.select();
            this.on('input', (value) => {
                let step = ~~this.propsProxy.step || 1, val = ~~value, max = ~~this.propsProxy.max, min = ~~this.propsProxy.min;
                if (!isNull(this.propsProxy.max)) {
                    if (val + step > max) {
                        this.incrEl.toggleAttribute('disabled', true);
                    }
                    else {
                        this.incrEl.removeAttribute('disabled');
                    }
                }
                if (!isNull(this.propsProxy.min)) {
                    if (val - step < min) {
                        this.decrEl.toggleAttribute('disabled', true);
                    }
                    else {
                        this.decrEl.removeAttribute('disabled');
                    }
                }
            });
        }
        static custAttrs = ['name', 'placeholder', 'layout', 'size', 'max', 'min', 'step', 'label', 'on-exceeded', ...this.evtsArr];
        static boolAttrs = ['tips', 'disabled', 'readonly', 'full'];
        static get observedAttributes() {
            return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.saveProps(name, newVal, NumberElem);
            if (NumberElem.boolAttrs.includes(name)) {
                this.inputEl[name === 'readonly' ? 'readOnly' : name] = this.propsProxy[name];
                this[name === 'readonly' ? 'readOnly' : name] = this.propsProxy[name];
                if (name === 'tips') {
                    if (this.propsProxy.tips) {
                        elState(this.tipsEl).isVirtual && this.appendChild(this.tipsEl);
                    }
                    else {
                        this.tipsEl.remove();
                    }
                }
            }
            else if (['value', 'max', 'min', 'step'].includes(name)) {
                this.inputEl[name] = newVal;
                this.value = newVal;
                (name === 'max' || name === 'min') && this.updateTips();
            }
            else if (['name', 'placeholder'].includes(name)) {
                this.inputEl.setAttribute(name, newVal);
                name === 'name' && (this.name = newVal);
            }
            else if (name === 'label') {
                if (newVal) {
                    this.labelEl.innerHTML = newVal;
                    elState(this.labelEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.labelEl);
                    this.setAttribute('layout', 'embed');
                }
                else {
                    this.labelEl.remove();
                }
            }
            if (oldVal !== newVal) {
                this.listen({ name: 'changed', params: [{ oldVal, newVal }] });
            }
        }
        getRawData() {
            this.getRawProps(NumberElem);
            this.propsRaw.value = parseFloat(this.getAttribute('value') || this.getConnCont('text'));
            this.getProxyProps();
            this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
            this.inputEl = createEl('input', { type: 'number', name: data.name, placeholder: data.placeholder || config.lang.form.placeholder, [orca.embedSign]: '' });
            data.value && (this.inputEl.value = data.value);
            this.decrEl = createEl('i', { [orca.alias]: 'decrease' }, 'minus');
            this.incrEl = createEl('i', { [orca.alias]: 'increase' }, 'plus');
            this.labelEl = createEl('span', { [orca.alias]: 'label' });
            this.wrapEl.append(this.decrEl, this.inputEl, this.incrEl);
            this.tipsEl = createEl('div', { [orca.alias]: 'tips' });
        }
        updateTips() {
            let max = isNull(this.propsProxy.max) ? '+∞' : this.propsProxy.max, min = isNull(this.propsProxy.min) ? '-∞' : this.propsProxy.min, val = this.propsProxy.value, old = ~~val, str = '';
            if (max === '+∞' && min === '-∞') {
                return this;
            }
            if (max !== '+∞' && min !== '-∞') {
                str = renderTpl(this.propsProxy.lang?.limit || config.lang.form.limitNumber, { max, min });
                if (~~val >= ~~min && ~~val <= ~~max) {
                    this.removeAttribute('exceeded');
                    this.decrEl.removeAttribute('disabled');
                    this.incrEl.removeAttribute('disabled');
                }
                else {
                    this.setAttribute('exceeded', '');
                    str += (this.propsProxy.lang?.exceed || config.lang.form.exceed);
                    val = (~~val < ~~min) ? min : (~~val > ~~max) ? max : val;
                    ~~val > old ? this.decrEl.setAttribute('disabled', '') : this.incrEl.setAttribute('disabled', '');
                    this.listen({ name: 'exceeded', params: [val, old] });
                }
            }
            else if (max !== '+∞') {
                str = renderTpl(this.propsProxy.lang?.max || config.lang.form.maxNumber, { max });
                if (~~val > ~~max) {
                    val = max;
                    this.setAttribute('exceeded', '');
                    str += (this.propsProxy.lang?.exceed || config.lang.form.exceed);
                    this.incrEl.setAttribute('disabled', '');
                    this.listen({ name: 'exceeded', params: [val, old] });
                }
                else {
                    this.removeAttribute('exceeded');
                    this.incrEl.removeAttribute('disabled');
                }
            }
            else if (min !== '-∞') {
                str = renderTpl(this.propsProxy.lang?.min || config.lang.form.minNumber, { min });
                if (~~val < ~~min) {
                    val = min;
                    this.setAttribute('exceeded', '');
                    str += (this.propsProxy.lang?.exceed || config.lang.form.exceed);
                    this.decrEl.setAttribute('disabled', '');
                    this.listen({ name: 'exceeded', params: [val, old] });
                }
                else {
                    this.removeAttribute('exceeded');
                    this.decrEl.removeAttribute('disabled');
                }
            }
            if (val !== this.propsProxy.value) {
                this.setAttribute('value', val);
            }
            this.tipsEl.innerHTML = str;
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            (this.propsProxy.tips && (this.propsProxy.max || this.propsProxy.min) && elState(this.tipsEl).isVirtual) ? this.appendChild(this.tipsEl) : null;
            let evt = new Event('input');
            this.decrEl.onclick = () => {
                this.inputEl.stepDown();
                this.inputEl.dispatchEvent(evt);
            };
            this.incrEl.onclick = () => {
                this.inputEl.stepUp();
                this.inputEl.dispatchEvent(evt);
            };
            this.inputEl.addEventListener('input', (e) => {
                this.propsProxy.value = this.inputEl.value;
                this.value = this.inputEl.value;
                this.updateTips();
                this.listen({ name: 'input', params: [this.inputEl.value] });
            }, false);
        }
    }

    class RangeElem extends CompBaseCommFieldMixin {
        type;
        constructor() {
            super();
            this.type = 'range-comp';
        }
        static custAttrs = ['name', 'step', 'max', 'min', 'axis', 'size', 'classes', 'separator', 'hyphen', 'fence', 'button', 'ruler', 'result'];
        static boolAttrs = ['async', 'disabled', 'full', 'limit-show', 'tip-show', 'multiple', 'locked', 'rtl'];
        
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.updateProxyOpts(RangeElem, optRange, name, newVal, oldVal);
        }
        getRawData() {
            this.getRawPropsOpts(RangeElem, optRange);
            this.setFieldProps(['name', 'value', 'disabled']);
            this.getListenKeys(RangeElem, ['name', 'disabled', 'value', 'size']);
        }
        createIns() {
            if (this.ins)
                return;
            let params = Object.assign({
                onSet: (data) => {
                    this.modsOpts['module'].value = this.propsProxy.value = this.value = data.value;
                    this.canListen = false;
                    this.setAttribute('value', data.value);
                    this.canListen = true;
                    this.dispatchEvent(this.events['input'].event);
                    this.listen({ name: 'input', params: [data.value] });
                    if (data.value !== data.raw) {
                        this.dispatchEvent(this.events['change'].event);
                        this.listen({ name: 'changed', params: [{ newVal: data.value, oldVal: data.raw }] });
                    }
                },
            }, deepClone(this.modsOpts['module']));
            this.ins = new Range(this.wrapEl, params);
            this.ins.inputEl.setAttribute(orca.embedSign, '');
            this.focus = () => {
                this.ins.handles[this.propsProxy.multiple ? 'from' : 'single'].focus();
            };
            this.blur = () => {
                if (this.propsProxy.multiple) {
                    this.ins.handles.from.blur();
                    this.ins.handles.to.blur();
                }
                else {
                    this.ins.handles.single.blur();
                }
            };
            this.clear = () => {
                this.ins.clear();
                this.listen({ name: 'cleared' });
            };
            for (let k in this.ins.handles) {
                if (this.ins.handles[k]) {
                    this.ins.handles[k].addEventListener('focus', () => {
                        this.dispatchEvent(this.events['focus'].event);
                    }, false);
                    this.ins.handles[k].addEventListener('blur', () => {
                        this.dispatchEvent(this.events['blur'].event);
                    }, false);
                }
            }
        }
        changedMaps = {
            size: this.changedSize,
            disabled: this.changedDisabled,
            name: this.changedName,
            value: this.changedValue,
        };
        changedName(opt) {
            let tmp = opt.newVal || '';
            this.ins && (this.ins.inputEl.name = tmp);
            this.name = tmp;
        }
        changedValue(opt) {
            this.ins && this.ins.setVals(opt.newVal);
            this.value = this.ins ? this.ins.output.value : opt.newVal;
        }
        changedDisabled(opt) {
            this.disabled = this.propsProxy[opt.name];
            if (this.ins) {
                this.disabled ? this.ins.disable() : this.ins.enable();
            }
        }
        changedSize(opt) {
            if (this.ins) {
                opt.newVal ? this.ins.targetEl.setAttribute('size', opt.newVal) : this.ins.targetEl.removeAttribute('size');
            }
        }
    }

    class StatsElem extends CompBaseComm {
        mainEl;
        badgeEl;
        tipsEl;
        labelEl;
        unitEl;
        iconEl;
        cubeEl;
        diskEl;
        headEl;
        imageEl;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static dependencies = [{ tag: 'oc-badge', comp: BadgeElem }];
        static custAttrs = ['unit', 'tips', 'icon', 'disk', 'cube', 'image', 'badge', 'dir', ...this.baseAttrs];
        static boolAttrs = ['inverted', 'disabled'];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, StatsElem);
        }
        getRawData() {
            this.getRawProps(StatsElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
            this.mainEl = createEl('div', { [orca.alias]: 'main' });
            this.iconEl = createEl('i', { [orca.alias]: 'icon', class: data.icon });
            this.diskEl = createEl('span', { [orca.alias]: 'disk' }, `<img src="${data.disk}"/>`);
            this.cubeEl = createEl('span', { [orca.alias]: 'cube' }, `<img src="${data.cube}"/>`);
            this.imageEl = createEl('span', { [orca.alias]: 'image' }, `<img src="${data.image}"/>`);
            this.labelEl = createEl('i', { [orca.alias]: 'label' }, data.label);
            this.headEl = createEl('div', { [orca.alias]: 'head' }, this.labelEl);
            this.tipsEl = createEl('div', { [orca.alias]: 'tips' }, data.tips);
            this.unitEl = createEl('i', { [orca.alias]: 'unit' }, data.unit);
            this.badgeEl = createEl('oc-badge', { [orca.alias]: 'badge', label: data?.badge?.trim() });
            this.mainEl.appendChild(this.headEl);
            this.wrapEl.appendChild(this.mainEl);
        }
        render() {
            this.insertSource();
            !this.hasAttribute('dir') && this.setAttribute('dir', 'v');
            this.append(this.wrapEl);
        }
        changedMaps = {
            badge: this.changedBadge,
            label: this.changedLabel,
            icon: this.changedIcon,
            disk: this.changedDisk,
            cube: this.changedCube,
            image: this.changedImage,
            tips: this.changedTips,
            unit: this.changedUnit,
        };
        changedBadge(opt) {
            if (opt.newVal === null) {
                this.badgeEl.remove();
            }
            else {
                this.badgeEl.setAttribute('label', opt.newVal.trim());
                elState(this.badgeEl).isVirtual && this.labelEl.appendChild(this.badgeEl);
            }
        }
        changedIcon(opt) {
            if (opt.newVal === null) {
                this.iconEl.remove();
            }
            else {
                this.iconEl.setAttribute('class', opt.newVal);
                if (elState(this.iconEl).isVirtual) {
                    this.diskEl.remove();
                    this.cubeEl.remove();
                    this.imageEl.remove();
                    this.wrapEl.insertAdjacentElement('afterbegin', this.iconEl);
                }
            }
        }
        changedDisk(opt) {
            if (opt.newVal === null) {
                this.diskEl.remove();
            }
            else {
                this.diskEl.querySelector('img').src = opt.newVal;
                if (elState(this.diskEl).isVirtual) {
                    this.iconEl.remove();
                    this.cubeEl.remove();
                    this.imageEl.remove();
                    this.wrapEl.insertAdjacentElement('afterbegin', this.diskEl);
                }
            }
        }
        changedCube(opt) {
            if (opt.newVal === null) {
                this.cubeEl.remove();
            }
            else {
                this.cubeEl.querySelector('img').src = opt.newVal;
                if (elState(this.cubeEl).isVirtual) {
                    this.diskEl.remove();
                    this.imageEl.remove();
                    this.iconEl.remove();
                    this.wrapEl.insertAdjacentElement('afterbegin', this.cubeEl);
                }
            }
        }
        changedImage(opt) {
            if (opt.newVal === null) {
                this.imageEl.remove();
            }
            else {
                this.imageEl.querySelector('img').src = opt.newVal;
                if (elState(this.cubeEl).isVirtual) {
                    this.diskEl.remove();
                    this.cubeEl.remove();
                    this.iconEl.remove();
                    this.wrapEl.insertAdjacentElement('afterbegin', this.imageEl);
                }
            }
        }
        changedTips(opt) {
            if (opt.newVal === null) {
                this.tipsEl.remove();
            }
            else {
                this.tipsEl.innerHTML = opt.newVal;
                this.mainEl.appendChild(this.tipsEl);
            }
        }
        changedUnit(opt) {
            if (opt.newVal === null) {
                this.unitEl.remove();
            }
            else {
                this.unitEl.innerHTML = opt.newVal;
                this.headEl.appendChild(this.unitEl);
            }
        }
        changedLabel(opt) {
            this.labelEl.innerHTML = opt.newVal || '';
        }
    }

    class IconElem extends CompBaseComm {
        badgeEl;
        tipsEl;
        iconEl;
        cubeEl;
        diskEl;
        imageEl;
        headEl;
        legendEl;
        tmp;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static dependencies = [{ tag: 'oc-badge', comp: BadgeElem }];
        static custAttrs = ['tips', 'type', 'badge', 'dir', 'bg', 'href', 'target', 'rel', 'download', ...this.baseAttrs];
        static boolAttrs = ['disabled'];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, IconElem);
        }
        getRawData() {
            this.getRawProps(IconElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.headEl = createEl('span', { [orca.alias]: 'head' });
            this.wrapEl = createEl(data.href ? 'a' : 'div', { [orca.alias]: 'wrap' }, this.headEl);
            this.iconEl = createEl('i', { [orca.alias]: 'icon', class: data.label });
            this.diskEl = createEl('span', { [orca.alias]: 'disk' }, `<img src="${data.label}"/>`);
            this.cubeEl = createEl('span', { [orca.alias]: 'cube' }, `<img src="${data.label}"/>`);
            this.imageEl = createEl('span', { [orca.alias]: 'image' }, `<img src="${data.label}"/>`);
            this.tipsEl = createEl('div', { [orca.alias]: 'tips' }, data.tips);
            this.toggleLegend('icon');
            this.badgeEl = createEl('oc-badge', { [orca.alias]: 'badge', label: data?.badge?.trim() });
        }
        setLegendBg(theme, old) {
            if (theme) {
                classes(this.iconEl).replace(`${orca.prefix}bg-${old}`, `${orca.prefix}bg-${theme}`);
                classes(this.diskEl).replace(`${orca.prefix}bg-${old}`, `${orca.prefix}bg-${theme}`);
                classes(this.cubeEl).replace(`${orca.prefix}bg-${old}`, `${orca.prefix}bg-${theme}`);
            }
            else {
                this.iconEl.classList.remove(`${orca.prefix}bg-${old}`);
                this.diskEl.classList.remove(`${orca.prefix}bg-${old}`);
                this.cubeEl.classList.remove(`${orca.prefix}bg-${old}`);
            }
        }
        toggleLegend(type) {
            let map = [{
                    type: 'icon',
                    show: this.iconEl,
                    hide: [this.diskEl, this.imageEl, this.cubeEl],
                }, {
                    type: 'disk',
                    show: this.diskEl,
                    hide: [this.iconEl, this.imageEl, this.cubeEl],
                }, {
                    type: 'cube',
                    show: this.cubeEl,
                    hide: [this.diskEl, this.imageEl, this.iconEl],
                }, {
                    type: 'image',
                    show: this.imageEl,
                    hide: [this.diskEl, this.cubeEl, this.iconEl],
                }];
            let item = map.find((k) => k.type === type);
            if (item) {
                for (let k of item.hide)
                    k.remove();
                elState(item.show).isVirtual && this.headEl.insertAdjacentElement('afterbegin', item.show);
                this.legendEl = item.show;
            }
            else {
                this.iconEl.remove();
                this.cubeEl.remove();
                this.diskEl.remove();
                this.imageEl.remove();
            }
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            !this.hasAttribute('dir') && this.setAttribute('dir', 'h');
            if (!this.hasAttribute('type')) {
                this.canListen = false;
                this.setAttribute('type', 'icon');
                this.canListen = true;
            }
        }
        changedMaps = {
            label: this.changedLabel,
            href: this.changedHref,
            badge: this.changedBadge,
            target: this.changedTarget,
            rel: this.changedTarget,
            download: this.changedTarget,
            tips: this.changedTips,
            type: this.changedType,
            bg: this.changedBg,
        };
        changedLabel(opt) {
            if (opt.newVal === null) {
                this.toggleLegend();
            }
            else {
                if (this.legendEl.nodeName === 'I') {
                    this.legendEl.setAttribute('class', opt.newVal);
                }
                else {
                    this.legendEl.querySelector('img').src = opt.newVal;
                }
            }
        }
        changedBadge(opt) {
            if (opt.newVal === null) {
                this.badgeEl.remove();
            }
            else {
                this.badgeEl.setAttribute('label', opt.newVal.trim());
                elState(this.badgeEl).isVirtual && this.headEl.appendChild(this.badgeEl);
            }
        }
        changedHref(opt) {
            if (opt.newVal === null) {
                let children = this.wrapEl.children;
                this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
                this.wrapEl.append(...children);
                this.render();
            }
            else {
                if (this.wrapEl.nodeName !== 'A') {
                    this.wrapEl = createEl('a', { [orca.alias]: 'wrap' }, [...this.wrapEl.children]);
                    this.render();
                }
                this.wrapEl.setAttribute('href', opt.newVal);
            }
        }
        changedTarget(opt) {
            opt.newVal ? this.wrapEl[opt.name] = opt.newVal : this.wrapEl.removeAttribute(opt.name);
        }
        changedTips(opt) {
            if (opt.newVal === null) {
                this.tipsEl.remove();
            }
            else {
                this.tipsEl.innerHTML = opt.newVal;
                this.wrapEl.appendChild(this.tipsEl);
            }
        }
        changedBg(opt) {
            this.setLegendBg(opt.newVal, opt.oldVal);
        }
        changedType(opt) {
            this.toggleLegend(opt.newVal);
        }
    }

    class DividerElem extends CompBaseComm {
        startEl;
        endEl;
        labelEl;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['break', 'size', 'fs', ...this.baseAttrs];
        static boolAttrs = [];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, DividerElem);
        }
        getRawData() {
            this.getRawProps(DividerElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.startEl = createEl('div', { [orca.alias]: 'start' });
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, this.startEl);
            this.endEl = createEl('div', { [orca.alias]: 'end' });
            this.labelEl = createEl('div', { [orca.alias]: 'label' }, this.propsProxy.label);
            this.propsProxy.label && this.wrapEl.append(this.labelEl, this.endEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            label: this.changedLabel,
        };
        changedLabel(opt) {
            if (opt.newVal === null) {
                this.labelEl.remove();
                this.endEl.remove();
            }
            else {
                this.labelEl.innerHTML = opt.newVal;
                elState(this.labelEl).isVirtual && this.wrapEl.append(this.labelEl, this.endEl);
            }
        }
    }

    class AlarmElem extends CompBaseComm {
        labelEl;
        iconEl;
        imageEl;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['icon', 'image', 'theme', 'size', ...this.baseAttrs];
        static boolAttrs = [];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, AlarmElem);
        }
        getRawData() {
            this.getRawProps(AlarmElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('span', { [orca.alias]: 'wrap' });
            this.labelEl = createEl('i', { [orca.alias]: 'label' }, this.propsProxy.label);
            this.iconEl = createEl('i', { [orca.alias]: 'icon' });
            this.imageEl = createEl('img', { [orca.alias]: 'image' });
            this.propsProxy.label && this.wrapEl.appendChild(this.labelEl);
        }
        render(data) {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            label: this.changedLabel,
            icon: this.changedIcon,
            image: this.changedImage,
        };
        changedLabel(opt) {
            if (opt.newVal === null) {
                this.labelEl.remove();
            }
            else {
                this.labelEl.innerHTML = opt.newVal;
                if (elState(this.labelEl).isVirtual) {
                    this.wrapEl.appendChild(this.labelEl);
                    this.iconEl.remove();
                    this.imageEl.remove();
                }
            }
        }
        changedIcon(opt) {
            if (opt.newVal === null) {
                this.iconEl.remove();
            }
            else {
                this.iconEl.setAttribute('class', opt.newVal);
                if (elState(this.iconEl).isVirtual) {
                    this.wrapEl.appendChild(this.iconEl);
                    this.labelEl.remove();
                    this.imageEl.remove();
                }
            }
        }
        changedImage(opt) {
            if (opt.newVal === null) {
                this.imageEl.remove();
            }
            else {
                this.imageEl.src = opt.newVal;
                if (elState(this.imageEl).isVirtual) {
                    this.wrapEl.appendChild(this.imageEl);
                    this.labelEl.remove();
                    this.iconEl.remove();
                }
            }
        }
    }

    class ProgressElem extends CompBaseComm {
        constructor() {
            super();
            this.createShadow();
            super.createPropsObs();
            this.fillWrap(this.propsProxy);
        }
        static get observedAttributes() {
            return [...optProgress.map((k) => k.attr), 'options', 'async'];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            if (name === 'value') {
                if (!this.connected || !this.ins)
                    return;
                let duration = this.getAttribute('duration'), value = this.getVal(newVal);
                if (duration == 0) {
                    this.ins.locateTo(value);
                }
                else {
                    !duration ? this.ins.animateTo(value) : this.ins.animateTo(value, { duration });
                }
            }
            else {
                super.updateProxy(name, newVal, optProgress);
            }
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'slot-host' }, this.rawHtml);
        }
        createIns() {
            if (this.ins)
                return;
            this.ins = new Progress(this.wrapEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
        }
        getVal(val) {
            return val == 0 ? 0 : ~~val === 0 ? val : parseFloat(val);
        }
    }

    class DatetimeElem extends CompBaseCommFieldMixin {
        labelEl;
        inputEvt;
        meanEl;
        datetimeIns;
        type;
        select;
        constructor() {
            super();
            this.type = 'datetime-comp';
            this.select = () => this.ins.inputEl.select();
        }
        static dependencies = [
            { tag: 'oc-input', comp: InputElem },
            { tag: 'oc-btn', comp: BtnElem },
            { tag: 'oc-textarea', comp: TextareaElem },
            { tag: 'oc-checkbox', comp: CheckboxElem }
        ];
        static custAttrs = ['name', 'value', 'size', 'format', 'classes', 'mode', 'feature', 'display', 'placeholder', 'label', 'tools',
            'moc-selection', 'min-date', 'moc-date', 'datespan', 'timespan', 'rows', 'cols', 'week-start', 'separator', 'btn-sel', 'pos-sel', 'input-sel', 'child-sel', 'lunar', 'events', 'menu', 'bubble', 'footer'];
        static boolAttrs = ['async', 'disabled', 'to-drawer', 'full', 'multiline', 'now-hide', 'now-show', 'clear-show', 'close-show', 'cancel-show', 'confirm-hide', 'auto-fill', 'manual', 'auto-correct', 'required', 'fill-now', 'rtl'];
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.updateProxyOpts(DatetimeElem, optDatetime, name, newVal, oldVal);
        }
        getRawData() {
            this.getRawPropsOpts(DatetimeElem, optDatetime);
            this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
            this.getListenKeys(DatetimeElem, ['name', 'disabled', 'value', 'size']);
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { class: `${orca.prefix}datetime-wrap` }, this.rawHtml);
        }
        createIns() {
            if (this.ins)
                return;
            let params = Object.assign(this.modsOpts['module'], {
                onOutput: (data) => {
                    this.modsOpts['module'].value = this.propsProxy.value = this.value = data.value;
                    this.canListen = false;
                    this.setAttribute('value', data.value);
                    this.canListen = true;
                    this.dispatchEvent(this.events['input'].event);
                    this.listen({ name: 'input', params: [data.value] });
                    if (data.value !== data.raw) {
                        this.dispatchEvent(this.events['change'].event);
                        this.listen({ name: 'changed', params: [data] });
                    }
                }
            });
            this.ins = new Datetime(this.wrapEl, params);
            this.ins.inputEl.setAttribute(orca.embedSign, '');
            this.focus = () => {
                this.ins.inputEl.focus();
            };
            this.blur = () => {
                this.ins.inputEl.blur();
            };
            this.clear = () => {
                this.ins.clear();
                this.ins.inputEl.clear();
                this.listen({ name: 'cleared' });
            };
            this.ins.inputEl.addEventListener('focus', () => {
                this.dispatchEvent(this.events['focus'].event);
            }, false);
            this.ins.inputEl.addEventListener('blur', () => {
                this.dispatchEvent(this.events['blur'].event);
            }, false);
        }
        changedMaps = {
            disabled: this.changedDisabled,
            size: this.changedSize,
            name: this.changedName,
            value: this.changedValue,
        };
        changedDisabled(opt) {
            this.disabled = this.propsProxy[opt.name];
            if (this.ins) {
                this.disabled ? this.ins.disable() : this.ins.enable();
            }
        }
        changedName(opt) {
            let tmp = opt.newVal || '';
            this.ins && (this.ins.inputEl.name = tmp);
            this.name = tmp;
        }
        changedValue(opt) {
            if (this.ins) {
                this.ins.setVals(opt.newVal);
                this.ins.confirm();
            }
            this.value = this.ins ? this.ins.output.value : opt.newVal;
        }
        changedSize(opt) {
            if (this.ins) {
                opt.newVal ? this.ins.inputEl.setAttribute('size', opt.newVal) : this.ins.inputEl.removeAttribute('size');
            }
        }
    }

    class RateElem extends CompBaseComm {
        constructor() {
            super();
            this.createShadow();
            super.createPropsObs();
            this.fillWrap(this.propsProxy);
        }
        static get observedAttributes() {
            return [...optRate.map((k) => k.attr), 'options', 'async'];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            if (name === 'value') {
                this.ins && newVal && this.ins.setVals(newVal);
            }
            else {
                super.updateProxy(name, newVal, optRate);
            }
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'slot-host' }, this.rawHtml);
        }
        createIns() {
            if (this.ins)
                return;
            this.ins = new Rate(this.wrapEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
        }
    }

    class TreeElem extends CompBaseComm {
        name;
        value;
        constructor() {
            super();
            this.createShadow();
            super.createPropsObs();
            this.fillWrap(this.propsProxy);
        }
        static get observedAttributes() {
            return [...optTree.map((k) => k.attr), 'options', 'async'];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            if (name === 'name') {
                this.name = newVal;
            }
            else {
                super.updateProxy(name, newVal, optTree);
            }
        }
        createIns() {
            if (this.ins)
                return;
            this.ins = this.ins = new Tree(this.wrapEl, {
                onInitiated: function () {
                    this.inputEl && this.inputEl.setAttribute(orca.embedSign, '');
                },
                onOutput: (data) => {
                    this.value = data.value;
                }
            });
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'slot-host' }, this.rawHtml);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
        }
    }

    class AccordionElem extends CompBaseComm {
        constructor() {
            super();
            this.createShadow();
            super.createPropsObs();
            this.fillWrap(this.propsProxy);
        }
        static get observedAttributes() {
            return [...optAccordion.map((k) => k.attr), 'options', 'async'];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            if (name === 'value') {
                this.ins && newVal && this.ins.setVals(newVal);
            }
            else {
                super.updateProxy(name, newVal, optAccordion);
            }
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'slot-host' }, this.rawHtml);
        }
        createIns() {
            if (this.ins)
                return;
            this.ins = new Accordion(this.wrapEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
        }
    }

    class EditorElem extends CompBaseCommFieldMixin {
        type;
        select;
        constructor() {
            super();
            this.type = 'editor-comp';
            this.select = () => this.ins.inputEl.select();
        }
        static custAttrs = ['name', 'value', 'delay', 'classes', 'content', 'cont-type',
            'cont-data', 'ajax', 'appear', 'header', 'mode', 'min-height', 'moc-height', 'feature'];
        static boolAttrs = ['async', 'disabled', 'readonly', 'deferred'];
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.updateProxyOpts(EditorElem, optEditor, name, newVal, oldVal);
        }
        getRawData() {
            this.getRawPropsOpts(EditorElem, optEditor);
            this.propsRaw.value = this.rawHtml || this.propsRaw.value || '';
            this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
            this.getListenKeys(EditorElem, ['name', 'disabled', 'value', 'readonly']);
        }
        createIns() {
            if (this.ins)
                return;
            let params = Object.assign(this.modsOpts['module'], {
                onOutput: (data) => {
                    this.modsOpts['module'].value = this.propsProxy.value = this.value = data.value;
                    this.canListen = false;
                    this.setAttribute('value', data.value);
                    this.canListen = true;
                    this.dispatchEvent(this.events['input'].event);
                    this.listen({ name: 'input', params: [data.value] });
                    if (data.value !== data.raw) {
                        this.dispatchEvent(this.events['change'].event);
                        this.listen({ name: 'changed', params: [{ newVal: data.value, oldVal: data.raw }] });
                    }
                }
            });
            this.ins = new Editor(this.wrapEl, params);
            this.ins.inputEl.setAttribute(orca.embedSign, '');
            this.focus = () => {
                (elState(this.ins.inputEl).isVisible ? this.ins.inputEl : this.ins.contEl).focus();
            };
            this.blur = () => {
                (elState(this.ins.inputEl).isVisible ? this.ins.inputEl : this.ins.contEl).blur();
            };
            this.clear = () => {
                this.ins.clearVals();
                this.listen({ name: 'cleared' });
            };
            this.ins.inputEl.addEventListener('focus', () => {
                this.dispatchEvent(this.events['focus'].event);
            }, false);
            this.ins.contEl.addEventListener('focus', () => {
                this.dispatchEvent(this.events['focus'].event);
            }, false);
            this.ins.inputEl.addEventListener('blur', () => {
                this.dispatchEvent(this.events['blur'].event);
            }, false);
            this.ins.contEl.addEventListener('blur', () => {
                this.dispatchEvent(this.events['blur'].event);
            }, false);
            this.ins.inputEl.addEventListener('input', (e) => {
                e.stopPropagation();
            }, false);
            this.ins.contEl.addEventListener('input', (e) => {
                e.stopPropagation();
            }, false);
            this.ins.inputEl.addEventListener('change', (e) => {
                e.stopPropagation();
            }, false);
        }
        changedMaps = {
            readOnly: this.changedReadOnly,
            disabled: this.changedDisabled,
            name: this.changedName,
            value: this.changedValue,
        };
        changedBool(opt) {
            this.disabled = this.propsProxy[opt.name];
            if (this.ins) {
                this.disabled ? this.ins.disable() : this.ins.enable();
            }
        }
        changedName(opt) {
            let tmp = opt.newVal || '';
            this.ins && (this.ins.inputEl.name = tmp);
            this.name = tmp;
        }
        changedValue(opt) {
            this.ins && this.ins.setVals(opt.newVal);
        }
        changedDisabled(opt) {
            this.disabled = this.propsProxy[opt.name];
            if (this.ins) {
                this.disabled ? this.ins.disable() : this.ins.enable();
            }
        }
        changedReadOnly(opt) {
            this.readOnly = this.propsProxy[opt.name];
            if (this.ins) {
                this.readOnly ? this.ins.readonly() : this.ins.enable();
            }
        }
    }

    class SelectElem extends CompBaseCommFieldMixin {
        type;
        constructor() {
            super();
            this.type = 'select-comp';
        }
        static custAttrs = ['name', 'value', 'field', 'type', 'exclude', 'min', 'max', 'span', 'content', 'cont-type', 'cont-Data', 'ajax', 'size', 'moc-height', 'search', 'tools', 'popup'];
        static boolAttrs = ['async', 'manual', 'disabled', 'readonly', 'full', 'multiple', 'sliced', 'removable', 'unique', 'collapse', 'status', 'auto-width'];
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.updateProxyOpts(SelectElem, optSelect, name, newVal, oldVal);
        }
        getRawData() {
            this.getRawPropsOpts(SelectElem, optSelect);
            this.setFieldProps(['name', 'disabled']);
            this.value = '';
            this.getListenKeys(SelectElem, ['name', 'disabled', 'value', 'size']);
        }
        createIns() {
            if (this.ins)
                return;
            let params = Object.assign(this.modsOpts['module'], {
                onOutput: (data) => {
                    this.modsOpts['module'].value = this.propsProxy.value = this.value = data.value;
                    this.canListen = false;
                    this.setAttribute('value', data.value);
                    this.canListen = true;
                    this.dispatchEvent(this.events['input'].event);
                    this.listen({ name: 'input', params: [data.value] });
                    if (data.value !== data.raw) {
                        this.dispatchEvent(this.events['change'].event);
                        this.listen({ name: 'changed', params: [{ newVal: data.value, oldVal: data.raw }] });
                    }
                }
            });
            this.ins = new Select(this.wrapEl, params);
            this.ins.inputEl.setAttribute(orca.embedSign, '');
            this.focus = () => {
                this.wrapEl.focus();
            };
            this.blur = () => {
                this.wrapEl.blur();
            };
            this.clear = () => {
                this.ins.clear();
                this.listen({ name: 'cleared' });
            };
            this.wrapEl.addEventListener('focus', () => {
                this.dispatchEvent(this.events['focus'].event);
            }, false);
            this.wrapEl.addEventListener('blur', () => {
                this.dispatchEvent(this.events['blur'].event);
            }, false);
        }
        changedMaps = {
            size: this.changedSize,
            disabled: this.changedDisabled,
            name: this.changedName,
            value: this.changedValue,
        };
        changedName(opt) {
            let tmp = opt.newVal || '';
            this.ins && (this.ins.inputEl.name = tmp);
            this.name = tmp;
        }
        changedValue(opt) {
            this.ins && this.ins.select(opt.newVal);
        }
        changedDisabled(opt) {
            this.disabled = this.propsProxy[opt.name];
            if (this.ins) {
                this.disabled ? this.ins.disable() : this.ins.enable();
            }
        }
        changedSize(opt) {
            if (this.ins) {
                opt.newVal ? this.ins.targetEl.setAttribute('size', opt.newVal) : this.ins.targetEl.removeAttribute('size');
            }
        }
    }

    class UploadElem extends CompBaseCommFieldMixin {
        type;
        focusEl;
        constructor() {
            super();
            this.type = 'upload-comp';
        }
        static custAttrs = ['name', 'value', 'url', 'content', 'cont-type', 'cont-data', 'ajax', 'limit', 'accept', 'type', 'feature', 'size', 'table', 'classes', 'status', 'choose-btn', 'upload-btn', 'clear-btn', 'cloud'];
        static boolAttrs = ['async', 'disabled', 'readonly', 'multiple', 'manual', 'pastable'];
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.updateProxyOpts(UploadElem, optUpload, name, newVal, oldVal);
        }
        getRawData() {
            this.getRawPropsOpts(UploadElem, optUpload);
            this.setFieldProps(['name', 'value', 'disabled']);
            this.getListenKeys(UploadElem, ['name', 'disabled', 'value', 'size']);
        }
        createIns() {
            if (this.ins)
                return;
            let params = Object.assign(this.modsOpts['module'], {
                onOutput: (data) => {
                    this.modsOpts['module'].value = this.propsProxy.value = this.value = data.value;
                    this.canListen = false;
                    this.setAttribute('value', data.value);
                    this.canListen = true;
                    this.dispatchEvent(this.events['input'].event);
                    this.listen({ name: 'input', params: [data.value] });
                    if (data.value !== data.raw) {
                        this.dispatchEvent(this.events['change'].event);
                        this.listen({ name: 'changed', params: [{ newVal: data.value, oldVal: data.raw }] });
                    }
                }
            });
            this.ins = new Upload(this.wrapEl, params);
            this.ins.inputEl.setAttribute(orca.embedSign, '');
            this.focusEl = this.ins.options.feature === 'gallery' ? this.wrapEl : this.ins.chooseBtn;
            this.focus = () => {
                this.focusEl.focus();
            };
            this.blur = () => {
                this.focusEl.blur();
            };
            this.clear = () => {
                this.ins.clear();
                this.listen({ name: 'cleared' });
            };
            this.focusEl.addEventListener('focus', () => {
                this.dispatchEvent(this.events['focus'].event);
            }, false);
            this.focusEl.addEventListener('blur', () => {
                this.dispatchEvent(this.events['blur'].event);
            }, false);
        }
        changedMaps = {
            size: this.changedSize,
            disabled: this.changedDisabled,
            name: this.changedName,
            value: this.changedValue,
        };
        changedName(opt) {
            let tmp = opt.newVal || '';
            this.ins && (this.ins.inputEl.name = tmp);
            this.name = tmp;
        }
        changedValue(opt) {
            this.ins && this.ins.add(opt.newVal);
            this.value = this.ins ? this.ins.output.value : opt.newVal;
        }
        changedDisabled(opt) {
            this.disabled = this.propsProxy[opt.name];
            if (this.ins) {
                this.disabled ? this.ins.lock() : this.ins.unlock();
            }
        }
        changedSize(opt) {
            if (this.ins) {
                opt.newVal ? this.ins.targetEl.setAttribute('size', opt.newVal) : this.ins.targetEl.removeAttribute('size');
            }
        }
    }

    class FieldsElem extends CompBaseCommField {
        labelEl;
        limitEl;
        diskEl;
        cubeEl;
        iconEl;
        btnEl;
        meanEl;
        type;
        childEls;
        compEls;
        fieldsEl;
        unitEl;
        constructor() {
            super();
            this.type = 'fields-comp';
            this.getRawData();
            this.btnEl = getEl(':scope > OC-BTN', this);
            this.childEls = [...this.children].filter((k) => k !== this.btnEl);
            this.compEls = this.childEls.filter((k) => fieldTypes.includes(k.nodeName.toLowerCase().replace('oc-', '')));
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['size', 'label', 'unit', 'connector', 'align', 'shape'];
        static boolAttrs = ['disabled', 'full', 'dividable'];
        static get observedAttributes() {
            return [...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, FieldsElem);
        }
        getRawData() {
            this.getRawProps(FieldsElem);
            this.getProxyProps();
        }
        fillWrap(data) {
            this.fieldsEl = createEl('div', { [orca.alias]: 'fields' });
            this.fieldsEl.append(...this.childEls);
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, this.fieldsEl);
            this.btnEl && this.wrapEl.appendChild(this.btnEl);
            this.labelEl = createEl('span', { [orca.alias]: 'label' });
            this.unitEl = createEl('span', { [orca.alias]: 'unit' });
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            size: this.changedSize,
            align: this.changedSize,
            label: this.changedLabel,
            unit: this.changedUnit,
            connector: this.changedConn,
            shape: this.changedShape,
        };
        changedLabel(opt) {
            if (opt.newVal) {
                this.labelEl.innerHTML = opt.newVal;
                elState(this.labelEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.labelEl);
            }
            else {
                this.labelEl.remove();
            }
        }
        changedUnit(opt) {
            if (opt.newVal) {
                this.unitEl.innerHTML = opt.newVal;
                elState(this.unitEl).isVirtual && this.fieldsEl.insertAdjacentElement('afterend', this.unitEl);
            }
            else {
                this.unitEl.remove();
            }
        }
        changedSize(opt) {
            if (opt.newVal) {
                for (let k of this.compEls)
                    k.setAttribute(opt.name, opt.newVal);
                this.btnEl && opt.name === 'size' && this.btnEl.setAttribute(opt.name, opt.newVal);
            }
            else {
                for (let k of this.compEls)
                    k.removeAttribute(opt.name);
                this.btnEl && opt.name === 'size' && this.btnEl.removeAttribute(opt.name);
            }
        }
        changedConn(opt) {
            if (opt.newVal) {
                for (let [i, k] of this.childEls.entries())
                    (i !== this.childEls.length - 1) && k.insertAdjacentHTML('afterend', `<i ${orca.alias}="connector">${opt.newVal}</i>`);
            }
            else {
                let conns = getEls(`[${orca.alias}="connector"]`, this.fieldsEl);
                for (let k of conns)
                    k.remove();
            }
        }
        changedShape(opt) {
            if (opt.newVal) {
                this.btnEl && this.btnEl.setAttribute('shape', opt.newVal);
            }
            else {
                this.btnEl && this.btnEl.removeAttribute('shape');
            }
        }
    }

    class SearchElem extends CompBaseCommField {
        labelEl;
        limitEl;
        diskEl;
        cubeEl;
        iconEl;
        btnEl;
        meanEl;
        type;
        fieldsEl;
        constructor() {
            super();
            this.type = 'search-comp';
            this.getRawData();
            this.fieldsEl = getEl(':scope > OC-FIELDS', this);
            this.fillWrap(this.propsProxy);
        }
        static dependencies = [{ tag: 'oc-fields', comp: FieldsElem }];
        static custAttrs = ['size', 'label', 'feature', 'shape'];
        static boolAttrs = ['disabled', 'full', 'notable'];
        static get observedAttributes() {
            return [...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.propsProxy[name] = SearchElem.boolAttrs.includes(name) ? getAttrBool(newVal) : newVal;
            this.changedMaps[name] && this.changedMaps[name].call(this, { name, newVal, oldVal, proxy: this.propsProxy });
        }
        getRawData() {
            for (let k of [...SearchElem.custAttrs, ...SearchElem.lazyAttrs])
                this.propsRaw[k] = this.getAttribute(k);
            for (let k of SearchElem.boolAttrs)
                this.propsRaw[k] = getAttrBool(this.getAttribute(k));
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, this.fieldsEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            full: this.changedFull,
            size: this.changedSize,
            notable: this.changedNotable,
            shape: this.changedShape,
        };
        changedFull(opt) {
            this.fieldsEl = this.querySelector('oc-fields');
            if (!this.fieldsEl)
                return;
            this.fieldsEl.toggleAttribute('full', !!opt.newVal);
        }
        changedSize(opt) {
            this.fieldsEl = this.querySelector('oc-fields');
            if (!this.fieldsEl)
                return;
            if (opt.newVal) {
                this.fieldsEl.setAttribute('size', opt.newVal);
            }
            else {
                this.fieldsEl.removeAttribute('size');
            }
        }
        changedNotable(opt) {
            this.fieldsEl = this.querySelector('oc-fields');
            if (!this.fieldsEl.btnEl)
                return;
            if (this.propsProxy.notable) {
                this.fieldsEl.btnEl.setAttribute('theme', 'prim');
            }
            else {
                this.fieldsEl.btnEl.removeAttribute('theme');
            }
        }
        changedShape(opt) {
            this.fieldsEl = this.querySelector('oc-fields');
            if (!this.fieldsEl.btnEl)
                return;
            if (opt.newVal) {
                this.fieldsEl.setAttribute('shape', opt.newVal);
            }
            else {
                this.fieldsEl.removeAttribute('shape');
            }
        }
    }

    class CalloutElem extends CompBaseComm {
        resultEl;
        iconEl;
        diskEl;
        cubeEl;
        imageEl;
        closeEl;
        linkEl;
        maskEl;
        toolsEl;
        captEl;
        contEl;
        bodyEl;
        progEl;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static dependencies = [{ tag: 'oc-result', comp: ResultElem }, { tag: 'oc-progress', comp: ProgressElem }];
        static custAttrs = ['theme', 'label', 'icon', 'disk', 'cube', 'image', 'href', 'target', 'rel', 'feature', 'autoclose', 'size', ...this.baseAttrs];
        static boolAttrs = ['closable', 'square', 'opaque', 'notable', 'hidden', 'result'];
        static get observedAttributes() {
            return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, CalloutElem);
        }
        getRawData() {
            this.getRawProps(CalloutElem);
            this.propsRaw.content = this.getAttribute('content') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
            this.resultEl = createEl('oc-result');
            this.iconEl = createEl('i', { [orca.alias]: 'icon' });
            this.diskEl = createEl('i', { [orca.alias]: 'disk' });
            this.cubeEl = createEl('i', { [orca.alias]: 'cube' });
            this.imageEl = createEl('i', { [orca.alias]: 'image' });
            this.closeEl = createEl('span', { [orca.alias]: 'close' }, `<i class="${orca.prefix}icon-close"></i>`);
            this.linkEl = createEl('a', { [orca.alias]: 'link' }, `<i class="${orca.prefix}icon-right-up"></i>`);
            this.maskEl = createEl('a', { [orca.alias]: 'mask' });
            this.toolsEl = createEl('span', { [orca.alias]: 'tools', class: `${orca.prefix}box-tools` });
            this.captEl = createEl('div', { [orca.alias]: 'title' });
            this.contEl = createEl('div', { [orca.alias]: 'content' }, this.propsProxy.content);
            this.bodyEl = createEl('div', { [orca.alias]: 'body' }, this.contEl);
            this.progEl = createEl('oc-progress', { [orca.alias]: 'prog', linecap: 'square', thk: 'xs', theme: 'warn', value: '100', label: false });
            this.wrapEl.append(this.bodyEl, this.toolsEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.propsProxy.autoclose && this.progEl.setAttribute('value', 0);
            this.closeEl.onclick = () => {
                this.toggleAttribute('hidden', true);
            };
        }
        changedMaps = {
            theme: this.changedTheme,
            label: this.changedLabel,
            content: this.changedCont,
            icon: this.changedIcon,
            disk: this.changedDisk,
            cube: this.changedDisk,
            image: this.changedDisk,
            result: this.changedResult,
            href: this.changedHref,
            ref: this.changedRel,
            target: this.changedRel,
            closable: this.changedClose,
            feature: this.changedFeature,
            hidden: this.changedHidden,
            autoclose: this.changedAuto,
        };
        changedTheme(opt) {
            this.progEl.setAttribute('theme', opt.newVal || 'warn');
        }
        changedHidden(opt) {
            if (this.propsProxy.hidden) {
                slideUp({
                    el: this,
                    done: () => {
                        this.listen({ name: 'hidden' });
                    }
                });
            }
            else {
                slideDown({
                    el: this,
                    done: () => {
                        this.listen({ name: 'shown' });
                    }
                });
            }
        }
        changedLabel(opt) {
            if (opt.newVal) {
                this.captEl.innerHTML = opt.newVal;
                elState(this.captEl).isVirtual && this.contEl.insertAdjacentElement('beforebegin', this.captEl);
            }
            else {
                this.captEl.remove();
            }
        }
        changedCont(opt) {
            this.contEl.innerHTML = opt.newVal || '';
        }
        changedIcon(opt) {
            if (opt.newVal) {
                this.iconEl.setAttribute('class', opt.newVal);
                elState(this.iconEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.iconEl);
            }
            else {
                this.iconEl.remove();
            }
        }
        changedDisk(opt) {
            let target = this[opt.name + 'El'];
            if (opt.newVal) {
                target.innerHTML = `<img src="${opt.newVal}"/>`;
                elState(target).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', target);
            }
            else {
                target.remove();
            }
        }
        changedResult(opt) {
            if (this.propsProxy.result) {
                elState(this.resultEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.resultEl);
                this.resultEl.setAttribute('to', this.propsProxy.theme || 'warn');
            }
            else {
                this.resultEl.remove();
            }
        }
        changedHref(opt) {
            if (opt.newVal) {
                this.maskEl.setAttribute('href', opt.newVal);
                this.linkEl.setAttribute('href', opt.newVal);
                elState(this.maskEl).isVirtual && this.wrapEl.appendChild(this.maskEl);
                elState(this.linkEl).isVirtual && this.toolsEl.insertAdjacentElement('afterbegin', this.linkEl);
            }
            else {
                this.maskEl.remove();
                this.linkEl.remove();
            }
        }
        changedRel(opt) {
            if (opt.newVal) {
                this.maskEl.setAttribute(opt.name, opt.newVal);
                this.linkEl.setAttribute(opt.name, opt.newVal);
            }
            else {
                this.maskEl.removeAttribute(opt.name);
                this.linkEl.removeAttribute(opt.name);
            }
        }
        changedClose(opt) {
            if (this.propsProxy.closable) {
                this.toolsEl.appendChild(this.closeEl);
            }
            else {
                this.closeEl.remove();
            }
        }
        changedFeature(opt) {
            if (opt.newVal === 'alert') {
                this.setAttribute('icon', `${orca.prefix}icon-warn-o-f`);
                this.setAttribute('theme', 'warn');
                this.toggleAttribute('notable', true);
            }
            else if (opt.newVal === 'note') {
                this.setAttribute('icon', `${orca.prefix}icon-info-o-f`);
                this.setAttribute('theme', 'info');
                this.toggleAttribute('notable', true);
            }
        }
        changedAuto(opt) {
            if (opt.newVal !== null) {
                this.progEl.setAttribute('duration', opt.newVal || 3000);
                elState(this.progEl).isVirtual && this.wrapEl.appendChild(this.progEl);
                this.progEl?.ins?.on('zero', () => {
                    this.closeEl.click();
                });
                this.onmouseenter = () => {
                    this.progEl.ins.pause();
                };
                this.onmouseleave = () => {
                    this.progEl.ins.continue();
                };
                this.progEl.setAttribute('value', 0);
            }
            else {
                this.progEl.remove();
            }
        }
    }

    class TwilightElem extends CompBaseComm {
        labelEl;
        legendEl;
        targetEl;
        labels;
        isDay;
        toggleEvt;
        constructor() {
            super();
            this.getRawData();
            this.labels = [config.lang.twilight.day, config.lang.twilight.night];
            this.isDay = true;
            this.toggleEvt = () => {
                let target = this.targetEl || document.body;
                if (target.hasAttribute('scheme')) {
                    this.labelEl.innerHTML = this.labels[0];
                    target.removeAttribute('scheme');
                    this.isDay = true;
                }
                else {
                    this.labelEl.innerHTML = this.labels[1];
                    target.setAttribute('scheme', 'dark');
                    this.isDay = false;
                }
            };
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['labels', 'target', 'feature', ...this.baseAttrs];
        static boolAttrs = [''];
        static get observedAttributes() {
            return [...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, TwilightElem);
        }
        getRawData() {
            this.getRawProps(TwilightElem);
            this.getProxyProps();
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' });
            this.labelEl = createEl('i', { [orca.alias]: 'label' }, this.labels[0]);
            let now = Date.now();
            this.legendEl = createEl('i', { [orca.alias]: 'legend' }, `
                <svg viewBox="0 0 24 24">
                    <mask id="mask-${now}">
                        <rect x="0" y="0" width="100%" height="100%" fill="white" />
                        <circle cx="25" cy="13" r="6" stroke="none" class="${orca.prefix}twilight-mask" fill="dark" />
                    </mask>
                    <circle fill="currentColor" cx="12" cy="12" r="6" class="${orca.prefix}twilight-main" mask="url(#mask-${now})" />
                    <g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="${orca.prefix}twilight-rays">
                        <line x1="12" y1="1" x2="12" y2="3" />
                        <line x1="12" y1="21" x2="12" y2="23" />
                        <line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
                        <line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
                        <line x1="1" y1="12" x2="3" y2="12" />
                        <line x1="21" y1="12" x2="23" y2="12" />
                        <line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
                        <line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
                    </g>
                </svg>
        `);
            this.wrapEl.append(this.labelEl, this.legendEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.removeEventListener('click', this.toggleEvt);
            this.addEventListener('click', this.toggleEvt, false);
        }
        changedMaps = {
            feature: this.changedFeature,
            target: this.changedTarget,
            labels: this.changedLabels,
        };
        changedTarget(opt) {
            this.targetEl = getEl(opt.newVal);
        }
        changedFeature(opt) {
            opt.newVal ? this.labelEl.remove() : this.wrapEl.insertAdjacentElement('afterbegin', this.labelEl);
        }
        changedLabels(opt) {
            if (opt.newVal) {
                this.labels = valToArr(opt.newVal);
                this.labelEl.innerHTML = this.labels[this.isDay ? 0 : 1];
            }
        }
    }

    class PaginationElem extends CompBaseComm {
        constructor() {
            super();
            this.createShadow();
            super.createPropsObs();
            this.fillWrap(this.propsProxy);
        }
        static get observedAttributes() {
            return [...optPagination.map((k) => k.attr), 'options', 'async'];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            if (name === 'current') {
                this.ins && newVal && this.ins.locate(newVal);
            }
            else {
                super.updateProxy(name, newVal, optPagination);
            }
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'slot-host' }, this.rawHtml);
        }
        createIns() {
            if (this.ins)
                return;
            this.ins = new Pagination(this.wrapEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
        }
    }

    class StepElem extends CompBaseComm {
        content;
        template;
        constructor() {
            super();
            this.template = `
        {{let active = this.active?'active':'',
            href = this.href ?'href="'+this.href+'"':'',
            name = href?'a':'div',
            target = href && this.target?'target="'+this.target+'"':'',
            rel= href && this.rel?'rel="'+this.rel+'"':'';
        /}}
        <{{name}} {{href}} {{target}} {{rel}} {{active}} class="_step-item _reset">
            <div class="_step-track">
                <div></div>
                <span ${orca.alias}="node"></span>
                <div></div>
            </div>
        </{{name}}>
    `;
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['active', 'type', 'theme', 'dir', 'error', ...this.baseAttrs];
        static boolAttrs = ['head-show', 'body-show', 'inverted', 'justify'];
        static get observedAttributes() {
            return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, StepElem);
        }
        getRawData() {
            this.getRawProps(StepElem);
            this.propsRaw.content = this.getAttribute('content') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.content = this.stdContent(this.getArrContent());
            let fragment = document.createDocumentFragment();
            for (let k of this.content) {
                let node = tplToEl(renderTpl(this.template, k));
                k.wrapEl = node;
                k.wrapEl.querySelector(`[${orca.alias}="node"]`).innerHTML = this.getLegend(k);
                k.headEl = createEl('div', { class: `${orca.prefix}step-head` }, k.tips);
                k.labelEl = createEl('div', { [orca.alias]: 'label' }, k.label);
                k.briefEl = createEl('div', { [orca.alias]: 'brief' }, k.brief);
                k.bodyEl = createEl('div', { class: `${orca.prefix}step-body` }, [k.labelEl, k.briefEl]);
                fragment.appendChild(node);
            }
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, data.label);
            this.wrapEl.appendChild(fragment);
        }
        getArrContent(content = this.propsProxy.content) {
            let trim = content.trim(), tmp = createEl('div', {}, trim), firstChild = tmp.firstElementChild, result = [];
            if (trim.startsWith('<') && firstChild) {
                let nodeName = firstChild.nodeName;
                if (nodeName === 'SCRIPT' && firstChild.getAttribute('type').includes('content')) {
                    result = parseStr({
                        content: firstChild.textContent,
                        type: 'array',
                        error: (err) => {
                            console.info(config.error.parse, err);
                        }
                    });
                }
                else {
                    result = [...tmp.children].map((k, i) => {
                        let _tmp = {
                            label: k.getAttribute('label') || k.textContent.trim(),
                            brief: k.getAttribute('brief'),
                            tips: k.getAttribute('tips'),
                            icon: k.getAttribute('icon'),
                            cube: k.getAttribute('cube'),
                            image: k.getAttribute('image'),
                            disk: k.getAttribute('disk'),
                        };
                        if (k.nodeName === 'A') {
                            _tmp.target = k.getAttribute('target');
                            _tmp.rel = k.getAttribute('rel');
                            _tmp.href = k.getAttribute('href');
                        }
                        return _tmp;
                    });
                }
            }
            else {
                result = parseStr({
                    content,
                    type: 'array',
                    error: (err) => {
                        console.info(config.error.parse, err);
                    }
                });
            }
            return result;
        }
        stdContent(content) {
            if (!Array.isArray(content)) {
                console.warn(`The obtained data is not an array, an empty array has been returned!`);
                return [];
            }
            return content.map((k, i) => {
                if (typeof k === 'string' || typeof k === 'number') {
                    return { label: k, index: i + 1 };
                }
                else {
                    return Object.assign(k, { index: i + 1 });
                }
            });
        }
        getLegend(data) {
            let type = this.propsProxy.type, dft = data.icon ? '<i class="' + data.icon + '"></i>' : data.image ? '<img src="' + data.image + '"/>' : data.index, result = '';
            if (type?.includes('circle')) {
                result = dft;
            }
            else if (type === 'plain') {
                result = data.field ? (data.field === 'icon' ? '<i class="' + data.icon + '"></i>' : data.field === 'image' ? '<img src="' + data.image + '"/>' : data[data.field]) : dft;
            }
            return result;
        }
        setLegendType() {
            for (let k of this.content) {
                let tmp = this.getLegend(k);
                k.wrapEl.querySelector(`[${orca.alias}="node"]`).innerHTML = tmp;
            }
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            'head-show': this.changedHeadshow,
            'body-show': this.changedBodyshow,
            active: this.changedActive,
            error: this.changedError,
            content: this.changedContent,
            type: this.changedType,
        };
        changedHeadshow(opt) {
            for (let k of this.content) {
                this.propsProxy['head-show'] ? k.wrapEl.insertAdjacentElement('afterbegin', k.headEl) : k.headEl.remove();
            }
        }
        changedBodyshow(opt) {
            for (let k of this.content) {
                this.propsProxy['body-show'] ? k.wrapEl.insertAdjacentElement('beforeend', k.bodyEl) : k.bodyEl.remove();
            }
        }
        changedActive(opt) {
            if (opt.newVal) {
                let tmp = Math.min(~~opt.newVal, this.content.length - 1);
                for (let [i, k] of this.content.entries()) {
                    let bool = i === tmp ? true : false;
                    k.wrapEl.toggleAttribute('active', bool);
                    k.active = bool;
                }
            }
        }
        changedError(opt) {
            let tmp = opt.newVal ? valToArr(opt.newVal) : [];
            if (!tmp.length) {
                for (let k of this.content) {
                    k.wrapEl.toggleAttribute('error', false);
                }
            }
            else {
                for (let [i, k] of this.content.entries()) {
                    k.wrapEl.toggleAttribute('error', tmp.includes(i) ? true : false);
                }
            }
        }
        changedContent(opt) {
            if (opt.newVal) {
                this.wrapEl.remove();
                this.fillWrap(this.propsProxy);
                this.appendChild(this.wrapEl);
            }
        }
        changedType(opt) {
            this.setLegendType();
        }
    }

    class StatusElem extends CompBaseComm {
        lampEl;
        labelEl;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['type', 'lamp', 'current', ...this.baseAttrs];
        static boolAttrs = [];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, StatusElem);
        }
        getRawData() {
            this.getRawProps(StatusElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.lampEl = createEl('i', { [orca.alias]: 'lamp' });
            this.labelEl = createEl('i', { [orca.alias]: 'label' }, this.propsProxy.lang?.info || config.lang.status.info);
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, this.lampEl);
            this.propsRaw.label && this.wrapEl.appendChild(this.labelEl);
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            label: this.changedLabel,
            lamp: this.changedLamp,
            current: this.changedCurrent,
        };
        changedLabel(opt) {
            if (opt.newVal === null) {
                this.labelEl.remove();
            }
            else {
                elState(this.labelEl).isVirtual && this.wrapEl.appendChild(this.labelEl);
                let tmp = this.propsProxy.current || 'info';
                this.labelEl.innerHTML = opt.newVal ? opt.newVal : this.propsProxy.lang?.[tmp] || config.lang.status[tmp];
            }
        }
        changedLamp(opt) {
            let attr = this.propsProxy.type === 'circle' ? 'borderColor' : 'background';
            this.lampEl.style[attr] = opt.newVal || null;
        }
        changedCurrent(opt) {
            if (opt.newVal) {
                this.labelEl.innerHTML = this.propsProxy.lang?.[opt.newVal] || config.lang.status[opt.newVal];
            }
        }
    }

    class CategoryElem extends CompBaseComm {
        headEl;
        iconEl;
        diskEl;
        cubeEl;
        imageEl;
        labelEl;
        tipsEl;
        arrowEl;
        legends;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = [...this.baseAttrs, 'size', 'theme', 'icon', 'disk', 'cube', 'image', 'tips', 'arrow'];
        static get observedAttributes() {
            return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, CategoryElem);
        }
        getRawData() {
            this.getRawProps(CategoryElem);
            this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
            this.getProxyProps();
        }
        fillWrap(data) {
            this.labelEl = createEl('i', { [orca.alias]: 'label' }, data.label);
            this.headEl = createEl('div', { [orca.alias]: 'head' }, this.labelEl);
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, this.headEl);
            this.arrowEl = createEl('i', { [orca.alias]: 'arrow', class: `${orca.prefix}icon-right` });
            this.tipsEl = createEl('i', { [orca.alias]: 'tips' }, data.tips);
            this.iconEl = createEl('i', { [orca.alias]: 'icon', class: data.label });
            this.diskEl = createEl('img', { [orca.alias]: 'disk', src: data.disk });
            this.cubeEl = createEl('img', { [orca.alias]: 'cube', src: data.cube });
            this.imageEl = createEl('img', { [orca.alias]: 'image', src: data.image });
            this.legends = [
                { name: 'icon', el: this.iconEl, attr: 'class' },
                { name: 'disk', el: this.diskEl, attr: 'src' },
                { name: 'cube', el: this.cubeEl, attr: 'src' },
                { name: 'image', el: this.imageEl, attr: 'src' },
            ];
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            label: this.changedLabel,
            icon: this.changedLegend,
            disk: this.changedLegend,
            cube: this.changedLegend,
            image: this.changedLegend,
            tips: this.changedTips,
            arrow: this.changedArrow,
        };
        changedLabel(opt) {
            this.labelEl.innerHTML = opt.newVal;
        }
        changedTips(opt) {
            if (opt.newVal === null) {
                this.tipsEl.remove();
            }
            else {
                this.tipsEl.innerHTML = opt.newVal;
                this.headEl.insertAdjacentElement('afterend', this.tipsEl);
            }
        }
        changedArrow(opt) {
            if (opt.newVal === null) {
                this.arrowEl.remove();
            }
            else {
                this.arrowEl.setAttribute('class', opt.newVal ? opt.newVal : `${orca.prefix}icon-right`);
                this.wrapEl.appendChild(this.arrowEl);
            }
        }
        changedLegend(opt) {
            let item = this.legends.find((k) => k.name === opt.name);
            if (opt.newVal) {
                item.el.setAttribute(item.attr, opt.newVal);
                elState(item.el).isVirtual && this.headEl.insertAdjacentElement('beforebegin', item.el);
                for (let k of this.legends) {
                    k !== item && !elState(k.el).isVirtual && k.el.remove();
                }
            }
            else {
                item.el.remove();
            }
        }
    }

    class SkeletonElem extends CompBaseComm {
        headEl;
        iconEl;
        diskEl;
        cubeEl;
        imageEl;
        labelEl;
        tipsEl;
        arrowEl;
        legends;
        cols;
        rows;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['type', 'anim', 'cols', 'rows', ...this.baseAttrs];
        static get observedAttributes() {
            return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, SkeletonElem);
        }
        getRawData() {
            this.getRawProps(SkeletonElem);
            this.propsRaw.content = this.getAttribute('content') || this.rawHtml;
            this.getProxyProps();
            this.cols = this.getCols();
            this.rows = this.getRows();
        }
        fillWrap(data) {
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, this.getSkelStr());
        }
        getRows(str = this.propsProxy.rows) {
            return ~~this.propsProxy.rows || 1;
        }
        getCols(str = this.propsProxy.cols) {
            let val = null, obj;
            if (isNull(str))
                return val;
            if (str?.includes(',')) {
                obj = strToJson(str);
                val = ~~obj[getScreenSize()];
            }
            else {
                val = ~~str;
            }
            return val || 4;
        }
        getSkelStr() {
            if (!this.propsProxy.type) {
                if (this.propsProxy.content) {
                    return this.propsProxy.content.repeat((this.cols || 1) * this.rows);
                }
                else {
                    return '';
                }
            }
            if (this.propsProxy.type === 'article') {
                return `
            <section>
                <div rep="legend">
                </div>
                <div rep="text">
                ${'<div></div>'.repeat(this.rows > 1 ? this.rows : 19)}
                </div>
            </section>
            `;
            }
            else {
                let repeatNum = this.propsProxy.type.includes('avatar') ? 2 :
                    this.propsProxy.type === 'paragraph' ? 4 : 3, itemStr = `
        <section>
                <div rep="legend"></div>
                <div rep="text">
                ${'<div></div>'.repeat(repeatNum)}
                </div>
            </section>
        `;
                return itemStr.repeat((this.cols || 1) * this.rows);
            }
        }
        render() {
            this.insertSource();
            this.appendChild(this.wrapEl);
        }
        changedMaps = {
            content: this.changedContent,
            cols: this.changedCols,
            rows: this.changedRows,
            type: this.changedType
        };
        changedContent(opt) {
            this.wrapEl.innerHTML = this.getSkelStr();
        }
        changedType(opt) {
            this.wrapEl.innerHTML = this.getSkelStr();
        }
        changedCols(opt) {
            this.cols = this.getCols(opt.newVal);
            this.wrapEl.style.gridTemplateColumns = this.cols ? `repeat(${this.cols}, 1fr)` : null;
            this.wrapEl.innerHTML = this.getSkelStr();
        }
        changedRows(opt) {
            this.rows = this.getRows(opt.newVal);
            this.wrapEl.innerHTML = this.getSkelStr();
        }
    }

    class PillElem extends CompBaseComm {
        content;
        itemsEl;
        thumbEl;
        activeItem;
        bodyEl;
        inputEl;
        value;
        name;
        constructor() {
            super();
            this.getRawData();
            this.fillWrap(this.propsProxy);
        }
        static custAttrs = ['active', 'disable', 'refer', 'name', 'on-changed', ...this.baseAttrs];
        static boolAttrs = ['disabled'];
        static get observedAttributes() {
            return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
        }
        attributeChangedCallback(name, oldVal, newVal) {
            if (!this.canListen)
                return;
            this.savePropsToListen(name, oldVal, newVal, PillElem);
        }
        getRawData() {
            this.getRawProps(PillElem);
            this.propsRaw.content = this.getAttribute('content') || this.rawHtml;
            this.propsRaw.active = ~~this.propsRaw.active || 0;
            this.getProxyProps();
        }
        getLegend(data) {
            let tmp = (data.disk || data.cube || data.image);
            return data.icon ? `<i class="${data.icon}" rep="icon"></i>` : tmp ? `<img src="${tmp}" rep="${tmp}" />` : '';
        }
        getItemsData(data) {
            let content = super.getAttrHtmlData(data);
            if (!Array.isArray(content)) {
                console.warn(`The obtained data is not an array, an empty array has been returned!`);
                return [];
            }
            return content.map((k, i) => {
                return (typeof k === 'string' || typeof k === 'number') ? { label: k, index: i } : Object.assign(k, { index: i });
            });
        }
        getItems(data = this.propsProxy) {
            this.content = this.getItemsData(data.content);
            let fragment = document.createDocumentFragment();
            for (let [i, k] of this.content.entries()) {
                let legend = this.getLegend(k), node = tplToEl(renderTpl(`<span ${orca.alias}="item" {{this.selected?'selected':''}}  {{this.disabled?'disabled':''}}>${legend}<i rep=label>{{this.label}}</i></span>`, k));
                k.wrapEl = node;
                fragment.appendChild(node);
                k.wrapEl.onclick = () => {
                    !k.selected && !k.disabled && this.active(i);
                };
            }
            return fragment;
        }
        active(val = 0) {
            let oldVal = this.content.find((k) => k.selected);
            let tmp = Math.min(~~val, this.content.length - 1);
            for (let [i, k] of this.content.entries()) {
                let bool = i === tmp ? true : false;
                k.wrapEl.toggleAttribute('selected', bool);
                k.selected = bool;
                if (bool) {
                    this.setTranslate(k.wrapEl);
                    this.activeItem = k;
                    this.value = k.label;
                    this.inputEl && (this.inputEl.value = k.label);
                    this.listen({ name: 'changed', params: [{ oldVal, newVal: k }] });
                }
            }
            if (this.bodyEl) {
                for (let [i, k] of [...this.bodyEl.children].entries()) {
                    let bool = i === tmp ? true : false;
                    k.toggleAttribute('selected', bool);
                }
            }
            this.updateCache({ active: val });
        }
        disable(val) {
            let arr = valToArr(val);
            if (!arr.length)
                return;
            for (let k of arr) {
                let tmp = Math.min(~~k, this.content.length - 1);
                for (let [i, o] of this.content.entries()) {
                    let bool = i === tmp ? true : false;
                    o.wrapEl.toggleAttribute('disabled', bool);
                    o.disabled = bool;
                }
            }
            this.updateCache({ disable: val });
            this.listen({ name: 'disabled', params: [arr.map((k) => this.content[k])] });
        }
        setTranslate(el) {
            this.style.setProperty(`--${orca.prefix}pill-thumb-offset`, el.offsetLeft + 'px');
            this.style.setProperty(`--${orca.prefix}pill-thumb-w`, el.offsetWidth + 'px');
        }
        fillWrap(data = this.propsProxy) {
            this.itemsEl = createEl('div', { [orca.alias]: 'items' });
            this.thumbEl = createEl('span', { [orca.alias]: 'thumb' });
            this.bodyEl = getEl(data.refer);
            this.wrapEl = createEl('div', { [orca.alias]: 'wrap' }, [this.itemsEl, this.thumbEl]);
            this.itemsEl.appendChild(this.getItems(data));
        }
        render(data = this.propsProxy) {
            this.insertSource();
            this.appendChild(this.wrapEl);
            this.active(data.active);
        }
        changedMaps = {
            active: this.changedActive,
            disable: this.changedDisable,
            content: this.changedContent,
            refer: this.changedRefer,
            name: this.changedName,
        };
        changedActive(opt) {
            opt.newVal && this.active(opt.newVal);
        }
        changedContent(opt) {
            if (opt.newVal) {
                this.itemsEl.innerHTML = '';
                this.itemsEl.appendChild(this.getItems());
                this.propsProxy.active && this.active(this.propsProxy.active);
                this.propsProxy.disable && this.disable(this.propsProxy.disable);
            }
        }
        changedDisable(opt) {
            opt.newVal && this.disable(opt.newVal);
        }
        changedRefer(opt) {
            if (opt.newVal) {
                this.bodyEl = getEl(opt.newVal);
                this.bodyEl && this.bodyEl.classList.add(`${orca.prefix}pill-body`);
            }
        }
        changedName(opt) {
            this.name = opt.newVal || '';
            if (opt.newVal) {
                if (this.inputEl) {
                    this.inputEl.setAttribute(opt.name, opt.newVal);
                }
                else {
                    this.inputEl = createEl('input', { type: 'text', name: opt.newVal, [orca.embedSign]: '' });
                    this.wrapEl.appendChild(this.inputEl);
                }
            }
            else {
                this.inputEl && this.inputEl.remove();
            }
        }
    }

    const init = (type, parent) => {
        let parentEl = getEl(parent) || document.body, evalFn = new Function('el', 'module', `"use strict";try {return new module(el)} catch {return null}`), moduleNodeMaps = [], setProp = (node, module) => {
            storeNode(node)?.addModule(module);
        }, getUsableModules = () => {
            let result = [];
            for (let [key, value] of Object.entries(orca)) {
                value?.hostType === 'node' ? result.push(key) : null;
            }
            return result;
        }, getNodeList = (types) => {
            let allModules = getUsableModules(), modules = !isEmpty(types) ? types.filter(k => allModules.includes(k)) : allModules, modulesNodes = modules.map(k => {
                let nodes = getEls(`[oc-${k}]`, parentEl).filter((i) => !i.orca || (i.orca && !i.orca[k]));
                return nodes.map((i) => { return { module: k, node: i }; });
            });
            return modulesNodes;
        }, activeFun = (obj) => {
            if (['Dialog', 'Drawer', 'Popup'].includes(obj.module)) {
                higherParent(obj.module, obj.node);
            }
            else {
                let ins = evalFn(obj.node, orca[obj.module]);
                ins ? setProp(obj.node, obj.module) : null;
            }
        }, higherParent = (module, node) => {
            let eachInstance = (host, parent) => {
                let ins = evalFn(host, orca[module]), children;
                if (ins) {
                    host[module] = true;
                    parent ? ins.targetEl.style.zIndex = parseInt(getComputedStyle(parent.targetEl).zIndex) + 1 : null;
                    children = getEls(`[oc-${module}]`, ins.contEl);
                    if (children.length > 0) {
                        for (let k of children)
                            eachInstance(k, ins);
                    }
                }
            };
            eachInstance(node);
        };
        if (!isEmpty(type)) {
            let moduleType = getDataType(type), types;
            types = (moduleType === 'String') ? [type] :
                (moduleType === 'Array') ? type : [];
            moduleNodeMaps = types.length > 0 ? getNodeList(types) : [];
        }
        else {
            moduleNodeMaps = getNodeList();
        }
        let flatArr = moduleNodeMaps.flat();
        if (flatArr.length) {
            decompTask({
                tasks: flatArr,
                count: 4,
                type: 'idle',
                done: () => {
                    console.info(`Initialization finished, all tasks of orcaui are done!`);
                },
                run: (task) => activeFun(task),
            });
        }
        let lazySrcs = getEls('[lazy-src]', parentEl), lazyAsyncs = getEls('[lazy-async]', parentEl);
        for (let k of lazySrcs) {
            if (k?.orca?.lazy)
                continue;
            new Lazy(k, {
                content: k.getAttribute('lazy-src'),
                type: 'src'
            });
        }
        for (let k of lazyAsyncs) {
            if (k?.orca?.lazy)
                continue;
            new Lazy(k, {
                content: k.getAttribute('lazy-async'),
                contType: k.getAttribute('lazy-type'),
                contData: strToJson(k.getAttribute('lazy-data')),
                tplStr: k.getAttribute('lazy-tpl'),
                type: 'async'
            });
        }
        return orca;
    };

    var modules = {
        orca,
        config,
        fieldTypes,
        getDataType,
        renderTpl,
        getScreenSize,
        sliceStrEnd,
        delay,
        toNumber,
        toPixel,
        preventDft,
        events,
        icons,
        propsMap,
        augment,
        privacy,
        support,
        requireTypes,
        trim,
        getSelectorType,
        isEmpty,
        isNull,
        getEl,
        deepClone,
        deepMerge,
        strToJson,
        attrToJson,
        attrJoinVal,
        extend,
        plan,
        instance,
        breakpoints,
        createEl,
        purifyHtml,
        startUpper,
        storage,
        isDateStr,
        getExpiration,
        ajax,
        offset,
        elState,
        contains,
        getEls,
        getContent,
        setContent,
        createBtns,
        createFooter,
        createTools,
        tplToEl,
        tplToEls,
        getHeights,
        getWidths,
        getElSpace,
        slideDown,
        slideUp,
        slideToggle,
        curveFns,
        ease,
        easeHeight,
        fadeIn,
        fadeOut,
        fadeToggle,
        style,
        show,
        hide,
        toggle,
        spreadBool,
        getClasses,
        classes,
        validTools,
        toLocalTime,
        regExps,
        replaceFrag,
        combineArr,
        sliceFrags,
        paramToJson,
        getLast,
        fieldTools,
        isSubset,
        debounce,
        throttle,
        storeNode,
        convertByte,
        clampVal,
        formTools,
        fileTools,
        unique,
        increaseId,
        treeTools,
        valToArr,
        moveItem,
        getValsFromAttrs,
        dl2Tree,
        findItem,
        findItems,
        getAttrBool,
        getAttrArr,
        theme,
        attrValBool,
        getBetweenEls,
        scrollTo,
        allToEls,
        getUTCTimestamp,
        setAttr,
        setAttrs,
        getScrollObj,
        transformTools,
        isScrollUp,
        eventMap,
        getClientObj,
        bulletTools,
        arrSearch,
        arrSort,
        isProxy,
        getNestProp,
        getIntArr,
        clearRegx,
        isOutside,
        getRectPoints,
        elsSort,
        getEvtTarget,
        getEvtClient,
        getStrFromTpl,
        stdParam,
        setSingleSel,
        splitNum,
        parseUrlArr,
        getPlaces,
        dateTools,
        repeatStr,
        createModule,
        createComp,
        getArrMap,
        includes,
        capStart,
        removeItem,
        deepEqual,
        splice,
        appendEls,
        decompTask,
        filterPrims,
        createEvt,
        confirm,
        alert,
        notice,
        prompt,
        keyCond,
        removeStyle,
        removeStyles,
        addStyle,
        addStyles,
        regComp,
        getComputedVar,
        select2Tree,
        ul2Tree,
        parseStr,
        getAutoDur,
        getHypotenuse,
        promiseRaf,
        getRtl,
        setRtl,
        ModBase,
        ModBaseListen,
        ModBaseListenCache,
        ModBaseListenCacheBubble,
        ModBaseListenCacheNest,
        More,
        Observe,
        Position,
        Hover,
        Popup,
        Dodge,
        Message,
        Valid,
        Menu,
        Tab,
        Drawer,
        Dialog,
        Spy,
        Tooltip,
        Dropdown,
        Gesture,
        Tags,
        Retrieval,
        Autocomplete,
        Scroll,
        Drag,
        Masonry,
        Swipe,
        Lazy,
        Progress,
        Infinite,
        Virtualize,
        Pagination,
        Range,
        Datetime,
        Tree,
        Rate,
        Accordion,
        Editor,
        Select,
        Upload,
        Panel,
        Router,
        Flip,
        CompBase,
        CompBaseComm,
        CompBaseCommField,
        CompBaseCommFieldMixin,
        MoreElem,
        ResultElem,
        DeformElem,
        RadioElem,
        CheckboxElem,
        BtnElem,
        LineElem,
        AvatarElem,
        FormatElem,
        FlagElem,
        BuoyElem,
        GoodElem,
        AnchorsElem,
        MenuElem,
        FileElem,
        InputElem,
        TextareaElem,
        RadiosElem,
        CheckboxesElem,
        NumberElem,
        RangeElem,
        StatsElem,
        IconElem,
        BadgeElem,
        DividerElem,
        AlarmElem,
        ProgressElem,
        DatetimeElem,
        RateElem,
        TreeElem,
        AccordionElem,
        EditorElem,
        SelectElem,
        UploadElem,
        FieldsElem,
        SearchElem,
        CalloutElem,
        TwilightElem,
        PaginationElem,
        StepElem,
        StatusElem,
        CategoryElem,
        SkeletonElem,
        PillElem,
        init,
    };

    var tmp = /*#__PURE__*/Object.freeze({
        __proto__: null,
        Accordion: Accordion,
        AccordionElem: AccordionElem,
        AlarmElem: AlarmElem,
        AnchorsElem: AnchorsElem,
        Autocomplete: Autocomplete,
        AvatarElem: AvatarElem,
        BadgeElem: BadgeElem,
        BtnElem: BtnElem,
        BuoyElem: BuoyElem,
        CalloutElem: CalloutElem,
        CategoryElem: CategoryElem,
        CheckboxElem: CheckboxElem,
        CheckboxesElem: CheckboxesElem,
        CompBase: CompBase,
        CompBaseComm: CompBaseComm,
        CompBaseCommField: CompBaseCommField,
        CompBaseCommFieldMixin: CompBaseCommFieldMixin,
        Datetime: Datetime,
        DatetimeElem: DatetimeElem,
        DeformElem: DeformElem,
        Dialog: Dialog,
        DividerElem: DividerElem,
        Dodge: Dodge,
        Drag: Drag,
        Drawer: Drawer,
        Dropdown: Dropdown,
        Editor: Editor,
        EditorElem: EditorElem,
        FieldsElem: FieldsElem,
        FileElem: FileElem,
        FlagElem: FlagElem,
        Flip: Flip,
        FormatElem: FormatElem,
        Gesture: Gesture,
        GoodElem: GoodElem,
        Hover: Hover,
        IconElem: IconElem,
        Infinite: Infinite,
        InputElem: InputElem,
        Lazy: Lazy,
        LineElem: LineElem,
        Masonry: Masonry,
        Menu: Menu,
        MenuElem: MenuElem,
        Message: Message,
        ModBase: ModBase,
        ModBaseListen: ModBaseListen,
        ModBaseListenCache: ModBaseListenCache,
        ModBaseListenCacheBubble: ModBaseListenCacheBubble,
        ModBaseListenCacheNest: ModBaseListenCacheNest,
        More: More,
        MoreElem: MoreElem,
        NumberElem: NumberElem,
        Observe: Observe,
        Pagination: Pagination,
        PaginationElem: PaginationElem,
        Panel: Panel,
        PillElem: PillElem,
        Popup: Popup,
        Position: Position,
        Progress: Progress,
        ProgressElem: ProgressElem,
        RadioElem: RadioElem,
        RadiosElem: RadiosElem,
        Range: Range,
        RangeElem: RangeElem,
        Rate: Rate,
        RateElem: RateElem,
        ResultElem: ResultElem,
        Retrieval: Retrieval,
        Router: Router,
        Scroll: Scroll,
        SearchElem: SearchElem,
        Select: Select,
        SelectElem: SelectElem,
        SkeletonElem: SkeletonElem,
        Spy: Spy,
        StatsElem: StatsElem,
        StatusElem: StatusElem,
        StepElem: StepElem,
        Swipe: Swipe,
        Tab: Tab,
        Tags: Tags,
        TextareaElem: TextareaElem,
        Tooltip: Tooltip,
        Tree: Tree,
        TreeElem: TreeElem,
        TwilightElem: TwilightElem,
        Upload: Upload,
        UploadElem: UploadElem,
        Valid: Valid,
        Virtualize: Virtualize,
        addStyle: addStyle,
        addStyles: addStyles,
        ajax: ajax,
        alert: alert,
        allToEls: allToEls,
        appendEls: appendEls,
        arrSearch: arrSearch,
        arrSort: arrSort,
        attrJoinVal: attrJoinVal,
        attrToJson: attrToJson,
        attrValBool: attrValBool,
        augment: augment,
        breakpoints: breakpoints,
        bulletTools: bulletTools,
        capStart: capStart,
        clampVal: clampVal,
        classes: classes,
        clearRegx: clearRegx,
        combineArr: combineArr,
        config: config,
        confirm: confirm,
        contains: contains,
        convertByte: convertByte,
        createBtns: createBtns,
        createComp: createComp,
        createEl: createEl,
        createEvt: createEvt,
        createFooter: createFooter,
        createModule: createModule,
        createTools: createTools,
        curveFns: curveFns,
        dateTools: dateTools,
        debounce: debounce,
        decompTask: decompTask,
        deepClone: deepClone,
        deepEqual: deepEqual,
        deepMerge: deepMerge,
        default: modules,
        delay: delay,
        dl2Tree: dl2Tree,
        ease: ease,
        easeHeight: easeHeight,
        elState: elState,
        elsSort: elsSort,
        eventMap: eventMap,
        events: events,
        extend: extend,
        fadeIn: fadeIn,
        fadeOut: fadeOut,
        fadeToggle: fadeToggle,
        fieldTools: fieldTools,
        fieldTypes: fieldTypes,
        fileTools: fileTools,
        filterPrims: filterPrims,
        findItem: findItem,
        findItems: findItems,
        formTools: formTools,
        getArrMap: getArrMap,
        getAttrArr: getAttrArr,
        getAttrBool: getAttrBool,
        getAutoDur: getAutoDur,
        getBetweenEls: getBetweenEls,
        getClasses: getClasses,
        getClientObj: getClientObj,
        getComputedVar: getComputedVar,
        getContent: getContent,
        getDataType: getDataType,
        getEl: getEl,
        getElSpace: getElSpace,
        getEls: getEls,
        getEvtClient: getEvtClient,
        getEvtTarget: getEvtTarget,
        getExpiration: getExpiration,
        getHeights: getHeights,
        getHypotenuse: getHypotenuse,
        getIntArr: getIntArr,
        getLast: getLast,
        getNestProp: getNestProp,
        getPlaces: getPlaces,
        getRectPoints: getRectPoints,
        getRtl: getRtl,
        getScreenSize: getScreenSize,
        getScrollObj: getScrollObj,
        getSelectorType: getSelectorType,
        getStrFromTpl: getStrFromTpl,
        getUTCTimestamp: getUTCTimestamp,
        getValsFromAttrs: getValsFromAttrs,
        getWidths: getWidths,
        hide: hide,
        icons: icons,
        includes: includes,
        increaseId: increaseId,
        init: init,
        instance: instance,
        isDateStr: isDateStr,
        isEmpty: isEmpty,
        isNull: isNull,
        isOutside: isOutside,
        isProxy: isProxy,
        isScrollUp: isScrollUp,
        isSubset: isSubset,
        keyCond: keyCond,
        moveItem: moveItem,
        notice: notice,
        offset: offset,
        orca: orca,
        paramToJson: paramToJson,
        parseStr: parseStr,
        parseUrlArr: parseUrlArr,
        plan: plan,
        preventDft: preventDft,
        privacy: privacy,
        promiseRaf: promiseRaf,
        prompt: prompt,
        propsMap: propsMap,
        purifyHtml: purifyHtml,
        regComp: regComp,
        regExps: regExps,
        removeItem: removeItem,
        removeStyle: removeStyle,
        removeStyles: removeStyles,
        renderTpl: renderTpl,
        repeatStr: repeatStr,
        replaceFrag: replaceFrag,
        requireTypes: requireTypes,
        scrollTo: scrollTo,
        select2Tree: select2Tree,
        setAttr: setAttr,
        setAttrs: setAttrs,
        setContent: setContent,
        setRtl: setRtl,
        setSingleSel: setSingleSel,
        show: show,
        sliceFrags: sliceFrags,
        sliceStrEnd: sliceStrEnd,
        slideDown: slideDown,
        slideToggle: slideToggle,
        slideUp: slideUp,
        splice: splice,
        splitNum: splitNum,
        spreadBool: spreadBool,
        startUpper: startUpper,
        stdParam: stdParam,
        storage: storage,
        storeNode: storeNode,
        strToJson: strToJson,
        style: style,
        support: support,
        theme: theme,
        throttle: throttle,
        toLocalTime: toLocalTime,
        toNumber: toNumber,
        toPixel: toPixel,
        toggle: toggle,
        tplToEl: tplToEl,
        tplToEls: tplToEls,
        transformTools: transformTools,
        treeTools: treeTools,
        trim: trim,
        ul2Tree: ul2Tree,
        unique: unique,
        valToArr: valToArr,
        validTools: validTools
    });

    const _tmp = { ...tmp };
    for (let k in _tmp) {
        let comp = _tmp[k];
        if (typeof comp !== 'function' || !comp?.name?.endsWith(`Elem`))
            continue;
        _tmp.regComp(comp);
    }
    document.addEventListener("DOMContentLoaded", () => {
        for (let k of orca.tasks)
            k();
        orca.tasks = [];
    });
    orca.config.support && _tmp.support(true);
    orca.config.privacy && _tmp.privacy({});
    Reflect.deleteProperty(_tmp, 'orca');
    Object.assign(orca, _tmp);

    return orca;

}));
