/**
 * Copyright IBM Corp. 2026
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

import "../../globals/settings.js";
import { find, forEach, indexOf } from "../../globals/internal/collection-helpers.js";
import { carbonElement } from "../../globals/decorators/carbon-element.js";
import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.126.0/helpers/decorate.js";
import iconLoader from "../../globals/internal/icon-loader.js";
import FocusMixin from "../../globals/mixins/focus.js";
import HostListener from "../../globals/decorators/host-listener.js";
import HostListenerMixin from "../../globals/mixins/host-listener.js";
import FloatingController from "../../globals/controllers/floating-controller.js";
import FormMixin from "../../globals/mixins/form.js";
import ValidityMixin from "../../globals/mixins/validity.js";
import { DROPDOWN_DIRECTION, DROPDOWN_KEYBOARD_ACTION, DROPDOWN_SIZE, DROPDOWN_TYPE, NAVIGATION_DIRECTION } from "./defs.js";
import dropdown_default$1 from "./dropdown.scss.js";
import { LitElement, html } from "lit";
import { property, query, state } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import { ifDefined } from "lit/directives/if-defined.js";
import WarningFilled16 from "@carbon/icons/es/warning--filled/16.js";
import WarningAltFilled16 from "@carbon/icons/es/warning--alt--filled/16.js";
import ChevronDown16 from "@carbon/icons/es/chevron--down/16.js";
//#region src/components/dropdown/dropdown.ts
/**
* Copyright IBM Corp. 2019, 2026
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Dropdown.
*
* @element cds-dropdown
* @csspart label-text The label text.
* @csspart helper-text The helper text.
* @csspart trigger-button The trigger button.
* @csspart menu-body The menu body.
* @csspart validity-message The validity message.
* @fires cds-dropdown-beingselected
*   The custom event fired before a dropdown item is selected upon a user gesture.
*   Cancellation of this event stops changing the user-initiated selection.
* @fires cds-dropdown-beingtoggled
*   The custom event fired before the open state of this dropdown is toggled upon a user gesture.
*   Cancellation of this event stops the user-initiated toggling.
* @fires cds-dropdown-selected - The custom event fired after a dropdown item is selected upon a user gesture.
* @fires cds-dropdown-toggled - The custom event fired after the open state of this dropdown is toggled upon a user gesture.
*/
let CDSDropdown = class CDSDropdown extends ValidityMixin(HostListenerMixin(FormMixin(FocusMixin(LitElement)))) {
	constructor(..._args) {
		super(..._args);
		this._hasAILabel = false;
		this._aiDecoratorNodes = [];
		this._floatingController = new FloatingController(this);
		this._handleAIDecoratorInteraction = () => {
			if (!this.open) return;
			this._handleUserInitiatedToggle(false);
		};
		this._selectedItemContent = null;
		this._shouldTriggerBeFocusable = true;
		this.ariaLabel = "";
		this.direction = "bottom";
		this.autoalign = false;
		this.disabled = false;
		this.helperText = "";
		this.hideLabel = false;
		this.invalid = false;
		this.invalidText = "";
		this.titleText = "";
		this.name = "";
		this.open = false;
		this.readOnly = false;
		this.required = false;
		this.isFluid = false;
		this.requiredValidityMessage = "Please fill out this field.";
		this.size = "md";
		this.toggleLabelClosed = "";
		this.toggleLabelOpen = "";
		this.label = "";
		this.type = "";
		this.validityMessage = "";
		this.#_value_accessor_storage = "";
		this.warn = false;
		this.warnText = "";
	}
	/**
	* @param itemToSelect A dropdown item. Absense of this argument means clearing selection.
	* @returns `true` if the selection of this dropdown should change if the given item is selected upon user interaction.
	*/
	_selectionShouldChange(itemToSelect) {
		return !itemToSelect || itemToSelect.value !== this.value;
	}
	/**
	* A callback that runs after change in dropdown selection upon user interaction is confirmed.
	*
	* @param itemToSelect
	*   A dropdown item.
	*   Absense of this argument means clearing selection, which may be handled by a derived class.
	*/
	_selectionDidChange(itemToSelect) {
		const constructor = this.constructor;
		if (itemToSelect) {
			this.value = itemToSelect.value;
			this._activeDescendant = itemToSelect.id;
			forEach(this.querySelectorAll(constructor.selectorItemSelected), (item) => {
				item.selected = false;
				item.setAttribute("aria-selected", "false");
			});
			itemToSelect.selected = true;
			itemToSelect.setAttribute("aria-selected", "true");
			this._updateSelectedNextSibling(itemToSelect);
		} else this._updateSelectedNextSibling();
	}
	/**
	* Handles `click` event on the top-level element in the shadow DOM.
	*
	* @param event The event.
	*/
	_handleClickInner(event) {
		if (this.readOnly) return;
		if (this.shadowRoot.contains(event.target)) {
			const opening = !this.open;
			const constructor = this.constructor;
			const selectedItem = this.querySelector(constructor.selectorItemSelected);
			if (opening) {
				const shouldFocusMenu = Boolean(selectedItem);
				this._handleUserInitiatedToggle(true, {
					focusMenu: shouldFocusMenu,
					highlightSelectedOnOpen: shouldFocusMenu
				});
			} else this._handleUserInitiatedToggle(false, { restoreTriggerFocus: true });
		} else {
			const item = event.target.closest(this.constructor.selectorItem);
			if (this.contains(item)) this._handleUserInitiatedSelectItem(item);
		}
	}
	/**
	* Handler for the `keydown` event on the top-level element in the shadow DOM.
	*/
	_handleKeydownInner(event) {
		if (this._handleMenuInputKeydown(event)) return;
		const { key } = event;
		const action = this.constructor.getAction(key);
		if (!this.open) switch (action) {
			case "navigating": {
				const shouldKeepInputFocus = this._shouldRetainMenuInputFocus(event);
				const menuInputNode = this._menuInputNode;
				if (this.readOnly) {
					event.preventDefault();
					return;
				}
				const direction = NAVIGATION_DIRECTION[key];
				event.preventDefault();
				if (direction === -1) break;
				const constructor = this.constructor;
				const selectedItem = this.querySelector(constructor.selectorItemSelected);
				const shouldHighlightSelected = Boolean(selectedItem);
				this._handleUserInitiatedToggle(true, {
					focusMenu: false,
					highlightSelectedOnOpen: shouldHighlightSelected
				});
				this.updateComplete.then(() => {
					const constructor = this.constructor;
					const items = this.querySelectorAll(constructor.selectorItem);
					if (items.length > 0) {
						const selectedItem = this.querySelector(constructor.selectorItemSelected);
						const firstEnabledItem = Array.from(items).find((item) => !item.hasAttribute("disabled"));
						const initialItem = selectedItem && !selectedItem.hasAttribute("disabled") ? selectedItem : firstEnabledItem ?? null;
						if (initialItem) this._setHighlightedItem(initialItem, { scrollIntoView: true });
						else this._clearHighlight();
						const menu = this.shadowRoot?.getElementById("menu-body");
						if (shouldKeepInputFocus && menuInputNode) menuInputNode.focus({ preventScroll: true });
						else if (menu) menu.focus();
					}
				});
				break;
			}
			default: break;
		}
		else switch (action) {
			case "closing":
				this._handleUserInitiatedToggle(false, { restoreTriggerFocus: true });
				break;
			case "navigating": {
				event.preventDefault();
				const menu = this.shadowRoot?.getElementById("menu-body");
				const menuInputNode = this._menuInputNode;
				if (this._shouldRetainMenuInputFocus(event) && menuInputNode) menuInputNode.focus({ preventScroll: true });
				else if (menu) menu.focus();
				this._navigate(NAVIGATION_DIRECTION[key]);
				break;
			}
			default: break;
		}
	}
	_handleMenuInputKeydown(event) {
		if (event.defaultPrevented || !this._supportsMenuInputFiltering || !this._menuInputNode) return false;
		const input = this._menuInputNode;
		if (!input) return false;
		const isInputTarget = event.target === input;
		const hasFilterValue = Boolean(input.value || this.value);
		if (event.key === "Escape" && hasFilterValue && this._shouldClearMenuInputOnEscape({
			event,
			menuOpen: this.open,
			isInputTarget
		})) {
			event.preventDefault();
			this._clearMenuInputFiltering();
			return true;
		}
		if (!this.open || isInputTarget) return false;
		if (this._shouldForwardKeyToMenuInput(event)) {
			event.preventDefault();
			this._forwardKeyToMenuInput(event, input);
			return true;
		}
		return false;
	}
	_shouldClearMenuInputOnEscape({ menuOpen }) {
		return menuOpen;
	}
	get _supportsMenuInputFiltering() {
		return false;
	}
	get _menuInputNode() {
		return null;
	}
	_clearMenuInputFiltering() {}
	_shouldForwardKeyToMenuInput(event) {
		if (event.altKey || event.metaKey || event.ctrlKey) return false;
		const { key } = event;
		if (key === "Backspace" || key === "Delete") return true;
		return key.length === 1;
	}
	_forwardKeyToMenuInput(event, input) {
		input.focus({ preventScroll: true });
		const key = event.key;
		const selectionStart = input.selectionStart ?? input.value.length;
		const selectionEnd = input.selectionEnd ?? input.value.length;
		if (key === "Backspace") {
			if (selectionStart === 0 && selectionEnd === 0) return;
			const start = selectionStart === selectionEnd ? Math.max(0, selectionStart - 1) : selectionStart;
			input.setRangeText("", start, selectionEnd, "end");
		} else if (key === "Delete") {
			if (selectionStart === input.value.length && selectionStart === selectionEnd) return;
			const end = selectionStart === selectionEnd ? Math.min(input.value.length, selectionEnd + 1) : selectionEnd;
			input.setRangeText("", selectionStart, end, "end");
		} else if (key.length === 1) input.setRangeText(key, selectionStart, selectionEnd, "end");
		input.dispatchEvent(new Event("input", {
			bubbles: true,
			composed: true
		}));
	}
	_shouldRetainMenuInputFocus(event) {
		if (!this._supportsMenuInputFiltering || !this._menuInputNode) return false;
		if (event.target === this._menuInputNode) return true;
		return (typeof event.composedPath === "function" ? event.composedPath() : []).includes(this._menuInputNode);
	}
	/**
	* Handles keypress events (Space, Enter)
	*/
	_handleKeypressInner(event) {
		const { key } = event;
		const action = this.constructor.getAction(key);
		if (!this.open) {
			if (this.readOnly && action === "triggering") {
				if (key === " " || key === "Space") event.preventDefault();
				return;
			}
			switch (action) {
				case "triggering": {
					if (key === " " || key === "Space") event.preventDefault();
					const constructor = this.constructor;
					const selectedItem = this.querySelector(constructor.selectorItemSelected);
					const shouldFocusMenu = Boolean(selectedItem);
					this._handleUserInitiatedToggle(true, {
						focusMenu: shouldFocusMenu,
						highlightSelectedOnOpen: shouldFocusMenu
					});
					break;
				}
				default: break;
			}
		} else switch (action) {
			case "triggering": {
				const constructor = this.constructor;
				const selectedItem = this.querySelector(constructor.selectorItemSelected);
				const highlightedItem = this.querySelector(constructor.selectorItemHighlighted);
				if (highlightedItem) this._handleUserInitiatedSelectItem(highlightedItem);
				else if (selectedItem) this._handleUserInitiatedSelectItem(selectedItem);
				else this._handleUserInitiatedToggle(false, { restoreTriggerFocus: true });
				break;
			}
			default: break;
		}
	}
	/**
	* Handles `blur` event handler on the document this element is in.
	*
	* @param event The event.
	*/
	_handleMouseoverInner(event) {
		if (!this.open) return;
		const item = this._getDropdownItemFromEvent(event);
		if (!item) return;
		if (item.hasAttribute("disabled")) {
			this._clearHighlight();
			return;
		}
	}
	_handleMouseleaveInner(event) {
		if (!this.open) return;
		const menu = this.shadowRoot?.getElementById("menu-body");
		const relatedTarget = event.relatedTarget;
		if (menu && relatedTarget && menu.contains(relatedTarget)) return;
		const shadowActiveElement = this.shadowRoot?.activeElement;
		if (menu && shadowActiveElement && menu.contains(shadowActiveElement)) return;
		if (this._supportsMenuInputFiltering && this._menuInputNode && this.shadowRoot?.activeElement === this._menuInputNode) return;
		this._clearHighlight();
	}
	_handleFocusOut(event) {
		if (!this.contains(event.relatedTarget)) this._handleUserInitiatedToggle(false);
	}
	/**
	* Handles `slotchange` event for the `<slot>` for helper text.
	*/
	_handleSlotchangeHelperText() {
		this.requestUpdate();
	}
	/**
	* Handles `slotchange` event for the `<slot>` for label text.
	*/
	_handleSlotchangeLabelText() {
		this.requestUpdate();
	}
	/**
	* Handles `slotchange` event.
	*/
	_handleAILabelSlotChange({ target }) {
		const decoratorElements = target.assignedNodes().filter((elem) => elem.matches !== void 0 ? elem.matches(this.constructor.aiLabelItem) || elem.matches(this.constructor.slugItem) : false).filter((node) => node instanceof HTMLElement);
		this._updateAIDecoratorListeners(decoratorElements);
		this._hasAILabel = Boolean(decoratorElements.length);
		decoratorElements[0]?.setAttribute("size", "mini");
		this.requestUpdate();
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		this._updateAIDecoratorListeners([]);
	}
	/**
	* Updates listeners for AI decorator nodes to ensure only one menu stays open.
	*/
	_updateAIDecoratorListeners(nodes) {
		this._aiDecoratorNodes.forEach((node) => {
			node.removeEventListener("click", this._handleAIDecoratorInteraction);
		});
		this._aiDecoratorNodes = nodes;
		this._aiDecoratorNodes.forEach((node) => {
			node.addEventListener("click", this._handleAIDecoratorInteraction);
		});
	}
	/**
	* Handles user-initiated selection of a dropdown item.
	*
	* @param [item] The dropdown item user wants to select. Absense of this argument means clearing selection.
	*/
	_handleUserInitiatedSelectItem(item) {
		if (item?.hasAttribute("disabled")) return;
		const shouldClose = this._shouldCloseAfterSelection(item);
		if (this._selectionShouldChange(item)) {
			const init = {
				bubbles: true,
				composed: true,
				detail: { item }
			};
			const constructor = this.constructor;
			const beforeSelectEvent = new CustomEvent(constructor.eventBeforeSelect, {
				...init,
				cancelable: true
			});
			if (this.dispatchEvent(beforeSelectEvent)) {
				this._selectionDidChange(item);
				const afterSelectEvent = new CustomEvent(constructor.eventSelect, init);
				this.dispatchEvent(afterSelectEvent);
				if (shouldClose) this._handleUserInitiatedToggle(false, { restoreTriggerFocus: true });
			}
		} else if (item && shouldClose) this._handleUserInitiatedToggle(false, { restoreTriggerFocus: true });
	}
	_shouldCloseAfterSelection(item) {
		return true;
	}
	/**
	* Handles user-initiated toggling the open state.
	*
	* @param [force] If specified, forces the open state to the given one.
	*/
	_handleUserInitiatedToggle(force = !this.open, { restoreTriggerFocus = false, focusMenu = true, highlightSelectedOnOpen = false } = {}) {
		const { eventBeforeToggle, eventToggle } = this.constructor;
		const { disabled } = this;
		const init = {
			bubbles: true,
			cancelable: true,
			composed: true,
			detail: { open: force }
		};
		if (!disabled) {
			if (this.dispatchEvent(new CustomEvent(eventBeforeToggle, init))) {
				this.open = force;
				if (this.open) {
					const activeElement = this.shadowRoot?.activeElement;
					const preserveFocusTarget = activeElement instanceof HTMLInputElement ? activeElement : null;
					this.updateComplete.then(() => {
						if (preserveFocusTarget) preserveFocusTarget.focus();
						else if (focusMenu) (this.shadowRoot?.getElementById("menu-body"))?.focus();
						else if (this._shouldTriggerBeFocusable) (this.shadowRoot?.getElementById("trigger-button"))?.focus();
						if (highlightSelectedOnOpen) this._highlightSelectedItem();
					});
				} else if (restoreTriggerFocus && this._shouldTriggerBeFocusable) this.updateComplete.then(() => {
					(this.shadowRoot?.getElementById("trigger-button"))?.focus();
				});
				if (!this.open) this._clearHighlight();
				this.requestUpdate();
				this.dispatchEvent(new CustomEvent(eventToggle, init));
			}
		}
	}
	/**
	* Clears the selection of dropdown items.
	*/
	_clearHighlight() {
		this._setHighlightedItem();
	}
	_getDropdownItemFromEvent(event) {
		const selector = this.constructor.selectorItem;
		const path = event.composedPath();
		for (const node of path) if (node instanceof Element && typeof node.matches === "function" && node.matches(selector)) return node;
		return null;
	}
	_setHighlightedItem(item, { scrollIntoView = false } = {}) {
		const constructor = this.constructor;
		const items = this.querySelectorAll(constructor.selectorItem);
		const target = item && !item.hasAttribute("disabled") ? item : null;
		forEach(items, (listItem) => {
			const dropdownItem = listItem;
			dropdownItem.highlighted = dropdownItem === target;
			dropdownItem.removeAttribute("highlighted-next-sibling");
		});
		if (target) {
			const nextSibling = this._getNextDropdownItem(target);
			if (nextSibling) nextSibling.setAttribute("highlighted-next-sibling", "");
			const itemId = target.id;
			if (itemId) this._activeDescendant = itemId;
			if (scrollIntoView) target.scrollIntoView({ block: "nearest" });
		} else this._activeDescendant = void 0;
	}
	_getNextDropdownItem(item) {
		const selector = this.constructor.selectorItem;
		let next = item.nextElementSibling;
		while (next) {
			if (typeof next.matches === "function" && next.matches(selector)) return next;
			next = next.nextElementSibling;
		}
		return null;
	}
	_updateSelectedNextSibling(item) {
		const constructor = this.constructor;
		forEach(this.querySelectorAll(constructor.selectorItem), (listItem) => {
			listItem.removeAttribute("selected-next-sibling");
		});
		if (item) {
			const nextSibling = this._getNextDropdownItem(item);
			if (nextSibling) nextSibling.setAttribute("selected-next-sibling", "");
		}
	}
	_highlightSelectedItem() {
		const constructor = this.constructor;
		const selectedItem = this.querySelector(constructor.selectorItemSelected);
		if (selectedItem && !selectedItem.hasAttribute("disabled")) this._setHighlightedItem(selectedItem, { scrollIntoView: true });
		else this._clearHighlight();
	}
	_navigate(direction) {
		const constructor = this.constructor;
		const items = this.querySelectorAll(constructor.selectorItem);
		if (!items.length) return;
		const highlightedIndex = indexOf(items, this.querySelector(constructor.selectorItemHighlighted));
		let nextIndex = highlightedIndex === -1 ? direction > 0 ? 0 : items.length - 1 : highlightedIndex + direction;
		while (nextIndex >= 0 && nextIndex < items.length && items[nextIndex]?.hasAttribute("disabled")) nextIndex += direction;
		if (nextIndex < 0 || nextIndex >= items.length) return;
		const nextItem = items[nextIndex];
		this._setHighlightedItem(nextItem, { scrollIntoView: true });
	}
	/**
	* @returns The content preceding the trigger button.
	*/
	_renderPrecedingLabel() {}
	/**
	* @returns The main content of the trigger button.
	*/
	_renderLabel() {
		const { label, _selectedItemContent: selectedItemContent } = this;
		return html`
      <span id="trigger-label" class="${"cds"}--list-box__label"
        >${selectedItemContent || label}</span
      >
    `;
	}
	/**
	* @returns The title label.
	*/
	_renderTitleLabel() {
		const { disabled, hideLabel, titleText, _slotTitleTextNode: slotTitleTextNode, _handleSlotchangeLabelText: handleSlotchangeLabelText } = this;
		return html`
      <label
        id="dropdown-label"
        part="title-text"
        class="${classMap({
			[`cds--label`]: true,
			[`cds--label--disabled`]: disabled,
			[`cds--visually-hidden`]: hideLabel
		})}"
        for="trigger-button"
        ?hidden="${!(titleText || slotTitleTextNode && slotTitleTextNode.assignedNodes().length > 0)}">
        <slot name="title-text" @slotchange="${handleSlotchangeLabelText}"
          >${titleText}</slot
        >
      </label>
    `;
	}
	/**
	* @returns The content following the trigger button.
	*/
	_renderFollowingLabel() {}
	/**
	* Handles event to include selected value on the parent form.
	*
	* @param event The event.
	*/
	_handleFormdata(event) {
		const { formData } = event;
		const { disabled, name, value } = this;
		if (!disabled) formData.append(name, value);
	}
	#_value_accessor_storage;
	get value() {
		return this.#_value_accessor_storage;
	}
	set value(value) {
		this.#_value_accessor_storage = value;
	}
	/**
	* The computed aria-label for the toggle button based on open state.
	*/
	get toggleLabel() {
		return (this.open ? this.toggleLabelOpen : this.toggleLabelClosed) || "";
	}
	shouldUpdate(changedProperties) {
		const { selectorItem } = this.constructor;
		if (changedProperties.has("size")) forEach(this.querySelectorAll(selectorItem), (elem) => {
			elem.size = this.size;
		});
		if (changedProperties.has("disabled")) {
			const { disabled } = this;
			forEach(this.querySelectorAll(selectorItem), (elem) => {
				const item = elem;
				if (disabled) {
					if (!item.disabled) item.setAttribute("parent-disabled", "");
					item.disabled = true;
				} else if (item.hasAttribute("parent-disabled")) {
					item.removeAttribute("parent-disabled");
					item.disabled = false;
				}
			});
		}
		if (changedProperties.has("value")) {
			forEach(this.querySelectorAll(selectorItem), (elem) => {
				elem.selected = elem.value === this.value;
			});
			const selectedItem = find(this.querySelectorAll(selectorItem), (elem) => elem.value === this.value);
			if (selectedItem) {
				const range = this.ownerDocument.createRange();
				range.selectNodeContents(selectedItem);
				this._selectedItemContent = range.cloneContents();
			} else this._selectedItemContent = null;
			this._updateSelectedNextSibling(selectedItem);
		}
		return true;
	}
	updated(changedProperties) {
		if (this._hasAILabel) this.setAttribute("ai-label", "");
		else this.removeAttribute("ai-label");
		const label = this.shadowRoot?.querySelector("slot[name='ai-label']");
		if (label) label?.classList.toggle(`cds--slug--revert`, this.querySelector(`cds-ai-label`)?.hasAttribute("revert-active"));
		else this.shadowRoot?.querySelector("slot[name='slug']")?.classList.toggle(`cds--slug--revert`, this.querySelector(`cds-slug`)?.hasAttribute("revert-active"));
		if (this.autoalign && this.open && (changedProperties.has("open") || changedProperties.has("autoalign") && this.autoalign || changedProperties.has("direction") || changedProperties.has("size"))) this._updateAutoAlignPlacement();
		else if (changedProperties.has("autoalign") && !this.autoalign || changedProperties.has("open") && !this.open) {
			this._floatingController.hostDisconnected();
			this._resetFloatingStyles();
		}
	}
	/**
	* Clears Floating UI styles when auto-align is off or the menu closes.
	*/
	_resetFloatingStyles() {
		const menu = this._menuBodyNode;
		if (!menu) return;
		menu.style.removeProperty("left");
		menu.style.removeProperty("top");
		menu.style.removeProperty("position");
		menu.style.removeProperty("width");
		menu.style.removeProperty("visibility");
		menu.removeAttribute("align");
	}
	/**
	* Runs Floating UI placement while auto-align is active.
	*/
	_updateAutoAlignPlacement() {
		if (!this.autoalign || !this.open) return;
		const menu = this._menuBodyNode;
		const trigger = this._triggerButtonNode || this._listBoxNode;
		if (!menu || !trigger) return;
		const alignment = this.direction === "top" ? "top" : "bottom";
		this._floatingController.setPlacement({
			alignment,
			matchWidth: true,
			open: this.open,
			target: menu,
			trigger
		});
	}
	/**
	* Normalizes validation props based on disabled and readOnly states
	*/
	get _normalizedProps() {
		const { disabled, readOnly, invalid, warn } = this;
		return {
			disabled: !readOnly && disabled,
			invalid: !readOnly && !disabled && invalid,
			warn: !readOnly && !invalid && !disabled && warn
		};
	}
	/**
	* The CSS class list for dropdown listbox
	*/
	get _classes() {
		const { size, type, open, autoalign } = this;
		const inline = type === "inline";
		const normalizedProps = this._normalizedProps;
		const selectedItemsCount = this.querySelectorAll(this.constructor.selectorItemSelected).length;
		return classMap({
			[`cds--dropdown`]: true,
			[`cds--list-box`]: true,
			[`cds--list-box--disabled`]: normalizedProps.disabled,
			[`cds--list-box--inline`]: inline,
			[`cds--list-box--expanded`]: open,
			[`cds--list-box--${size}`]: size,
			[`cds--dropdown--invalid`]: normalizedProps.invalid,
			[`cds--dropdown--warn`]: normalizedProps.warn,
			[`cds--dropdown--inline`]: inline,
			[`cds--dropdown--selected`]: selectedItemsCount > 0,
			[`cds--list-box__wrapper--decorator`]: this._hasAILabel,
			[`cds--autoalign`]: autoalign
		});
	}
	render() {
		const { ariaLabel, _classes: classes, disabled, helperText, invalidText, open, toggleLabelClosed, toggleLabelOpen, type, warnText, _activeDescendant: activeDescendant, _shouldTriggerBeFocusable: shouldTriggerBeFocusable, _handleClickInner: handleClickInner, _handleKeydownInner: handleKeydownInner, _handleKeypressInner: handleKeypressInner, _handleMouseleaveInner: handleMouseleaveInner, _handleMouseoverInner: handleMouseoverInner, _handleSlotchangeHelperText: handleSlotchangeHelperText, _handleAILabelSlotChange: handleAILabelSlotChange, _slotHelperTextNode: slotHelperTextNode } = this;
		const inline = type === "inline";
		const normalizedProps = this._normalizedProps;
		let activeDescendantFallback;
		if (open && !activeDescendant) {
			const constructor = this.constructor;
			activeDescendantFallback = this.querySelectorAll(constructor.selectorItem)[0]?.id;
		}
		const helperClasses = classMap({
			[`cds--form__helper-text`]: true,
			[`cds--form__helper-text--disabled`]: normalizedProps.disabled
		});
		const iconContainerClasses = classMap({
			[`cds--list-box__menu-icon`]: true,
			[`cds--list-box__menu-icon--open`]: open
		});
		const toggleLabel = (open ? toggleLabelOpen : toggleLabelClosed) || "";
		const hasHelperText = helperText || invalidText || warnText || slotHelperTextNode && slotHelperTextNode.assignedNodes().length > 0;
		const validityIcon = !normalizedProps.invalid ? void 0 : iconLoader(WarningFilled16, {
			class: `cds--list-box__invalid-icon`,
			"aria-label": toggleLabel
		});
		const warningIcon = !normalizedProps.warn ? void 0 : iconLoader(WarningAltFilled16, {
			class: `cds--list-box__invalid-icon cds--list-box__invalid-icon--warning`,
			"aria-label": toggleLabel
		});
		const helperMessage = normalizedProps.invalid ? invalidText : normalizedProps.warn ? warnText : helperText;
		const menuBody = html`
      <div
        aria-labelledby="${ifDefined(ariaLabel ? void 0 : "dropdown-label")}"
        aria-label="${ifDefined(ariaLabel ? ariaLabel : void 0)}"
        id="menu-body"
        part="menu-body"
        class="${"cds"}--list-box__menu"
        role="listbox"
        tabindex="-1"
        ?hidden=${!open}
        @mouseover=${handleMouseoverInner}
        @mouseleave=${handleMouseleaveInner}>
        <slot></slot>
      </div>
    `;
		return html`
      ${this._renderTitleLabel()}
      <div
        class="${classes}"
        ?data-invalid=${normalizedProps.invalid}
        @click=${handleClickInner}
        @keydown=${handleKeydownInner}
        @keypress=${handleKeypressInner}>
        ${validityIcon}${warningIcon}
        <div
          id="${ifDefined(!shouldTriggerBeFocusable ? void 0 : "trigger-button")}"
          class="${"cds"}--list-box__field"
          part="trigger-button"
          tabindex="${ifDefined(!shouldTriggerBeFocusable ? void 0 : disabled ? void 0 : "0")}"
          role="${ifDefined(!shouldTriggerBeFocusable ? void 0 : "combobox")}"
          aria-label="${ifDefined(ariaLabel ? ariaLabel : void 0)}"
          aria-labelledby="${ifDefined(!shouldTriggerBeFocusable ? void 0 : "dropdown-label")}"
          aria-expanded="${ifDefined(!shouldTriggerBeFocusable ? void 0 : String(open))}"
          aria-haspopup="${ifDefined(!shouldTriggerBeFocusable ? void 0 : "listbox")}"
          aria-controls="${ifDefined(!shouldTriggerBeFocusable ? void 0 : "menu-body")}"
          aria-activedescendant="${ifDefined(!shouldTriggerBeFocusable ? void 0 : open ? activeDescendant ?? activeDescendantFallback : "")}">
          ${this._renderPrecedingLabel()}${this._renderLabel()}${this._renderFollowingLabel()}
          <div id="trigger-caret" class="${iconContainerClasses}">
            ${iconLoader(ChevronDown16, { "aria-label": toggleLabel })}
          </div>
        </div>
        ${this.isFluid && (normalizedProps.invalid || normalizedProps.warn) ? html`<hr class="${"cds"}--list-box__divider" />` : null}
        <slot name="ai-label" @slotchange=${handleAILabelSlotChange}></slot>
        <slot name="slug" @slotchange=${handleAILabelSlotChange}></slot>
        ${menuBody}
      </div>
      <div
        part="helper-text"
        class="${helperClasses}"
        ?hidden="${inline && !this.warn && !normalizedProps.invalid || !hasHelperText}">
        <slot name="helper-text" @slotchange="${handleSlotchangeHelperText}"
          >${helperMessage}</slot
        >
      </div>
    `;
	}
	static {
		this.TRIGGER_KEYS = new Set([" ", "Enter"]);
	}
	/**
	* A selector that will return highlighted items.
	*/
	static get selectorItemHighlighted() {
		return `cds-dropdown-item[highlighted]`;
	}
	/**
	* A selector that will return dropdown items.
	*/
	static get selectorItem() {
		return `cds-dropdown-item`;
	}
	/**
	* A selector that will return selected items.
	*/
	static get selectorItemSelected() {
		return `cds-dropdown-item[selected]`;
	}
	/**
	* The name of the custom event fired before a dropdown item is selected upon a user gesture.
	* Cancellation of this event stops changing the user-initiated selection.
	*/
	static get eventBeforeSelect() {
		return `cds-dropdown-beingselected`;
	}
	/**
	* The name of the custom event fired after a a dropdown item is selected upon a user gesture.
	*/
	static get eventSelect() {
		return `cds-dropdown-selected`;
	}
	/**
	* The name of the custom event fired before this dropdown item is being toggled upon a user gesture.
	* Cancellation of this event stops the user-initiated action of toggling this dropdown item.
	*/
	static get eventBeforeToggle() {
		return `cds-dropdown-beingtoggled`;
	}
	/**
	* The name of the custom event fired after this dropdown item is toggled upon a user gesture.
	*/
	static get eventToggle() {
		return `cds-dropdown-toggled`;
	}
	/**
	* A selector that will return the slug item.
	*
	* remove in v12
	*/
	static get slugItem() {
		return `cds-slug`;
	}
	/**
	* A selector that will return the AI Label item.
	*/
	static get aiLabelItem() {
		return `cds-ai-label`;
	}
	static {
		this.shadowRootOptions = {
			...LitElement.shadowRootOptions,
			delegatesFocus: true
		};
	}
	static {
		this.styles = dropdown_default$1;
	}
	/**
	* @returns A action for dropdown for the given key symbol.
	*/
	static getAction(key) {
		if (key === "Escape") return "closing";
		if (key in NAVIGATION_DIRECTION) return "navigating";
		if (this.TRIGGER_KEYS.has(key)) return "triggering";
		return "none";
	}
};
__decorate([state()], CDSDropdown.prototype, "_activeDescendant", void 0);
__decorate([query(`.cds--list-box`)], CDSDropdown.prototype, "_listBoxNode", void 0);
__decorate([query("#menu-body")], CDSDropdown.prototype, "_menuBodyNode", void 0);
__decorate([query("#trigger-button")], CDSDropdown.prototype, "_triggerButtonNode", void 0);
__decorate([query("slot[name=\"helper-text\"]")], CDSDropdown.prototype, "_slotHelperTextNode", void 0);
__decorate([query("slot[name=\"title-text\"]")], CDSDropdown.prototype, "_slotTitleTextNode", void 0);
__decorate([HostListener("focusout")], CDSDropdown.prototype, "_handleFocusOut", null);
__decorate([property({
	type: String,
	attribute: "aria-label"
})], CDSDropdown.prototype, "ariaLabel", void 0);
__decorate([property({
	type: String,
	reflect: true
})], CDSDropdown.prototype, "direction", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSDropdown.prototype, "autoalign", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSDropdown.prototype, "disabled", void 0);
__decorate([property({ attribute: "helper-text" })], CDSDropdown.prototype, "helperText", void 0);
__decorate([property({
	type: Boolean,
	reflect: true,
	attribute: "hide-label"
})], CDSDropdown.prototype, "hideLabel", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSDropdown.prototype, "invalid", void 0);
__decorate([property({ attribute: "invalid-text" })], CDSDropdown.prototype, "invalidText", void 0);
__decorate([property({ attribute: "title-text" })], CDSDropdown.prototype, "titleText", void 0);
__decorate([property()], CDSDropdown.prototype, "name", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSDropdown.prototype, "open", void 0);
__decorate([property({
	type: Boolean,
	reflect: true,
	attribute: "read-only"
})], CDSDropdown.prototype, "readOnly", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSDropdown.prototype, "required", void 0);
__decorate([property({ type: Boolean })], CDSDropdown.prototype, "isFluid", void 0);
__decorate([property({ attribute: "required-validity-message" })], CDSDropdown.prototype, "requiredValidityMessage", void 0);
__decorate([property({ reflect: true })], CDSDropdown.prototype, "size", void 0);
__decorate([property({ attribute: "toggle-label-closed" })], CDSDropdown.prototype, "toggleLabelClosed", void 0);
__decorate([property({ attribute: "toggle-label-open" })], CDSDropdown.prototype, "toggleLabelOpen", void 0);
__decorate([property({ attribute: "label" })], CDSDropdown.prototype, "label", void 0);
__decorate([property({ reflect: true })], CDSDropdown.prototype, "type", void 0);
__decorate([property({ attribute: "validity-message" })], CDSDropdown.prototype, "validityMessage", void 0);
__decorate([property({ reflect: true })], CDSDropdown.prototype, "value", null);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSDropdown.prototype, "warn", void 0);
__decorate([property({ attribute: "warn-text" })], CDSDropdown.prototype, "warnText", void 0);
CDSDropdown = __decorate([carbonElement(`cds-dropdown`)], CDSDropdown);
var dropdown_default = CDSDropdown;
//#endregion
export { DROPDOWN_DIRECTION, DROPDOWN_KEYBOARD_ACTION, DROPDOWN_SIZE, DROPDOWN_TYPE, NAVIGATION_DIRECTION, dropdown_default as default };

//# sourceMappingURL=dropdown.js.map