@universal-material/web
Version:
Material web components
108 lines • 3.41 kB
JavaScript
export class MenuFieldNavigationController {
#element;
constructor(host) {
this.#element = null;
this.focusedMenu = null;
this.#handleMenuClose = () => this.blurMenu();
this.host = host;
this._bindHandleKeyDown = this.handleKeyDown.bind(this);
}
attach(element) {
this.detach();
element?.addEventListener('keydown', this._bindHandleKeyDown, { capture: true });
this.host._menu?.addEventListener('close', this.#handleMenuClose);
this.#element = element;
}
detach() {
this.#element?.removeEventListener('keydown', this._bindHandleKeyDown);
this.host._menu?.removeEventListener('close', this.#handleMenuClose);
this.#element = null;
}
#handleMenuClose;
handleKeyDown(event) {
if (this.host._menu?.open !== true) {
return false;
}
const isEscape = event.key === 'Escape';
if (isEscape) {
this.host._menu.close();
}
if (event.key === 'Home') {
this.navigateTo(event, this.host._menuItems[0], 0);
return true;
}
if (event.key === 'End') {
this.navigateTo(event, this.host._menuItems[this.host._menuItems.length - 1], this.host._menuItems.length - 1);
return true;
}
const isDown = event.key === 'ArrowDown';
const isUp = event.key === 'ArrowUp';
if (isDown || isUp) {
this.navigate(event, isDown);
return true;
}
const isEnter = event.key === 'Enter';
const isTab = event.key === 'Tab';
if (isEnter || isTab) {
this.selectActiveItem(event);
return true;
}
return false;
}
navigate(event, forwards) {
const menuItems = this.host._menuItems;
if (!menuItems.length) {
return;
}
event.preventDefault();
const activeMenu = this.focusedMenu;
const activeMenuIndex = activeMenu ? menuItems.indexOf(activeMenu) : -1;
const nextMenu = forwards
? menuItems[activeMenuIndex + 1] ?? menuItems[0]
: menuItems[activeMenuIndex - 1] ?? menuItems[menuItems.length - 1];
if (!nextMenu) {
return;
}
this.navigateTo(event, nextMenu, menuItems.indexOf(nextMenu));
}
navigateTo(event, menu, index) {
event.preventDefault();
this.blurMenu();
if (!menu) {
return;
}
this.focusMenu(menu, index);
}
focusMenu(menu, index, active = true, scroll = true) {
if (this.focusedMenu) {
this.focusedMenu.active = false;
}
this.focusedMenu = menu;
menu.active = active;
if (scroll) {
menu.scrollIntoView({ block: 'nearest' });
}
this.afterFocus(menu, index);
}
blurMenu() {
if (!this.focusedMenu) {
return;
}
this.focusedMenu.active = false;
this.focusedMenu = null;
this.afterBlur();
}
selectActiveItem(event) {
if (!this.focusedMenu) {
return;
}
event.preventDefault();
this.focusedMenu.click();
this.host._menu.open = false;
}
afterFocus(_, __) {
}
afterBlur() {
}
}
//# sourceMappingURL=menu-field-navigation-controller.js.map