'use client';
import { __decorate } from 'tslib';
import { provide } from '@lit/context';
import { html } from 'lit';
import { state, query, property, queryAssignedElements } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import SgdsElement from '../../base/sgds-element.js';
import { stopAnimations, animateTo, shimKeyframesHeightAuto } from '../../utils/animate.js';
import { setDefaultAnimation, getAnimation } from '../../utils/animation-registry.js';
import { SM_BREAKPOINT, MD_BREAKPOINT, LG_BREAKPOINT, XL_BREAKPOINT, XXL_BREAKPOINT } from '../../utils/breakpoints.js';
import { waitForEvent } from '../../utils/event.js';
import genId from '../../utils/generateId.js';
import { watch } from '../../utils/watch.js';
import { SgdsIconButton } from '../IconButton/sgds-icon-button.js';
import { MainnavBreakpointContext, MainnavExpandedContext } from './mainnav-context.js';
import css_248z from './mainnav.js';

const SIZES = {
    sm: SM_BREAKPOINT,
    md: MD_BREAKPOINT,
    lg: LG_BREAKPOINT,
    xl: XL_BREAKPOINT,
    xxl: XXL_BREAKPOINT,
    never: Infinity,
    always: -1
};
/**
 * @summary This component is the primary means that your users will use to navigate through your portal. It includes horizontal navigation and branding to identify your site.
 *
 * @event sgds-show - Emitted on show. Only for collapsed menu.
 * @event sgds-after-show - Emitted on show after animation has completed. Only for collapsed menu.
 * @event sgds-hide - Emitted on hide. Only for collapsed menu.
 * @event sgds-after-hide - Emitted on hide after animation has completed. Only for collapsed menu.
 *
 * @slot default - Default slot of SgdsMainnav. Pass in SgdsMainnavItem elements here.
 * @slot end - Elements in this slot will be positioned to the right end of .navbar-nav. Elements in this slot will also be included in collapsed menu.
 * @slot brand - Brand slot of SgdsMainnav. Pass in brand logo img here
 * @slot non-collapsible - Elements in this slot will not be collapsed
 *
 */
