mirror of
https://github.com/material-components/material-web.git
synced 2024-09-11 13:46:10 +03:00
refactor(menu)!: pull logic out of menuitem into a controller & change enum vals
BREAKING CHANGE: Several enums in menu had their values changed from SCREAM_CASE to kebab-case to follow style guide. They are NAVIGABLE_KEYS -> NavigableKey, SELECTION_KEY -> SelectionKey, CLOSE_REASON -> CloseReason, KEYDOWN_CLOSE_KEY -> KeydownCloseKey PiperOrigin-RevId: 567727434
This commit is contained in:
parent
63b01425e7
commit
1217b62ef2
@ -13,7 +13,7 @@ import '@material/web/divider/divider.js';
|
||||
import '@material/web/icon/icon.js';
|
||||
|
||||
import {MaterialStoryInit} from './material-collection.js';
|
||||
import {CloseMenuEvent} from '@material/web/menu/internal/shared.js';
|
||||
import {CloseMenuEvent} from '@material/web/menu/internal/controllers/shared.js';
|
||||
import {Corner, FocusState, MdMenu, MenuItem} from '@material/web/menu/menu.js';
|
||||
import {css, html} from 'lit';
|
||||
|
||||
|
183
menu/internal/controllers/menuItemController.ts
Normal file
183
menu/internal/controllers/menuItemController.ts
Normal file
@ -0,0 +1,183 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2023 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {ReactiveController, ReactiveControllerHost} from 'lit';
|
||||
|
||||
import {CloseReason, createDefaultCloseMenuEvent, isClosableKey} from './shared.js';
|
||||
|
||||
/**
|
||||
* Interface specific to menu item and not HTMLElement.
|
||||
*
|
||||
* NOTE: required properties are expected to be reactive.
|
||||
*/
|
||||
interface MenuItemAdditions {
|
||||
/**
|
||||
* Whether or not the item is in the disabled state.
|
||||
*/
|
||||
disabled: boolean;
|
||||
/**
|
||||
* The text of the item that will be used for typeahead. If not set, defaults
|
||||
* to the textContent of the element slotted into the headline.
|
||||
*/
|
||||
typeaheadText: string;
|
||||
/**
|
||||
* Whether or not the item is in the selected visual state.
|
||||
*/
|
||||
selected: boolean;
|
||||
/**
|
||||
* Sets the behavior and role of the menu item, defaults to "menuitem".
|
||||
*/
|
||||
type: MenuItemType;
|
||||
/**
|
||||
* Whether it should keep the menu open after click.
|
||||
*/
|
||||
keepOpen?: boolean;
|
||||
/**
|
||||
* Sets the underlying `HTMLAnchorElement`'s `href` resource attribute.
|
||||
*/
|
||||
href?: string;
|
||||
/**
|
||||
* Focuses the item.
|
||||
*/
|
||||
focus: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface of every menu item interactive with a menu. All menu items
|
||||
* should implement this interface to be compatible with md-menu. Additionally
|
||||
* it should have the `md-menu-item` attribute set.
|
||||
*
|
||||
* NOTE, the required properties are recommended to be reactive properties.
|
||||
*/
|
||||
export type MenuItem = MenuItemAdditions&HTMLElement;
|
||||
|
||||
/**
|
||||
* Supported behaviors for a menu item.
|
||||
*/
|
||||
export type MenuItemType = 'menuitem'|'option'|'button'|'link';
|
||||
|
||||
/**
|
||||
* The options used to inialize MenuItemController.
|
||||
*/
|
||||
export interface MenuItemControllerConfig {
|
||||
/**
|
||||
* A function that returns the headline element of the menu item.
|
||||
*/
|
||||
getHeadlineElements: () => HTMLElement[];
|
||||
}
|
||||
|
||||
/**
|
||||
* A controller that provides most functionality of an element that implements
|
||||
* the MenuItem interface.
|
||||
*/
|
||||
export class MenuItemController implements ReactiveController {
|
||||
private internalTypeaheadText: string|null = null;
|
||||
private readonly getHeadlineElements:
|
||||
MenuItemControllerConfig['getHeadlineElements'];
|
||||
|
||||
/**
|
||||
* @param host The MenuItem in which to attach this controller to.
|
||||
* @param config The object that configures this controller's behavior.
|
||||
*/
|
||||
constructor(
|
||||
private readonly host: ReactiveControllerHost&MenuItem,
|
||||
config: MenuItemControllerConfig) {
|
||||
const {
|
||||
getHeadlineElements,
|
||||
} = config;
|
||||
this.getHeadlineElements = getHeadlineElements;
|
||||
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.
|
||||
*/
|
||||
get typeaheadText() {
|
||||
if (this.internalTypeaheadText !== null) {
|
||||
return this.internalTypeaheadText;
|
||||
}
|
||||
|
||||
const headlineElements = this.getHeadlineElements();
|
||||
|
||||
let text = '';
|
||||
headlineElements.forEach((headlineElement) => {
|
||||
if (headlineElement.textContent && headlineElement.textContent.trim()) {
|
||||
text += ` ${headlineElement.textContent.trim()}`;
|
||||
}
|
||||
});
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* The recommended tag name to render as the list item.
|
||||
*/
|
||||
get tagName() {
|
||||
const type = this.host.type;
|
||||
|
||||
switch (type) {
|
||||
case 'link':
|
||||
return 'a' as const;
|
||||
case 'button':
|
||||
return 'button' as const;
|
||||
default:
|
||||
case 'menuitem':
|
||||
case 'option':
|
||||
return 'li' as const;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The recommended role of the menu item.
|
||||
*/
|
||||
get role() {
|
||||
return this.host.type === 'option' ? 'option' : 'menuitem';
|
||||
}
|
||||
|
||||
hostConnected() {
|
||||
this.host.toggleAttribute('md-menu-item', true);
|
||||
}
|
||||
|
||||
hostUpdate() {
|
||||
if (this.host.href) {
|
||||
this.host.type = 'link';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind this click listener to the interactive element. Handles closing the
|
||||
* menu.
|
||||
*/
|
||||
onClick = () => {
|
||||
if (this.host.keepOpen) return;
|
||||
|
||||
this.host.dispatchEvent(createDefaultCloseMenuEvent(
|
||||
this.host, {kind: CloseReason.CLICK_SELECTION}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Bind this click listener to the interactive element. Handles closing the
|
||||
* menu.
|
||||
*/
|
||||
onKeydown = (event: KeyboardEvent) => {
|
||||
if (this.host.keepOpen || event.defaultPrevented) return;
|
||||
const keyCode = event.code;
|
||||
|
||||
if (!event.defaultPrevented && isClosableKey(keyCode)) {
|
||||
event.preventDefault();
|
||||
this.host.dispatchEvent(createDefaultCloseMenuEvent(
|
||||
this.host, {kind: CloseReason.KEYDOWN, key: keyCode}));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Use to set the typeaheadText when it changes.
|
||||
*/
|
||||
setTypeaheadText(text: string) {
|
||||
this.internalTypeaheadText = text;
|
||||
}
|
||||
}
|
@ -4,39 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface specific to menu item and not HTMLElement.
|
||||
*/
|
||||
interface MenuItemAdditions {
|
||||
/**
|
||||
* Whether or not the item is in the disabled state.
|
||||
*/
|
||||
disabled: boolean;
|
||||
/**
|
||||
* The text of the item that will be used for typeahead. If not set, defaults
|
||||
* to the textContent of the element slotted into the headline.
|
||||
*/
|
||||
typeaheadText: string;
|
||||
/**
|
||||
* Whether it should keep the menu open after click.
|
||||
*/
|
||||
keepOpen: boolean;
|
||||
/**
|
||||
* Whether or not the item is in the selected visual state.
|
||||
*/
|
||||
selected: boolean;
|
||||
/**
|
||||
* Focuses the item.
|
||||
*/
|
||||
focus: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface of every menu item interactive with a menu. All menu items
|
||||
* should implement this interface to be compatible with md-menu. Additionally
|
||||
* they should have both the `md-menu-item` and `md-list-item` attributes set.
|
||||
*/
|
||||
export type MenuItem = MenuItemAdditions&HTMLElement;
|
||||
import {MenuItem} from './menuItemController.js';
|
||||
|
||||
/**
|
||||
* The reason the `close-menu` event was dispatched.
|
||||
@ -50,7 +18,7 @@ export interface Reason {
|
||||
* because an item was selected via user click.
|
||||
*/
|
||||
export interface ClickReason extends Reason {
|
||||
kind: typeof CLOSE_REASON.CLICK_SELECTION;
|
||||
kind: typeof CloseReason.CLICK_SELECTION;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,7 +27,7 @@ export interface ClickReason extends Reason {
|
||||
* `md-menu-item` are, Space, Enter or Escape.
|
||||
*/
|
||||
export interface KeydownReason extends Reason {
|
||||
kind: typeof CLOSE_REASON.KEYDOWN;
|
||||
kind: typeof CloseReason.KEYDOWN;
|
||||
key: string;
|
||||
}
|
||||
|
||||
@ -141,7 +109,8 @@ export type ActivateTypeaheadEvent =
|
||||
/**
|
||||
* Keys that are used to navigate menus.
|
||||
*/
|
||||
export const NAVIGABLE_KEY = {
|
||||
// tslint:disable-next-line:enforce-name-casing We are mimicking enum style
|
||||
export const NavigableKey = {
|
||||
UP: 'ArrowUp',
|
||||
DOWN: 'ArrowDown',
|
||||
RIGHT: 'ArrowRight',
|
||||
@ -151,7 +120,8 @@ export const NAVIGABLE_KEY = {
|
||||
/**
|
||||
* Keys that are used for selection in menus.
|
||||
*/
|
||||
export const SELECTION_KEY = {
|
||||
// tslint:disable-next-line:enforce-name-casing We are mimicking enum style
|
||||
export const SelectionKey = {
|
||||
SPACE: 'Space',
|
||||
ENTER: 'Enter',
|
||||
} as const;
|
||||
@ -159,18 +129,20 @@ export const SELECTION_KEY = {
|
||||
/**
|
||||
* Default close `Reason` kind values.
|
||||
*/
|
||||
export const CLOSE_REASON = {
|
||||
CLICK_SELECTION: 'CLICK_SELECTION',
|
||||
KEYDOWN: 'KEYDOWN',
|
||||
// tslint:disable-next-line:enforce-name-casing We are mimicking enum style
|
||||
export const CloseReason = {
|
||||
CLICK_SELECTION: 'click-selection',
|
||||
KEYDOWN: 'keydown',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Keys that can close menus.
|
||||
*/
|
||||
export const KEYDOWN_CLOSE_KEYS = {
|
||||
// tslint:disable-next-line:enforce-name-casing We are mimicking enum style
|
||||
export const KeydownCloseKey = {
|
||||
ESCAPE: 'Escape',
|
||||
SPACE: SELECTION_KEY.SPACE,
|
||||
ENTER: SELECTION_KEY.ENTER,
|
||||
SPACE: SelectionKey.SPACE,
|
||||
ENTER: SelectionKey.ENTER,
|
||||
} as const;
|
||||
|
||||
type Values<T> = T[keyof T];
|
||||
@ -184,8 +156,8 @@ type Values<T> = T[keyof T];
|
||||
* menu.
|
||||
*/
|
||||
export function isClosableKey(code: string):
|
||||
code is Values<typeof KEYDOWN_CLOSE_KEYS> {
|
||||
return Object.values(KEYDOWN_CLOSE_KEYS).some(value => (value === code));
|
||||
code is Values<typeof KeydownCloseKey> {
|
||||
return Object.values(KeydownCloseKey).some(value => (value === code));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -197,8 +169,8 @@ export function isClosableKey(code: string):
|
||||
* menu item.
|
||||
*/
|
||||
export function isSelectableKey(code: string):
|
||||
code is Values<typeof SELECTION_KEY> {
|
||||
return Object.values(SELECTION_KEY).some(value => (value === code));
|
||||
code is Values<typeof SelectionKey> {
|
||||
return Object.values(SelectionKey).some(value => (value === code));
|
||||
}
|
||||
|
||||
/**
|
@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {MenuItem} from './shared.js';
|
||||
import {MenuItem} from './menuItemController.js';
|
||||
|
||||
/**
|
||||
* The options that are passed to the typeahead controller.
|
@ -15,13 +15,14 @@ import {styleMap} from 'lit/directives/style-map.js';
|
||||
import {polyfillElementInternalsAria, setupHostAria} from '../../internal/aria/aria.js';
|
||||
import {createAnimationSignal, EASING} from '../../internal/motion/animation.js';
|
||||
|
||||
import {MenuItem} from './controllers/menuItemController.js';
|
||||
import {ActivateTypeaheadEvent, DeactivateTypeaheadEvent, FocusState, isClosableKey, isElementInSubtree} from './controllers/shared.js';
|
||||
import {Corner, SurfacePositionController, SurfacePositionTarget} from './controllers/surfacePositionController.js';
|
||||
import {TypeaheadController} from './controllers/typeaheadController.js';
|
||||
import {ListController, NavigableKeys} from './list-controller.js';
|
||||
import {getActiveItem, getFirstActivatableItem, getLastActivatableItem} from './list-navigation-helpers.js';
|
||||
import {ActivateTypeaheadEvent, DeactivateTypeaheadEvent, FocusState, isClosableKey, isElementInSubtree, MenuItem} from './shared.js';
|
||||
import {Corner, SurfacePositionController, SurfacePositionTarget} from './surfacePositionController.js';
|
||||
import {TypeaheadController} from './typeaheadController.js';
|
||||
|
||||
export {Corner} from './surfacePositionController.js';
|
||||
export {Corner} from './controllers/surfacePositionController.js';
|
||||
|
||||
/**
|
||||
* The default value for the typeahead buffer time in Milliseconds.
|
||||
|
@ -8,19 +8,14 @@ import '../../../ripple/ripple.js';
|
||||
import '../../../focus/md-focus-ring.js';
|
||||
import '../../../item/item.js';
|
||||
|
||||
import {html, LitElement, nothing, PropertyValues, TemplateResult} from 'lit';
|
||||
import {html, LitElement, nothing, TemplateResult} from 'lit';
|
||||
import {property, query, queryAssignedElements} from 'lit/decorators.js';
|
||||
import {ClassInfo, classMap} from 'lit/directives/class-map.js';
|
||||
import {html as staticHtml, literal, StaticValue} from 'lit/static-html.js';
|
||||
|
||||
import {ARIAMixinStrict} from '../../../internal/aria/aria.js';
|
||||
import {requestUpdateOnAriaChange} from '../../../internal/aria/delegate.js';
|
||||
import {CLOSE_REASON, createDefaultCloseMenuEvent, isClosableKey, MenuItem} from '../shared.js';
|
||||
|
||||
/**
|
||||
* Supported behaviors for a menu item.
|
||||
*/
|
||||
export type MenuItemType = 'menuitem'|'option'|'button'|'link';
|
||||
import {MenuItem, MenuItemController, MenuItemType} from '../controllers/menuItemController.js';
|
||||
|
||||
/**
|
||||
* @fires close-menu {CloseMenuEvent}
|
||||
@ -57,12 +52,6 @@ export class MenuItemEl extends LitElement implements MenuItem {
|
||||
*/
|
||||
@property() target: '_blank'|'_parent'|'_self'|'_top'|'' = '';
|
||||
|
||||
/**
|
||||
* READONLY: self-identifies as a menu item and sets its identifying attribute
|
||||
*/
|
||||
@property({type: Boolean, attribute: 'md-menu-item', reflect: true})
|
||||
isMenuItem = true;
|
||||
|
||||
/**
|
||||
* Keeps the menu open if clicked or keyboard selected.
|
||||
*/
|
||||
@ -83,35 +72,18 @@ export class MenuItemEl extends LitElement implements MenuItem {
|
||||
* innerText of the item slotted into the `"headline"` slot.
|
||||
*/
|
||||
get typeaheadText() {
|
||||
if (this.internalTypeaheadText !== null) {
|
||||
return this.internalTypeaheadText;
|
||||
}
|
||||
|
||||
const headlineElements = this.headlineElements;
|
||||
|
||||
let text = '';
|
||||
headlineElements.forEach((headlineElement) => {
|
||||
if (headlineElement.textContent && headlineElement.textContent.trim()) {
|
||||
text += ` ${headlineElement.textContent.trim()}`;
|
||||
}
|
||||
});
|
||||
|
||||
return '';
|
||||
return this.menuItemController.typeaheadText;
|
||||
}
|
||||
|
||||
set typeaheadText(text: string) {
|
||||
this.internalTypeaheadText = text;
|
||||
this.menuItemController.setTypeaheadText(text);
|
||||
}
|
||||
|
||||
private internalTypeaheadText: string|null = null;
|
||||
|
||||
protected override willUpdate(changed: PropertyValues<MenuItemEl>) {
|
||||
if (this.href) {
|
||||
this.type = 'link';
|
||||
private readonly menuItemController = new MenuItemController(this, {
|
||||
getHeadlineElements: () => {
|
||||
return this.headlineElements;
|
||||
}
|
||||
|
||||
super.willUpdate(changed);
|
||||
}
|
||||
});
|
||||
|
||||
protected override render() {
|
||||
return this.renderListItem(html`
|
||||
@ -135,22 +107,17 @@ export class MenuItemEl extends LitElement implements MenuItem {
|
||||
protected renderListItem(content: unknown) {
|
||||
const isAnchor = this.type === 'link';
|
||||
let tag: StaticValue;
|
||||
let role: 'menuitem'|'option' = 'menuitem';
|
||||
switch (this.type) {
|
||||
case 'link':
|
||||
switch (this.menuItemController.tagName) {
|
||||
case 'a':
|
||||
tag = literal`a`;
|
||||
break;
|
||||
case 'button':
|
||||
tag = literal`button`;
|
||||
break;
|
||||
default:
|
||||
case 'menuitem':
|
||||
case 'li':
|
||||
tag = literal`li`;
|
||||
break;
|
||||
case 'option':
|
||||
tag = literal`li`;
|
||||
role = 'option';
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(b/265339866): announce "button"/"link" inside of a list item. Until
|
||||
@ -160,7 +127,7 @@ export class MenuItemEl extends LitElement implements MenuItem {
|
||||
<${tag}
|
||||
id="item"
|
||||
tabindex=${this.disabled && !isAnchor ? -1 : 0}
|
||||
role=${role}
|
||||
role=${this.menuItemController.role}
|
||||
aria-label=${(this as ARIAMixinStrict).ariaLabel || nothing}
|
||||
aria-selected=${(this as ARIAMixinStrict).ariaSelected || nothing}
|
||||
aria-checked=${(this as ARIAMixinStrict).ariaChecked || nothing}
|
||||
@ -169,8 +136,8 @@ export class MenuItemEl extends LitElement implements MenuItem {
|
||||
class="list-item ${classMap(this.getRenderClasses())}"
|
||||
href=${this.href || nothing}
|
||||
target=${target}
|
||||
@click=${this.onClick}
|
||||
@keydown=${this.onKeydown}
|
||||
@click=${this.menuItemController.onClick}
|
||||
@keydown=${this.menuItemController.onKeydown}
|
||||
>${content}</${tag}>
|
||||
`;
|
||||
}
|
||||
@ -226,22 +193,4 @@ export class MenuItemEl extends LitElement implements MenuItem {
|
||||
// work programmatically like in FF and select-option
|
||||
this.listItemRoot?.focus();
|
||||
}
|
||||
|
||||
protected onClick() {
|
||||
if (this.keepOpen) return;
|
||||
|
||||
this.dispatchEvent(createDefaultCloseMenuEvent(
|
||||
this, {kind: CLOSE_REASON.CLICK_SELECTION}));
|
||||
}
|
||||
|
||||
protected onKeydown(event: KeyboardEvent) {
|
||||
if (this.keepOpen || event.defaultPrevented) return;
|
||||
const keyCode = event.code;
|
||||
|
||||
if (!event.defaultPrevented && isClosableKey(keyCode)) {
|
||||
event.preventDefault();
|
||||
this.dispatchEvent(createDefaultCloseMenuEvent(
|
||||
this, {kind: CLOSE_REASON.KEYDOWN, key: keyCode}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,10 @@
|
||||
import {html, isServer, LitElement} from 'lit';
|
||||
import {property, queryAssignedElements} from 'lit/decorators.js';
|
||||
|
||||
import {MenuItem} from '../controllers/menuItemController.js';
|
||||
import {CloseMenuEvent, CloseReason, createActivateTypeaheadEvent, createDeactivateTypeaheadEvent, KeydownCloseKey, NavigableKey, SelectionKey} from '../controllers/shared.js';
|
||||
import {createDeactivateItemsEvent, createRequestActivationEvent, deactivateActiveItem, getFirstActivatableItem} from '../list-navigation-helpers.js';
|
||||
import {Corner, Menu} from '../menu.js';
|
||||
import {CLOSE_REASON, CloseMenuEvent, createActivateTypeaheadEvent, createDeactivateTypeaheadEvent, KEYDOWN_CLOSE_KEYS, MenuItem, NAVIGABLE_KEY, SELECTION_KEY} from '../shared.js';
|
||||
|
||||
/**
|
||||
* @fires deactivate-items Requests the parent menu to deselect other items when
|
||||
@ -261,10 +262,9 @@ export class SubMenu extends LitElement {
|
||||
if (event.defaultPrevented) return;
|
||||
|
||||
const openedWithLR = shouldOpenSubmenu &&
|
||||
(NAVIGABLE_KEY.LEFT === event.code ||
|
||||
NAVIGABLE_KEY.RIGHT === event.code);
|
||||
(NavigableKey.LEFT === event.code || NavigableKey.RIGHT === event.code);
|
||||
|
||||
if (event.code === SELECTION_KEY.SPACE || openedWithLR) {
|
||||
if (event.code === SelectionKey.SPACE || openedWithLR) {
|
||||
// prevent space from scrolling and Left + Right from selecting previous /
|
||||
// next items or opening / closing parent menus. Only open the submenu.
|
||||
event.preventDefault();
|
||||
@ -301,8 +301,8 @@ export class SubMenu extends LitElement {
|
||||
this.dispatchEvent(createActivateTypeaheadEvent());
|
||||
// Escape should only close one menu not all of the menus unlike space or
|
||||
// click selection which should close all menus.
|
||||
if (reason.kind === CLOSE_REASON.KEYDOWN &&
|
||||
reason.key === KEYDOWN_CLOSE_KEYS.ESCAPE) {
|
||||
if (reason.kind === CloseReason.KEYDOWN &&
|
||||
reason.key === KeydownCloseKey.ESCAPE) {
|
||||
event.stopPropagation();
|
||||
this.item.dispatchEvent(createRequestActivationEvent());
|
||||
return;
|
||||
@ -321,7 +321,7 @@ export class SubMenu extends LitElement {
|
||||
// keydowns from bubbling up to the parent menu and confounding things.
|
||||
event.preventDefault();
|
||||
|
||||
if (keyCode === NAVIGABLE_KEY.LEFT || keyCode === NAVIGABLE_KEY.RIGHT) {
|
||||
if (keyCode === NavigableKey.LEFT || keyCode === NavigableKey.RIGHT) {
|
||||
// Prevent this from bubbling to parents
|
||||
event.stopPropagation();
|
||||
}
|
||||
@ -343,11 +343,11 @@ export class SubMenu extends LitElement {
|
||||
*/
|
||||
private isSubmenuOpenKey(code: string) {
|
||||
const isRtl = getComputedStyle(this).direction === 'rtl';
|
||||
const arrowEnterKey = isRtl ? NAVIGABLE_KEY.LEFT : NAVIGABLE_KEY.RIGHT;
|
||||
const arrowEnterKey = isRtl ? NavigableKey.LEFT : NavigableKey.RIGHT;
|
||||
switch (code) {
|
||||
case arrowEnterKey:
|
||||
case SELECTION_KEY.SPACE:
|
||||
case SELECTION_KEY.ENTER:
|
||||
case SelectionKey.SPACE:
|
||||
case SelectionKey.ENTER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -363,10 +363,10 @@ export class SubMenu extends LitElement {
|
||||
*/
|
||||
private isSubmenuCloseKey(code: string) {
|
||||
const isRtl = getComputedStyle(this).direction === 'rtl';
|
||||
const arrowEnterKey = isRtl ? NAVIGABLE_KEY.RIGHT : NAVIGABLE_KEY.LEFT;
|
||||
const arrowEnterKey = isRtl ? NavigableKey.RIGHT : NavigableKey.LEFT;
|
||||
switch (code) {
|
||||
case arrowEnterKey:
|
||||
case KEYDOWN_CLOSE_KEYS.ESCAPE:
|
||||
case KeydownCloseKey.ESCAPE:
|
||||
return {close: true, keyCode: code} as const;
|
||||
default:
|
||||
return {close: false} as const;
|
||||
|
@ -10,7 +10,8 @@ import {styles as forcedColorsStyles} from './internal/menuitem/forced-colors-st
|
||||
import {MenuItemEl} from './internal/menuitem/menu-item.js';
|
||||
import {styles} from './internal/menuitem/menu-item-styles.css.js';
|
||||
|
||||
export {CloseMenuEvent, MenuItem} from './internal/shared.js';
|
||||
export {MenuItem} from './internal/controllers/menuItemController.js';
|
||||
export {CloseMenuEvent} from './internal/controllers/shared.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
|
@ -11,8 +11,9 @@ import {Menu} from './internal/menu.js';
|
||||
import {styles} from './internal/menu-styles.css.js';
|
||||
|
||||
export {ListItem} from '../list/internal/listitem/list-item.js';
|
||||
export {MenuItem} from './internal/controllers/menuItemController.js';
|
||||
export {CloseMenuEvent, FocusState} from './internal/controllers/shared.js';
|
||||
export {Corner} from './internal/menu.js';
|
||||
export {CloseMenuEvent, FocusState, MenuItem} from './internal/shared.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
|
@ -14,9 +14,9 @@ import {html as staticHtml, StaticValue} from 'lit/static-html.js';
|
||||
import {Field} from '../../field/internal/field.js';
|
||||
import {redispatchEvent} from '../../internal/controller/events.js';
|
||||
import {List} from '../../list/internal/list.js';
|
||||
import {CloseMenuEvent, isElementInSubtree, isSelectableKey} from '../../menu/internal/controllers/shared.js';
|
||||
import {TYPEAHEAD_RECORD} from '../../menu/internal/controllers/typeaheadController.js';
|
||||
import {DEFAULT_TYPEAHEAD_BUFFER_TIME, Menu} from '../../menu/internal/menu.js';
|
||||
import {CloseMenuEvent, isElementInSubtree, isSelectableKey} from '../../menu/internal/shared.js';
|
||||
import {TYPEAHEAD_RECORD} from '../../menu/internal/typeaheadController.js';
|
||||
|
||||
import {createRequestDeselectionEvent, createRequestSelectionEvent, getSelectedItems, SelectOption, SelectOptionRecord} from './shared.js';
|
||||
|
||||
@ -666,9 +666,9 @@ export abstract class Select extends LitElement {
|
||||
this.open = false;
|
||||
let hasChanged = false;
|
||||
|
||||
if (reason.kind === 'CLICK_SELECTION') {
|
||||
if (reason.kind === 'click-selection') {
|
||||
hasChanged = this.selectItem(item);
|
||||
} else if (reason.kind === 'KEYDOWN' && isSelectableKey(reason.key)) {
|
||||
} else if (reason.kind === 'keydown' && isSelectableKey(reason.key)) {
|
||||
hasChanged = this.selectItem(item);
|
||||
} else {
|
||||
// This can happen on ESC being pressed
|
||||
|
@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {MenuItem} from '../../menu/internal/shared.js';
|
||||
import {MenuItem} from '../../menu/internal/controllers/menuItemController.js';
|
||||
|
||||
/**
|
||||
* The interface specific to a Select Option
|
||||
|
Loading…
Reference in New Issue
Block a user