/*!
 * (C) Ionic http://ionicframework.com - MIT License
 */
import { w as win } from './ionic-global-2R0iPB51.js';
import { r as raf } from './helpers-Bsml3FcE.js';

/**
 * A utility to calculate the size of an outline notch
 * width relative to the content passed. This is used in
 * components such as `ion-select` with `fill="outline"`
 * where we need to pass slotted HTML content. This is not
 * needed when rendering plaintext content because we can
 * render the plaintext again hidden with `opacity: 0` inside
 * of the notch. As a result we can rely on the intrinsic size
 * of the element to correctly compute the notch width. We
 * cannot do this with slotted content because we cannot project
 * it into 2 places at once.
 *
 * @internal
 * @param el: The host element
 * @param getNotchSpacerEl: A function that returns a reference to the notch spacer element inside of the component template.
 * @param getLabelSlot: A function that returns a reference to the slotted content.
 */
const createNotchController = (el, getNotchSpacerEl, getLabelSlot) => {
    let notchVisibilityIO;
    const needsExplicitNotchWidth = () => {
        const notchSpacerEl = getNotchSpacerEl();
        if (
        /**
         * If the notch is not being used
         * then we do not need to set the notch width.
         */
        notchSpacerEl === undefined ||
            /**
             * If either the label property is being
             * used or the label slot is not defined,
             * then we do not need to estimate the notch width.
             */
            el.label !== undefined ||
            getLabelSlot() === null) {
            return false;
        }
        return true;
    };
    const calculateNotchWidth = () => {
        if (needsExplicitNotchWidth()) {
            /**
             * Run this the frame after
             * the browser has re-painted the host element.
             * Otherwise, the label element may have a width
             * of 0 and the IntersectionObserver will be used.
             */
            raf(() => {
                setNotchWidth();
            });
        }
    };
    /**
     * When using a label prop we can render
     * the label value inside of the notch and
     * let the browser calculate the size of the notch.
     * However, we cannot render the label slot in multiple
     * places so we need to manually calculate the notch dimension
     * based on the size of the slotted content.
     *
     * This function should only be used to set the notch width
     * on slotted label content. The notch width for label prop
     * content is automatically calculated based on the
     * intrinsic size of the label text.
     */
    const setNotchWidth = () => {
        const notchSpacerEl = getNotchSpacerEl();
        if (notchSpacerEl === undefined) {
            return;
        }
        if (!needsExplicitNotchWidth()) {
            notchSpacerEl.style.removeProperty('width');
            return;
        }
        const width = getLabelSlot().scrollWidth;
        if (
        /**
         * If the computed width of the label is 0
         * and notchSpacerEl's offsetParent is null
         * then that means the element is hidden.
         * As a result, we need to wait for the element
         * to become visible before setting the notch width.
         *
         * We do not check el.offsetParent because
         * that can be null if the host element has
         * position: fixed applied to it.
         * notchSpacerEl does not have position: fixed.
         */
        width === 0 &&
            notchSpacerEl.offsetParent === null &&
            win !== undefined &&
            'IntersectionObserver' in win) {
            /**
             * If there is an IO already attached
             * then that will update the notch
             * once the element becomes visible.
             * As a result, there is no need to create
             * another one.
             */
            if (notchVisibilityIO !== undefined) {
                return;
            }
            const io = (notchVisibilityIO = new IntersectionObserver((ev) => {
                /**
                 * If the element is visible then we
                 * can try setting the notch width again.
                 */
                if (ev[0].intersectionRatio === 1) {
                    setNotchWidth();
                    io.disconnect();
                    notchVisibilityIO = undefined;
                }
            }, 
            /**
             * Set the root to be the host element
             * This causes the IO callback
             * to be fired in WebKit as soon as the element
             * is visible. If we used the default root value
             * then WebKit would only fire the IO callback
             * after any animations (such as a modal transition)
             * finished, and there would potentially be a flicker.
             */
            { threshold: 0.01, root: el }));
            io.observe(notchSpacerEl);
            return;
        }
        /**
         * If the element is visible then we can set the notch width.
         * The notch is only visible when the label is scaled,
         * which is why we multiply the width by 0.75 as this is
         * the same amount the label element is scaled by in the host CSS.
         * (See $form-control-label-stacked-scale in ionic.globals.scss).
         */
        notchSpacerEl.style.setProperty('width', `${width * 0.75}px`);
    };
    const destroy = () => {
        if (notchVisibilityIO) {
            notchVisibilityIO.disconnect();
            notchVisibilityIO = undefined;
        }
    };
    return {
        calculateNotchWidth,
        destroy,
    };
};

export { createNotchController as c };
