/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { proxyCustomElement, HTMLElement, Build, Host } from '@stencil/core/internal/client';
import { d as debounce } from './throttle.js';
import { t as transformTag, h } from './renderer.js';
import { d as defineCustomElement$5 } from './icon.js';
import { d as defineCustomElement$4 } from './icon-button.js';
import { d as defineCustomElement$3 } from './masked-overflow.js';
import { d as defineCustomElement$2 } from './tooltip.js';

const tableCss = ".sc-nano-table-h,*.sc-nano-table,*.sc-nano-table::before,*.sc-nano-table::after{box-sizing:border-box}[hidden].sc-nano-table{display:none !important}@media (prefers-reduced-motion: reduce){.sc-nano-table-h,*.sc-nano-table,*.sc-nano-table::before,*.sc-nano-table::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important;scroll-behavior:auto !important}}.sc-nano-table-h,*.sc-nano-table,*.sc-nano-table::before,*.sc-nano-table::after{box-sizing:border-box}[hidden].sc-nano-table{display:none !important}@media (prefers-reduced-motion: reduce){.sc-nano-table-h,*.sc-nano-table,*.sc-nano-table::before,*.sc-nano-table::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important;scroll-behavior:auto !important}}";

const NanoTable$1 = /*@__PURE__*/ proxyCustomElement(class NanoTable extends HTMLElement {
    get host() { return this; }
    propsReady = false;
    /** If true, the table will be rendered in a compact style. */
    compact = 'auto';
    handleCompactChange() {
        this.setupProperties();
    }
    /** If true, will render any nested table in a scrollable container (using `overflow: auto`) */
    scrollable = true;
    /** Visually hide the table's caption */
    hideCaption = false;
    handleHideCaptionChange() {
        const caption = this.caption;
        if (!caption)
            return;
        caption.classList.toggle('visually-hidden', this.hideCaption);
    }
    /** Disable the clickable rows functionality. */
    disableClickableRows = false;
    resizeObserver;
    mutationObserver;
    intersectionObserver;
    settingUp = false;
    get table() {
        return this.host.querySelector('table');
    }
    get caption() {
        const caption = this.host.querySelector('caption');
        if (!caption) {
            console.error('nano-table: No caption found. For better a11y, please add a <caption> element to the table.');
            return null;
        }
        return caption;
    }
    setupProperties = () => {
        const table = this.table;
        if (!table || this.settingUp)
            return;
        this.settingUp = true;
        // Clickable rows
        if (!this.disableClickableRows) {
            const rows = Array.from(this.host.querySelectorAll('tr'));
            for (const row of rows) {
                if (this.getRowClickElements(row).length === 1) {
                    row.setAttribute('clickable', 'true');
                    row.addEventListener('click', this.rowClickHandler);
                }
                else {
                    row.removeAttribute('clickable');
                    row.removeEventListener('click', this.rowClickHandler);
                }
            }
        }
        // Sticky columns and rows
        const tableSections = table.querySelectorAll('thead, tbody, tfoot');
        let offset = 0;
        if (table.querySelector('[sticky=start], [sticky=end]')) {
            for (const section of tableSections) {
                const sectionHeight = section.offsetHeight;
                // this is used to make the column shadows when the columns stick;
                // it allows to have one long shadow instead of one per row
                section.style.setProperty('--section-height', `${sectionHeight}px`);
            }
            const headCols = Array.from(this.host.querySelectorAll('thead th, thead td'));
            for (const col of headCols) {
                if (col.matches('[sticky=start]')) {
                    this.makeCellsSticky(col, 'start', offset);
                    if (offset > 0) {
                        col.style.setProperty('--sticky-start', `${offset}px`);
                    }
                    offset += col.offsetWidth - 1;
                }
            }
            offset = 0;
            for (const col of [...headCols].reverse()) {
                if (col.matches('[sticky=end]')) {
                    this.makeCellsSticky(col, 'end', offset);
                    if (offset > 0) {
                        col.style.setProperty('--sticky-end', `${offset}px`);
                    }
                    offset += col.offsetWidth - 1;
                }
            }
        }
        if (table.querySelector('[sticky=top]')) {
            // sticky rows are slightly different; we only want one per section to be visible (the rest will overlap)
            // e.g. 1 tr in thead, 1 tr in tbody, 1 tr in tfoot
            offset = 0;
            for (const section of tableSections) {
                const stickyRows = Array.from(section.querySelectorAll('tr[sticky]'));
                for (const [idx, row] of stickyRows.entries()) {
                    if (row.matches('[sticky=top]') && offset > 0) {
                        row.style.setProperty('--sticky-top', `${offset}px`);
                    }
                    if (idx === stickyRows.length - 1) {
                        offset += row.offsetHeight - 1;
                    }
                }
            }
        }
        this.settingUp = false;
        this.propsReady = true;
    };
    getRowClickElements(row) {
        const anchors = row.querySelectorAll('a');
        const buttons = row.querySelectorAll('button');
        const cbs = Array.from(row.querySelectorAll('input[type="checkbox"]')).filter((cb) => {
            // filter out checkboxes that are not nano-checkboxes
            return !cb.closest('nano-checkbox');
        });
        const radios = Array.from(row.querySelectorAll('input[type="radio"]')).filter((radio) => {
            // filter out radios that are not nano-checkboxes
            return !radio.closest('nano-checkbox');
        });
        const nanoCbs = row.querySelectorAll('nano-checkbox');
        return [...anchors, ...buttons, ...nanoCbs, ...cbs, ...radios];
    }
    rowClickHandler = (e) => {
        const target = e.target;
        const row = target.closest('tr');
        if (!row)
            return;
        const clickEle = this.getRowClickElements(row);
        if (clickEle.length === 1 &&
            target.closest(clickEle[0].tagName) !== clickEle[0]) {
            clickEle[0].click();
        }
    };
    makeCellsSticky(thElement, sticky, offset = 0) {
        const table = thElement.closest('table');
        const theadRow = thElement.closest('tr');
        const ths = Array.from(theadRow.cells);
        // Step 1: Get the visual column index of the target th (respecting colspan)
        let targetColIndex = 0;
        for (const th of ths) {
            if (th === thElement)
                break;
            targetColIndex += th.colSpan || 1;
        }
        // Step 2: Iterate through tbody rows and find the corresponding cell
        for (const tbody of table.tBodies) {
            for (const row of tbody.rows) {
                let colIndex = 0;
                for (const cell of row.cells) {
                    const span = cell.colSpan || 1;
                    if (colIndex <= targetColIndex && targetColIndex < colIndex + span) {
                        cell.setAttribute('sticky', sticky);
                        if (offset > 0) {
                            cell.style.setProperty('--sticky-' + sticky, `${offset}px`);
                        }
                        break;
                    }
                    colIndex += span;
                }
            }
        }
    }
    addObservers() {
        if (!Build.isBrowser)
            return;
        this.resizeObserver = new ResizeObserver(() => {
            this.setupProperties();
        });
        this.resizeObserver.observe(this.host);
        this.mutationObserver = new MutationObserver(() => {
            this.setupProperties();
        });
        const table = this.table;
        this.mutationObserver.observe(table, {
            childList: true,
            subtree: true,
        });
        // dimensions will not be accurate until table is in the viewport
        this.intersectionObserver = new IntersectionObserver(() => {
            this.setupProperties();
            this.intersectionObserver.disconnect();
        }, { threshold: 1 });
        this.intersectionObserver.observe(table);
    }
    cleanUpObservers() {
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
            this.resizeObserver = null;
        }
        if (this.mutationObserver) {
            this.mutationObserver.disconnect();
            this.mutationObserver = null;
        }
        if (this.intersectionObserver) {
            this.intersectionObserver.disconnect();
            this.intersectionObserver = null;
        }
    }
    constructor() {
        super();
        this.__registerHost();
        this.setupProperties = debounce(this.setupProperties, 100);
    }
    connectedCallback() {
        this.addObservers();
        this.handleHideCaptionChange();
    }
    componentDidRender() {
        if (Build.isBrowser && this.scrollable !== false && this.table) {
            // a hack. Revise in-future.
            // the table is always rendered in the light DOM - so it should always be visible, but
            // if we conditionally render the slot within the masked overflow there's quite a noticeable
            //  CLS as it moves before the nano-masked-overflow is bootstrapped.
            customElements
                .whenDefined(transformTag('nano-masked-overflow'))
                .then(() => {
                this.host
                    .querySelector('.nano-table__overflow')
                    ?.appendChild(this.table);
            });
        }
    }
    disconnectedCallback() {
        this.cleanUpObservers();
    }
    render() {
        return (h(Host, { key: 'fa8f3bb2dfffee9a213d372282b5902ed56c5a2b', class: {
                'nano-table': true,
                'nano-table--props-ready': this.propsReady,
            } }, this.scrollable && (h("nano-masked-overflow", { key: 'da0d773c42fb2c1b9f694fa4b2c307c2c070d67d', hideScrollbars: false, scrollControls: false, label: this.caption?.textContent || undefined, class: "nano-table__overflow-container" }, h("div", { key: '83f36ec8ff79fa21fb1ae03f1746ccc544ffa7f3', class: "nano-table__overflow" }))), h("slot", { key: '57821514111245364971a5f85c6ff95309590eb3' })));
    }
    static get watchers() { return {
        "compact": ["handleCompactChange"],
        "hideCaption": ["handleHideCaptionChange"]
    }; }
    static get style() { return tableCss; }
}, [262, "nano-table", {
        "compact": [520],
        "scrollable": [516],
        "hideCaption": [516, "hide-caption"],
        "disableClickableRows": [516, "disable-clickable-rows"],
        "propsReady": [32]
    }, undefined, {
        "compact": ["handleCompactChange"],
        "hideCaption": ["handleHideCaptionChange"]
    }]);
function defineCustomElement$1() {
    if (typeof customElements === "undefined") {
        return;
    }
    const components = ["nano-table", "nano-icon", "nano-icon-button", "nano-masked-overflow", "nano-tooltip"];
    components.forEach(tagName => { switch (tagName) {
        case "nano-table":
            if (!customElements.get(tagName)) {
                customElements.define(tagName, NanoTable$1);
            }
            break;
        case "nano-icon":
            if (!customElements.get(tagName)) {
                defineCustomElement$5();
            }
            break;
        case "nano-icon-button":
            if (!customElements.get(tagName)) {
                defineCustomElement$4();
            }
            break;
        case "nano-masked-overflow":
            if (!customElements.get(tagName)) {
                defineCustomElement$3();
            }
            break;
        case "nano-tooltip":
            if (!customElements.get(tagName)) {
                defineCustomElement$2();
            }
            break;
    } });
}

const NanoTable = NanoTable$1;
const defineCustomElement = defineCustomElement$1;

export { NanoTable, defineCustomElement };
