import { r as registerInstance, c as createEvent, h, H as Host, g as getElement } from './index-442cf464.js';
import { g as getClassMap } from './theme-a8bb96f5.js';
import { r as raf } from './helpers-09d305fe.js';

const attachComponent = async (delegate, container, component, cssClasses, componentProps) => {
    if (delegate) {
        return delegate.attachViewToDom(container, component, componentProps, cssClasses);
    }
    if (typeof component !== 'string' && !(component instanceof HTMLElement)) {
        throw new Error('framework delegate is missing');
    }
    const el = (typeof component === 'string')
        ? container.ownerDocument && container.ownerDocument.createElement(component)
        : component;
    if (cssClasses) {
        cssClasses.forEach(c => el.classList.add(c));
    }
    if (componentProps) {
        Object.assign(el, componentProps);
    }
    container.appendChild(el);
    if (el.componentOnReady) {
        await el.componentOnReady();
    }
    return el;
};
const detachComponent = (delegate, element) => {
    if (element) {
        if (delegate) {
            const container = element.parentElement;
            return delegate.removeViewFromDom(container, element);
        }
        element.remove();
    }
    return Promise.resolve();
};

let lastId = 0;
const prepareOverlay = (el) => {
    const doc = document;
    connectListeners(doc);
    const overlayIndex = lastId++;
    el.overlayIndex = overlayIndex;
    if (!el.hasAttribute('id')) {
        el.id = `lu-overlay-${overlayIndex}`;
    }
};
const connectListeners = (doc) => {
    if (lastId === 0) {
        lastId = 1;
        // trap focus inside overlays
        doc.addEventListener('focusin', ev => {
            const lastOverlay = getOverlay(doc);
            if (lastOverlay && lastOverlay.backdropDismiss && !isDescendant(lastOverlay, ev.target)) {
                const firstInput = lastOverlay.querySelector('input,button');
                if (firstInput) {
                    firstInput.focus();
                }
            }
        });
        // handle ESC to close overlay
        doc.addEventListener('keyup', ev => {
            if (ev.key === 'Escape') {
                const lastOverlay = getOverlay(doc);
                if (lastOverlay && lastOverlay.backdropDismiss) {
                    lastOverlay.dismiss(undefined, BACKDROP);
                }
            }
        });
    }
};
const getOverlays = (doc, selector) => {
    if (selector === undefined) {
        selector = 'lu-modal';
    }
    return Array.from(doc.querySelectorAll(selector))
        .filter(c => c.overlayIndex > 0);
};
const getOverlay = (doc, overlayTag, id) => {
    const overlays = getOverlays(doc, overlayTag);
    return (id === undefined)
        ? overlays[overlays.length - 1]
        : overlays.find(o => o.id === id);
};
const present = async (overlay, enterAnimation, opts) => {
    if (overlay.presented) {
        return;
    }
    overlay.presented = true;
    overlay.willPresent.emit();
    // get the user's animation fn if one was provided
    const animationBuilder = (overlay.enterAnimation)
        ? overlay.enterAnimation
        : enterAnimation;
    const completed = await overlayAnimation(overlay, animationBuilder, overlay.el, opts);
    if (completed) {
        overlay.didPresent.emit();
    }
};
const dismiss = async (overlay, data, role, leaveAnimation, opts) => {
    if (!overlay.presented) {
        return false;
    }
    overlay.presented = false;
    try {
        overlay.willDismiss.emit({ data, role });
        const animationBuilder = (overlay.leaveAnimation)
            ? overlay.leaveAnimation
            : leaveAnimation;
        await overlayAnimation(overlay, animationBuilder, overlay.el, opts);
        overlay.didDismiss.emit({ data, role });
    }
    catch (err) {
        console.error(err);
    }
    overlay.el.remove();
    return true;
};
const overlayAnimation = async (overlay, animationBuilder, baseEl, opts) => {
    if (overlay.animation) {
        overlay.animation.destroy();
        overlay.animation = undefined;
        return false;
    }
    // Make overlay visible in case it's hidden
    baseEl.classList.remove('overlay-hidden');
    const aniRoot = baseEl.shadowRoot || overlay.el;
    /**
     * TODO: Remove AnimationBuilder
     */
    let isAnimationBuilder = true;
    const animation = animationBuilder(aniRoot, opts);
    animation.fill('both');
    isAnimationBuilder = false;
    overlay.animation = animation;
    if (!overlay.animated) {
        animation.duration(0);
    }
    if (overlay.keyboardClose) {
        animation.beforeAddWrite(() => {
            const activeElement = baseEl.ownerDocument.activeElement;
            if (activeElement && activeElement.matches('input, ion-input, ion-textarea')) {
                activeElement.blur();
            }
        });
    }
    const animationResult = await animation.playAsync();
    /**
     * TODO: Remove AnimationBuilder
     */
    const hasCompleted = (typeof animationResult === 'boolean') ? animationResult : animation.hasCompleted;
    if (isAnimationBuilder) {
        animation.destroy();
    }
    overlay.animation = undefined;
    return hasCompleted;
};
const eventMethod = (element, eventName) => {
    let resolve;
    const promise = new Promise(r => resolve = r);
    onceEvent(element, eventName, (event) => {
        resolve(event.detail);
    });
    return promise;
};
const onceEvent = (element, eventName, callback) => {
    const handler = (ev) => {
        element.removeEventListener(eventName, handler);
        callback(ev);
    };
    element.addEventListener(eventName, handler);
};
const isDescendant = (parent, child) => {
    while (child) {
        if (child === parent) {
            return true;
        }
        child = child.parentElement;
    }
    return false;
};
const BACKDROP = 'backdrop';

