mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
5ec0b1668b
On mobile, focusing a long nav item shows a matTooltip that escapes the drawer, ignores inner scroll, and blocks scrolling while open. Suppress it on mobile using the existing isMobile helper.
124 lines
3.8 KiB
TypeScript
124 lines
3.8 KiB
TypeScript
/*!
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.dev/license
|
|
*/
|
|
|
|
import {NgTemplateOutlet} from '@angular/common';
|
|
import {Component, inject, input, output} from '@angular/core';
|
|
import {MatTooltip} from '@angular/material/tooltip';
|
|
import {RouterLink, RouterLinkActive} from '@angular/router';
|
|
import {NavigationItem} from '../../interfaces/index';
|
|
import {IsActiveNavigationItem} from '../../pipes';
|
|
import {NavigationState} from '../../services/index';
|
|
import {isMobile} from '../../utils';
|
|
import {IconComponent} from '../icon/icon.component';
|
|
|
|
@Component({
|
|
selector: 'docs-navigation-list',
|
|
imports: [
|
|
RouterLink,
|
|
RouterLinkActive,
|
|
IconComponent,
|
|
IsActiveNavigationItem,
|
|
NgTemplateOutlet,
|
|
MatTooltip,
|
|
],
|
|
templateUrl: './navigation-list.component.html',
|
|
styleUrls: ['./navigation-list.component.scss'],
|
|
})
|
|
export class NavigationList {
|
|
readonly navigationItems = input.required<NavigationItem[]>();
|
|
readonly preserveOtherCategoryOrder = input.required<boolean>();
|
|
readonly displayItemsToLevel = input(2);
|
|
readonly collapsableLevel = input<number | undefined>();
|
|
readonly expandableLevel = input(2);
|
|
readonly isDropdownView = input(false);
|
|
|
|
readonly linkClicked = output<void>();
|
|
|
|
protected readonly labelTruncationThreshold = 27;
|
|
|
|
private readonly navigationState = inject(NavigationState);
|
|
private readonly crossCategoryOrigin = this.navigationState.crossCategoryOrigin;
|
|
|
|
readonly activeItem = this.navigationState.activeNavigationItem;
|
|
|
|
protected readonly isMobile = isMobile;
|
|
|
|
toggle(item: NavigationItem): void {
|
|
if (
|
|
item.level === 1 &&
|
|
item.level !== this.expandableLevel() &&
|
|
item.level !== this.collapsableLevel()
|
|
) {
|
|
return;
|
|
}
|
|
const prevParentItem = this.crossCategoryOrigin();
|
|
if (prevParentItem) {
|
|
this.crossCategoryOrigin.set(undefined);
|
|
this.navigationState.toggleItem(prevParentItem);
|
|
return;
|
|
}
|
|
this.navigationState.toggleItem(item);
|
|
}
|
|
|
|
emitClickOnLink(item: NavigationItem): void {
|
|
if (item.isCrossReferenced) {
|
|
this.crossCategoryOrigin.set(item.parent);
|
|
}
|
|
this.linkClicked.emit();
|
|
}
|
|
|
|
private hasCategories(items: NavigationItem[]): boolean {
|
|
return items.some((item) => !!item.category);
|
|
}
|
|
|
|
private getCategoryStatus(item: NavigationItem, category: string): 'new' | 'updated' | undefined {
|
|
const categoriesStatus = item.parent?.categoriesStatus;
|
|
|
|
if (!categoriesStatus) {
|
|
return undefined;
|
|
}
|
|
|
|
return categoriesStatus.find((status) => status[category])?.[category];
|
|
}
|
|
|
|
protected groupItems(
|
|
items: NavigationItem[],
|
|
preserveOtherCategoryOrder: boolean,
|
|
): Map<string, {items: NavigationItem[]; status: 'new' | 'updated' | undefined}> {
|
|
const hasCategories = this.hasCategories(items);
|
|
if (hasCategories) {
|
|
const others: NavigationItem[] = [];
|
|
const categorizedItems = new Map<
|
|
string,
|
|
{items: NavigationItem[]; status: 'new' | 'updated' | undefined}
|
|
>();
|
|
for (const item of items) {
|
|
const category = item.category || 'Other';
|
|
if (!preserveOtherCategoryOrder && category === 'Other') {
|
|
others.push(item);
|
|
continue;
|
|
}
|
|
if (!categorizedItems.has(category)) {
|
|
categorizedItems.set(category, {
|
|
items: [],
|
|
status: this.getCategoryStatus(item, category),
|
|
});
|
|
}
|
|
categorizedItems.get(category)!.items.push(item);
|
|
}
|
|
if (others.length) {
|
|
categorizedItems.set('Other', {items: others, status: undefined});
|
|
}
|
|
|
|
return categorizedItems;
|
|
} else {
|
|
return new Map([['', {items, status: undefined}]]);
|
|
}
|
|
}
|
|
}
|