import {
  __decorateClass,
  __privateAdd,
  __privateGet,
  __privateMethod,
  __privateSet
} from "../../chunks/chunk.QU3DSPNU.js";
var _optionElements, _Dropdown_instances, shouldShowFooter_fn, _renderCombobox, _renderTriggerButton, _handleBlur, _calcMaxHeight, _dispatchUISateEvent, _handlePopoverStateChange, _handleClearButton, _handleSearchFieldInput, _handleSearchFieldKeyDown, _handleListboxKeyDown, _handleOptionFocusChange, handleSelectionChange_fn, _dispatchInputEvent, _dispatchChangeEvent, registerAutoCloseListener_fn, unregisterAutoCloseListener_fn, _blurCloseListener, _tabCloseListener;
import { localized, msg, str } from "@lit/localize";
import { nothing } from "lit";
import { property, query, queryAsync } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { unsafeHTML } from "lit/directives/unsafe-html.js";
import { when } from "lit/directives/when.js";
import { flip, offset } from "@floating-ui/dom";
import { GdsFieldBase } from "../../primitives/field-base/field-base.component.js";
import { GdsFormControlFooter } from "../../primitives/form-control-footer/form-control-footer.component.js";
import { GdsFormControlHeader } from "../../primitives/form-control-header/form-control-header.component.js";
import { GdsListbox } from "../../primitives/listbox/listbox.component.js";
import { gdsCustomElement, html } from "../../scoping.js";
import formControlHostStyle from "../../shared-styles/form-control-host.style.js";
import { tokens } from "../../tokens.style.js";
import { observeLightDOM } from "../../utils/decorators/observe-light-dom.js";
import { watch } from "../../utils/decorators/watch.js";
import {
  withLayoutChildProps,
  withMarginProps,
  withSizeXProps
} from "../../utils/mixins/declarative-layout-mixins.js";
import { GdsFormControlElement } from "../form/form-control.js";
import { IconCheckmark } from "../icon/icons/checkmark.component.js";
import { IconChevronBottom } from "../icon/icons/chevron-bottom.component.js";
import { IconCrossSmall } from "../icon/icons/cross-small.component.js";
import { GdsPopover } from "../popover/popover.component.js";
import DropdownStyles from "./dropdown.styles.js";
export * from "../../primitives/listbox/option.component.js";
let Dropdown = class extends GdsFormControlElement {
  constructor() {
    super(...arguments);
    __privateAdd(this, _Dropdown_instances);
    this.supportingText = "";
    this.open = false;
    this.searchable = false;
    this.multiple = false;
    this.clearable = false;
    this.combobox = false;
    this.compareWith = (a, b) => a === b;
    this.searchFilter = (q, o) => o.innerHTML.toLowerCase().includes(q.toLowerCase());
    this.syncPopoverWidth = false;
    this.maxHeight = 500;
    this.size = "medium";
    this.hideLabel = false;
    this.plain = false;
    this.disableMobileStyles = false;
    this.showExtendedSupportingText = false;
    __privateAdd(this, _optionElements);
    __privateAdd(this, _renderCombobox, () => {
      return html`
      <input
        id="trigger"
        role="combobox"
        class="native-control"
        aria-expanded="${this.open}"
        aria-owns="listbox"
        aria-haspopup="listbox"
        aria-controls="listbox"
        placeholder="${this.placeholder?.innerHTML}"
        name="trigger"
        aria-label="${this.label} ${this.displayValue}"
        aria-describedby="supporting-text extended-supporting-text sub-label message"
        aria-invalid="${this.invalid}"
        aria-required="${this.required}"
        aria-disabled="${this.disabled}"
        .value=${this.value}
        @click=${(e) => {
        e.stopImmediatePropagation();
      }}
        @input=${(e) => {
        this.value = e.target.value;
        __privateGet(this, _dispatchInputEvent).call(this);
        __privateGet(this, _handleSearchFieldInput).call(this, e);
        __privateGet(this, _dispatchUISateEvent).call(this, true, "show") && (this.open = true);
      }}
        @keydown=${(e) => {
        if (e.key === "ArrowDown") {
          e.preventDefault();
          __privateGet(this, _dispatchUISateEvent).call(this, true, "show") && (this.open = true);
          this._elListbox.then((listbox) => listbox.focus());
        }
        if (e.key === "Enter") {
          __privateGet(this, _dispatchChangeEvent).call(this);
        }
      }}
      />
    `;
    });
    __privateAdd(this, _renderTriggerButton, () => {
      return html`
      <button
        id="trigger"
        role="combobox"
        class="native-control"
        aria-expanded="${this.open}"
        aria-owns="listbox"
        aria-haspopup="listbox"
        aria-controls="listbox"
        name="trigger"
        aria-label="${this.label}"
        aria-describedby="supporting-text extended-supporting-text sub-label message"
        aria-invalid="${this.invalid}"
        aria-required="${this.required}"
        aria-disabled="${this.disabled}"
      >
        <slot name="trigger">
          <span>${unsafeHTML(this.displayValue)}</span>
        </slot>
      </button>
    `;
    });
    __privateAdd(this, _handleBlur, (e) => {
      if (!this.open) {
        this.dispatchCustomEvent("gds-blur", {
          detail: { relatedTarget: e.relatedTarget },
          bubbles: false,
          composed: true
        });
      }
    });
    __privateAdd(this, _calcMaxHeight, (trigger) => {
      if (this.combobox) {
        const triggerRect = trigger.getBoundingClientRect();
        const windowHeight = window.innerHeight;
        const bottomSpace = windowHeight - triggerRect.bottom;
        const topSpace = triggerRect.top;
        let height2 = Math.min(topSpace, this.maxHeight);
        if (bottomSpace > topSpace) height2 = Math.min(bottomSpace, this.maxHeight);
        return `${height2 - 16}px`;
      }
      const height = Math.min(window.innerHeight, this.maxHeight);
      return `${height - 16}px`;
    });
    __privateAdd(this, _dispatchUISateEvent, (toState, reason) => this.dispatchCustomEvent("gds-ui-state", {
      detail: { reason, open: toState },
      bubbles: false,
      composed: false
    }));
    __privateAdd(this, _handlePopoverStateChange, (e) => {
      if (__privateGet(this, _dispatchUISateEvent).call(this, e.detail.open, e.detail.reason)) {
        this.open = e.detail.open;
      }
    });
    __privateAdd(this, _handleClearButton, (e) => {
      e.preventDefault();
      e.stopPropagation();
      this.value = void 0;
      this.dispatchCustomEvent("gds-input-cleared", {
        bubbles: true,
        composed: true
      });
      __privateGet(this, _dispatchInputEvent).call(this);
      __privateGet(this, _dispatchChangeEvent).call(this);
    });
    /**
     * Event handler for filtering the options in the dropdown.
     */
    __privateAdd(this, _handleSearchFieldInput, (e) => {
      if (!e.currentTarget) return;
      e.stopPropagation();
      const wasCancelled = !this.dispatchCustomEvent("gds-filter-input", {
        detail: { value: e.currentTarget.value }
      });
      if (wasCancelled) return;
      const input = e.currentTarget;
      this.options.forEach((o) => o.hidden = false);
      if (!input.value) return;
      const filteredOptions = this.options.filter(
        (o) => !this.searchFilter(input.value, o)
      );
      filteredOptions.forEach((o) => o.hidden = true);
    });
    /**
     * Check for ArrowDown or Tab in the search field.
     * If found, focus should be moved to the listbox.
     */
    __privateAdd(this, _handleSearchFieldKeyDown, (e) => {
      this._elListbox?.then((listbox) => {
        if (e.key === "ArrowDown" || e.key === "Tab") {
          e.preventDefault();
          listbox.focus();
          return;
        }
      });
    });
    /**
     * Check for Tab in the listbox.
     * If found, focus should be moved to the search field.
     */
    __privateAdd(this, _handleListboxKeyDown, (e) => {
      if (e.key === "Tab" && this.searchable) {
        e.preventDefault();
        this._elSearchInput?.focus();
        return;
      }
    });
    __privateAdd(this, _handleOptionFocusChange, (e) => {
      const triggerButton = this._elTriggerBtn;
      if (triggerButton)
        triggerButton.ariaActiveDescendantElement = e.target;
    });
    __privateAdd(this, _dispatchInputEvent, () => {
      this.updateComplete.then(
        () => this.dispatchStandardEvent("input", {
          bubbles: true,
          composed: true
        })
      );
    });
    __privateAdd(this, _dispatchChangeEvent, () => {
      this.updateComplete.then(
        () => this.dispatchCustomEvent("change", {
          detail: { value: this.value },
          bubbles: true,
          composed: true
        })
      );
    });
    /**
     * A listener to close the dropdown when any other element is focused.
     */
    __privateAdd(this, _blurCloseListener, (e) => {
      const isFocusOutside = e instanceof FocusEvent && e.relatedTarget && !this.contains(e.relatedTarget);
      if (isFocusOutside && __privateGet(this, _dispatchUISateEvent).call(this, false, "close"))
        this.open = false;
    });
    __privateAdd(this, _tabCloseListener, (e) => {
      if (e.key === "Tab" && !this.searchable && __privateGet(this, _dispatchUISateEvent).call(this, false, "close")) {
        e.preventDefault();
        this.open = false;
        this._elTriggerBtn?.focus();
      }
    });
  }
  get type() {
    return "gds-dropdown";
  }
  /**
   * Get the options of the dropdown.
   */
  get options() {
    if (!__privateGet(this, _optionElements)) return [];
    return Array.from(__privateGet(this, _optionElements)).filter(
      (o) => !o.hasAttribute("isplaceholder")
    );
  }
  /**
   * Return the first option with a isPlaceholder attribute.
   * If no placeholder is found, this will be undefined.
   */
  get placeholder() {
    if (!__privateGet(this, _optionElements)) return;
    return Array.from(__privateGet(this, _optionElements)).find(
      (o) => o.hasAttribute("isplaceholder")
    );
  }
  /**
   * Returns the display value as a string.
   * If the dropdown is in multiple mode, this will be a comma separated list of the selected values.
   */
  get displayValue() {
    let displayValue;
    if (Array.isArray(this.value)) {
      displayValue = this.value.slice(0, 5).reduce(
        (acc, cur) => acc + this.options.find((v) => v.value === cur)?.innerText + ", ",
        ""
      ).slice(0, -2).replace(/(.{25})(.*)/, "$1...");
    } else {
      displayValue = this.options.find((v) => v.selected)?.innerText;
    }
    return displayValue || this.placeholder?.innerText || "";
  }
  /**
   * Moves focus to this element.
   */
  focus() {
    this._getValidityAnchor().focus();
  }
  /**
   * A reference to the field element. This does not refer to the trigger button element itself,
   * but the wrapper that makes up the visual field.
   * Intended for use in integration tests.
   */
  test_getFieldElement() {
    return this.shadowRoot?.querySelector("#field");
  }
  connectedCallback() {
    super.connectedCallback();
    this.addEventListener("blur", __privateGet(this, _handleBlur));
    this.updateComplete.then(() => {
      this._handleLightDOMChange();
      this._handleValueChange();
      this._handleOpenChange();
    });
  }
  disconnectedCallback() {
    super.disconnectedCallback();
    this.removeEventListener("blur", __privateGet(this, _handleBlur));
  }
  render() {
    return html`
      ${when(
      !this.plain && !this.hideLabel,
      () => html`
          <gds-form-control-header
            class="size-${this.size}"
            .showExtendedSupportingText="${this.showExtendedSupportingText}"
          >
            <label id="label" for="trigger" slot="label">${this.label}</label>
            ${when(
        this.supportingText.length > 0,
        () => html`<span slot="supporting-text" id="supporting-text">
                  ${this.supportingText}
                </span>`
      )}
            <slot
              id="extended-supporting-text"
              name="extended-supporting-text"
              slot="extended-supporting-text"
            ></slot>
            <!-- @deprecated: use 'supporting-text' slot instead. Remove in 2.0 release. -->
            <slot id="sub-label" name="sub-label" slot="supporting-text"></slot>
          </gds-form-control-header>
        `
    )}
      <gds-popover
        .autofocus=${!this.combobox}
        .label=${this.label}
        .open=${this.open}
        .calcMaxWidth=${(trigger) => this.syncPopoverWidth ? `${trigger.offsetWidth}px` : `auto`}
        .calcMaxHeight=${__privateGet(this, _calcMaxHeight)}
        .disableMobileStyles=${this.disableMobileStyles || this.combobox}
        .nonmodal=${this.combobox}
        .floatingUIMiddleware=${this.combobox ? [offset(8), flip()] : GdsPopover.DefaultMiddleware}
        @gds-ui-state=${__privateGet(this, _handlePopoverStateChange)}
      >
        <gds-field-base
          .size=${this.size}
          .disabled=${this.disabled}
          .invalid=${this.invalid}
          slot="trigger"
          id="field"
        >
          <slot name="lead" slot="lead"></slot>
          ${when(
      this.value && this.multiple && this.value.length > 0,
      () => html`<gds-badge
                rounded
                size=${this.size === "small" ? "small" : "default"}
                slot="lead"
                aria-label=${msg(
        str`${this.value.length} options selected`
      )}
              >
                ${this.value.length}</gds-badge
              >`
    )}
          ${when(
      this.clearable && this.value && !this.disabled,
      () => html`<gds-button
                id="clear-btn"
                rank="tertiary"
                size=${this.size === "small" ? "xs" : "small"}
                label="${msg("Clear selection")}"
                @click=${__privateGet(this, _handleClearButton)}
                slot="action"
              >
                <gds-icon-cross-small></gds-icon-cross-small>
              </gds-button>`
    )}
          ${when(this.combobox && !this.multiple, () => __privateGet(this, _renderCombobox).call(this))}
          ${when(
      !this.combobox || this.multiple,
      () => __privateGet(this, _renderTriggerButton).call(this)
    )}
          <gds-icon-chevron-bottom
            size=${this.size === "small" ? "m" : "l"}
            slot="action"
          ></gds-icon-chevron-bottom>
        </gds-field-base>

        ${when(
      this.searchable,
      () => html`<input
              id="searchinput"
              type="text"
              aria-label="${msg("Filter available options")}"
              placeholder="${msg("Search")}"
              @keydown=${__privateGet(this, _handleSearchFieldKeyDown)}
              @input=${__privateGet(this, _handleSearchFieldInput)}
            />`
    )}
        <gds-listbox
          id="listbox"
          .multiple="${ifDefined(this.multiple)}"
          .compareWith="${this.compareWith}"
          @change="${__privateMethod(this, _Dropdown_instances, handleSelectionChange_fn)}"
          @gds-focus="${__privateGet(this, _handleOptionFocusChange)}"
          @keydown=${__privateGet(this, _handleListboxKeyDown)}
        >
          <slot></slot>
        </gds-listbox>
      </gds-popover>

      ${when(
      __privateMethod(this, _Dropdown_instances, shouldShowFooter_fn).call(this),
      () => html`
          <gds-form-control-footer
            class="size-${this.size}"
            .errorMessage=${this.invalid ? this.errorMessage : void 0}
          >
            ${``}
            <slot id="message" name="message" slot="message">
              <gds-icon-triangle-exclamation
                solid
              ></gds-icon-triangle-exclamation>
              ${this.invalid ? this.errorMessage : nothing}
            </slot>
          </gds-form-control-footer>
        `
    )}
    `;
  }
  _getValidityAnchor() {
    return this._elTriggerBtn;
  }
  _handleLightDOMChange() {
    this.requestUpdate();
    __privateSet(this, _optionElements, this.querySelectorAll("[gds-element=gds-option]"));
    if (this.multiple) {
      this._handleValueChange();
      return;
    }
    if (this.value === void 0) {
      if (this.placeholder) this.value = this.placeholder.value;
      else this.value = this.options[0]?.value;
    } else if (!this.combobox && !this.placeholder && this.options.find((o) => this.compareWith(o.value, this.value)) === void 0) {
      this.options[0] && (this.options[0].selected = true);
      this.value = this.options[0]?.value;
    }
    this._handleValueChange();
  }
  _handleValueChange() {
    this._elListbox.then((listbox) => {
      if (listbox) {
        if (Array.isArray(this.value)) listbox.selection = this.value;
        else listbox.selection = [this.value];
      }
    });
  }
  _handleOpenChange() {
    const open = this.open;
    this.options.forEach((o) => o.hidden = !open);
    if (open) __privateMethod(this, _Dropdown_instances, registerAutoCloseListener_fn).call(this);
    else {
      __privateMethod(this, _Dropdown_instances, unregisterAutoCloseListener_fn).call(this);
      this._elSearchInput && (this._elSearchInput.value = "");
    }
    const selectedOption = this.options.find((option) => option.selected);
    requestAnimationFrame(async () => {
      await this.updateComplete;
      selectedOption?.scrollIntoView({
        block: "center"
      });
    });
  }
};
_optionElements = new WeakMap();
_Dropdown_instances = new WeakSet();
shouldShowFooter_fn = function() {
  return !this.plain;
};
_renderCombobox = new WeakMap();
_renderTriggerButton = new WeakMap();
_handleBlur = new WeakMap();
_calcMaxHeight = new WeakMap();
_dispatchUISateEvent = new WeakMap();
_handlePopoverStateChange = new WeakMap();
_handleClearButton = new WeakMap();
_handleSearchFieldInput = new WeakMap();
_handleSearchFieldKeyDown = new WeakMap();
_handleListboxKeyDown = new WeakMap();
_handleOptionFocusChange = new WeakMap();
handleSelectionChange_fn = function() {
  this._elListbox.then((listbox) => {
    if (this.multiple) this.value = listbox.selection.map((s) => s.value);
    else {
      this.value = listbox.selection[0]?.value;
      if (__privateGet(this, _dispatchUISateEvent).call(this, false, "close")) {
        this.open = false;
        setTimeout(() => this._elTriggerBtn?.focus(), 0);
      }
    }
    __privateGet(this, _dispatchInputEvent).call(this);
    __privateGet(this, _dispatchChangeEvent).call(this);
  });
};
_dispatchInputEvent = new WeakMap();
_dispatchChangeEvent = new WeakMap();
registerAutoCloseListener_fn = function() {
  this.addEventListener("blur", __privateGet(this, _blurCloseListener));
  this.addEventListener("gds-blur", __privateGet(this, _blurCloseListener));
  this.addEventListener("keydown", __privateGet(this, _tabCloseListener));
};
unregisterAutoCloseListener_fn = function() {
  this.removeEventListener("blur", __privateGet(this, _blurCloseListener));
  this.removeEventListener("gds-blur", __privateGet(this, _blurCloseListener));
  this.removeEventListener("keydown", __privateGet(this, _tabCloseListener));
};
_blurCloseListener = new WeakMap();
_tabCloseListener = new WeakMap();
Dropdown.styles = [tokens, formControlHostStyle, DropdownStyles];
__decorateClass([
  property({ attribute: "supporting-text" })
], Dropdown.prototype, "supportingText", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], Dropdown.prototype, "open", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], Dropdown.prototype, "searchable", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], Dropdown.prototype, "multiple", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], Dropdown.prototype, "clearable", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], Dropdown.prototype, "combobox", 2);
__decorateClass([
  property()
], Dropdown.prototype, "compareWith", 2);
__decorateClass([
  property()
], Dropdown.prototype, "searchFilter", 2);
__decorateClass([
  property({ type: Boolean, attribute: "sync-popover-width" })
], Dropdown.prototype, "syncPopoverWidth", 2);
__decorateClass([
  property({ type: Number, attribute: "max-height" })
], Dropdown.prototype, "maxHeight", 2);
__decorateClass([
  property({ reflect: true })
], Dropdown.prototype, "size", 2);
__decorateClass([
  property({ type: Boolean, attribute: "hide-label" })
], Dropdown.prototype, "hideLabel", 2);
__decorateClass([
  property({ type: Boolean })
], Dropdown.prototype, "plain", 2);
__decorateClass([
  property({ type: Boolean })
], Dropdown.prototype, "disableMobileStyles", 2);
__decorateClass([
  property({
    attribute: "show-extended-supporting-text",
    type: Boolean,
    reflect: true
  })
], Dropdown.prototype, "showExtendedSupportingText", 2);
__decorateClass([
  query("#trigger")
], Dropdown.prototype, "_elTriggerBtn", 2);
__decorateClass([
  queryAsync("#listbox")
], Dropdown.prototype, "_elListbox", 2);
__decorateClass([
  query("#searchinput")
], Dropdown.prototype, "_elSearchInput", 2);
__decorateClass([
  observeLightDOM({
    attributes: true,
    childList: true,
    subtree: true,
    characterData: true
  })
], Dropdown.prototype, "_handleLightDOMChange", 1);
__decorateClass([
  watch("value")
], Dropdown.prototype, "_handleValueChange", 1);
__decorateClass([
  watch("open")
], Dropdown.prototype, "_handleOpenChange", 1);
Dropdown = __decorateClass([
  localized()
], Dropdown);
let GdsDropdown = class extends withSizeXProps(
  withMarginProps(withLayoutChildProps(Dropdown))
) {
};
GdsDropdown = __decorateClass([
  gdsCustomElement("gds-dropdown", {
    dependsOn: [
      GdsFormControlHeader,
      GdsFormControlFooter,
      GdsFieldBase,
      GdsListbox,
      GdsPopover,
      IconCheckmark,
      IconChevronBottom,
      IconCrossSmall
    ]
  })
], GdsDropdown);
export {
  GdsDropdown
};