const setStyleProperty = (element, propertyName, value) => {
    element.style.setProperty(propertyName, value);
};
const removeStyleProperty = (element, propertyName) => {
    element.style.removeProperty(propertyName);
};
const animationEnd = (el, callback) => {
    let unRegTrans;
    const opts = { passive: true };
    const unregister = () => {
        if (unRegTrans) {
            unRegTrans();
        }
    };
    const onTransitionEnd = (ev) => {
        if (el === ev.target) {
            unregister();
            callback(ev);
        }
    };
    if (el) {
        el.addEventListener('webkitAnimationEnd', onTransitionEnd, opts);
        el.addEventListener('animationend', onTransitionEnd, opts);
        unRegTrans = () => {
            el.removeEventListener('webkitAnimationEnd', onTransitionEnd, opts);
            el.removeEventListener('animationend', onTransitionEnd, opts);
        };
    }
    return unregister;
};
const generateKeyframeRules = (keyframes = []) => {
    return keyframes.map(keyframe => {
        const offset = keyframe.offset;
        const frameString = [];
        for (const property in keyframe) {
            if (keyframe.hasOwnProperty(property) && property !== 'offset') {
                frameString.push(`${property}: ${keyframe[property]};`);
            }
        }
        return `${offset * 100}% { ${frameString.join(' ')} }`;
    }).join(' ');
};
const keyframeIds = [];
const generateKeyframeName = (keyframeRules) => {
    let index = keyframeIds.indexOf(keyframeRules);
    if (index < 0) {
        index = (keyframeIds.push(keyframeRules) - 1);
    }
    return `ion-animation-${index}`;
};
const getStyleContainer = (element) => {
    const rootNode = element.getRootNode();
    return (rootNode.head || rootNode);
};
const createKeyframeStylesheet = (keyframeName, keyframeRules, element) => {
    const styleContainer = getStyleContainer(element);
    const existingStylesheet = styleContainer.querySelector('#' + keyframeName);
    if (existingStylesheet) {
        return existingStylesheet;
    }
    const stylesheet = (element.ownerDocument || document).createElement('style');
    stylesheet.id = keyframeName;
    stylesheet.textContent = `@keyframes ${keyframeName} { ${keyframeRules} } @keyframes ${keyframeName}-alt { ${keyframeRules} }`;
    styleContainer.appendChild(stylesheet);
    return stylesheet;
};
const addClassToArray = (classes = [], className) => {
    if (className !== undefined) {
        const classNameToAppend = (Array.isArray(className)) ? className : [className];
        return [...classes, ...classNameToAppend];
    }
    return classes;
};

