MCPcopy Create free account
hub / github.com/angular/components / MenuTriggerPattern

Class MenuTriggerPattern

src/aria/private/menu/menu.ts:641–764  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

639
640/** The menu trigger ui pattern class. */
641export class MenuTriggerPattern<V> {
642 /** Whether the menu trigger is expanded. */
643 readonly expanded = signal(false);
644
645 /** Whether the menu trigger has received interaction. */
646 readonly hasBeenInteracted = signal(false);
647
648 /** The pending focus target when the menu is opened before the menu instance is available. */
649 readonly pendingFocus = signal<'first' | 'last' | undefined>(undefined);
650
651 /** The role of the menu trigger. */
652 readonly role = () => 'button';
653
654 /** Whether the menu trigger has a popup. */
655 readonly hasPopup = () => true;
656
657 /** The menu associated with the trigger. */
658 readonly menu: SignalLike<MenuPattern<V> | undefined>;
659
660 /** The tab index of the menu trigger. */
661 readonly tabIndex = computed(() =>
662 this.expanded() && this.menu()?.inputs.activeItem() ? -1 : 0,
663 );
664
665 /** Whether the menu trigger is disabled. */
666 readonly disabled = () => this.inputs.disabled();
667
668 /** Handles keyboard events for the menu trigger. */
669 readonly keydownManager = computed(() => {
670 return new KeyboardEventManager()
671 .on(' ', () => this.open({first: true}))
672 .on('Enter', () => this.open({first: true}))
673 .on('ArrowDown', () => this.open({first: true}))
674 .on('ArrowUp', () => this.open({last: true}))
675 .on('Escape', () => this.close({refocus: true}));
676 });
677
678 constructor(readonly inputs: MenuTriggerInputs<V>) {
679 this.menu = this.inputs.menu;
680 }
681
682 /** Flushes any pending focus when the menu instance becomes available. */
683 pendingFocusEffect(): void {
684 const menu = this.inputs.menu();
685 const intent = this.pendingFocus();
686 const items = menu?.items();
687
688 // We check the items so that we don't try calling into
689 // `first/last` until the items are actually available.
690 if (menu && intent && items?.length) {
691 if (intent === 'first') {
692 menu.first();
693 } else if (intent === 'last') {
694 menu.last();
695 }
696 this.pendingFocus.set(undefined);
697 }
698 }

Callers

nothing calls this directly

Calls 9

openMethod · 0.95
closeMethod · 0.95
signalFunction · 0.90
computedFunction · 0.90
expandedMethod · 0.80
activeItemMethod · 0.80
menuMethod · 0.45
disabledMethod · 0.45
onMethod · 0.45

Tested by

no test coverage detected