import { __esDecorate, __runInitializers } from "tslib";
import { html } from 'lit';
import { property, state, queryAssignedElements } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { nanoid } from 'nanoid';
import UiList from '../../list/internals/List.js';
import { setDisabled } from '../../../lib/disabled.js';
import { bound } from '../../../decorators/bound.js';
let Menu = (() => {
    let _classSuper = UiList;
    let _instanceExtraInitializers = [];
    let _open_decorators;
    let _open_initializers = [];
    let _open_extraInitializers = [];
    let _disabled_decorators;
    let _disabled_initializers = [];
    let _disabled_extraInitializers = [];
    let _activeSubMenu_decorators;
    let _activeSubMenu_initializers = [];
    let _activeSubMenu_extraInitializers = [];
    let _assignedMenuItems_decorators;
    let _assignedMenuItems_initializers = [];
    let _assignedMenuItems_extraInitializers = [];
    let _handleSubMenuSelect_decorators;
    return class Menu extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _open_decorators = [property({ type: Boolean, reflect: true })];
            _disabled_decorators = [property({ type: Boolean, reflect: true })];
            _activeSubMenu_decorators = [state()];
            _assignedMenuItems_decorators = [queryAssignedElements({ selector: 'ui-menu-item' })];
            _handleSubMenuSelect_decorators = [bound];
            __esDecorate(this, null, _open_decorators, { kind: "accessor", name: "open", static: false, private: false, access: { has: obj => "open" in obj, get: obj => obj.open, set: (obj, value) => { obj.open = value; } }, metadata: _metadata }, _open_initializers, _open_extraInitializers);
            __esDecorate(this, null, _disabled_decorators, { kind: "accessor", name: "disabled", static: false, private: false, access: { has: obj => "disabled" in obj, get: obj => obj.disabled, set: (obj, value) => { obj.disabled = value; } }, metadata: _metadata }, _disabled_initializers, _disabled_extraInitializers);
            __esDecorate(this, null, _activeSubMenu_decorators, { kind: "accessor", name: "activeSubMenu", static: false, private: false, access: { has: obj => "activeSubMenu" in obj, get: obj => obj.activeSubMenu, set: (obj, value) => { obj.activeSubMenu = value; } }, metadata: _metadata }, _activeSubMenu_initializers, _activeSubMenu_extraInitializers);
            __esDecorate(this, null, _assignedMenuItems_decorators, { kind: "accessor", name: "assignedMenuItems", static: false, private: false, access: { has: obj => "assignedMenuItems" in obj, get: obj => obj.assignedMenuItems, set: (obj, value) => { obj.assignedMenuItems = value; } }, metadata: _metadata }, _assignedMenuItems_initializers, _assignedMenuItems_extraInitializers);
            __esDecorate(this, null, _handleSubMenuSelect_decorators, { kind: "method", name: "handleSubMenuSelect", static: false, private: false, access: { has: obj => "handleSubMenuSelect" in obj, get: obj => obj.handleSubMenuSelect }, metadata: _metadata }, null, _instanceExtraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #open_accessor_storage = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _open_initializers, false
        /**
         * Whether the menu is disabled
         * @attribute
         */
        ));
        /**
         * Whether the menu is currently open
         * @attribute
         */
        get open() { return this.#open_accessor_storage; }
        set open(value) { this.#open_accessor_storage = value; }
        #disabled_accessor_storage = (__runInitializers(this, _open_extraInitializers), __runInitializers(this, _disabled_initializers, false
        /**
         * Currently active sub-menu
         */
        ));
        /**
         * Whether the menu is disabled
         * @attribute
         */
        get disabled() { return this.#disabled_accessor_storage; }
        set disabled(value) { this.#disabled_accessor_storage = value; }
        #activeSubMenu_accessor_storage = (__runInitializers(this, _disabled_extraInitializers), __runInitializers(this, _activeSubMenu_initializers, null
        /**
         * Assigned menu items from light DOM
         */
        ));
        /**
         * Currently active sub-menu
         */
        get activeSubMenu() { return this.#activeSubMenu_accessor_storage; }
        set activeSubMenu(value) { this.#activeSubMenu_accessor_storage = value; }
        #assignedMenuItems_accessor_storage = (__runInitializers(this, _activeSubMenu_extraInitializers), __runInitializers(this, _assignedMenuItems_initializers, void 0));
        /**
         * Assigned menu items from light DOM
         */
        get assignedMenuItems() { return this.#assignedMenuItems_accessor_storage; }
        set assignedMenuItems(value) { this.#assignedMenuItems_accessor_storage = value; }
        constructor() {
            super();
            __runInitializers(this, _assignedMenuItems_extraInitializers);
            this.selector = 'ui-menu-item';
            this.ariaExpanded = 'false';
            this.addEventListener('beforetoggle', this.handleBeforeToggle.bind(this));
        }
        connectedCallback() {
            super.connectedCallback();
            this.setAttribute('role', 'menu');
            this.setAttribute('tabindex', '-1');
            if (!this.hasAttribute('popover')) {
                this.setAttribute('popover', 'auto');
            }
            if (!this.id) {
                this.id = nanoid();
            }
        }
        updated(changedProperties) {
            super.updated(changedProperties);
            if (changedProperties.has('disabled')) {
                setDisabled(this, this.disabled);
            }
        }
        togglePopover(force) {
            this.open = !this.open;
            this.ariaExpanded = String(this.open);
            this.tabIndex = this.open ? 0 : -1;
            const result = super.togglePopover(force);
            if (this.open) {
                this.positionMenu();
                this.focus();
            }
            return result;
        }
        /**
         * Shows the menu
         */
        show() {
            this.tabIndex = 0; // Make menu focusable
            this.ariaExpanded = 'true';
            this.showPopover();
            this.open = true;
            this.positionMenu();
            this.focus();
            this.dispatchEvent(new CustomEvent('open', { bubbles: false, composed: true }));
        }
        /**
         * Hides the menu
         */
        hide() {
            this.tabIndex = -1;
            this.ariaExpanded = 'false';
            this.hidePopover();
            this.open = false;
            this.closeSubMenu();
            this.dispatchEvent(new CustomEvent('close', { bubbles: false, composed: true }));
        }
        positionMenu() {
            // when there's more space above the anchor, position the menu above it
            const box = this.getBoundingClientRect();
            // Now, we determine, whether to position the menu above or below the anchor
            // in a way, that if we have enough space below the anchor, we position it below,
            // otherwise we position it above the anchor.
            // our starting point is the anchor being positioned below the anchor
            const menuBottom = box.top + box.height;
            if (menuBottom <= innerHeight) {
                // if the menu fits below the anchor, we leave it as is.
                return;
            }
            // we do not make association from the menu to the anchor, so we make an assumption
            // that the anchor is 40px high, which is the default height of a button.
            // it can be different, but this is a good starting point.
            const anchorHeight = 40;
            const anchorBottom = box.top;
            const anchorTop = anchorBottom - anchorHeight;
            const menuHeight = box.height;
            const spaceBelow = innerHeight - anchorBottom;
            const spaceAbove = anchorTop;
            const diffBelow = spaceBelow - menuHeight;
            const diffAbove = spaceAbove - menuHeight;
            // The initial check ensures the menu does not fit below. Now, check if it fits above.
            if (diffAbove >= 0) {
                this.style.setProperty('position-area', 'top span-right');
            }
            else if (diffAbove > diffBelow) {
                // It doesn't fit in either direction. Choose the one with less overflow (larger, i.e., less negative, diff).
                this.style.setProperty('position-area', 'top span-right');
                this.style.maxHeight = `${spaceAbove}px`;
            }
            else {
                this.style.setProperty('position-area', 'bottom span-right');
                this.style.maxHeight = `${spaceBelow}px`;
            }
        }
        /**
         * Handles beforetoggle event from popover
         */
        handleBeforeToggle(e) {
            const toggleEvent = e;
            if (toggleEvent.newState === 'closed') {
                this.open = false;
                this.closeSubMenu();
            }
        }
        /**
         * Handles keyboard navigation for the menu
         */
        handleKeydown(e) {
            if (!this.open || e.defaultPrevented)
                return;
            switch (e.key) {
                case 'Escape':
                    e.preventDefault();
                    this.hide();
                    break;
                case 'ArrowRight':
                    e.preventDefault();
                    this.openSubMenu();
                    break;
                case 'ArrowLeft':
                    e.preventDefault();
                    this.closeSubMenu();
                    break;
                default:
                    // Let the parent UiList handle other keys
                    super.handleKeydown(e);
            }
        }
        handleSubMenuSelect(e) {
            super.notifySelect(e.detail.item, e.detail.index);
        }
        /**
         * Opens the sub-menu for the currently active item
         */
        openSubMenu() {
            const activeItem = this.activeListItem;
            if (activeItem?.hasSubMenu) {
                activeItem.openSubMenu();
            }
        }
        /**
         * Closes the currently open sub-menu
         */
        closeSubMenu() {
            if (this.activeSubMenu) {
                this.activeSubMenu.removeEventListener('select', this.handleSubMenuSelect);
                this.activeSubMenu.hide();
                this.activeSubMenu = null;
            }
        }
        /**
         * Sets the active sub-menu
         */
        setActiveSubMenu(subMenu) {
            this.activeSubMenu = subMenu;
            subMenu?.addEventListener('select', this.handleSubMenuSelect);
        }
        notifySelect(item, index) {
            this.hide();
            return super.notifySelect(item, index);
        }
        /**
         * Handles sub-menu opening
         */
        handleSubMenuOpen(e) {
            const subMenu = e.detail.subMenu;
            this.setActiveSubMenu(subMenu);
        }
        /**
         * Handles slot changes to update menu items
         */
        handleSlotChange() {
            // Update the items list when slot content changes
            this.updateItems();
        }
        render() {
            const classes = classMap({
                'menu-container': true,
            });
            return html `
      <div class=${classes}>
        <slot @slotchange=${this.handleSlotChange}></slot>
      </div>
    `;
        }
    };
})();
/**
 * Material Design 3 Menu component with sub-menu support.
 * Uses Popover API and Anchor Positioning API for modern positioning.
 *
 * @fires select - Dispatched when a menu item is selected
 * @fires close - Dispatched when the menu is closed
 */
export default Menu;
//# sourceMappingURL=Menu.js.map