/
githubmirror
/
components
Обзор
Документация
Войти
/
githubmirror
/
components
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/cdk/menu/menu.ts
137 строк
4 KB
Andrew Seguin
refactor: use relative imports within module npm packages (#30588)
12 мар 2025, 00:40
Не верифицирован
12 мар 2025, 00:40
626a465
Код
Авторство
О чём код?
/** * @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 {AfterContentInit, Directive, EventEmitter, inject, OnDestroy, Output} from '@angular/core'; import {ESCAPE, hasModifierKey, LEFT_ARROW, RIGHT_ARROW, TAB} from '../keycodes'; import {takeUntil} from 'rxjs/operators'; import {CdkMenuGroup} from './menu-group'; import {CDK_MENU} from './menu-interface'; import {FocusNext, PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER} from './menu-stack'; import {MENU_TRIGGER} from './menu-trigger-base'; import {CdkMenuBase} from './menu-base'; /** * Directive which configures the element as a Menu which should contain child elements marked as * CdkMenuItem or CdkMenuGroup. Sets the appropriate role and aria-attributes for a menu and * contains accessible keyboard and mouse handling logic. * * It also acts as a RadioGroup for elements marked with role `menuitemradio`. */ @Directive({ selector: '[cdkMenu]', exportAs: 'cdkMenu', host: { 'role': 'menu', 'class': 'cdk-menu', '[class.cdk-menu-inline]': 'isInline', '(keydown)': '_handleKeyEvent($event)', }, providers: [ {provide: CdkMenuGroup, useExisting: CdkMenu}, {provide: CDK_MENU, useExisting: CdkMenu}, PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER('vertical'), ], }) export class CdkMenu extends CdkMenuBase implements AfterContentInit, OnDestroy { private _parentTrigger = inject(MENU_TRIGGER, {optional: true}); /** Event emitted when the menu is closed. */ @Output() readonly closed: EventEmitter<void> = new EventEmitter(); /** The direction items in the menu flow. */ override readonly orientation = 'vertical'; /** Whether the menu is displayed inline (i.e. always present vs a conditional popup that the user triggers with a trigger element). */ override readonly isInline = !this._parentTrigger; constructor() { super(); this.destroyed.subscribe(this.closed); this._parentTrigger?.registerChildMenu(this); } override ngAfterContentInit() { super.ngAfterContentInit(); this._subscribeToMenuStackEmptied(); } override ngOnDestroy() { super.ngOnDestroy(); this.closed.complete(); } /** * Handle keyboard events for the Menu. * @param event The keyboard event to be handled. */ _handleKeyEvent(event: KeyboardEvent) { const keyManager = this.keyManager; switch (event.keyCode) { case LEFT_ARROW: case RIGHT_ARROW: if (!hasModifierKey(event)) { event.preventDefault(); keyManager.setFocusOrigin('keyboard'); keyManager.onKeydown(event); } break; case ESCAPE: if (!hasModifierKey(event)) { event.preventDefault(); this.menuStack.close(this, { focusNextOnEmpty: FocusNext.currentItem, focusParentTrigger: true, }); } break; case TAB: if (!hasModifierKey(event, 'altKey', 'metaKey', 'ctrlKey')) { this.menuStack.closeAll({focusParentTrigger: true}); } break; default: keyManager.onKeydown(event); } } /** * Set focus the either the current, previous or next item based on the FocusNext event. * @param focusNext The element to focus. */ private _toggleMenuFocus(focusNext: FocusNext | undefined) { const keyManager = this.keyManager; switch (focusNext) { case FocusNext.nextItem: keyManager.setFocusOrigin('keyboard'); keyManager.setNextItemActive(); break; case FocusNext.previousItem: keyManager.setFocusOrigin('keyboard'); keyManager.setPreviousItemActive(); break; case FocusNext.currentItem: if (keyManager.activeItem) { keyManager.setFocusOrigin('keyboard'); keyManager.setActiveItem(keyManager.activeItem); } break; } } /** Subscribe to the MenuStack emptied events. */ private _subscribeToMenuStackEmptied() { this.menuStack.emptied .pipe(takeUntil(this.destroyed)) .subscribe(event => this._toggleMenuFocus(event)); } }