import { __esDecorate, __runInitializers } from "tslib";
import { html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js';
import { nanoid } from 'nanoid';
import { UiElement } from '../../UiElement.js';
import { isDisabled, setDisabled } from '../../../lib/disabled.js';
import { findElementInShadowRoots } from '../../../lib/Dom.js';
import '../../ripple/ui-ripple.js';
import '../../focus-ring/ui-focus-ring.js';
let BaseButton = (() => {
    let _classSuper = UiElement;
    let _instanceExtraInitializers = [];
    let _name_decorators;
    let _name_initializers = [];
    let _name_extraInitializers = [];
    let _set_value_decorators;
    let _trailingIcon_decorators;
    let _trailingIcon_initializers = [];
    let _trailingIcon_extraInitializers = [];
    let _type_decorators;
    let _type_initializers = [];
    let _type_extraInitializers = [];
    let _toggle_decorators;
    let _toggle_initializers = [];
    let _toggle_extraInitializers = [];
    let _selected_decorators;
    let _selected_initializers = [];
    let _selected_extraInitializers = [];
    let _shape_decorators;
    let _shape_initializers = [];
    let _shape_extraInitializers = [];
    let _size_decorators;
    let _size_initializers = [];
    let _size_extraInitializers = [];
    let _set_disabled_decorators;
    let _ripple_decorators;
    let _ripple_initializers = [];
    let _ripple_extraInitializers = [];
    let _popoverTarget_decorators;
    let _popoverTarget_initializers = [];
    let _popoverTarget_extraInitializers = [];
    let _popoverTargetAction_decorators;
    let _popoverTargetAction_initializers = [];
    let _popoverTargetAction_extraInitializers = [];
    let _inwardFocus_decorators;
    let _inwardFocus_initializers = [];
    let _inwardFocus_extraInitializers = [];
    return class BaseButton extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _name_decorators = [property({ type: String })];
            _set_value_decorators = [property({ type: String })];
            _trailingIcon_decorators = [property({ type: Boolean, attribute: 'trailingicon', reflect: true })];
            _type_decorators = [property({ type: String, reflect: true })];
            _toggle_decorators = [property({ type: Boolean, reflect: true })];
            _selected_decorators = [property({ type: Boolean, reflect: true })];
            _shape_decorators = [property({ type: String, reflect: true })];
            _size_decorators = [property({ type: String, reflect: true })];
            _set_disabled_decorators = [property({ reflect: true, type: Boolean })];
            _ripple_decorators = [query('ui-ripple')];
            _popoverTarget_decorators = [property({ type: String, reflect: true })];
            _popoverTargetAction_decorators = [property({ type: String, reflect: true })];
            _inwardFocus_decorators = [property({ type: Boolean })];
            __esDecorate(this, null, _name_decorators, { kind: "accessor", name: "name", static: false, private: false, access: { has: obj => "name" in obj, get: obj => obj.name, set: (obj, value) => { obj.name = value; } }, metadata: _metadata }, _name_initializers, _name_extraInitializers);
            __esDecorate(this, null, _set_value_decorators, { kind: "setter", name: "value", static: false, private: false, access: { has: obj => "value" in obj, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _trailingIcon_decorators, { kind: "accessor", name: "trailingIcon", static: false, private: false, access: { has: obj => "trailingIcon" in obj, get: obj => obj.trailingIcon, set: (obj, value) => { obj.trailingIcon = value; } }, metadata: _metadata }, _trailingIcon_initializers, _trailingIcon_extraInitializers);
            __esDecorate(this, null, _type_decorators, { kind: "accessor", name: "type", static: false, private: false, access: { has: obj => "type" in obj, get: obj => obj.type, set: (obj, value) => { obj.type = value; } }, metadata: _metadata }, _type_initializers, _type_extraInitializers);
            __esDecorate(this, null, _toggle_decorators, { kind: "accessor", name: "toggle", static: false, private: false, access: { has: obj => "toggle" in obj, get: obj => obj.toggle, set: (obj, value) => { obj.toggle = value; } }, metadata: _metadata }, _toggle_initializers, _toggle_extraInitializers);
            __esDecorate(this, null, _selected_decorators, { kind: "accessor", name: "selected", static: false, private: false, access: { has: obj => "selected" in obj, get: obj => obj.selected, set: (obj, value) => { obj.selected = value; } }, metadata: _metadata }, _selected_initializers, _selected_extraInitializers);
            __esDecorate(this, null, _shape_decorators, { kind: "accessor", name: "shape", static: false, private: false, access: { has: obj => "shape" in obj, get: obj => obj.shape, set: (obj, value) => { obj.shape = value; } }, metadata: _metadata }, _shape_initializers, _shape_extraInitializers);
            __esDecorate(this, null, _size_decorators, { kind: "accessor", name: "size", static: false, private: false, access: { has: obj => "size" in obj, get: obj => obj.size, set: (obj, value) => { obj.size = value; } }, metadata: _metadata }, _size_initializers, _size_extraInitializers);
            __esDecorate(this, null, _set_disabled_decorators, { kind: "setter", name: "disabled", static: false, private: false, access: { has: obj => "disabled" in obj, set: (obj, value) => { obj.disabled = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _ripple_decorators, { kind: "accessor", name: "ripple", static: false, private: false, access: { has: obj => "ripple" in obj, get: obj => obj.ripple, set: (obj, value) => { obj.ripple = value; } }, metadata: _metadata }, _ripple_initializers, _ripple_extraInitializers);
            __esDecorate(this, null, _popoverTarget_decorators, { kind: "accessor", name: "popoverTarget", static: false, private: false, access: { has: obj => "popoverTarget" in obj, get: obj => obj.popoverTarget, set: (obj, value) => { obj.popoverTarget = value; } }, metadata: _metadata }, _popoverTarget_initializers, _popoverTarget_extraInitializers);
            __esDecorate(this, null, _popoverTargetAction_decorators, { kind: "accessor", name: "popoverTargetAction", static: false, private: false, access: { has: obj => "popoverTargetAction" in obj, get: obj => obj.popoverTargetAction, set: (obj, value) => { obj.popoverTargetAction = value; } }, metadata: _metadata }, _popoverTargetAction_initializers, _popoverTargetAction_extraInitializers);
            __esDecorate(this, null, _inwardFocus_decorators, { kind: "accessor", name: "inwardFocus", static: false, private: false, access: { has: obj => "inwardFocus" in obj, get: obj => obj.inwardFocus, set: (obj, value) => { obj.inwardFocus = value; } }, metadata: _metadata }, _inwardFocus_initializers, _inwardFocus_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        static formAssociated = true;
        #internals = (__runInitializers(this, _instanceExtraInitializers), this.attachInternals());
        /**
         * The form associated with this element
         * @attribute
         */
        get form() {
            return this.#internals.form;
        }
        get validity() {
            return this.#internals.validity;
        }
        get validationMessage() {
            return this.#internals.validationMessage;
        }
        get willValidate() {
            return this.#internals.willValidate;
        }
        #name_accessor_storage = __runInitializers(this, _name_initializers, void 0);
        /**
         * The name of the button, submitted as a pair with the button's value as part of the form data.
         * @attribute
         */
        get name() { return this.#name_accessor_storage; }
        set name(value) { this.#name_accessor_storage = value; }
        #value = __runInitializers(this, _name_extraInitializers);
        get value() {
            return this.#value;
        }
        /**
         * Defines the value associated with the button's name when it's submitted with the form data.
         * @attribute
         */
        set value(value) {
            if (this.#value === value) {
                return;
            }
            this.#value = value;
            this.#internals?.setFormValue(value || null);
        }
        #trailingIcon_accessor_storage = __runInitializers(this, _trailingIcon_initializers, false
        /**
         * The default behavior of the button.
         * @attribute
         */
        );
        /**
         * Whether to render the icon at the inline end of the label rather than the inline start.
         * @attribute
         */
        get trailingIcon() { return this.#trailingIcon_accessor_storage; }
        set trailingIcon(value) { this.#trailingIcon_accessor_storage = value; }
        #type_accessor_storage = (__runInitializers(this, _trailingIcon_extraInitializers), __runInitializers(this, _type_initializers, 'button'
        /**
         * When set, the button is a toggle button.
         * @attribute
         */
        ));
        /**
         * The default behavior of the button.
         * @attribute
         */
        get type() { return this.#type_accessor_storage; }
        set type(value) { this.#type_accessor_storage = value; }
        #toggle_accessor_storage = (__runInitializers(this, _type_extraInitializers), __runInitializers(this, _toggle_initializers, false
        /**
         * Indicates that the button is currently selected.
         * @attribute
         */
        ));
        /**
         * When set, the button is a toggle button.
         * @attribute
         */
        get toggle() { return this.#toggle_accessor_storage; }
        set toggle(value) { this.#toggle_accessor_storage = value; }
        #selected_accessor_storage = (__runInitializers(this, _toggle_extraInitializers), __runInitializers(this, _selected_initializers, false
        /**
         * The shape of the button.
         * @attribute
         */
        ));
        /**
         * Indicates that the button is currently selected.
         * @attribute
         */
        get selected() { return this.#selected_accessor_storage; }
        set selected(value) { this.#selected_accessor_storage = value; }
        #shape_accessor_storage = (__runInitializers(this, _selected_extraInitializers), __runInitializers(this, _shape_initializers, 'round'
        /**
         * The size of the button.
         * @attribute
         */
        ));
        /**
         * The shape of the button.
         * @attribute
         */
        get shape() { return this.#shape_accessor_storage; }
        set shape(value) { this.#shape_accessor_storage = value; }
        #size_accessor_storage = (__runInitializers(this, _shape_extraInitializers), __runInitializers(this, _size_initializers, 's'));
        /**
         * The size of the button.
         * @attribute
         */
        get size() { return this.#size_accessor_storage; }
        set size(value) { this.#size_accessor_storage = value; }
        get disabled() {
            return isDisabled(this);
        }
        /**
         * When set, the button is in a disabled state.
         * @attribute
         */
        set disabled(value) {
            const old = isDisabled(this);
            setDisabled(this, value);
            this.requestUpdate('disabled', old);
        }
        #ripple_accessor_storage = (__runInitializers(this, _size_extraInitializers), __runInitializers(this, _ripple_initializers, void 0));
        get ripple() { return this.#ripple_accessor_storage; }
        set ripple(value) { this.#ripple_accessor_storage = value; }
        #popoverTarget_accessor_storage = (__runInitializers(this, _ripple_extraInitializers), __runInitializers(this, _popoverTarget_initializers, void 0));
        /**
         * Turns a `<ui-button>` element into a popover control button; takes the ID
         * of the popover element to control as its value.
         *
         * Note: this is required for now as the spec only allows to control popovers
         * via buttons. Custom elements are not allowed to control popovers.
         * @attribute
         */
        get popoverTarget() { return this.#popoverTarget_accessor_storage; }
        set popoverTarget(value) { this.#popoverTarget_accessor_storage = value; }
        #popoverTargetAction_accessor_storage = (__runInitializers(this, _popoverTarget_extraInitializers), __runInitializers(this, _popoverTargetAction_initializers, void 0));
        /**
         * Specifies the action to be performed on a popover element being controlled
         * by a control <ui-button>. Possible values are:
         *
         * - `hide` - The button will hide a shown popover. If you try to hide an already hidden popover,
         *   no action will be taken.
         * - `show` - The button will show a hidden popover. If you try to show an already showing popover,
         *   no action will be taken.
         * - `toggle` - The button will toggle a popover between showing and hidden. If the popover is hidden,
         *   it will be shown; if the popover is showing, it will be hidden. If popoverTargetAction is omitted,
         *   "toggle" is the default action that will be performed by the control button.
         */
        get popoverTargetAction() { return this.#popoverTargetAction_accessor_storage; }
        set popoverTargetAction(value) { this.#popoverTargetAction_accessor_storage = value; }
        #inwardFocus_accessor_storage = (__runInitializers(this, _popoverTargetAction_extraInitializers), __runInitializers(this, _inwardFocus_initializers, void 0));
        /**
         * When true, the focus ring effect will be constrained to the inside of the button's bounds.
         * @attribute
         */
        get inwardFocus() { return this.#inwardFocus_accessor_storage; }
        set inwardFocus(value) { this.#inwardFocus_accessor_storage = value; }
        constructor() {
            super();
            __runInitializers(this, _inwardFocus_extraInitializers);
            this.actionController.cancelKeyboardEvents = true;
            this.addEventListener('keydown', this.handleKeyDown.bind(this));
            this.addEventListener('keyup', this.handleKeyUp.bind(this));
            this.addEventListener('click', this.handleClick.bind(this));
            this.addEventListener('pointerdown', this.handlePointerDown.bind(this));
            this.addEventListener('pointerup', this.handlePointerUp.bind(this));
            this.addEventListener('pointercancel', this.handlePointerCancel.bind(this));
            this.addEventListener('pointerleave', this.handlePointerLeave.bind(this));
            this.addEventListener('pointerenter', this.handlePointerEnter.bind(this));
            this.addEventListener('contextmenu', this.handleContextMenu.bind(this));
        }
        connectedCallback() {
            super.connectedCallback();
            if (!this.hasAttribute('role')) {
                this.setAttribute('role', 'button');
            }
            if (!this.hasAttribute('tabindex') && !this.disabled) {
                this.setAttribute('tabindex', '0');
            }
        }
        update(changedProperties) {
            if (changedProperties.has('popoverTarget')) {
                this.setupPopoverTarget();
            }
            super.update(changedProperties);
        }
        updated(cp) {
            super.updated(cp);
            // If the button is disabled, remove the tabindex attribute
            if (cp.has('disabled')) {
                if (this.disabled) {
                    this.removeAttribute('tabindex');
                }
                else if (!this.hasAttribute('tabindex')) {
                    this.setAttribute('tabindex', '0');
                }
            }
            if (cp.has('toggle') || cp.has('selected')) {
                this.updatePressedState();
            }
        }
        updatePressedState() {
            if (this.toggle) {
                this.ariaPressed = String(this.selected);
            }
            else {
                this.selected = false;
                this.removeAttribute('aria-pressed');
            }
        }
        checkValidity() {
            return this.#internals.checkValidity();
        }
        reportValidity() {
            return this.#internals.reportValidity();
        }
        firstUpdated() {
            this.#internals?.setFormValue(this.value || null);
        }
        beginPress(options) {
            super.beginPress(options);
            this.classList.add('pressed');
            this.ripple?.beginFocus();
        }
        endPress(config) {
            super.endPress(config);
            this.classList.remove('pressed');
            this.ripple?.endFocus();
            const { cancelled, reason } = config;
            if (cancelled) {
                return;
            }
            const allowedReasons = reason === 'enter' || reason === 'space';
            if (this.type === 'submit' && (!reason || allowedReasons)) {
                this.handleSubmit();
            }
            else if (this.type === 'reset' && (!reason || allowedReasons)) {
                this.handleReset();
            }
            else if (allowedReasons) {
                this.click();
            }
        }
        handleClick(e) {
            if (this.disabled) {
                e.preventDefault();
                e.stopPropagation();
                return;
            }
            if (this.toggle) {
                this.selected = !this.selected;
                const e = new ToggleEvent('toggle', {
                    bubbles: true,
                    composed: true,
                    newState: this.selected ? 'selected' : 'unselected',
                    oldState: this.selected ? 'unselected' : 'selected',
                });
                this.dispatchEvent(e);
            }
            this.handlePopoverAction();
            // Delegate to ActionController to properly end the press and reset phase
            // state; this removes the 'pressed' class via endPress() and ensures
            // subsequent pointerdown events work again.
            super.handleClick(e);
        }
        setupPopoverTarget() {
            const id = this.popoverTarget;
            if (!id) {
                return;
            }
            const element = findElementInShadowRoots(id, this);
            if (!element) {
                return;
            }
            // A regular button first sets its value to the popover target ID,
            this.value = id;
            // create an anchor association with the popover target
            if (!this.id) {
                this.id = nanoid();
            }
            const anchorName = `--anchor-${this.id}`;
            this.style.setProperty('anchor-name', anchorName);
            element.style.setProperty('position-anchor', anchorName);
            this.setAttribute('aria-details', id);
            this.setAttribute('aria-controls', id);
        }
        /**
         * When the button has a popover target, this method toggles the popover
         * visibility by finding the element in the shadow roots and calling its
         * `togglePopover` method.
         */
        handlePopoverAction() {
            const id = this.popoverTarget;
            if (!id) {
                return;
            }
            const element = findElementInShadowRoots(id, this);
            if (!element) {
                return;
            }
            const action = this.popoverTargetAction || 'toggle';
            if (action === 'hide') {
                element.hidePopover();
            }
            else if (action === 'show') {
                element.showPopover();
            }
            else {
                // default to toggle
                element.togglePopover();
            }
            element.focus();
        }
        handleSubmit() {
            const { name, value, type, disabled, form } = this;
            if (!form || !type || disabled) {
                return;
            }
            const typedForm = form;
            let button;
            if (name || value) {
                button = document.createElement('button');
                if (name) {
                    button.name = name;
                }
                if (value) {
                    button.value = value;
                }
                button.type = type;
                button.hidden = true;
                typedForm.append(button);
            }
            try {
                typedForm.requestSubmit(button);
            }
            catch {
                // Ignore errors
            }
            if (button) {
                typedForm.removeChild(button);
            }
        }
        handleReset() {
            const form = this.form;
            form?.reset();
        }
        handlePointerEnter(e) {
            super.handlePointerEnter(e);
            this.ripple?.beginHover(e);
        }
        handlePointerLeave(e) {
            super.handlePointerLeave(e);
            this.ripple?.endHover();
        }
        render() {
            const { trailingIcon = false } = this;
            const icon = this.renderIcon();
            return html `
      ${this.renderFocusRing()} ${this.renderRipple()} ${trailingIcon ? nothing : icon}
      <slot></slot>
      ${trailingIcon ? icon : nothing}
    `;
        }
        renderIcon() {
            return html `<slot name="icon"></slot>`;
        }
        renderFocusRing() {
            return html `<ui-focus-ring
      part="focus-ring"
      class="focus-ring"
      .control="${this}"
      ?inward="${this.inwardFocus}"
    ></ui-focus-ring>`;
        }
        renderRipple() {
            return html `<ui-ripple class="ripple" ?disabled="${this.disabled}"></ui-ripple>`;
        }
    };
})();
/**
 * A material design button with M3 Expressive features - CSS-native implementation.
 *
 * @slot icon - A slot for the icon element
 * @slot - The default slot for the label
 * @attribute {string} form - The form associated with this element when the element is outside the form.
 * @fires {ToggleEvent} toggle - Fired when the `toggle` property is true and the button is clicked,
 *                               changing its selection state.
 *                               The event's `newState` and `oldState` properties (string values: 'selected' or
 *                               'unselected') detail this selection change.
 */
export default BaseButton;
//# sourceMappingURL=base.js.map