/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import '../../../focus/md-focus-ring.js';
import '../../../labs/item/item.js';
import '../../../ripple/ripple.js';
import {html, LitElement, nothing} from 'lit';
import {
property,
query,
queryAssignedElements,
queryAssignedNodes,
} from 'lit/decorators.js';
import {ClassInfo, classMap} from 'lit/directives/class-map.js';
import {ARIAMixinStrict} from '../../../internal/aria/aria.js';
import {mixinDelegatesAria} from '../../../internal/aria/delegate.js';
import {MenuItem} from '../../../menu/internal/controllers/menuItemController.js';
import {SelectOptionController} from './selectOptionController.js';
/**
* The interface specific to a Select Option
*/
interface SelectOptionSelf {
/**
* The form value associated with the Select Option. (Note: the visual portion
* of the SelectOption is the headline defined in ListItem)
*/
value: string;
/**
* Whether or not the SelectOption is selected.
*/
selected: boolean;
/**
* The text to display in the select when selected. Defaults to the
* textContent of the Element slotted into the headline.
*/
displayText: string;
}
/**
* The interface to implement for a select option. Additionally, the element
* must have `md-list-item` and `md-menu-item` attributes on the host.
*/
export type SelectOption = SelectOptionSelf & MenuItem;
// Separate variable needed for closure.
const selectOptionBaseClass = mixinDelegatesAria(LitElement);
/**
* @fires close-menu {CustomEvent<{initiator: SelectOption, reason: Reason, itemPath: SelectOption[]}>}
* Closes the encapsulating menu on closable interaction. --bubbles --composed
* @fires request-selection {Event} Requests the parent md-select to select this
* element (and deselect others if single-selection) when `selected` changed to
* `true`. --bubbles --composed
* @fires request-deselection {Event} Requests the parent md-select to deselect
* this element when `selected` changed to `false`. --bubbles --composed
*/
export class SelectOptionEl
extends selectOptionBaseClass
implements SelectOption
{
/** @nocollapse */
static override shadowRootOptions = {
...LitElement.shadowRootOptions,
delegatesFocus: true,
};
/**
* Disables the item and makes it non-selectable and non-interactive.
*/
@property({type: Boolean, reflect: true}) disabled = false;
/**
* READONLY: self-identifies as a menu item and sets its identifying attribute
*/
@property({type: Boolean, attribute: 'md-menu-item', reflect: true})
isMenuItem = true;
/**
* Sets the item in the selected visual state when a submenu is opened.
*/
@property({type: Boolean}) selected = false;
/**
* Form value of the option.
*/
@property() value = '';
@query('.list-item') protected readonly listItemRoot!: HTMLElement | null;
@queryAssignedElements({slot: 'headline'})
protected readonly headlineElements!: HTMLElement[];
@queryAssignedElements({slot: 'supporting-text'})
protected readonly supportingTextElements!: HTMLElement[];
@queryAssignedNodes({slot: ''})
protected readonly defaultElements!: Element[];
type = 'option' as const;
/**
* The text that is selectable via typeahead. If not set, defaults to the
* innerText of the item slotted into the `"headline"` slot.
*/
get typeaheadText() {
return this.selectOptionController.typeaheadText;
}
@property({attribute: 'typeahead-text'})
set typeaheadText(text: string) {
this.selectOptionController.setTypeaheadText(text);
}
/**
* The text that is displayed in the select field when selected. If not set,
* defaults to the textContent of the item slotted into the `"headline"` slot.
*/
get displayText() {
return this.selectOptionController.displayText;
}
@property({attribute: 'display-text'})
set displayText(text: string) {
this.selectOptionController.setDisplayText(text);
}
private readonly selectOptionController = new SelectOptionController(this, {
getHeadlineElements: () => {
return this.headlineElements;
},
getSupportingTextElements: () => {
return this.supportingTextElements;
},
getDefaultElements: () => {
return this.defaultElements;
},
getInteractiveElement: () => this.listItemRoot,
});
protected override render() {
return this.renderListItem(html`