mirror of
https://github.com/material-components/material-web.git
synced 2024-10-26 21:56:56 +03:00
refactor(menu)!: events no longer subclass Event but rather use CustomEvent
Fixes issues running in ES5 BREAKING CHANGE: subclassing events is not supported in ES5 so all menu-related events now use CustomEvent rather than subclassing Event PiperOrigin-RevId: 553304128
This commit is contained in:
parent
c148bf61fe
commit
043d548270
@ -244,9 +244,9 @@ function displayCloseEvent(outputRef: Ref<HTMLElement>) {
|
||||
if (!outputRef.value) return;
|
||||
|
||||
outputRef.value.innerText = `Closed by item(s) with text: ${
|
||||
JSON.stringify(event.itemPath.map(
|
||||
item =>
|
||||
item.headline))} For reason: ${JSON.stringify(event.reason)}`;
|
||||
JSON.stringify(
|
||||
event.detail.itemPath.map(item => item.headline))} For reason: ${
|
||||
JSON.stringify(event.detail.reason)}`;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import {property, state} from 'lit/decorators.js';
|
||||
|
||||
import type {MdFocusRing} from '../../../focus/md-focus-ring.js';
|
||||
import {ListItemEl, ListItemRole} from '../../../list/internal/listitem/list-item.js';
|
||||
import {CLOSE_REASON, DefaultCloseMenuEvent, isClosableKey, MenuItem} from '../shared.js';
|
||||
import {CLOSE_REASON, createDefaultCloseMenuEvent, isClosableKey, MenuItem} from '../shared.js';
|
||||
|
||||
export {ListItemRole} from '../../../list/internal/listitem/list-item.js';
|
||||
|
||||
@ -39,8 +39,8 @@ export class MenuItemEl extends ListItemEl implements MenuItem {
|
||||
protected override onClick() {
|
||||
if (this.keepOpen || this.keepOpenOnClick) return;
|
||||
|
||||
this.dispatchEvent(
|
||||
new DefaultCloseMenuEvent(this, {kind: CLOSE_REASON.CLICK_SELECTION}));
|
||||
this.dispatchEvent(createDefaultCloseMenuEvent(
|
||||
this, {kind: CLOSE_REASON.CLICK_SELECTION}));
|
||||
}
|
||||
|
||||
protected override getRenderClasses() {
|
||||
@ -61,7 +61,7 @@ export class MenuItemEl extends ListItemEl implements MenuItem {
|
||||
|
||||
if (!event.defaultPrevented && isClosableKey(keyCode)) {
|
||||
event.preventDefault();
|
||||
this.dispatchEvent(new DefaultCloseMenuEvent(
|
||||
this.dispatchEvent(createDefaultCloseMenuEvent(
|
||||
this, {kind: CLOSE_REASON.KEYDOWN, key: keyCode}));
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
import {property} from 'lit/decorators.js';
|
||||
|
||||
import {ListItemLink} from '../../../list/internal/listitemlink/list-item-link.js';
|
||||
import {CLOSE_REASON, DefaultCloseMenuEvent, isClosableKey, MenuItem, SELECTION_KEY} from '../shared.js';
|
||||
import {CLOSE_REASON, createDefaultCloseMenuEvent, isClosableKey, MenuItem, SELECTION_KEY} from '../shared.js';
|
||||
|
||||
/**
|
||||
* @fires close-menu {CloseMenuEvent}
|
||||
@ -29,8 +29,8 @@ export class MenuItemLink extends ListItemLink implements MenuItem {
|
||||
protected override onClick() {
|
||||
if (this.keepOpen || this.keepOpenOnClick) return;
|
||||
|
||||
this.dispatchEvent(
|
||||
new DefaultCloseMenuEvent(this, {kind: CLOSE_REASON.CLICK_SELECTION}));
|
||||
this.dispatchEvent(createDefaultCloseMenuEvent(
|
||||
this, {kind: CLOSE_REASON.CLICK_SELECTION}));
|
||||
}
|
||||
|
||||
protected override onKeydown(event: KeyboardEvent) {
|
||||
@ -41,7 +41,7 @@ export class MenuItemLink extends ListItemLink implements MenuItem {
|
||||
if (!event.defaultPrevented && isClosableKey(keyCode) &&
|
||||
keyCode !== SELECTION_KEY.ENTER) {
|
||||
event.preventDefault();
|
||||
this.dispatchEvent(new DefaultCloseMenuEvent(
|
||||
this.dispatchEvent(createDefaultCloseMenuEvent(
|
||||
this, {kind: CLOSE_REASON.KEYDOWN, key: keyCode}));
|
||||
}
|
||||
}
|
||||
|
@ -71,71 +71,92 @@ export interface KeydownReason extends Reason {
|
||||
export type DefaultReasons = ClickReason|KeydownReason;
|
||||
|
||||
/**
|
||||
* The event that closes any parent menus. It is recommended to subclass and
|
||||
* dispatch this event rather than creating your own `close-menu` event.
|
||||
* Creates an event that closes any parent menus.
|
||||
*/
|
||||
export class CloseMenuEvent<T extends Reason = DefaultReasons> extends Event {
|
||||
readonly itemPath: MenuItem[];
|
||||
constructor(public initiator: MenuItem, readonly reason: T) {
|
||||
super('close-menu', {bubbles: true, composed: true});
|
||||
this.itemPath = [initiator];
|
||||
}
|
||||
export function createCloseMenuEvent<T extends Reason = DefaultReasons>(
|
||||
initiator: MenuItem, reason: T) {
|
||||
return new CustomEvent<
|
||||
{initiator: MenuItem, itemPath: MenuItem[], reason: T}>('close-menu', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: {initiator, reason, itemPath: [initiator]}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The event that signals to the menu that it should stay open on the focusout
|
||||
* event.
|
||||
* Creates an event that signals to the menu that it should stay open on the
|
||||
* focusout event.
|
||||
*/
|
||||
export class StayOpenOnFocusoutEvent extends Event {
|
||||
constructor() {
|
||||
super('stay-open-on-focusout', {bubbles: true, composed: true});
|
||||
}
|
||||
export function createStayOpenOnFocusoutEvent() {
|
||||
return new Event('stay-open-on-focusout', {bubbles: true, composed: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* The event that signals to the menu that it should close open on the focusout
|
||||
* event.
|
||||
* Creates an event that signals to the menu that it should close open on the
|
||||
* focusout event.
|
||||
*/
|
||||
export class CloseOnFocusoutEvent extends Event {
|
||||
constructor() {
|
||||
super('close-on-focusout', {bubbles: true, composed: true});
|
||||
}
|
||||
export function createCloseOnFocusoutEvent() {
|
||||
return new Event('close-on-focusout', {bubbles: true, composed: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* The default close menu event used by md-menu. To create your own `close-menu`
|
||||
* event, you should subclass the `CloseMenuEvent` instead.
|
||||
* Creates a default close menu event used by md-menu.
|
||||
*/
|
||||
export const createDefaultCloseMenuEvent = createCloseMenuEvent<DefaultReasons>;
|
||||
|
||||
/**
|
||||
* The type of the default close menu event used by md-menu.
|
||||
*/
|
||||
// tslint:disable-next-line
|
||||
export const DefaultCloseMenuEvent = CloseMenuEvent<DefaultReasons>;
|
||||
export type CloseMenuEvent<T extends Reason = DefaultReasons> =
|
||||
ReturnType<typeof createCloseMenuEvent<T>>;
|
||||
|
||||
/**
|
||||
* The event that requests the parent md-menu to deactivate all other items.
|
||||
* Creates an event that requests the parent md-menu to deactivate all other
|
||||
* items.
|
||||
*/
|
||||
export class DeactivateItemsEvent extends Event {
|
||||
constructor() {
|
||||
super('deactivate-items', {bubbles: true, composed: true});
|
||||
}
|
||||
export function createDeactivateItemsEvent() {
|
||||
return new Event('deactivate-items', {bubbles: true, composed: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the typeahead functionality of containing menu be deactivated.
|
||||
* The type of the event that requests the parent md-menu to deactivate all
|
||||
* other items.
|
||||
*/
|
||||
export class DeactivateTypeaheadEvent extends Event {
|
||||
constructor() {
|
||||
super('deactivate-typeahead', {bubbles: true, composed: true});
|
||||
}
|
||||
export type DeactivateItemsEvent =
|
||||
ReturnType<typeof createDeactivateItemsEvent>;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an event that requests the typeahead functionality of containing menu
|
||||
* be deactivated.
|
||||
*/
|
||||
export function createDeactivateTypeaheadEvent() {
|
||||
return new Event('deactivate-typeahead', {bubbles: true, composed: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the typeahead functionality of containing menu be activated.
|
||||
* The type of the event that requests the typeahead functionality of containing
|
||||
* menu be deactivated.
|
||||
*/
|
||||
export class ActivateTypeaheadEvent extends Event {
|
||||
constructor() {
|
||||
super('activate-typeahead', {bubbles: true, composed: true});
|
||||
}
|
||||
export type DeactivateTypeaheadEvent =
|
||||
ReturnType<typeof createDeactivateTypeaheadEvent>;
|
||||
|
||||
/**
|
||||
* Creates an event that requests the typeahead functionality of containing menu
|
||||
* be activated.
|
||||
*/
|
||||
export function createActivateTypeaheadEvent() {
|
||||
return new Event('activate-typeahead', {bubbles: true, composed: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the event that requests the typeahead functionality of containing
|
||||
* menu be activated.
|
||||
*/
|
||||
export type ActivateTypeaheadEvent =
|
||||
ReturnType<typeof createActivateTypeaheadEvent>;
|
||||
|
||||
/**
|
||||
* Keys that are used to navigate menus.
|
||||
*/
|
||||
|
@ -10,25 +10,24 @@ import {property, queryAssignedElements, state} from 'lit/decorators.js';
|
||||
import {List} from '../../../list/internal/list.js';
|
||||
import {Corner, Menu} from '../menu.js';
|
||||
import {MenuItemEl} from '../menuitem/menu-item.js';
|
||||
import {ActivateTypeaheadEvent, CLOSE_REASON, CloseMenuEvent, CloseOnFocusoutEvent, DeactivateItemsEvent, DeactivateTypeaheadEvent, KEYDOWN_CLOSE_KEYS, NAVIGABLE_KEY, SELECTION_KEY, StayOpenOnFocusoutEvent} from '../shared.js';
|
||||
import {CLOSE_REASON, CloseMenuEvent, createActivateTypeaheadEvent, createCloseOnFocusoutEvent, createDeactivateItemsEvent, createDeactivateTypeaheadEvent, createStayOpenOnFocusoutEvent, KEYDOWN_CLOSE_KEYS, NAVIGABLE_KEY, SELECTION_KEY} from '../shared.js';
|
||||
|
||||
function stopPropagation(event: Event) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
/**
|
||||
* @fires deactivate-items {DeactivateItemsEvent} Requests the parent menu to
|
||||
* deselect other items when a submenu opens
|
||||
* @fires deactivate-typeahead {DeactivateItemsEvent} Requests the parent menu
|
||||
* to deactivate the typeahead functionality when a submenu opens
|
||||
* @fires activate-typeahead {DeactivateItemsEvent} Requests the parent menu to
|
||||
* activate the typeahead functionality when a submenu closes
|
||||
* @fires stay-open-on-focusout {StayOpenOnFocusoutEvent} Requests the parent
|
||||
* menu to stay open when focusout event is fired or has a `null`
|
||||
* `relatedTarget` when submenu is opened.
|
||||
* @fires close-on-focusout {CloseOnFocusoutEvent} Requests the parent
|
||||
* menu to close when focusout event is fired or has a `null`
|
||||
* `relatedTarget` When submenu is closed.
|
||||
* @fires deactivate-items Requests the parent menu to deselect other items when
|
||||
* a submenu opens
|
||||
* @fires deactivate-typeahead Requests the parent menu to deactivate the
|
||||
* typeahead functionality when a submenu opens
|
||||
* @fires activate-typeahead Requests the parent menu to activate the typeahead
|
||||
* functionality when a submenu closes
|
||||
* @fires stay-open-on-focusout Requests the parent menu to stay open when
|
||||
* focusout event is fired or has a `null` `relatedTarget` when submenu is
|
||||
* opened.
|
||||
* @fires close-on-focusout Requests the parent menu to close when focusout
|
||||
* event is fired or has a `null` `relatedTarget` When submenu is closed.
|
||||
*/
|
||||
export class SubMenuItem extends MenuItemEl {
|
||||
/**
|
||||
@ -165,14 +164,15 @@ export class SubMenuItem extends MenuItemEl {
|
||||
}
|
||||
|
||||
private onCloseSubmenu(event: CloseMenuEvent) {
|
||||
event.itemPath.push(this);
|
||||
const {itemPath, reason} = event.detail;
|
||||
itemPath.push(this);
|
||||
// Restore focusout behavior
|
||||
this.dispatchEvent(new CloseOnFocusoutEvent());
|
||||
this.dispatchEvent(new ActivateTypeaheadEvent());
|
||||
this.dispatchEvent(createCloseOnFocusoutEvent());
|
||||
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 (event.reason.kind === CLOSE_REASON.KEYDOWN &&
|
||||
event.reason.key === KEYDOWN_CLOSE_KEYS.ESCAPE) {
|
||||
if (reason.kind === CLOSE_REASON.KEYDOWN &&
|
||||
reason.key === KEYDOWN_CLOSE_KEYS.ESCAPE) {
|
||||
event.stopPropagation();
|
||||
this.active = true;
|
||||
this.selected = false;
|
||||
@ -231,13 +231,13 @@ export class SubMenuItem extends MenuItemEl {
|
||||
// has a submenuitem hovered which opens a third submenut. Then if you hover
|
||||
// on yet another middle menu-item (not submenuitem) then focusout Event's
|
||||
// relatedTarget will be `null` thus, causing all the menus to close
|
||||
this.dispatchEvent(new StayOpenOnFocusoutEvent());
|
||||
this.dispatchEvent(createStayOpenOnFocusoutEvent());
|
||||
menu.show();
|
||||
|
||||
// Deactivate other items. This can be the case if the user has tabbed
|
||||
// around the menu and then mouses over an md-sub-menu.
|
||||
this.dispatchEvent(new DeactivateItemsEvent());
|
||||
this.dispatchEvent(new DeactivateTypeaheadEvent());
|
||||
this.dispatchEvent(createDeactivateItemsEvent());
|
||||
this.dispatchEvent(createDeactivateTypeaheadEvent());
|
||||
this.selected = true;
|
||||
|
||||
// This is the case of mouse hovering when already opened via keyboard or
|
||||
@ -258,11 +258,11 @@ export class SubMenuItem extends MenuItemEl {
|
||||
const menu = this.submenuEl;
|
||||
if (!menu || !menu.open) return;
|
||||
|
||||
this.dispatchEvent(new ActivateTypeaheadEvent());
|
||||
this.dispatchEvent(createActivateTypeaheadEvent());
|
||||
menu.quick = true;
|
||||
menu.close();
|
||||
// Restore focusout behavior.
|
||||
this.dispatchEvent(new CloseOnFocusoutEvent());
|
||||
this.dispatchEvent(createCloseOnFocusoutEvent());
|
||||
this.active = false;
|
||||
this.selected = false;
|
||||
menu.addEventListener('closed', onClosed, {once: true});
|
||||
|
@ -14,7 +14,7 @@ import {styles} from './internal/menuitem/menu-item-styles.css.js';
|
||||
import {MenuItemLink} from './internal/menuitemlink/menu-item-link.js';
|
||||
|
||||
export {ListItem} from '../list/internal/listitem/list-item.js';
|
||||
export {CloseMenuEvent, DeactivateItemsEvent, MenuItem} from './internal/shared.js';
|
||||
export {CloseMenuEvent, MenuItem} from './internal/shared.js';
|
||||
|
||||
|
||||
declare global {
|
||||
|
@ -14,7 +14,7 @@ import {MenuItemEl} from './internal/menuitem/menu-item.js';
|
||||
import {styles} from './internal/menuitem/menu-item-styles.css.js';
|
||||
|
||||
export {ListItem} from '../list/internal/listitem/list-item.js';
|
||||
export {CloseMenuEvent, DeactivateItemsEvent, MenuItem} from './internal/shared.js';
|
||||
export {CloseMenuEvent, MenuItem} from './internal/shared.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
|
@ -12,7 +12,7 @@ import {styles} from './internal/menu-styles.css.js';
|
||||
|
||||
export {ListItem} from '../list/internal/listitem/list-item.js';
|
||||
export {Corner, DefaultFocusState} from './internal/menu.js';
|
||||
export {CloseMenuEvent, DeactivateItemsEvent, MenuItem} from './internal/shared.js';
|
||||
export {CloseMenuEvent, MenuItem} from './internal/shared.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
|
@ -14,7 +14,7 @@ import {styles} from './internal/menuitem/menu-item-styles.css.js';
|
||||
import {SubMenuItem} from './internal/submenuitem/sub-menu-item.js';
|
||||
|
||||
export {ListItem} from '../list/internal/listitem/list-item.js';
|
||||
export {CloseMenuEvent, DeactivateItemsEvent, MenuItem} from './internal/shared.js';
|
||||
export {CloseMenuEvent, MenuItem} from './internal/shared.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
|
@ -14,7 +14,7 @@ import {html as staticHtml, StaticValue} from 'lit/static-html.js';
|
||||
import {Field} from '../../field/internal/field.js';
|
||||
import {List} from '../../list/internal/list.js';
|
||||
import {DEFAULT_TYPEAHEAD_BUFFER_TIME, Menu} from '../../menu/internal/menu.js';
|
||||
import {DefaultCloseMenuEvent, isElementInSubtree, isSelectableKey} from '../../menu/internal/shared.js';
|
||||
import {CloseMenuEvent, isElementInSubtree, isSelectableKey} from '../../menu/internal/shared.js';
|
||||
import {TYPEAHEAD_RECORD} from '../../menu/internal/typeaheadController.js';
|
||||
|
||||
import {getSelectedItems, RequestDeselectionEvent, RequestSelectionEvent, SelectOption, SelectOptionRecord} from './shared.js';
|
||||
@ -445,9 +445,9 @@ export abstract class Select extends LitElement {
|
||||
/**
|
||||
* Determines the reason for closing, and updates the UI accordingly.
|
||||
*/
|
||||
private handleCloseMenu(event: InstanceType<typeof DefaultCloseMenuEvent>) {
|
||||
const reason = event.reason;
|
||||
const item = event.itemPath[0] as SelectOption;
|
||||
private handleCloseMenu(event: CloseMenuEvent) {
|
||||
const reason = event.detail.reason;
|
||||
const item = event.detail.itemPath[0] as SelectOption;
|
||||
this.open = false;
|
||||
let hasChanged = false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user