| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 | 
import BaseFoundation, { DefaultAdapter } from '../base/foundation';import { handlePrevent, isPrintableCharacter, findIndexByCharacter, getAncestorNodeByRole, getMenuButton, setFocusToFirstItem, setFocusToItem, setFocusToNextMenuitem, setFocusToPreviousMenuItem } from '../utils/a11y';export default class DropdownMenuFoundation extends BaseFoundation<Partial<DefaultAdapter>> {    menuItemNodes: HTMLElement[] = null;    firstChars: string[] = [];    // if trigger is click, auto focus to the first menu item    autoFocus(ulElement: any): void {        const trigger = this._adapter.getContext('trigger');        if (trigger === 'click'){            // find all non-disabled li under this menu and set focus to the first menu            this.menuItemNodes = [...ulElement.getElementsByTagName('li')].filter(item => item.ariaDisabled !== "true");            setFocusToFirstItem(this.menuItemNodes);        }    }    handleEscape(menu: Element): void {        const trigger = this._adapter.getContext('trigger');        if (trigger === 'custom'){            const menuButton = menu && getMenuButton(document.querySelectorAll(`[data-popupid]`), menu.id);             menuButton.focus();        }    }    setFocusByFirstCharacter(curItem: any, char: string): void {        const index = findIndexByCharacter(this.menuItemNodes, curItem, this.firstChars, char);                if (index >= 0) {            setFocusToItem(this.menuItemNodes, this.menuItemNodes[index]);        }    }    onMenuKeydown(event: any): void {        const menu = getAncestorNodeByRole(event.target, 'tooltip');                if (!this.menuItemNodes){            this.menuItemNodes = [...(event.target.parentNode).getElementsByTagName('li')].filter(item => item.ariaDisabled !== "true");        }        if (this.firstChars.length === 0){            this.menuItemNodes.forEach((item: Element) => {                // the menuItemNodes can be an component and not exit textContent                this.firstChars.push(item.textContent.trim()[0]?.toLowerCase());            });        }        // get the currently focused menu item        const curItem = this.menuItemNodes.find(item => item.tabIndex === 0);                switch (event.key) {            case ' ':            case 'Enter':                event.target.click();                handlePrevent(event);                break;            case 'Escape':                this.handleEscape(menu);                break;            case 'ArrowUp':                setFocusToPreviousMenuItem(this.menuItemNodes, curItem);                handlePrevent(event);                break;            case 'ArrowDown':                setFocusToNextMenuitem(this.menuItemNodes, curItem);                handlePrevent(event);                break;            default:                if (isPrintableCharacter(event.key)) {                    this.setFocusByFirstCharacter(curItem, event.key);                    // it can be an input on Dropdown, handlePrevent may affect the input of the component                    // handlePrevent(event);                 }                break;        }    }}
 |