class SgdsMainnav extends SgdsElement {
    constructor() {
        super(...arguments);
        this._breakpointReached = false;
        /** Indicates if mobile menu is open or closed */
        this.expanded = false;
        /** Denotes the transition state of mobile mainnav menu opening  */
        this.expanding = false;
        /** The href link for brand logo */
        this.brandHref = "";
        this.collapseId = genId("mainnav", "collapse");
        /** The breakpoint, below which, the Navbar will collapse. When always the Navbar will always be expanded regardless of screen size. When never, the Navbar will always be collapsed */
        this.expand = "lg";
        /** When true, removes max-width constraint to allow content to stretch full screen width */
        this.fluid = false;
        /** @internal */
        this.breakpointReached = false;
        this._handleMobileNavBound = this._handleMobileNav.bind(this);
    }
    /** @internal */
    get defaultSlotItems() {
        return [...(this.defaultNodes || [])].filter((node) => typeof node.tagName !== "undefined");
    }
    /** @internal */
    get endSlotItems() {
        return [...(this.endNodes || [])].filter((node) => typeof node.tagName !== "undefined");
    }
    connectedCallback() {
        super.connectedCallback();
        this._handleResize();
        window.addEventListener("click", (event) => this._handleClickOutOfElement(event, this.body));
        window.addEventListener("resize", this._handleResize.bind(this));
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        window.removeEventListener("click", (event) => this._handleClickOutOfElement(event, this.body));
        window.removeEventListener("resize", this._handleResize.bind(this));
    }
    firstUpdated(changedProperties) {
        super.firstUpdated(changedProperties);
        if (this.breakpointReached && this.body) {
            this.expanded = false;
            this.body.hidden = true;
            this._handleMobileNav();
            this._breakpointReached = true;
        }
        const items = [...this.defaultSlotItems, ...this.endSlotItems];
        items.forEach((item) => {
            item.setAttribute("expand", this.expand);
        });
    }
    _handleClickOutOfElement(e, self) {
        if (!e.composedPath().includes(self) && !e.composedPath().includes(this.header)) {
            this.hide();
        }
    }
    _handleSummaryClick() {
        if (this.expanded) {
            this.hide();
        }
        else {
            document.querySelector("body").style.overflow = "hidden";
            this.show();
        }
    }
    _handleResize() {
        const newBreakpointReachedValue = window.innerWidth < SIZES[this.expand];
        if (newBreakpointReachedValue !== this.breakpointReached) {
            this.requestUpdate();
        }
        else {
            this.body ? (this.body.hidden = true) : null;
            // this.expanded = false;
            this.expanding = false;
        }
        if (newBreakpointReachedValue) {
            this._handleMobileNav();
            if (!this._breakpointReached) {
                this._breakpointReached = true;
                window.addEventListener("scrollend", this._handleMobileNavBound);
            }
        }
        else {
            this._handleDesktopNav();
            this._breakpointReached = false;
            window.removeEventListener("scrollend", this._handleMobileNavBound);
        }
    }
    async _handleMobileNav() {
        if (!this.nav)
            return;
        this.nav.appendChild(this.body);
        await customElements.whenDefined("sgds-masthead");
        const { bottom } = this.nav.getBoundingClientRect();
        const navBodyPaddingY = parseFloat(getComputedStyle(this.body).paddingTop) + parseFloat(getComputedStyle(this.body).paddingBottom);
        this.navScroll.style.maxHeight = `calc(100dvh - ${bottom}px - ${navBodyPaddingY}px)`;
    }
    _handleDesktopNav() {
        var _a;
        (_a = this.navbar) === null || _a === void 0 ? void 0 : _a.insertBefore(this.body, this.nonCollapsibleSlot);
    }
    async _animateToShow() {
        const sgdsShow = this.emit("sgds-show", { cancelable: true });
        if (sgdsShow.defaultPrevented) {
            this.expanding = false;
            this.expanded = false;
            return;
        }
        await stopAnimations(this.body);
        this.body.hidden = false;
        const { keyframes, options } = getAnimation(this, "mainnav.show");
        await animateTo(this.body, shimKeyframesHeightAuto(keyframes, this.body.scrollHeight), options);
        this.body.style.height = "auto";
        this.emit("sgds-after-show");
    }
    async _animateToHide() {
        const slHide = this.emit("sgds-hide", { cancelable: true });
        if (slHide.defaultPrevented) {
            this.expanding = false;
            this.expanded = true;
            return;
        }
        await stopAnimations(this.body);
        const { keyframes, options } = getAnimation(this, "mainnav.hide");
        await animateTo(this.body, shimKeyframesHeightAuto(keyframes, this.body.scrollHeight), options);
        this.body.hidden = true;
        this.body.style.height = "auto";
        this.emit("sgds-after-hide");
    }
    async handleOpenChange() {
        if (this.expanding) {
            // Show
            await this._animateToShow();
            this.expanded = true;
        }
        else {
            this.header.focus();
            // Hide
            await this._animateToHide();
            this.expanded = false;
        }
    }
    /** Shows the menu. For when mainnav is in the collapsed form */
    async show() {
        if (this.expanded) {
            return;
        }
        this.expanding = true;
        return waitForEvent(this, "sgds-after-show");
    }
    /** Hide the menu. For when mainnav is in the collapsed form */
    async hide() {
        if (!this.expanded) {
            return;
        }
        this.expanding = false;
        document.querySelector("body").style.removeProperty("overflow");
        return waitForEvent(this, "sgds-after-hide");
    }
    // assigning name attribute to elements added in slot="end", to use wildcard css selector to assign styles only to *-mainnav-item
    _handleSlotChange(e) {
        const childElements = e.target.assignedElements({ flatten: true });
        childElements.forEach(e => {
            e.setAttribute("name", e.tagName.toLowerCase());
        });
    }
    render() {
        this.breakpointReached = window.innerWidth < SIZES[this.expand];
        return html `
      <nav>
        <div class="navbar ${this._expandClass()}">
          <a class="navbar-brand" href=${this.brandHref} aria-label="brand-link">
            <slot name="brand"></slot>
          </a>
          <div class="navbar-body navbar-collapse" id=${this.collapseId}>
            <div class="navbar-nav navbar-nav-scroll">
              <slot></slot>
              <slot
                name="end"
                class=${classMap({ "slot-end": !this.breakpointReached })}
                @slotchange=${this._handleSlotChange}
              ></slot>
            </div>
          </div>
          <slot name="non-collapsible"></slot>
          <sgds-icon-button
            name=${this.expanded ? "cross" : "menu"}
            variant="ghost"
            size="sm"
            class="navbar-toggler"
            @click=${this._handleSummaryClick}
            aria-controls="${this.collapseId}"
            aria-expanded="${this.expanded}"
            aria-label="Toggle navigation"
          ></sgds-icon-button>
        </div>
      </nav>
    `;
    }
    _expandClass() {
        switch (this.expand) {
            case "always":
                return "navbar-expand";
            case "never":
                break;
            default:
                return `navbar-expand-${this.expand}`;
        }
    }
}
SgdsMainnav.styles = [...SgdsElement.styles, css_248z];
/** @internal */
SgdsMainnav.dependencies = {
    "sgds-icon-button": SgdsIconButton
};
__decorate([
    provide({ context: MainnavBreakpointContext }),
    state()
], SgdsMainnav.prototype, "_breakpointReached", void 0);
__decorate([
    provide({ context: MainnavExpandedContext }),
    state()
], SgdsMainnav.prototype, "expanded", void 0);
__decorate([
    state()
], SgdsMainnav.prototype, "expanding", void 0);
__decorate([
    query("nav")
], SgdsMainnav.prototype, "nav", void 0);
__decorate([
    query(".navbar")
], SgdsMainnav.prototype, "navbar", void 0);
__decorate([
    query(".navbar-toggler")
], SgdsMainnav.prototype, "header", void 0);
__decorate([
    query(".navbar-body")
], SgdsMainnav.prototype, "body", void 0);
__decorate([
    query(".navbar-nav-scroll")
], SgdsMainnav.prototype, "navScroll", void 0);
__decorate([
    query("slot[name='non-collapsible']")
], SgdsMainnav.prototype, "nonCollapsibleSlot", void 0);
__decorate([
    property({ type: String })
], SgdsMainnav.prototype, "brandHref", void 0);
__decorate([
    property({ type: String })
], SgdsMainnav.prototype, "expand", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], SgdsMainnav.prototype, "fluid", void 0);
__decorate([
    state()
], SgdsMainnav.prototype, "breakpointReached", void 0);
__decorate([
    queryAssignedElements()
], SgdsMainnav.prototype, "defaultNodes", void 0);
__decorate([
    queryAssignedElements({ slot: "end" })
], SgdsMainnav.prototype, "endNodes", void 0);
__decorate([
    watch("expanding", { waitUntilFirstUpdate: true })
], SgdsMainnav.prototype, "handleOpenChange", null);
setDefaultAnimation("mainnav.show", {
    keyframes: [
        { height: "0", opacity: "0" },
        { height: "auto", opacity: "1" }
    ],
    options: { duration: 200, easing: "ease-in-out" }
});
setDefaultAnimation("mainnav.hide", {
    keyframes: [
        { height: "auto", opacity: "1" },
        { height: "0", opacity: "0" }
    ],
    options: { duration: 200, easing: "ease-in-out" }
});

export { SgdsMainnav, SgdsMainnav as default };
//# sourceMappingURL=sgds-mainnav.js.map
