/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { getElement, Build, forceUpdate } from '@stencil/core/internal/client';

/**
 * Given an element (which can either be within a shadowRoot or not) find it's innerText
 * @param element the element to get the text content from
 * @returns a concatenated string of text
 */
function getTextContent(element) {
    const root = element.getRootNode();
    if (root.host)
        return root.host.innerText;
    return element.innerText;
}
/**
 * Decides if slots are being used and re-renders when slot content changes.
 *
 * @param instance The component instance
 * @param slotNames The names of the slots to watch for changes
 *
 * @example
 * // in your component
 * private slotController = new HasSlotController(this, [default], 'header', 'footer');
 * ...
 * // in your render method
 * {slotController.has('header') && <div class="header"><slot name="header /></div>}
 *
 */
class HasSlotController {
    host;
    slotNames = [];
    constructor(instance, ...slotNames) {
        this.slotNames = slotNames;
        const ogComponentWillLoad = instance.componentWillLoad;
        instance.componentWillLoad = () => {
            this.host = getElement(instance);
            if (ogComponentWillLoad) {
                ogComponentWillLoad.call(instance);
            }
        };
        const ogConnectedCallback = instance.connectedCallback;
        instance.connectedCallback = () => {
            this.host = getElement(instance);
            this.hostConnected();
            if (ogConnectedCallback) {
                ogConnectedCallback.call(instance);
            }
        };
        const ogDisconnectedCallback = instance.disconnectedCallback;
        instance.disconnectedCallback = () => {
            this.hostDisconnected();
            this.host = undefined;
            if (ogDisconnectedCallback) {
                ogDisconnectedCallback.call(instance);
            }
        };
    }
    hasDefaultSlot() {
        if (!this.host)
            return false;
        let childNodes;
        if (this.host.shadowRoot) {
            // * Regular shadow DOM component *
            childNodes = [...this.host.childNodes];
        }
        else if (!this.host.classList.contains('hydrated') &&
            this.host.__childNodes) {
            // * Non-shadow, polyfilled component *
            // Component has not done initial render. Return component internals
            childNodes = [...(this.host?.__childNodes ?? [])];
        }
        else {
            // Component is ready, return 'light DOM' children
            childNodes = [...this.host.childNodes];
        }
        return childNodes.some((node) => {
            if (node.nodeType === Node.TEXT_NODE && !!node.textContent.trim()) {
                return true;
            }
            if (node.nodeType === Node.ELEMENT_NODE) {
                const el = node;
                // If it doesn't have a slot attribute, it's part of the default slot
                if (!el.hasAttribute('slot')) {
                    return true;
                }
            }
            return false;
        });
    }
    hasNamedSlot(name) {
        if (!this.host)
            return false;
        return !!this.host.querySelector(`[slot="${name}"]`);
    }
    has(slotName) {
        return slotName === '[default]'
            ? this.hasDefaultSlot()
            : this.hasNamedSlot(slotName);
    }
    hostConnected() {
        if (Build.isServer)
            return;
        const listenTarget = this.host.shadowRoot ?? this.host;
        listenTarget.addEventListener('slotchange', this.handleSlotChange);
    }
    hostDisconnected() {
        if (Build.isServer || !this.host)
            return;
        const listenTarget = this.host.shadowRoot ?? this.host;
        listenTarget.removeEventListener('slotchange', this.handleSlotChange);
    }
    handleSlotChange = (event) => {
        const slot = event.target;
        if ((this.slotNames.includes('[default]') && !slot.name) ||
            (slot.name && this.slotNames.includes(slot.name))) {
            forceUpdate(this.host);
        }
    };
}

export { HasSlotController as H, getTextContent as g };