// TODO: Add more tests. until then, be sure to manually test menu and swipe to go back/routing transitions
const createAnimation = () => {
    let _delay;
    let _duration;
    let _easing;
    let _iterations;
    let _fill;
    let _direction;
    let _keyframes = [];
    let beforeAddClasses = [];
    let beforeRemoveClasses = [];
    let initialized = false;
    let parentAnimation;
    let beforeStylesValue = {};
    let afterAddClasses = [];
    let afterRemoveClasses = [];
    let afterStylesValue = {};
    let numAnimationsRunning = 0;
    let shouldForceLinearEasing = false;
    let shouldForceSyncPlayback = false;
    let cssAnimationsTimerFallback;
    let forceDirectionValue;
    let forceDurationValue;
    let forceDelayValue;
    let willComplete = true;
    let finished = false;
    let shouldCalculateNumAnimations = true;
    let keyframeName;
    let ani;
    const onFinishCallbacks = [];
    const onFinishOneTimeCallbacks = [];
    const elements = [];
    const childAnimations = [];
    const stylesheets = [];
    const _beforeAddReadFunctions = [];
    const _beforeAddWriteFunctions = [];
    const _afterAddReadFunctions = [];
    const _afterAddWriteFunctions = [];
    const webAnimations = [];
    const supportsAnimationEffect = (typeof AnimationEffect === 'function' || typeof window.AnimationEffect === 'function');
    const supportsWebAnimations = (typeof Element === 'function') && (typeof Element.prototype.animate === 'function') && supportsAnimationEffect;
    const ANIMATION_END_FALLBACK_PADDING_MS = 100;
    const getWebAnimations = () => {
        return webAnimations;
    };
    const destroy = () => {
        childAnimations.forEach(childAnimation => {
            childAnimation.destroy();
        });
        cleanUp();
        elements.length = 0;
        childAnimations.length = 0;
        _keyframes.length = 0;
        clearOnFinish();
        initialized = false;
        shouldCalculateNumAnimations = true;
        return ani;
    };
    /**
     * Cancels any Web Animations, removes
     * any animation properties from the
     * animation's elements, and removes the
     * animation's stylesheets from the DOM.
     */
    const cleanUp = () => {
        cleanUpElements();
        cleanUpStyleSheets();
    };
    const onFinish = (callback, opts) => {
        const callbacks = (opts && opts.oneTimeCallback) ? onFinishOneTimeCallbacks : onFinishCallbacks;
        callbacks.push({ c: callback, o: opts });
        return ani;
    };
    const clearOnFinish = () => {
        onFinishCallbacks.length = 0;
        onFinishOneTimeCallbacks.length = 0;
        return ani;
    };
    /**
     * Cancels any Web Animations and removes
     * any animation properties from the
     * the animation's elements.
     */
    const cleanUpElements = () => {
        if (supportsWebAnimations) {
            webAnimations.forEach(animation => {
                animation.cancel();
            });
            webAnimations.length = 0;
        }
        else {
            elements.forEach(element => {
                raf(() => {
                    removeStyleProperty(element, 'animation-name');
                    removeStyleProperty(element, 'animation-duration');
                    removeStyleProperty(element, 'animation-timing-function');
                    removeStyleProperty(element, 'animation-iteration-count');
                    removeStyleProperty(element, 'animation-delay');
                    removeStyleProperty(element, 'animation-play-state');
                    removeStyleProperty(element, 'animation-fill-mode');
                    removeStyleProperty(element, 'animation-direction');
                });
            });
        }
    };
    /**
     * Removes the animation's stylesheets
     * from the DOM.
     */
    const cleanUpStyleSheets = () => {
        stylesheets.forEach(stylesheet => {
            /**
             * When sharing stylesheets, it's possible
             * for another animation to have already
             * cleaned up a particular stylesheet
             */
            if (stylesheet && stylesheet.parentNode) {
                stylesheet.parentNode.removeChild(stylesheet);
            }
        });
        stylesheets.length = 0;
    };
    const beforeAddRead = (readFn) => {
        _beforeAddReadFunctions.push(readFn);
        return ani;
    };
    const beforeAddWrite = (writeFn) => {
        _beforeAddWriteFunctions.push(writeFn);
        return ani;
    };
    const afterAddRead = (readFn) => {
        _afterAddReadFunctions.push(readFn);
        return ani;
    };
    const afterAddWrite = (writeFn) => {
        _afterAddWriteFunctions.push(writeFn);
        return ani;
    };
    const beforeAddClass = (className) => {
        beforeAddClasses = addClassToArray(beforeAddClasses, className);
        return ani;
    };
    const beforeRemoveClass = (className) => {
        beforeRemoveClasses = addClassToArray(beforeRemoveClasses, className);
        return ani;
    };
    /**
     * Set CSS inline styles to the animation's
     * elements before the animation begins.
     */
    const beforeStyles = (styles = {}) => {
        beforeStylesValue = styles;
        return ani;
    };
    /**
     * Clear CSS inline styles from the animation's
     * elements before the animation begins.
     */
    const beforeClearStyles = (propertyNames = []) => {
        for (const property of propertyNames) {
            beforeStylesValue[property] = '';
        }
        return ani;
    };
    const afterAddClass = (className) => {
        afterAddClasses = addClassToArray(afterAddClasses, className);
        return ani;
    };
    const afterRemoveClass = (className) => {
        afterRemoveClasses = addClassToArray(afterRemoveClasses, className);
        return ani;
    };
    const afterStyles = (styles = {}) => {
        afterStylesValue = styles;
        return ani;
    };
    const afterClearStyles = (propertyNames = []) => {
        for (const property of propertyNames) {
            afterStylesValue[property] = '';
        }
        return ani;
    };
    const getFill = () => {
        if (_fill !== undefined) {
            return _fill;
        }
        if (parentAnimation) {
            return parentAnimation.getFill();
        }
        return 'both';
    };
    const getDirection = () => {
        if (forceDirectionValue !== undefined) {
            return forceDirectionValue;
        }
        if (_direction !== undefined) {
            return _direction;
        }
        if (parentAnimation) {
            return parentAnimation.getDirection();
        }
        return 'normal';
    };
    const getEasing = () => {
        if (shouldForceLinearEasing) {
            return 'linear';
        }
        if (_easing !== undefined) {
            return _easing;
        }
        if (parentAnimation) {
            return parentAnimation.getEasing();
        }
        return 'linear';
    };
    const getDuration = () => {
        if (shouldForceSyncPlayback) {
            return 0;
        }
        if (forceDurationValue !== undefined) {
            return forceDurationValue;
        }
        if (_duration !== undefined) {
            return _duration;
        }
        if (parentAnimation) {
            return parentAnimation.getDuration();
        }
        return 0;
    };
    const getIterations = () => {
        if (_iterations !== undefined) {
            return _iterations;
        }
        if (parentAnimation) {
            return parentAnimation.getIterations();
        }
        return 1;
    };
    const getDelay = () => {
        if (forceDelayValue !== undefined) {
            return forceDelayValue;
        }
        if (_delay !== undefined) {
            return _delay;
        }
        if (parentAnimation) {
            return parentAnimation.getDelay();
        }
        return 0;
    };
    const getKeyframes = () => {
        return _keyframes;
    };
    const direction = (animationDirection) => {
        _direction = animationDirection;
        update(true);
        return ani;
    };
    const fill = (animationFill) => {
        _fill = animationFill;
        update(true);
        return ani;
    };
    const delay = (animationDelay) => {
        _delay = animationDelay;
        update(true);
        return ani;
    };
    const easing = (animationEasing) => {
        _easing = animationEasing;
        update(true);
        return ani;
    };
    const duration = (animationDuration) => {
        /**
         * CSS Animation Durations of 0ms work fine on Chrome
         * but do not run on Safari, so force it to 1ms to
         * get it to run on both platforms.
         */
        if (!supportsWebAnimations && animationDuration === 0) {
            animationDuration = 1;
        }
        _duration = animationDuration;
        update(true);
        return ani;
    };
    const iterations = (animationIterations) => {
        _iterations = animationIterations;
        update(true);
        return ani;
    };
    const parent = (animation) => {
        parentAnimation = animation;
        return ani;
    };
    const addElement = (el) => {
        if (el != null) {
            if (el.nodeType === 1) {
                elements.push(el);
            }
            else if (el.length >= 0) {
                for (let i = 0; i < el.length; i++) {
                    elements.push(el[i]);
                }
            }
            else {
                console.error('Invalid addElement value');
            }
        }
        return ani;
    };
    const addAnimation = (animationToAdd) => {
        if (animationToAdd != null) {
            if (Array.isArray(animationToAdd)) {
                for (const animation of animationToAdd) {
                    animation.parent(ani);
                    childAnimations.push(animation);
                }
            }
            else {
                animationToAdd.parent(ani);
                childAnimations.push(animationToAdd);
            }
        }
        return ani;
    };
    const keyframes = (keyframeValues) => {
        _keyframes = keyframeValues;
        return ani;
    };
    /**
     * Runs all before read callbacks
     */
    const runBeforeRead = () => {
        _beforeAddReadFunctions.forEach(callback => {
            callback();
        });
    };
    /**
     * Runs all before write callbacks
     */
    const runBeforeWrite = () => {
        _beforeAddWriteFunctions.forEach(callback => {
            callback();
        });
    };
    /**
     * Updates styles and classes before animation runs
     */
    const runBeforeStyles = () => {
        const addClasses = beforeAddClasses;
        const removeClasses = beforeRemoveClasses;
        const styles = beforeStylesValue;
        elements.forEach(el => {
            const elementClassList = el.classList;
            addClasses.forEach(c => elementClassList.add(c));
            removeClasses.forEach(c => elementClassList.remove(c));
            for (const property in styles) {
                if (styles.hasOwnProperty(property)) {
                    setStyleProperty(el, property, styles[property]);
                }
            }
        });
    };
    /**
     * Run all "before" animation hooks.
     */
    const beforeAnimation = () => {
        runBeforeRead();
        runBeforeWrite();
        runBeforeStyles();
    };
    /**
     * Runs all after read callbacks
     */
    const runAfterRead = () => {
        _afterAddReadFunctions.forEach(callback => {
            callback();
        });
    };
    /**
     * Runs all after write callbacks
     */
    const runAfterWrite = () => {
        _afterAddWriteFunctions.forEach(callback => {
            callback();
        });
    };
    /**
     * Updates styles and classes before animation ends
     */
    const runAfterStyles = () => {
        const addClasses = afterAddClasses;
        const removeClasses = afterRemoveClasses;
        const styles = afterStylesValue;
        elements.forEach(el => {
            const elementClassList = el.classList;
            addClasses.forEach(c => elementClassList.add(c));
            removeClasses.forEach(c => elementClassList.remove(c));
            for (const property in styles) {
                if (styles.hasOwnProperty(property)) {
                    setStyleProperty(el, property, styles[property]);
                }
            }
        });
    };
    /**
     * Run all "after" animation hooks.
     */
    const afterAnimation = () => {
        clearCSSAnimationsTimeout();
        runAfterRead();
        runAfterWrite();
        runAfterStyles();
        const currentStep = willComplete ? 1 : 0;
        onFinishCallbacks.forEach(onFinishCallback => {
            return onFinishCallback.c(currentStep, ani);
        });
        onFinishOneTimeCallbacks.forEach(onFinishCallback => {
            return onFinishCallback.c(currentStep, ani);
        });
        onFinishOneTimeCallbacks.length = 0;
        shouldCalculateNumAnimations = true;
        finished = true;
    };
    const animationFinish = () => {
        if (numAnimationsRunning === 0) {
            return;
        }
        numAnimationsRunning--;
        if (numAnimationsRunning === 0) {
            afterAnimation();
            if (parentAnimation) {
                parentAnimation.animationFinish();
            }
        }
    };
    const initializeCSSAnimation = (toggleAnimationName = true) => {
        cleanUpStyleSheets();
        elements.forEach(element => {
            if (_keyframes.length > 0) {
                const keyframeRules = generateKeyframeRules(_keyframes);
                keyframeName = generateKeyframeName(keyframeRules);
                const stylesheet = createKeyframeStylesheet(keyframeName, keyframeRules, element);
                stylesheets.push(stylesheet);
                setStyleProperty(element, 'animation-duration', `${getDuration()}ms`);
                setStyleProperty(element, 'animation-timing-function', getEasing());
                setStyleProperty(element, 'animation-delay', `${getDelay()}ms`);
                setStyleProperty(element, 'animation-fill-mode', getFill());
                setStyleProperty(element, 'animation-direction', getDirection());
                const iterationsCount = (getIterations() === Infinity)
                    ? 'infinite'
                    : getIterations().toString();
                setStyleProperty(element, 'animation-iteration-count', iterationsCount);
                setStyleProperty(element, 'animation-play-state', 'paused');
                if (toggleAnimationName) {
                    setStyleProperty(element, 'animation-name', `${stylesheet.id}-alt`);
                }
                raf(() => {
                    setStyleProperty(element, 'animation-name', stylesheet.id || null);
                });
            }
        });
    };
    const initializeWebAnimation = () => {
        elements.forEach(element => {
            const animation = element.animate(_keyframes, {
                delay: getDelay(),
                duration: getDuration(),
                easing: getEasing(),
                iterations: getIterations(),
                fill: getFill(),
                direction: getDirection()
            });
            animation.pause();
            webAnimations.push(animation);
        });
        if (webAnimations.length > 0) {
            webAnimations[0].onfinish = () => {
                animationFinish();
            };
        }
    };
    const initializeAnimation = (toggleAnimationName = true) => {
        beforeAnimation();
        if (_keyframes.length > 0) {
            if (supportsWebAnimations) {
                initializeWebAnimation();
            }
            else {
                initializeCSSAnimation(toggleAnimationName);
            }
        }
        initialized = true;
    };
    const setAnimationStep = (step) => {
        step = Math.min(Math.max(step, 0), 0.999);
        if (supportsWebAnimations) {
            webAnimations.forEach(animation => {
                animation.currentTime = animation.effect.getComputedTiming().delay + (getDuration() * step);
                animation.pause();
            });
        }
        else {
            const animationDelay = getDelay() || 0;
            const animationDuration = `-${animationDelay + (getDuration() * step)}ms`;
            elements.forEach(element => {
                if (_keyframes.length > 0) {
                    setStyleProperty(element, 'animation-delay', animationDuration);
                    setStyleProperty(element, 'animation-play-state', 'paused');
                }
            });
        }
    };
    const updateWebAnimation = () => {
        webAnimations.forEach(animation => {
            animation.effect.updateTiming({
                delay: getDelay(),
                duration: getDuration(),
                easing: getEasing(),
                iterations: getIterations(),
                fill: getFill(),
                direction: getDirection()
            });
        });
    };
    const updateCSSAnimation = (toggleAnimationName = true) => {
        elements.forEach(element => {
            raf(() => {
                setStyleProperty(element, 'animation-name', keyframeName || null);
                setStyleProperty(element, 'animation-duration', `${getDuration()}ms`);
                setStyleProperty(element, 'animation-timing-function', getEasing());
                setStyleProperty(element, 'animation-delay', `${getDelay()}ms`);
                setStyleProperty(element, 'animation-fill-mode', getFill() || null);
                setStyleProperty(element, 'animation-direction', getDirection() || null);
                const iterationsCount = (getIterations() === Infinity)
                    ? 'infinite'
                    : getIterations().toString();
                setStyleProperty(element, 'animation-iteration-count', iterationsCount);
                if (toggleAnimationName) {
                    setStyleProperty(element, 'animation-name', `${keyframeName}-alt`);
                }
                raf(() => {
                    setStyleProperty(element, 'animation-name', keyframeName || null);
                });
            });
        });
    };
    const update = (deep = false, toggleAnimationName = true) => {
        if (deep) {
            childAnimations.forEach(animation => {
                animation.update(deep);
            });
        }
        if (supportsWebAnimations) {
            updateWebAnimation();
        }
        else {
            updateCSSAnimation(toggleAnimationName);
        }
        return ani;
    };
    const progressStart = (forceLinearEasing = false) => {
        childAnimations.forEach(animation => {
            animation.progressStart(forceLinearEasing);
        });
        pauseAnimation();
        shouldForceLinearEasing = forceLinearEasing;
        if (!initialized) {
            initializeAnimation();
        }
        else {
            update();
            setAnimationStep(0);
        }
        return ani;
    };
    const progressStep = (step) => {
        childAnimations.forEach(animation => {
            animation.progressStep(step);
        });
        setAnimationStep(step);
        return ani;
    };
    const progressEnd = (playTo, step, dur) => {
        shouldForceLinearEasing = false;
        childAnimations.forEach(animation => {
            animation.progressEnd(playTo, step, dur);
        });
        if (dur !== undefined) {
            forceDurationValue = dur;
        }
        finished = false;
        willComplete = playTo === 1;
        if (!willComplete) {
            forceDirectionValue = (getDirection() === 'reverse') ? 'normal' : 'reverse';
            if (supportsWebAnimations) {
                update();
                setAnimationStep(1 - step);
            }
            else {
                forceDelayValue = ((1 - step) * getDuration()) * -1;
                update(false, false);
            }
        }
        else {
            if (!supportsWebAnimations) {
                forceDelayValue = (step * getDuration()) * -1;
                update(false, false);
            }
        }
        onFinish(() => {
            willComplete = true;
            forceDurationValue = undefined;
            forceDirectionValue = undefined;
            forceDelayValue = undefined;
        }, {
            oneTimeCallback: true
        });
        if (!parentAnimation) {
            play();
        }
        return ani;
    };
    const pauseAnimation = () => {
        if (initialized) {
            if (supportsWebAnimations) {
                webAnimations.forEach(animation => {
                    animation.pause();
                });
            }
            else {
                elements.forEach(element => {
                    setStyleProperty(element, 'animation-play-state', 'paused');
                });
            }
        }
    };
    const pause = () => {
        childAnimations.forEach(animation => {
            animation.pause();
        });
        pauseAnimation();
        return ani;
    };
    const playAsync = () => {
        return play();
    };
    const playSync = () => {
        play({ sync: true });
        return ani;
    };
    const onAnimationEndFallback = () => {
        cssAnimationsTimerFallback = undefined;
        animationFinish();
    };
    const clearCSSAnimationsTimeout = () => {
        if (cssAnimationsTimerFallback) {
            clearTimeout(cssAnimationsTimerFallback);
        }
    };
    const playCSSAnimations = () => {
        clearCSSAnimationsTimeout();
        elements.forEach(element => {
            if (_keyframes.length > 0) {
                raf(() => {
                    setStyleProperty(element, 'animation-play-state', 'running');
                });
            }
        });
        if (_keyframes.length === 0 || elements.length === 0) {
            animationFinish();
        }
        else {
            /**
             * This is a catchall in the event that a CSS Animation did not finish.
             * The Web Animations API has mechanisms in place for preventing this.
             * CSS Animations will not fire an `animationend` event
             * for elements with `display: none`. The Web Animations API
             * accounts for this, but using raw CSS Animations requires
             * this workaround.
             */
            const animationDelay = getDelay() || 0;
            const animationDuration = getDuration() || 0;
            const animationIterations = getIterations() || 1;
            cssAnimationsTimerFallback = setTimeout(onAnimationEndFallback, animationDelay + (animationDuration * animationIterations) + ANIMATION_END_FALLBACK_PADDING_MS);
            animationEnd(elements[0], () => {
                clearCSSAnimationsTimeout();
                /**
                 * Ensure that clean up
                 * is always done a frame
                 * before the onFinish handlers
                 * are fired. Otherwise, there
                 * may be flickering if a new
                 * animation is started on the same
                 * element too quickly
                 *
                 * TODO: Is there a cleaner way to do this?
                 */
                raf(() => {
                    clearCSSAnimationPlayState();
                    raf(animationFinish);
                });
            });
        }
    };
    const clearCSSAnimationPlayState = () => {
        elements.forEach(element => {
            removeStyleProperty(element, 'animation-duration');
            removeStyleProperty(element, 'animation-delay');
            removeStyleProperty(element, 'animation-play-state');
        });
    };
    const playWebAnimations = () => {
        webAnimations.forEach(animation => {
            animation.play();
        });
        if (_keyframes.length === 0 || elements.length === 0) {
            animationFinish();
        }
    };
    const resetAnimation = () => {
        if (supportsWebAnimations) {
            setAnimationStep(0);
        }
        else {
            updateCSSAnimation();
        }
    };
    const play = (opts) => {
        return new Promise(resolve => {
            if (opts && opts.sync) {
                shouldForceSyncPlayback = true;
                onFinish(() => shouldForceSyncPlayback = false, { oneTimeCallback: true });
            }
            if (!initialized) {
                initializeAnimation();
            }
            if (finished) {
                resetAnimation();
                finished = false;
            }
            if (shouldCalculateNumAnimations) {
                numAnimationsRunning = childAnimations.length + 1;
                shouldCalculateNumAnimations = false;
            }
            onFinish(() => resolve(), { oneTimeCallback: true });
            childAnimations.forEach(animation => {
                animation.play();
            });
            if (supportsWebAnimations) {
                playWebAnimations();
            }
            else {
                playCSSAnimations();
            }
        });
    };
    const stop = () => {
        childAnimations.forEach(animation => {
            animation.stop();
        });
        if (initialized) {
            cleanUpElements();
            initialized = false;
        }
    };
    const from = (property, value) => {
        const firstFrame = _keyframes[0];
        if (firstFrame !== undefined && firstFrame.offset === 0) {
            firstFrame[property] = value;
        }
        else {
            _keyframes = [
                { offset: 0, [property]: value },
                ..._keyframes
            ];
        }
        return ani;
    };
    const to = (property, value) => {
        const lastFrame = _keyframes[_keyframes.length - 1];
        if (lastFrame !== undefined && lastFrame.offset === 1) {
            lastFrame[property] = value;
        }
        else {
            _keyframes = [
                ..._keyframes,
                { offset: 1, [property]: value }
            ];
        }
        return ani;
    };
    const fromTo = (property, fromValue, toValue) => {
        return from(property, fromValue).to(property, toValue);
    };
    return ani = {
        parentAnimation,
        elements,
        childAnimations,
        animationFinish,
        from,
        to,
        fromTo,
        parent,
        play,
        playAsync,
        playSync,
        pause,
        stop,
        destroy,
        keyframes,
        addAnimation,
        addElement,
        update,
        fill,
        direction,
        iterations,
        duration,
        easing,
        delay,
        getWebAnimations,
        getKeyframes,
        getFill,
        getDirection,
        getDelay,
        getIterations,
        getEasing,
        getDuration,
        afterAddRead,
        afterAddWrite,
        afterClearStyles,
        afterStyles,
        afterRemoveClass,
        afterAddClass,
        beforeAddRead,
        beforeAddWrite,
        beforeClearStyles,
        beforeStyles,
        beforeRemoveClass,
        beforeAddClass,
        onFinish,
        progressStart,
        progressStep,
        progressEnd
    };
};

