import { b as balBrowser } from './browser-B1u-Mq75.js';
import { h as balIconMenuBars, i as balIconUpload, j as balIconDocument, k as balIconDate, l as balIconCheck, m as balIconCaretRight, n as balIconCaretLeft, p as balIconCaretDown, q as balIconCaretUp, r as balIconNavGoUp, s as balIconNavGoDown, t as balIconNavGoRight, v as balIconNavGoLeft, w as balIconTrash, x as balIconEdit, y as balIconMinus, z as balIconPlus, A as balIconInfoCircle, B as balIconClose, g as useBalConfig } from './config.utils-B7jugjyM.js';

/**
 * Request Largest Contentful Paint (LCP) callback
 */
const rLCP = (callback, timeout = 3000) => {
    let isLargestContentPatinDone = false;
    if (!balBrowser.isSafari && balBrowser.hasWindow && 'PerformanceObserver' in window) {
        const observer = new PerformanceObserver(entryList => {
            const entries = entryList.getEntries();
            const lcpEntry = entries[entries.length - 1]; // Get the last (largest) entry
            if (lcpEntry) {
                // Disconnect the observer as we only need the LCP
                observer.disconnect();
                // Load the script after LCP
                isLargestContentPatinDone = true;
                rIC(() => callback());
            }
        });
        // Start observing for Largest Contentful Paint (LCP) entries
        observer.observe({ type: 'largest-contentful-paint', buffered: true });
        setTimeout(() => {
            if (!isLargestContentPatinDone) {
                observer.disconnect();
                callback();
            }
        }, timeout);
    }
    else {
        return setTimeout(callback, 32);
    }
};
const rOnLoad = (callback, timeout = 32) => {
    let called = false;
    const callOnce = () => {
        if (!called) {
            called = true;
            callback();
        }
    };
    if (balBrowser.hasWindow) {
        const timer = setTimeout(callOnce, timeout);
        window.addEventListener('load', () => {
            clearTimeout(timer);
            callOnce();
        });
    }
    else {
        setTimeout(callOnce, 32);
    }
};
const rIC = (callback, timeout = 5000) => {
    if (balBrowser.hasWindow && 'requestIdleCallback' in window) {
        window.requestIdleCallback(callback, { timeout });
    }
    else {
        setTimeout(callback, 32);
    }
};
const wait = (ms = 0) => {
    return new Promise(resolve => {
        setTimeout(() => resolve(), ms);
    });
};
const debounceEvent = (ev, wait) => {
    const original = ev._original || ev;
    return {
        _original: ev,
        emit: debounce(original.emit.bind(original), wait),
    };
};
const debounce = (func, wait = 0) => {
    let timer;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(func, wait, ...args);
    };
};
const hasTagName = (element, tag) => {
    return element && element.tagName && element.tagName === tag.toUpperCase();
};
const isDescendant = (parent, child) => {
    let node = child.parentNode;
    while (node != null) {
        if (node == parent) {
            return true;
        }
        node = node.parentNode;
    }
    return false;
};
const hasParent = (parentTag, child) => {
    let node = child.parentNode;
    while (node != null) {
        if (node.tagName === parentTag.toUpperCase()) {
            return true;
        }
        node = node.parentNode;
    }
    return false;
};
const getAppRoot = (doc) => {
    return doc.querySelector('bal-app') || doc.body;
};
/**
 * Waits for a component to be ready for
 * both custom element and non-custom element builds.
 * If non-custom element build, el.componentOnReady
 * will be used.
 * For custom element builds, we wait a frame
 * so that the inner contents of the component
 * have a chance to render.
 *
 * Use this utility rather than calling
 * el.componentOnReady yourself.
 */
const componentOnReady = (el, callback) => {
    if (el.componentOnReady !== null && el.componentOnReady !== undefined) {
        el.componentOnReady().then((resolvedEl) => callback(resolvedEl));
    }
    else {
        raf(() => callback(el));
    }
};
/**
 * Patched version of requestAnimationFrame that avoids ngzone
 * Use only when you know ngzone should not run
 */
const raf = (h) => {
    if (typeof __zone_symbol__requestAnimationFrame === 'function') {
        return __zone_symbol__requestAnimationFrame(h);
    }
    if (typeof requestAnimationFrame === 'function') {
        return requestAnimationFrame(h);
    }
    return setTimeout(h);
};
const transitionEndAsync = (el, expectedDuration = 0) => {
    return new Promise(resolve => {
        transitionEnd(el, expectedDuration, resolve);
    });
};
/**
 * Allows developer to wait for a transition
 * to finish and fallback to a timer if the
 * transition is cancelled or otherwise
 * never finishes. Also see transitionEndAsync
 * which is an await-able version of this.
 */
