refactor(menu): Made sure the menu can be used for more than group

This commit is contained in:
Michel Fedde 2025-06-20 17:48:00 +02:00
parent a79898b2e9
commit 1d73ee8a78
16 changed files with 650 additions and 406 deletions

View file

@ -0,0 +1,105 @@
import {AnyMenuItem, MenuItemType} from "./MenuRenderer.types";
import {TraversalMap, StringifiedTraversalPath, TraversalPath, TraversalKey} from "./MenuTraversal.types";
import {InvalidTraversalRouteError} from "./InvalidTraversalRouteError";
export class MenuTraversal {
private readonly traversalMap: TraversalMap
private currentPath: TraversalPath = [];
public get path() {
return this.currentPath;
}
public get stringifiedPath(): StringifiedTraversalPath {
return this.stringifyTraversalPath(this.currentPath);
}
public get currentMenuItem(): AnyMenuItem {
const path = this.stringifiedPath;
if (!this.traversalMap.has(path)) {
throw new InvalidTraversalRouteError(this.currentPath);
}
return <AnyMenuItem>this.traversalMap.get(path);
}
public get isRoot(): boolean {
return this.currentPath.length === 0;
}
constructor(
private readonly menu: AnyMenuItem[],
private readonly rootLabel: string = "",
private readonly rootDescription: string = ''
) {
this.traversalMap = this.generateTraversalMap();
}
public travelForward(next: TraversalKey) {
const nextPath = [
...this.currentPath,
next
];
if (!this.traversalMap.has(this.stringifyTraversalPath(nextPath))) {
throw new InvalidTraversalRouteError(nextPath);
}
this.currentPath = nextPath;
}
public travelBack() {
this.currentPath.pop();
}
public getMenuItem(path: StringifiedTraversalPath): AnyMenuItem
{
if (!this.traversalMap.has(path)) {
throw new InvalidTraversalRouteError([path]);
}
return <AnyMenuItem>this.traversalMap.get(path);
}
public static unstringifyTraversalPath(path: StringifiedTraversalPath): TraversalPath {
return path.split('/');
}
private generateTraversalMap(): TraversalMap {
const map = new Map<StringifiedTraversalPath, AnyMenuItem>();
map.set('', {
traversalKey: '',
label: this.rootLabel,
description: this.rootDescription,
type: MenuItemType.Collection,
children: this.menu
});
const that = this;
function traversePath(path: TraversalPath, menuItem: AnyMenuItem) {
path = [...path, menuItem.traversalKey];
map.set(that.stringifyTraversalPath(path), menuItem);
if (menuItem.type !== MenuItemType.Collection) {
return;
}
menuItem.children.forEach((nextMenuItem) => {
traversePath(path, nextMenuItem);
})
}
this.menu.forEach((menuItem) => {
traversePath([], menuItem);
})
return map;
}
private stringifyTraversalPath(path: TraversalPath): StringifiedTraversalPath {
return path.join('/');
}
}