feat: Add support for flyout menu mode in MegaMenu

- Introduced `MegaMenuMode` type and `normalizeMegaMenuMode` function to handle menu modes.
- Updated `MegaMenuApplicationCustomizer` to accept `menuMode` property.
- Enhanced `MegaMenuRenderer` to render flyout menus based on the selected mode.
- Created new HTML previews for both flyout and mega menu modes.
- Removed unused mock services and user custom action service interfaces.
This commit is contained in:
Torsten Brendgen
2026-07-20 20:37:32 +02:00
parent e75b11117f
commit bc61166267
27 changed files with 1320 additions and 1833 deletions
+91 -6
View File
@@ -5,8 +5,7 @@
import { IMenuItem } from '../../services/IMenuItem';
import { debugLog } from '../../services/MegaMenuDebug';
import styles from './MegaMenu.module.scss'; // tslint:disable-line:no-unused-variable
import { MegaMenuMode } from './MegaMenuMode';
const LOG_SOURCE: string = 'MegaMenuRenderer';
@@ -20,7 +19,8 @@ export class MegaMenuRenderer {
constructor(
private menuItems: IMenuItem[],
private debug: boolean = false
private debug: boolean = false,
private menuMode: MegaMenuMode = 'megaMenu'
) { }
public render(container: HTMLElement): void {
@@ -36,7 +36,8 @@ export class MegaMenuRenderer {
const nav = document.createElement('nav');
nav.id = 'Mega-Menu';
nav.className = 'mega-menu-main';
nav.className = this.joinClasses('mega-menu-main', 'mega-menu-mode-' + this.menuMode);
nav.setAttribute('data-menu-mode', this.menuMode);
nav.setAttribute('aria-label', 'Hauptnavigation');
const topLevelUl = document.createElement('ul');
@@ -99,8 +100,10 @@ export class MegaMenuRenderer {
li.appendChild(topElement);
if (hasChildren) {
const megaMenu = this.createMegaMenu(item);
li.appendChild(megaMenu);
const childMenu = this.menuMode === 'flyout'
? this.createFlyoutMenu(item)
: this.createMegaMenu(item);
li.appendChild(childMenu);
}
return li;
@@ -246,6 +249,88 @@ export class MegaMenuRenderer {
return categoryDiv;
}
private createFlyoutMenu(parentItem: IMenuItem): HTMLDivElement {
const flyout = document.createElement('div');
flyout.className = 'mega-menu mega-menu-flyout';
flyout.setAttribute('aria-expanded', 'false');
flyout.setAttribute('aria-label', parentItem.label + ' Untermenü');
const list = document.createElement('ul');
list.className = 'flyout-list flyout-level-2';
if (parentItem.items) {
parentItem.items.forEach(secondLevelItem => {
list.appendChild(this.createFlyoutItem(secondLevelItem));
});
}
flyout.appendChild(list);
return flyout;
}
private createFlyoutItem(item: IMenuItem): HTMLLIElement {
const li = document.createElement('li');
const hasChildren = item.hasChildren() && item.items && item.items.length > 0;
const isActive = this.isItemActive(item);
const isCurrent = this.isCurrentUrl(item.url);
li.className = this.joinClasses(
'flyout-item',
hasChildren ? 'has-children' : undefined,
isActive ? 'is-active' : undefined,
isCurrent ? 'is-current' : undefined
);
const element = this.createFlyoutElement(item, hasChildren, isActive, isCurrent);
li.appendChild(element);
if (hasChildren && item.items) {
const childList = document.createElement('ul');
childList.className = 'flyout-list flyout-level-3';
childList.setAttribute('aria-label', item.label + ' Untermenü');
item.items.forEach(thirdLevelItem => {
childList.appendChild(this.createFlyoutItem(thirdLevelItem));
});
li.appendChild(childList);
}
return li;
}
private createFlyoutElement(item: IMenuItem, hasChildren: boolean, isActive: boolean, isCurrent: boolean): HTMLElement {
const element: HTMLElement = item.url
? document.createElement('a')
: document.createElement('span');
if (item.url) {
(element as HTMLAnchorElement).href = item.url;
} else {
element.setAttribute('tabindex', '0');
}
element.textContent = item.label;
element.className = this.joinClasses(
'flyout-link',
hasChildren ? 'flyout-link-has-children' : undefined,
isActive ? 'is-active' : undefined,
isCurrent ? 'is-current' : undefined
);
if (hasChildren) {
element.setAttribute('aria-haspopup', 'true');
}
if (isCurrent && item.url) {
element.setAttribute('aria-current', 'page');
}
if (item.hoverText) {
element.title = item.hoverText;
}
return element;
}
private attachEventListeners(): void {
const headings = document.querySelectorAll('#Mega-Menu > ul > li > a, #Mega-Menu > ul > li > .menu-item-text');