var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
    r = Reflect.decorate(decorators, target, key, desc);
  else
    for (var i = decorators.length - 1; i >= 0; i--)
      if (d = decorators[i])
        r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { h, Host } from '@stencil/core';
import { createPopper } from '@popperjs/core';
import ClickOutside from '../../shared/decorators/click-outside';
import SlotChange from '../../shared/decorators/slot-change';
const CARET_POSITIONS = ['top', 'bottom', 'left', 'right'];
/**
 * @slot toggle - an element to use to toggle the dropdown visibility
 * @slot default - the dropdown content
 */
export class BsDropdown {
  constructor() {
    this._ariaToggleLabel = 'dropdownMenuToggle';
    this.placement = 'bottom-start';
    this.show = false;
    this.caret = true;
    this.split = false;
    this.hideOnClickOutside = true;
    this._visible = false;
    this._caretPosition = 'bottom';
  }
  /**
   * sets up the initial state of the dropdown
   */
  componentDidLoad() {
    this._toggle = this.getToggleElement();
    this._menu = this.el.shadowRoot.querySelector('.dropdown-menu');
    this._visible = this.show;
    this._toggle.id = this._ariaToggleLabel;
    this.initializeDropdown();
    this.addToggleEvents();
    this.setCaretPosition();
  }
  /**
   * if placement changes after the dropdown is initialized, change the placement option used in Popper.js
   */
  updateDropdownOptions() {
    // one of the props controlling the dropdown options changed, make Popper aware of the change
    this._popper.setOptions({
      placement: this.placement,
    });
    // placement changed, so caret position should change as well
    this.setCaretPosition();
  }
  /**
   * allows external access to showing/hiding the dropdown
   * @param show
   */
  showChanged(show) {
    this._visible = show;
  }
  /**
   * A method exposed on bs-dropdown elements to show the dropdown
   *
   * example: document.querySelector('bs-dropdown').showDropdown()
   */
  async showDropdown() {
    this._visible = true;
  }
  /**
   * A method exposed on bs-dropdown elements to hide the dropdown
   *
   * example: document.querySelector('bs-dropdown').hideDropdown()
   */
  async hideDropdown() {
    this._visible = false;
  }
  /**
   * A method exposed on bs-dropdown elements to toggle the dropdowns visibility
   *
   * example: document.querySelector('bs-dropdown').toggleDropdown()
   */
  async toggleDropdown() {
    this._visible = !this._visible;
  }
  /**
   * On user click outside of the component, close the dropdown
   */
  async hideDropdownOnClickOutside() {
    this.hideOnClickOutside && this.hideDropdown();
  }
  /**
   * make sure default slot items have the right Bootstrap class for rendering
   */
  slotItemsToDropdownItems(slot) {
    Array.from(slot.assignedElements())
      .filter((el) => el.tagName == 'A')
      .forEach((el) => {
      el.classList.add('dropdown-item');
    });
  }
  /**
   * make sure toggle item has the caret class if needed
   */
  addCaretToToggleItems() {
    const toggle = this._toggle || this.getToggleElement();
    if (!toggle) {
      return;
    }
    // remove any existing carets
    CARET_POSITIONS.forEach((pos) => toggle.classList.remove(`caret-${pos}`));
    toggle.classList.remove('caret');
    toggle.classList.remove('split');
    // add class for the given caret position
    if (this.caret || this.split) {
      toggle.classList.add(`caret-${this._caretPosition}`);
      toggle.classList.add('caret');
    }
    // add another class if the caret should be split from the button content
    if (this.split) {
      toggle.classList.add('split');
    }
  }
  /**
   * creates a new Popper instance
   */
  initializeDropdown() {
    this._popper = createPopper(this._toggle, this._menu, {
      placement: this.placement,
    });
  }
  /**
   * adds pointer events to the toggle element
   */
  addToggleEvents() {
    this._toggle.onpointerup = this.toggleDropdown.bind(this);
  }
  /**
   * The caret position is simple: either top, right, bottom, or left.
   * Popper has finely detailed control over the dropdown, so we need to convert it's position to caret position
   */
  setCaretPosition() {
    const position = CARET_POSITIONS.find(pos => new RegExp(pos).test(this.placement));
    this._caretPosition = position || 'bottom';
  }
  /**
   * the toggle element could either be the button in the toggle slot or the last button in the toggle slot if using a button group
   */
  getToggleElement() {
    var _a, _b;
    const toggleSlot = this.el.shadowRoot.querySelector('slot[name="toggle"]');
    const slotEls = toggleSlot.assignedElements();
    if (!slotEls || !slotEls.length) {
      return;
    }
    // if using a split button, find the last button and use that for the toggle
    if (slotEls[0].tagName == 'BS-BUTTON-GROUP') {
      const buttonEls = (_b = (_a = slotEls[0].shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('slot')) === null || _b === void 0 ? void 0 : _b.assignedElements();
      if (!buttonEls || buttonEls.length < 2) {
        throw new Error('You need two buttons to use a split toggle!');
      }
      return buttonEls[1];
    }
    return slotEls[0];
  }
  render() {
    return (h(Host, { class: "dropdown" }, h("slot", { name: "toggle" }), h("div", { class: `
                        dropdown-menu
                        ${this._visible ? 'show' : ''}
                    `, "aria-labelledby": this._ariaToggleLabel }, h("slot", null))));
  }
  static get is() { return "bs-dropdown"; }
  static get encapsulation() { return "shadow"; }
  static get originalStyleUrls() {
    return {
      "$": ["bs-dropdown.scss"]
    };
  }
  static get styleUrls() {
    return {
      "$": ["bs-dropdown.css"]
    };
  }
  static get properties() {
    return {
      "placement": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "Placement",
          "resolved": "\"auto\" | \"auto-end\" | \"auto-start\" | \"bottom\" | \"bottom-end\" | \"bottom-start\" | \"left\" | \"left-end\" | \"left-start\" | \"right\" | \"right-end\" | \"right-start\" | \"top\" | \"top-end\" | \"top-start\"",
          "references": {
            "Placement": {
              "location": "import",
              "path": "@popperjs/core"
            }
          }
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "where the dropdown should appear (see: https://popper.js.org/docs/v2/constructors/#options)"
        },
        "attribute": "placement",
        "reflect": false,
        "defaultValue": "'bottom-start'"
      },
      "show": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "used to control the dropdown visiblity manually, rather than relying on toggle clicks"
        },
        "attribute": "show",
        "reflect": false,
        "defaultValue": "false"
      },
      "caret": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "if true, toggle will automatically have a caret added to represent where the dropdown will appear"
        },
        "attribute": "caret",
        "reflect": false,
        "defaultValue": "true"
      },
      "split": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "the caret and button content will be split, and the dropdown will show up only when clicking the caret"
        },
        "attribute": "split",
        "reflect": false,
        "defaultValue": "false"
      },
      "hideOnClickOutside": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "whether to close the dropdown when clicking outside of it"
        },
        "attribute": "hide-on-click-outside",
        "reflect": false,
        "defaultValue": "true"
      }
    };
  }
  static get states() {
    return {
      "_visible": {},
      "_caretPosition": {}
    };
  }
  static get methods() {
    return {
      "showDropdown": {
        "complexType": {
          "signature": "() => Promise<void>",
          "parameters": [],
          "references": {
            "Promise": {
              "location": "global"
            }
          },
          "return": "Promise<void>"
        },
        "docs": {
          "text": "A method exposed on bs-dropdown elements to show the dropdown\n\nexample: document.querySelector('bs-dropdown').showDropdown()",
          "tags": []
        }
      },
      "hideDropdown": {
        "complexType": {
          "signature": "() => Promise<void>",
          "parameters": [],
          "references": {
            "Promise": {
              "location": "global"
            }
          },
          "return": "Promise<void>"
        },
        "docs": {
          "text": "A method exposed on bs-dropdown elements to hide the dropdown\n\nexample: document.querySelector('bs-dropdown').hideDropdown()",
          "tags": []
        }
      },
      "toggleDropdown": {
        "complexType": {
          "signature": "() => Promise<void>",
          "parameters": [],
          "references": {
            "Promise": {
              "location": "global"
            }
          },
          "return": "Promise<void>"
        },
        "docs": {
          "text": "A method exposed on bs-dropdown elements to toggle the dropdowns visibility\n\nexample: document.querySelector('bs-dropdown').toggleDropdown()",
          "tags": []
        }
      }
    };
  }
  static get elementRef() { return "el"; }
  static get watchers() {
    return [{
        "propName": "placement",
        "methodName": "updateDropdownOptions"
      }, {
        "propName": "show",
        "methodName": "showChanged"
      }, {
        "propName": "caret",
        "methodName": "addCaretToToggleItems"
      }, {
        "propName": "split",
        "methodName": "addCaretToToggleItems"
      }, {
        "propName": "_caretPosition",
        "methodName": "addCaretToToggleItems"
      }];
  }
}
__decorate([
  ClickOutside()
], BsDropdown.prototype, "hideDropdownOnClickOutside", null);
__decorate([
  SlotChange()
], BsDropdown.prototype, "slotItemsToDropdownItems", null);
__decorate([
  SlotChange('toggle')
], BsDropdown.prototype, "addCaretToToggleItems", null);
//# sourceMappingURL=bs-dropdown.js.map