const transitionEnd = (el, expectedDuration = 0, callback) => {
    let unRegTrans;
    let animationTimeout;
    const opts = { passive: true };
    const ANIMATION_FALLBACK_TIMEOUT = 500;
    const unregister = () => {
        if (unRegTrans) {
            unRegTrans();
        }
    };
    const onTransitionEnd = (ev) => {
        if (ev === undefined || el === ev.target) {
            unregister();
            callback(ev);
        }
    };
    if (el) {
        el.addEventListener('webkitTransitionEnd', onTransitionEnd, opts);
        el.addEventListener('transitionend', onTransitionEnd, opts);
        animationTimeout = setTimeout(onTransitionEnd, expectedDuration + ANIMATION_FALLBACK_TIMEOUT);
        unRegTrans = () => {
            if (animationTimeout) {
                clearTimeout(animationTimeout);
                animationTimeout = undefined;
            }
            el.removeEventListener('webkitTransitionEnd', onTransitionEnd, opts);
            el.removeEventListener('transitionend', onTransitionEnd, opts);
        };
    }
    return unregister;
};
const addEventListener = (el, eventName, callback, opts) => {
    if (balBrowser.hasWindow) {
        const config = useBalConfig();
        if (config) {
            const ael = config._ael;
            if (ael) {
                return ael(el, eventName, callback, opts);
            }
            else if (config._ael) {
                return config._ael(el, eventName, callback, opts);
            }
        }
    }
    return el.addEventListener(eventName, callback, opts);
};
const removeEventListener = (el, eventName, callback, opts) => {
    if (balBrowser.hasWindow) {
        const config = useBalConfig();
        if (config) {
            const rel = config._rel;
            if (rel) {
                return rel(el, eventName, callback, opts);
            }
            else if (config._rel) {
                return config._rel(el, eventName, callback, opts);
            }
        }
    }
    return el.removeEventListener(eventName, callback, opts);
};
const shallowReady = (el) => {
    if (el) {
        return new Promise(resolve => componentOnReady(el, resolve));
    }
    return Promise.resolve();
};
const deepReady = async (el, full = false) => {
    const element = el;
    if (element) {
        if (element.componentOnReady !== null && element.componentOnReady !== undefined) {
            const stencilEl = await element.componentOnReady();
            if (!full && stencilEl !== null && stencilEl !== undefined) {
                return;
            }
        }
        await Promise.all(Array.from(element.children).map(child => deepReady(child, full)));
    }
};
const waitForComponent = async (el) => {
    await deepReady(el, true);
    await waitAfterFramePaint();
    await waitAfterIdleCallback();
};
const isChildOfEventTarget = async (ev, el, callback) => {
    if (ev && ev.target && el && el !== ev.target) {
        let target = ev.target;
        // special case for the navbar case
        const isNavbarBrand = ev.target.nodeName === 'BAL-NAVBAR-BRAND';
        if (isNavbarBrand) {
            target = target.closest('bal-navbar');
        }
        if (target && isDescendant(target, el)) {
            callback(target);
        }
    }
};
const waitForDesignSystem = async (el, _config) => {
    const config = Object.assign({ animated: false, icons: {
            balIconClose,
            balIconInfoCircle,
            balIconPlus,
            balIconMinus,
            balIconEdit,
            balIconTrash,
            balIconNavGoLeft,
            balIconNavGoRight,
            balIconNavGoDown,
            balIconNavGoUp,
            balIconCaretUp,
            balIconCaretDown,
            balIconCaretLeft,
            balIconCaretRight,
            balIconCheck,
            balIconDate,
            balIconDocument,
            balIconUpload,
            balIconMenuBars,
        } }, _config);
    const element = el;
    if (element !== null && element !== undefined) {
        await deepReady(element, true);
        const webComponents = Array.prototype.slice
            .call(element.querySelectorAll('*'))
            .filter(el => el.tagName.match(/^bal/i));
        await Promise.all(webComponents.map(c => {
            if (c.configChanged !== null && c.configChanged !== undefined) {
                return c.configChanged(config);
            }
        }));
    }
    await Promise.all([waitAfterFramePaint(), waitAfterLargestContentfulPaintCallback(), waitAfterIdleCallback()]);
};
const waitAfterFramePaint = () => {
    return new Promise(resolve => raf(() => runHighPrioritizedTask(resolve)));
};
const waitAfterIdleCallback = () => {
    return new Promise(resolve => rIC(() => runHighPrioritizedTask(resolve)));
};
const waitAfterLargestContentfulPaintCallback = () => {
    return new Promise(resolve => rLCP(() => runHighPrioritizedTask(resolve)));
};
const waitOnLoadEventCallback = () => {
    return new Promise(resolve => rOnLoad(() => runHighPrioritizedTask(resolve)));
};
const runHighPrioritizedTask = (callback) => {
    if (balBrowser.hasWindow && 'MessageChannel' in window) {
        const messageChannel = new window.MessageChannel();
        messageChannel.port1.onmessage = callback;
        messageChannel.port2.postMessage(undefined);
    }
    else {
        setTimeout(callback, 32);
    }
};

export { waitAfterFramePaint as a, waitAfterIdleCallback as b, componentOnReady as c, deepReady as d, waitAfterLargestContentfulPaintCallback as e, waitForComponent as f, getAppRoot as g, waitForDesignSystem as h, isDescendant as i, waitOnLoadEventCallback as j, debounce as k, rOnLoad as l, raf as m, debounceEvent as n, addEventListener as o, removeEventListener as p, hasParent as q, rIC as r, shallowReady as s, transitionEndAsync as t, isChildOfEventTarget as u, hasTagName as v, wait as w };
