diff --git a/menu/internal/controllers/menuItemController.ts b/menu/internal/controllers/menuItemController.ts index 900b521df2..2587166e03 100644 --- a/menu/internal/controllers/menuItemController.ts +++ b/menu/internal/controllers/menuItemController.ts @@ -72,6 +72,16 @@ export interface MenuItemControllerConfig { */ getHeadlineElements: () => HTMLElement[]; + /** + * A function that returns the supporting-text element of the menu item. + */ + getSupportingTextElements: () => HTMLElement[]; + + /** + * A function that returns the default slot / misc content. + */ + getDefaultElements: () => Node[]; + /** * The HTML Element that accepts user interactions like click. Used for * occasions like programmatically clicking anchor tags when `Enter` is @@ -87,6 +97,8 @@ export interface MenuItemControllerConfig { export class MenuItemController implements ReactiveController { private internalTypeaheadText: string | null = null; private readonly getHeadlineElements: MenuItemControllerConfig['getHeadlineElements']; + private readonly getSupportingTextElements: MenuItemControllerConfig['getSupportingTextElements']; + private readonly getDefaultElements: MenuItemControllerConfig['getDefaultElements']; private readonly getInteractiveElement: MenuItemControllerConfig['getInteractiveElement']; /** @@ -97,15 +109,18 @@ export class MenuItemController implements ReactiveController { private readonly host: ReactiveControllerHost & MenuItem, config: MenuItemControllerConfig, ) { - const {getHeadlineElements, getInteractiveElement} = config; - this.getHeadlineElements = getHeadlineElements; - this.getInteractiveElement = getInteractiveElement; + this.getHeadlineElements = config.getHeadlineElements; + this.getSupportingTextElements = config.getSupportingTextElements; + this.getDefaultElements = config.getDefaultElements; + this.getInteractiveElement = config.getInteractiveElement; this.host.addController(this); } /** * The text that is selectable via typeahead. If not set, defaults to the - * innerText of the item slotted into the `"headline"` slot. + * innerText of the item slotted into the `"headline"` slot, and if there are + * no slotted elements into headline, then it checks the _default_ slot, and + * then the `"supporting-text"` slot if nothing is in _default_. */ get typeaheadText() { if (this.internalTypeaheadText !== null) { @@ -121,6 +136,28 @@ export class MenuItemController implements ReactiveController { } }); + // If there are no headline elements, check the default slot's text content + if (textParts.length === 0) { + this.getDefaultElements().forEach((defaultElement) => { + if (defaultElement.textContent && defaultElement.textContent.trim()) { + textParts.push(defaultElement.textContent.trim()); + } + }); + } + + // If there are no headline nor default slot elements, check the + //supporting-text slot's text content + if (textParts.length === 0) { + this.getSupportingTextElements().forEach((supportingTextElement) => { + if ( + supportingTextElement.textContent && + supportingTextElement.textContent.trim() + ) { + textParts.push(supportingTextElement.textContent.trim()); + } + }); + } + return textParts.join(' '); } diff --git a/menu/internal/menuitem/menu-item.ts b/menu/internal/menuitem/menu-item.ts index 9aaf020a19..68d075b096 100644 --- a/menu/internal/menuitem/menu-item.ts +++ b/menu/internal/menuitem/menu-item.ts @@ -9,7 +9,12 @@ import '../../../labs/item/item.js'; import '../../../ripple/ripple.js'; import {html, LitElement, nothing, TemplateResult} from 'lit'; -import {property, query, queryAssignedElements} from 'lit/decorators.js'; +import { + property, + query, + queryAssignedElements, + queryAssignedNodes, +} from 'lit/decorators.js'; import {ClassInfo, classMap} from 'lit/directives/class-map.js'; import {literal, html as staticHtml, StaticValue} from 'lit/static-html.js'; @@ -71,6 +76,10 @@ export class MenuItemEl extends LitElement implements MenuItem { @queryAssignedElements({slot: 'headline'}) protected readonly headlineElements!: HTMLElement[]; + @queryAssignedElements({slot: 'supporting-text'}) + protected readonly supportingTextElements!: HTMLElement[]; + @queryAssignedNodes({slot: ''}) + protected readonly defaultElements!: Node[]; /** * The text that is selectable via typeahead. If not set, defaults to the @@ -89,6 +98,12 @@ export class MenuItemEl extends LitElement implements MenuItem { getHeadlineElements: () => { return this.headlineElements; }, + getSupportingTextElements: () => { + return this.supportingTextElements; + }, + getDefaultElements: () => { + return this.defaultElements; + }, getInteractiveElement: () => this.listItemRoot, }); diff --git a/select/internal/selectoption/select-option.ts b/select/internal/selectoption/select-option.ts index b952c17dbc..7a8ba586f8 100644 --- a/select/internal/selectoption/select-option.ts +++ b/select/internal/selectoption/select-option.ts @@ -9,7 +9,12 @@ import '../../../labs/item/item.js'; import '../../../ripple/ripple.js'; import {html, LitElement, nothing} from 'lit'; -import {property, query, queryAssignedElements} from 'lit/decorators.js'; +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'; @@ -61,6 +66,10 @@ export class SelectOptionEl extends LitElement implements SelectOption { @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; @@ -94,6 +103,12 @@ export class SelectOptionEl extends LitElement implements SelectOption { getHeadlineElements: () => { return this.headlineElements; }, + getSupportingTextElements: () => { + return this.supportingTextElements; + }, + getDefaultElements: () => { + return this.defaultElements; + }, getInteractiveElement: () => this.listItemRoot, }); diff --git a/select/internal/selectoption/selectOptionController.ts b/select/internal/selectoption/selectOptionController.ts index 2131570cbd..a62f126f19 100644 --- a/select/internal/selectoption/selectOptionController.ts +++ b/select/internal/selectoption/selectOptionController.ts @@ -71,7 +71,6 @@ export type SelectOptionConfig = MenuItemControllerConfig; */ export class SelectOptionController implements ReactiveController { private readonly menuItemController: MenuItemController; - private readonly getHeadlineElements: SelectOptionConfig['getHeadlineElements']; private internalDisplayText: string | null = null; private lastSelected = this.host.selected; private firstUpdate = true; @@ -85,7 +84,9 @@ export class SelectOptionController implements ReactiveController { /** * The text that is selectable via typeahead. If not set, defaults to the - * innerText of the item slotted into the `"headline"` slot. + * innerText of the item slotted into the `"headline"` slot, and if there are + * no slotted elements into headline, then it checks the _default_ slot, and + * then the `"supporting-text"` slot if nothing is in _default_. */ get typeaheadText() { return this.menuItemController.typeaheadText; @@ -97,23 +98,17 @@ export class SelectOptionController implements ReactiveController { /** * 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. + * defaults to the textContent of the item slotted into the `"headline"` slot, + * and if there are no slotted elements into headline, then it checks the + * _default_ slot, and then the `"supporting-text"` slot if nothing is in + * _default_. */ get displayText() { if (this.internalDisplayText !== null) { return this.internalDisplayText; } - const headlineElements = this.getHeadlineElements(); - - const textParts: string[] = []; - headlineElements.forEach((headlineElement) => { - if (headlineElement.textContent && headlineElement.textContent.trim()) { - textParts.push(headlineElement.textContent.trim()); - } - }); - - return textParts.join(' '); + return this.menuItemController.typeaheadText; } setDisplayText(text: string) { @@ -129,7 +124,6 @@ export class SelectOptionController implements ReactiveController { config: SelectOptionConfig, ) { this.menuItemController = new MenuItemController(host, config); - this.getHeadlineElements = config.getHeadlineElements; host.addController(this); }