const deepReady = async (el) => {
    const element = el;
    if (element) {
        if (element.componentOnReady != null) {
            const stencilEl = await element.componentOnReady();
            if (stencilEl != null) {
                return;
            }
        }
        await Promise.all(Array.from(element.children).map(deepReady));
    }
};

/**
 * Md Modal Enter Animation
 */
const enterAnimation = (baseEl) => {
    const baseAnimation = createAnimation();
    const backdropAnimation = createAnimation();
    const wrapperAnimation = createAnimation();
    backdropAnimation
        .addElement(baseEl.querySelector('lu-backdrop'))
        .fromTo('opacity', 0.01, 0.32);
    wrapperAnimation
        .addElement(baseEl.querySelector('.modal-wrapper'))
        .keyframes([
        { offset: 0, opacity: 0.01, transform: 'translateY(40px)' },
        { offset: 1, opacity: 1, transform: 'translateY(0px)' }
    ]);
    return baseAnimation
        .addElement(baseEl)
        .easing('cubic-bezier(0.36,0.66,0.04,1)')
        .duration(280)
        .beforeAddClass('show-modal')
        .addAnimation([backdropAnimation, wrapperAnimation]);
};

/**
 * Md Modal Leave Animation
 */
const leaveAnimation = (baseEl) => {
    const baseAnimation = createAnimation();
    const backdropAnimation = createAnimation();
    const wrapperAnimation = createAnimation();
    const wrapperEl = baseEl.querySelector('.modal-wrapper');
    backdropAnimation
        .addElement(baseEl.querySelector('lu-backdrop'))
        .fromTo('opacity', 0.32, 0.0);
    wrapperAnimation
        .addElement(wrapperEl)
        .keyframes([
        { offset: 0, opacity: 0.99, transform: 'translateY(0px)' },
        { offset: 1, opacity: 0, transform: 'translateY(40px)' }
    ]);
    return baseAnimation
        .addElement(baseEl)
        .easing('cubic-bezier(0.47,0,0.745,0.715)')
        .duration(200)
        .addAnimation([backdropAnimation, wrapperAnimation]);
};

