()
| 288 | } |
| 289 | |
| 290 | ngAfterContentInit() { |
| 291 | this._updateDirectDescendants(); |
| 292 | this._keyManager = new FocusKeyManager(this._directDescendantItems) |
| 293 | .withWrap() |
| 294 | .withTypeAhead() |
| 295 | .withHomeAndEnd(); |
| 296 | this._keyManager.tabOut.subscribe(() => this.closed.emit('tab')); |
| 297 | |
| 298 | // If a user manually (programmatically) focuses a menu item, we need to reflect that focus |
| 299 | // change back to the key manager. Note that we don't need to unsubscribe here because _focused |
| 300 | // is internal and we know that it gets completed on destroy. |
| 301 | this._directDescendantItems.changes |
| 302 | .pipe( |
| 303 | startWith(this._directDescendantItems), |
| 304 | switchMap(items => merge(...items.map((item: MatMenuItem) => item._focused))), |
| 305 | ) |
| 306 | .subscribe(focusedItem => this._keyManager.updateActiveItem(focusedItem as MatMenuItem)); |
| 307 | |
| 308 | this._directDescendantItems.changes.subscribe((itemsList: QueryList<MatMenuItem>) => { |
| 309 | // Move focus to another item, if the active item is removed from the list. |
| 310 | // We need to debounce the callback, because multiple items might be removed |
| 311 | // in quick succession. |
| 312 | const manager = this._keyManager; |
| 313 | |
| 314 | if (this._panelAnimationState === 'enter' && manager.activeItem?._hasFocus()) { |
| 315 | const items = itemsList.toArray(); |
| 316 | const index = Math.max(0, Math.min(items.length - 1, manager.activeItemIndex || 0)); |
| 317 | |
| 318 | if (items[index] && !items[index].disabled) { |
| 319 | manager.setActiveItem(index); |
| 320 | } else { |
| 321 | manager.setNextItemActive(); |
| 322 | } |
| 323 | } |
| 324 | }); |
| 325 | } |
| 326 | |
| 327 | ngOnDestroy() { |
| 328 | this._keyManager?.destroy(); |
nothing calls this directly
no test coverage detected