@@ -17,20 +17,20 @@ import {
17
17
ChangeDetectionStrategy ,
18
18
Component ,
19
19
ContentChild ,
20
- ContentChildren ,
21
20
ElementRef ,
22
21
EventEmitter ,
23
22
Inject ,
24
23
InjectionToken ,
25
24
Input ,
26
25
OnDestroy ,
27
26
Output ,
28
- QueryList ,
29
27
TemplateRef ,
30
28
ViewChild ,
31
29
ViewEncapsulation ,
32
30
NgZone ,
33
31
OnInit ,
32
+ QueryList ,
33
+ ContentChildren ,
34
34
} from '@angular/core' ;
35
35
import { Observable } from 'rxjs' ;
36
36
import { Subject } from 'rxjs' ;
@@ -39,11 +39,12 @@ import {Subscription} from 'rxjs';
39
39
import { matMenuAnimations } from './menu-animations' ;
40
40
import { throwMatMenuInvalidPositionX , throwMatMenuInvalidPositionY } from './menu-errors' ;
41
41
import { MatMenuItem } from './menu-item' ;
42
- import { MatMenuPanel } from './menu-panel' ;
42
+ import { MatMenuPanel , MAT_MENU_PANEL } from './menu-panel' ;
43
43
import { MatMenuContent } from './menu-content' ;
44
44
import { MenuPositionX , MenuPositionY } from './menu-positions' ;
45
45
import { coerceBooleanProperty } from '@angular/cdk/coercion' ;
46
46
import { FocusOrigin } from '@angular/cdk/a11y' ;
47
+ import { AnimationEvent } from '@angular/animations' ;
47
48
48
49
49
50
/** Default `mat-menu` options that can be overridden. */
@@ -90,18 +91,28 @@ const MAT_MENU_BASE_ELEVATION = 2;
90
91
styleUrls : [ 'menu.css' ] ,
91
92
changeDetection : ChangeDetectionStrategy . OnPush ,
92
93
encapsulation : ViewEncapsulation . None ,
94
+ preserveWhitespaces : false ,
95
+ exportAs : 'matMenu' ,
93
96
animations : [
94
97
matMenuAnimations . transformMenu ,
95
98
matMenuAnimations . fadeInItems
96
99
] ,
97
- exportAs : 'matMenu'
100
+ providers : [
101
+ { provide : MAT_MENU_PANEL , useExisting : MatMenu }
102
+ ]
98
103
} )
99
- export class MatMenu implements OnInit , AfterContentInit , MatMenuPanel , OnDestroy {
104
+ export class MatMenu implements OnInit , AfterContentInit , MatMenuPanel < MatMenuItem > , OnDestroy {
100
105
private _keyManager : FocusKeyManager < MatMenuItem > ;
101
106
private _xPosition : MenuPositionX = this . _defaultOptions . xPosition ;
102
107
private _yPosition : MenuPositionY = this . _defaultOptions . yPosition ;
103
108
private _previousElevation : string ;
104
109
110
+ /** Menu items inside the current menu. */
111
+ private _items : MatMenuItem [ ] = [ ] ;
112
+
113
+ /** Emits whenever the amount of menu items changes. */
114
+ private _itemChanges = new Subject < MatMenuItem [ ] > ( ) ;
115
+
105
116
/** Subscription to tab events on the menu panel */
106
117
private _tabSubscription = Subscription . EMPTY ;
107
118
@@ -112,7 +123,10 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
112
123
_panelAnimationState : 'void' | 'enter' = 'void' ;
113
124
114
125
/** Emits whenever an animation on the menu completes. */
115
- _animationDone = new Subject < void > ( ) ;
126
+ _animationDone = new Subject < AnimationEvent > ( ) ;
127
+
128
+ /** Whether the menu is animating. */
129
+ _isAnimating : boolean ;
116
130
117
131
/** Parent menu of the current menu panel. */
118
132
parentMenu : MatMenuPanel | undefined ;
@@ -148,7 +162,11 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
148
162
/** @docs -private */
149
163
@ViewChild ( TemplateRef ) templateRef : TemplateRef < any > ;
150
164
151
- /** List of the items inside of a menu. */
165
+ /**
166
+ * List of the items inside of a menu.
167
+ * @deprecated
168
+ * @deletion -target 7.0.0
169
+ */
152
170
@ContentChildren ( MatMenuItem ) items : QueryList < MatMenuItem > ;
153
171
154
172
/**
@@ -224,7 +242,7 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
224
242
}
225
243
226
244
ngAfterContentInit ( ) {
227
- this . _keyManager = new FocusKeyManager < MatMenuItem > ( this . items ) . withWrap ( ) . withTypeAhead ( ) ;
245
+ this . _keyManager = new FocusKeyManager < MatMenuItem > ( this . _items ) . withWrap ( ) . withTypeAhead ( ) ;
228
246
this . _tabSubscription = this . _keyManager . tabOut . subscribe ( ( ) => this . close . emit ( 'tab' ) ) ;
229
247
}
230
248
@@ -235,16 +253,10 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
235
253
236
254
/** Stream that emits whenever the hovered menu item changes. */
237
255
_hovered ( ) : Observable < MatMenuItem > {
238
- if ( this . items ) {
239
- return this . items . changes . pipe (
240
- startWith ( this . items ) ,
241
- switchMap ( items => merge ( ...items . map ( item => item . _hovered ) ) )
242
- ) ;
243
- }
244
-
245
- return this . _ngZone . onStable
246
- . asObservable ( )
247
- . pipe ( take ( 1 ) , switchMap ( ( ) => this . _hovered ( ) ) ) ;
256
+ return this . _itemChanges . pipe (
257
+ startWith ( this . _items ) ,
258
+ switchMap ( items => merge ( ...items . map ( item => item . _hovered ) ) )
259
+ ) ;
248
260
}
249
261
250
262
/** Handle a keyboard event from the menu, delegating to the appropriate action. */
@@ -322,6 +334,35 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
322
334
}
323
335
}
324
336
337
+ /**
338
+ * Registers a menu item with the menu.
339
+ * @docs -private
340
+ */
341
+ addItem ( item : MatMenuItem ) {
342
+ // We register the items through this method, rather than picking them up through
343
+ // `ContentChildren`, because we need the items to be picked up by their closest
344
+ // `mat-menu` ancestor. If we used `@ContentChildren(MatMenuItem, {descendants: true})`,
345
+ // all descendant items will bleed into the top-level menu in the case where the consumer
346
+ // has `mat-menu` instances nested inside each other.
347
+ if ( this . _items . indexOf ( item ) === - 1 ) {
348
+ this . _items . push ( item ) ;
349
+ this . _itemChanges . next ( this . _items ) ;
350
+ }
351
+ }
352
+
353
+ /**
354
+ * Removes an item from the menu.
355
+ * @docs -private
356
+ */
357
+ removeItem ( item : MatMenuItem ) {
358
+ const index = this . _items . indexOf ( item ) ;
359
+
360
+ if ( this . _items . indexOf ( item ) > - 1 ) {
361
+ this . _items . splice ( index , 1 ) ;
362
+ this . _itemChanges . next ( this . _items ) ;
363
+ }
364
+ }
365
+
325
366
/** Starts the enter animation. */
326
367
_startAnimation ( ) {
327
368
// @deletion -target 6.0.0 Combine with _resetAnimation.
@@ -335,7 +376,8 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
335
376
}
336
377
337
378
/** Callback that is invoked when the panel animation completes. */
338
- _onAnimationDone ( ) {
339
- this . _animationDone . next ( ) ;
379
+ _onAnimationDone ( event : AnimationEvent ) {
380
+ this . _animationDone . next ( event ) ;
381
+ this . _isAnimating = false ;
340
382
}
341
383
}
0 commit comments