const modalCss = ".sc-lu-modal-h{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--lu-background-color, #fff);--box-shadow:none;left:0;right:0;top:0;bottom:0;display:flex;position:absolute;align-items:center;justify-content:center;contain:strict}.overlay-hidden.sc-lu-modal-h{display:none}.modal-wrapper.sc-lu-modal{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}@media only screen and (min-width: 768px) and (min-height: 600px){.sc-lu-modal-h{--width:600px;--height:500px;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px;--border-radius:2px;--box-shadow:0 28px 48px var(--lu-background-color, #fff)}.modal-wrapper.sc-lu-modal{transform:translate3d(0,  40px,  0);opacity:0.01}}@media only screen and (min-width: 768px) and (min-height: 768px){.sc-lu-modal-h{--width:600px;--height:600px}}";

const Modal = class {
  constructor(hostRef) {
    registerInstance(this, hostRef);
    this.didPresent = createEvent(this, "luModalDidPresent", 7);
    this.willPresent = createEvent(this, "luModalWillPresent", 7);
    this.willDismiss = createEvent(this, "luModalWillDismiss", 7);
    this.didDismiss = createEvent(this, "luModalDidDismiss", 7);
    this.currentFocusableElements = [];
    this.presented = false;
    this.FOCUSABLE_ELEMENTS = "button:not([disabled]), [href], input, select, textarea, [tabindex]:not([tabindex='-1'])";
    this.LU_ELEMENTS = "lu-button:not([disabled]), lu-checkbox, lu-combo-box, lu-dropdown-listbox, lu-input, lu-radio, lu-select, lu-text-area";
    /**
     * If `true`, the keyboard will be automatically dismissed when the overlay is presented.
     */
    this.keyboardClose = true;
    /**
     * If `true`, the modal will be dismissed when the backdrop is clicked.
     */
    this.backdropDismiss = true;
    /**
     * If `true`, a backdrop will be displayed behind the modal.
     */
    this.showBackdrop = true;
    /**
     * If `true`, the modal will animate.
     */
    this.animated = true;
    this.onBackdropTap = () => {
      this.dismiss(undefined, BACKDROP);
    };
    this.onDismiss = (ev) => {
      ev.stopPropagation();
      ev.preventDefault();
      this.dismiss();
    };
    this.onLifecycle = (modalEvent) => {
      const el = this.usersElement;
      const name = LIFECYCLE_MAP[modalEvent.type];
      if (el && name) {
        const ev = new CustomEvent(name, {
          bubbles: false,
          cancelable: false,
          detail: modalEvent.detail,
        });
        el.dispatchEvent(ev);
      }
    };
    /**
     * Collect an array of all focusable elements within the modal.
     */
    this.getFocusableElements = () => {
      this.currentFocusableElements = [];
      const allElements = this.el.children.length > 0
        ? Array.prototype.slice.call(this.el.getElementsByTagName("*"))
        : [];
      allElements.forEach((element) => {
        if (element.tabIndex < 0 && element.shadowRoot) {
          const shadowElement = this.searchShadowDomForEl(element);
          shadowElement && this.currentFocusableElements.push(shadowElement);
        }
        else if (element.matches(this.FOCUSABLE_ELEMENTS)) {
          this.currentFocusableElements.push(element);
        }
      });
    };
    /**
     * Drill down through shadow doms of a single element to find a focusable element.
     */
    this.searchShadowDomForEl = (baseElement) => {
      let shadowRoot = baseElement.shadowRoot;
      let shadowElement = null;
      while (shadowRoot && !shadowElement) {
        shadowElement = shadowRoot.querySelector(this.FOCUSABLE_ELEMENTS);
        if (!shadowElement) {
          const luElement = shadowRoot.querySelector(this.LU_ELEMENTS);
          shadowRoot = luElement && luElement.shadowRoot && luElement.shadowRoot;
        }
      }
      return shadowElement;
    };
    prepareOverlay(this.el);
  }
  handleFocusChangeForSR() {
    const shadowRoot = document.activeElement && document.activeElement.shadowRoot;
    let focusedElement = null;
    focusedElement =
      shadowRoot &&
        this.searchShadowDomForEl(document.activeElement);
    if (!focusedElement) {
      focusedElement = document.activeElement;
    }
    return (focusedElement.id &&
      this.el.setAttribute("aria-activedescendant", focusedElement.id));
  }
  handleKeyDown(event) {
    const isTabPressed = event.key === "Tab" || event.keyCode === 9;
    if (!isTabPressed) {
      return;
    }
    else {
      this.getFocusableElements();
      if (this.currentFocusableElements.length > 0) {
        const firstElement = this.currentFocusableElements[0];
        const lastElement = this.currentFocusableElements[this.currentFocusableElements.length - 1];
        const shadowRoot = document.activeElement && document.activeElement.shadowRoot;
        let focusedElement = null;
        focusedElement =
          shadowRoot &&
            this.searchShadowDomForEl(document.activeElement);
        if (!focusedElement) {
          focusedElement = document.activeElement;
        }
        if (event.shiftKey) {
          if (focusedElement === firstElement) {
            event.preventDefault();
            return lastElement.focus();
          }
        }
        else {
          if (focusedElement === lastElement) {
            event.preventDefault();
            return firstElement.focus();
          }
        }
      }
      return;
    }
  }
  /**
   * Present the modal overlay after it has been created.
   */
  async present() {
    if (this.presented) {
      return;
    }
    const container = this.el.querySelector(`.modal-wrapper`);
    if (!container) {
      throw new Error("container is undefined");
    }
    const componentProps = Object.assign(Object.assign({}, this.componentProps), { modal: this.el });
    this.usersElement = await attachComponent(this.delegate, container, this.component, [], componentProps);
    await deepReady(this.usersElement);
    present(this, enterAnimation);
    window.requestAnimationFrame(() => {
      if (this.firstFocusableElement) {
        this.firstFocusableElement.focus();
      }
      else {
        this.getFocusableElements();
        if (this.currentFocusableElements.length > 0) {
          if (this.currentFocusableElements[0].classList.contains("close-button") &&
            this.currentFocusableElements.length > 1) {
            this.currentFocusableElements[1].focus();
          }
          else {
            this.currentFocusableElements[0].focus();
          }
        }
      }
    });
    this.didPresent.emit();
    return;
  }
  /**
   * Dismiss the modal overlay after it has been presented.
   *
   * @param data Any data to emit in the dismiss events.
   * @param role The role of the element that is dismissing the modal. For example, 'cancel' or 'backdrop'.
   */
  async dismiss(data, role) {
    const dismissed = await dismiss(this, data, role, leaveAnimation);
    if (dismissed) {
      await detachComponent(this.delegate, this.usersElement);
    }
    if (this.activator) {
      if (this.activator.tabIndex < 0 && this.activator.shadowRoot) {
        const shadowElement = this.searchShadowDomForEl(this.activator);
        shadowElement && shadowElement.focus();
      }
      else if (this.activator.matches(this.FOCUSABLE_ELEMENTS)) {
        this.activator.focus();
      }
    }
    return dismissed;
  }
  /**
   * Returns a promise that resolves when the modal did dismiss.
   */
  onDidDismiss() {
    return eventMethod(this.el, "luModalDidDismiss");
  }
  /**
   * Returns a promise that resolves when the modal will dismiss.
   */
  onWillDismiss() {
    return eventMethod(this.el, "luModalWillDismiss");
  }
  render() {
    return (h(Host, { "aria-modal": "true", "aria-role": "group", class: Object.assign({}, getClassMap(this.cssClass)), onluBackdropTap: this.onBackdropTap, onluDismiss: this.onDismiss, onluModalDidDismiss: this.onLifecycle, onluModalDidPresent: this.onLifecycle, onluModalWillDismiss: this.onLifecycle, onluModalWillPresent: this.onLifecycle, "no-router": true, style: {
        zIndex: `${20000 + this.overlayIndex}`,
      }, tabindex: "0" }, h("lu-backdrop", { visible: this.showBackdrop, tappable: this.backdropDismiss }), h("div", Object.assign({}, (this.modalLabel && { "aria-labelledby": this.modalLabel }), { class: {
        [`modal-wrapper`]: true,
      }, role: "dialog" }))));
  }
  get el() { return getElement(this); }
};
const LIFECYCLE_MAP = {
  luModalDidPresent: "ionViewDidEnter",
  luModalWillPresent: "ionViewWillEnter",
  luModalWillDismiss: "ionViewWillLeave",
  luModalDidDismiss: "ionViewDidLeave",
};
Modal.style = modalCss;

export { Modal as lu_modal };

//# sourceMappingURL=lu-modal.entry.js.map