@angular/cdk-experimental 14.0.0-next.6 → 14.0.0-next.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/combobox/combobox-module.d.ts +3 -4
  2. package/combobox/combobox-popup.d.ts +6 -8
  3. package/combobox/combobox.d.ts +15 -18
  4. package/combobox/public-api.d.ts +0 -1
  5. package/dialog/dialog-config.d.ts +6 -1
  6. package/esm2020/column-resize/column-resize-directives/column-resize-flex.mjs +3 -3
  7. package/esm2020/column-resize/column-resize-directives/column-resize.mjs +3 -3
  8. package/esm2020/column-resize/column-resize-directives/default-enabled-column-resize-flex.mjs +3 -3
  9. package/esm2020/column-resize/column-resize-directives/default-enabled-column-resize.mjs +3 -3
  10. package/esm2020/column-resize/column-resize-module.mjs +8 -8
  11. package/esm2020/column-resize/column-resize-notifier.mjs +6 -6
  12. package/esm2020/column-resize/column-resize.mjs +3 -3
  13. package/esm2020/column-resize/column-size-store.mjs +3 -3
  14. package/esm2020/column-resize/event-dispatcher.mjs +3 -3
  15. package/esm2020/column-resize/overlay-handle.mjs +3 -3
  16. package/esm2020/column-resize/resizable.mjs +3 -3
  17. package/esm2020/column-resize/resize-strategy.mjs +9 -9
  18. package/esm2020/combobox/combobox-module.mjs +6 -7
  19. package/esm2020/combobox/combobox-popup.mjs +12 -23
  20. package/esm2020/combobox/combobox.mjs +50 -34
  21. package/esm2020/combobox/public-api.mjs +1 -2
  22. package/esm2020/dialog/dialog-config.mjs +1 -1
  23. package/esm2020/dialog/dialog-container.mjs +12 -7
  24. package/esm2020/dialog/dialog-module.mjs +4 -4
  25. package/esm2020/dialog/dialog.mjs +5 -5
  26. package/esm2020/listbox/listbox-module.mjs +4 -4
  27. package/esm2020/listbox/listbox.mjs +26 -44
  28. package/esm2020/menu/context-menu.mjs +46 -118
  29. package/esm2020/menu/menu-aim.mjs +6 -6
  30. package/esm2020/menu/menu-bar.mjs +46 -134
  31. package/esm2020/menu/menu-base.mjs +129 -0
  32. package/esm2020/menu/menu-errors.mjs +1 -9
  33. package/esm2020/menu/menu-group.mjs +9 -9
  34. package/esm2020/menu/menu-interface.mjs +1 -1
  35. package/esm2020/menu/menu-item-checkbox.mjs +3 -3
  36. package/esm2020/menu/menu-item-radio.mjs +13 -8
  37. package/esm2020/menu/menu-item-selectable.mjs +3 -3
  38. package/esm2020/menu/menu-item-trigger.mjs +66 -151
  39. package/esm2020/menu/menu-item.mjs +51 -45
  40. package/esm2020/menu/menu-module.mjs +5 -9
  41. package/esm2020/menu/menu-stack.mjs +31 -6
  42. package/esm2020/menu/menu-trigger.mjs +70 -0
  43. package/esm2020/menu/menu.mjs +58 -155
  44. package/esm2020/menu/public-api.mjs +3 -3
  45. package/esm2020/popover-edit/edit-event-dispatcher.mjs +3 -3
  46. package/esm2020/popover-edit/edit-ref.mjs +3 -3
  47. package/esm2020/popover-edit/edit-services.mjs +3 -3
  48. package/esm2020/popover-edit/focus-dispatcher.mjs +3 -3
  49. package/esm2020/popover-edit/focus-escape-notifier.mjs +3 -3
  50. package/esm2020/popover-edit/lens-directives.mjs +9 -9
  51. package/esm2020/popover-edit/popover-edit-module.mjs +4 -4
  52. package/esm2020/popover-edit/popover-edit-position-strategy-factory.mjs +6 -6
  53. package/esm2020/popover-edit/table-directives.mjs +15 -15
  54. package/esm2020/scrolling/auto-size-virtual-scroll.mjs +3 -3
  55. package/esm2020/scrolling/scrolling-module.mjs +4 -4
  56. package/esm2020/selection/row-selection.mjs +3 -3
  57. package/esm2020/selection/select-all.mjs +3 -3
  58. package/esm2020/selection/selection-column.mjs +3 -3
  59. package/esm2020/selection/selection-module.mjs +4 -4
  60. package/esm2020/selection/selection-toggle.mjs +3 -3
  61. package/esm2020/selection/selection.mjs +3 -3
  62. package/esm2020/table-scroll-container/table-scroll-container-module.mjs +4 -4
  63. package/esm2020/table-scroll-container/table-scroll-container.mjs +3 -3
  64. package/esm2020/version.mjs +1 -1
  65. package/fesm2015/cdk-experimental.mjs +1 -1
  66. package/fesm2015/cdk-experimental.mjs.map +1 -1
  67. package/fesm2015/column-resize.mjs +50 -50
  68. package/fesm2015/combobox.mjs +63 -106
  69. package/fesm2015/combobox.mjs.map +1 -1
  70. package/fesm2015/dialog.mjs +20 -14
  71. package/fesm2015/dialog.mjs.map +1 -1
  72. package/fesm2015/listbox.mjs +31 -47
  73. package/fesm2015/listbox.mjs.map +1 -1
  74. package/fesm2015/menu.mjs +587 -766
  75. package/fesm2015/menu.mjs.map +1 -1
  76. package/fesm2015/popover-edit.mjs +49 -49
  77. package/fesm2015/scrolling.mjs +7 -7
  78. package/fesm2015/selection.mjs +19 -19
  79. package/fesm2015/table-scroll-container.mjs +7 -7
  80. package/fesm2020/cdk-experimental.mjs +1 -1
  81. package/fesm2020/cdk-experimental.mjs.map +1 -1
  82. package/fesm2020/column-resize.mjs +50 -50
  83. package/fesm2020/combobox.mjs +62 -103
  84. package/fesm2020/combobox.mjs.map +1 -1
  85. package/fesm2020/dialog.mjs +19 -14
  86. package/fesm2020/dialog.mjs.map +1 -1
  87. package/fesm2020/listbox.mjs +29 -46
  88. package/fesm2020/listbox.mjs.map +1 -1
  89. package/fesm2020/menu.mjs +482 -655
  90. package/fesm2020/menu.mjs.map +1 -1
  91. package/fesm2020/popover-edit.mjs +49 -49
  92. package/fesm2020/scrolling.mjs +7 -7
  93. package/fesm2020/selection.mjs +19 -19
  94. package/fesm2020/table-scroll-container.mjs +7 -7
  95. package/listbox/listbox.d.ts +16 -13
  96. package/menu/context-menu.d.ts +7 -46
  97. package/menu/menu-bar.d.ts +9 -50
  98. package/menu/menu-base.d.ts +64 -0
  99. package/menu/menu-errors.d.ts +0 -5
  100. package/menu/menu-group.d.ts +2 -2
  101. package/menu/menu-interface.d.ts +1 -1
  102. package/menu/menu-item-radio.d.ts +4 -3
  103. package/menu/menu-item-trigger.d.ts +8 -38
  104. package/menu/menu-item.d.ts +11 -6
  105. package/menu/menu-module.d.ts +9 -10
  106. package/menu/menu-stack.d.ts +22 -6
  107. package/menu/menu-trigger.d.ts +48 -0
  108. package/menu/menu.d.ts +11 -67
  109. package/menu/public-api.d.ts +2 -2
  110. package/package.json +2 -2
  111. package/combobox/combobox-panel.d.ts +0 -27
  112. package/esm2020/combobox/combobox-panel.mjs +0 -48
  113. package/esm2020/menu/menu-panel.mjs +0 -37
  114. package/menu/menu-panel.d.ts +0 -30
package/fesm2015/menu.mjs CHANGED
@@ -1,16 +1,16 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Injectable, Directive, EventEmitter, Optional, Inject, Input, Output, Self, ContentChildren, NgModule } from '@angular/core';
2
+ import { InjectionToken, Optional, SkipSelf, Inject, Injectable, Directive, EventEmitter, Injector, Self, Input, Output, ContentChildren, NgModule } from '@angular/core';
3
3
  import * as i1 from '@angular/cdk/overlay';
4
- import { OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
5
- import { FocusKeyManager } from '@angular/cdk/a11y';
4
+ import { OverlayConfig, STANDARD_DROPDOWN_BELOW_POSITIONS, STANDARD_DROPDOWN_ADJACENT_POSITIONS, OverlayModule } from '@angular/cdk/overlay';
6
5
  import { UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, ENTER, SPACE, TAB, ESCAPE, hasModifierKey } from '@angular/cdk/keycodes';
7
- import { Subject, fromEvent, merge, defer, partition } from 'rxjs';
8
- import { filter, takeUntil, startWith, mergeMap, mapTo, mergeAll, take, switchMap, skip } from 'rxjs/operators';
9
- import * as i1$1 from '@angular/cdk/collections';
6
+ import { filter, takeUntil, startWith, mergeMap, mapTo, mergeAll, switchMap, take, skip } from 'rxjs/operators';
7
+ import * as i1$2 from '@angular/cdk/collections';
10
8
  import { UniqueSelectionDispatcher } from '@angular/cdk/collections';
11
9
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
12
- import * as i2 from '@angular/cdk/bidi';
10
+ import { Subject, fromEvent, merge, defer, partition } from 'rxjs';
11
+ import * as i1$1 from '@angular/cdk/bidi';
13
12
  import { TemplatePortal } from '@angular/cdk/portal';
13
+ import { FocusKeyManager } from '@angular/cdk/a11y';
14
14
 
15
15
  /**
16
16
  * @license
@@ -29,14 +29,134 @@ const CDK_MENU = new InjectionToken('cdk-menu');
29
29
  * Use of this source code is governed by an MIT-style license that can be
30
30
  * found in the LICENSE file at https://angular.io/license
31
31
  */
32
+ /** Injection token used for an implementation of MenuStack. */
33
+ const MENU_STACK = new InjectionToken('cdk-menu-stack');
34
+ /** A provider that provides the parent menu stack, or a new menu stack if there is no parent one. */
35
+ const PARENT_OR_NEW_MENU_STACK_PROVIDER = {
36
+ provide: MENU_STACK,
37
+ deps: [[new Optional(), new SkipSelf(), new Inject(MENU_STACK)]],
38
+ useFactory: (parentMenuStack) => parentMenuStack || new MenuStack(),
39
+ };
40
+ /** A provider that provides the parent menu stack, or a new menu stack if there is no parent one. */
41
+ const PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER = {
42
+ provide: MENU_STACK,
43
+ deps: [[new Optional(), new SkipSelf(), new Inject(MENU_STACK)]],
44
+ useFactory: (parentMenuStack) => parentMenuStack || MenuStack.inline(),
45
+ };
32
46
  /**
33
- * Throws an exception when a menu panel already has a menu stack.
34
- * @docs-private
47
+ * MenuStack allows subscribers to listen for close events (when a MenuStackItem is popped off
48
+ * of the stack) in order to perform closing actions. Upon the MenuStack being empty it emits
49
+ * from the `empty` observable specifying the next focus action which the listener should perform
50
+ * as requested by the closer.
35
51
  */
36
- function throwExistingMenuStackError() {
37
- throw Error('CdkMenuPanel is already referenced by different CdkMenuTrigger. Ensure that a menu is' +
38
- ' opened by a single trigger only.');
52
+ class MenuStack {
53
+ constructor() {
54
+ /** All MenuStackItems tracked by this MenuStack. */
55
+ this._elements = [];
56
+ /** Emits the element which was popped off of the stack when requested by a closer. */
57
+ this._close = new Subject();
58
+ /** Emits once the MenuStack has become empty after popping off elements. */
59
+ this._empty = new Subject();
60
+ /** Observable which emits the MenuStackItem which has been requested to close. */
61
+ this.closed = this._close;
62
+ /**
63
+ * Observable which emits when the MenuStack is empty after popping off the last element. It
64
+ * emits a FocusNext event which specifies the action the closer has requested the listener
65
+ * perform.
66
+ */
67
+ this.emptied = this._empty;
68
+ this._hasInlineMenu = false;
69
+ }
70
+ static inline() {
71
+ const stack = new MenuStack();
72
+ stack._hasInlineMenu = true;
73
+ return stack;
74
+ }
75
+ /** @param menu the MenuStackItem to put on the stack. */
76
+ push(menu) {
77
+ this._elements.push(menu);
78
+ }
79
+ /**
80
+ * Pop items off of the stack up to and including `lastItem` and emit each on the close
81
+ * observable. If the stack is empty or `lastItem` is not on the stack it does nothing.
82
+ * @param lastItem the last item to pop off the stack.
83
+ * @param focusNext the event to emit on the `empty` observable if the method call resulted in an
84
+ * empty stack. Does not emit if the stack was initially empty or if `lastItem` was not on the
85
+ * stack.
86
+ */
87
+ close(lastItem, focusNext) {
88
+ if (this._elements.indexOf(lastItem) >= 0) {
89
+ let poppedElement;
90
+ do {
91
+ poppedElement = this._elements.pop();
92
+ this._close.next(poppedElement);
93
+ } while (poppedElement !== lastItem);
94
+ if (this.isEmpty()) {
95
+ this._empty.next(focusNext);
96
+ }
97
+ }
98
+ }
99
+ /**
100
+ * Pop items off of the stack up to but excluding `lastItem` and emit each on the close
101
+ * observable. If the stack is empty or `lastItem` is not on the stack it does nothing.
102
+ * @param lastItem the element which should be left on the stack
103
+ * @return whether or not an item was removed from the stack
104
+ */
105
+ closeSubMenuOf(lastItem) {
106
+ let removed = false;
107
+ if (this._elements.indexOf(lastItem) >= 0) {
108
+ removed = this.peek() !== lastItem;
109
+ while (this.peek() !== lastItem) {
110
+ this._close.next(this._elements.pop());
111
+ }
112
+ }
113
+ return removed;
114
+ }
115
+ /**
116
+ * Pop off all MenuStackItems and emit each one on the `close` observable one by one.
117
+ * @param focusNext the event to emit on the `empty` observable once the stack is emptied. Does
118
+ * not emit if the stack was initially empty.
119
+ */
120
+ closeAll(focusNext) {
121
+ if (!this.isEmpty()) {
122
+ while (!this.isEmpty()) {
123
+ const menuStackItem = this._elements.pop();
124
+ if (menuStackItem) {
125
+ this._close.next(menuStackItem);
126
+ }
127
+ }
128
+ this._empty.next(focusNext);
129
+ }
130
+ }
131
+ /** Return true if this stack is empty. */
132
+ isEmpty() {
133
+ return !this._elements.length;
134
+ }
135
+ /** Return the length of the stack. */
136
+ length() {
137
+ return this._elements.length;
138
+ }
139
+ /** Get the top most element on the stack. */
140
+ peek() {
141
+ return this._elements[this._elements.length - 1];
142
+ }
143
+ hasInlineMenu() {
144
+ return this._hasInlineMenu;
145
+ }
39
146
  }
147
+ MenuStack.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: MenuStack, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
148
+ MenuStack.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: MenuStack });
149
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: MenuStack, decorators: [{
150
+ type: Injectable
151
+ }] });
152
+
153
+ /**
154
+ * @license
155
+ * Copyright Google LLC All Rights Reserved.
156
+ *
157
+ * Use of this source code is governed by an MIT-style license that can be
158
+ * found in the LICENSE file at https://angular.io/license
159
+ */
40
160
  /**
41
161
  * Throws an exception when an instance of the PointerFocusTracker is not provided.
42
162
  * @docs-private
@@ -223,9 +343,9 @@ class TargetMenuAim {
223
343
  this._destroyed.complete();
224
344
  }
225
345
  }
226
- TargetMenuAim.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: TargetMenuAim, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
227
- TargetMenuAim.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: TargetMenuAim });
228
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: TargetMenuAim, decorators: [{
346
+ TargetMenuAim.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: TargetMenuAim, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
347
+ TargetMenuAim.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: TargetMenuAim });
348
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: TargetMenuAim, decorators: [{
229
349
  type: Injectable
230
350
  }], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
231
351
  /**
@@ -234,9 +354,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
234
354
  */
235
355
  class CdkTargetMenuAim {
236
356
  }
237
- CdkTargetMenuAim.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkTargetMenuAim, deps: [], target: i0.ɵɵFactoryTarget.Directive });
238
- CdkTargetMenuAim.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkTargetMenuAim, selector: "[cdkTargetMenuAim]", providers: [{ provide: MENU_AIM, useClass: TargetMenuAim }], exportAs: ["cdkTargetMenuAim"], ngImport: i0 });
239
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkTargetMenuAim, decorators: [{
357
+ CdkTargetMenuAim.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkTargetMenuAim, deps: [], target: i0.ɵɵFactoryTarget.Directive });
358
+ CdkTargetMenuAim.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkTargetMenuAim, selector: "[cdkTargetMenuAim]", providers: [{ provide: MENU_AIM, useClass: TargetMenuAim }], exportAs: ["cdkTargetMenuAim"], ngImport: i0 });
359
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkTargetMenuAim, decorators: [{
240
360
  type: Directive,
241
361
  args: [{
242
362
  selector: '[cdkTargetMenuAim]',
@@ -252,103 +372,66 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
252
372
  * Use of this source code is governed by an MIT-style license that can be
253
373
  * found in the LICENSE file at https://angular.io/license
254
374
  */
255
- /**
256
- * MenuStack allows subscribers to listen for close events (when a MenuStackItem is popped off
257
- * of the stack) in order to perform closing actions. Upon the MenuStack being empty it emits
258
- * from the `empty` observable specifying the next focus action which the listener should perform
259
- * as requested by the closer.
260
- */
261
- class MenuStack {
262
- constructor() {
263
- /** All MenuStackItems tracked by this MenuStack. */
264
- this._elements = [];
265
- /** Emits the element which was popped off of the stack when requested by a closer. */
266
- this._close = new Subject();
267
- /** Emits once the MenuStack has become empty after popping off elements. */
268
- this._empty = new Subject();
269
- /** Observable which emits the MenuStackItem which has been requested to close. */
270
- this.closed = this._close;
271
- /**
272
- * Observable which emits when the MenuStack is empty after popping off the last element. It
273
- * emits a FocusNext event which specifies the action the closer has requested the listener
274
- * perform.
275
- */
276
- this.emptied = this._empty;
277
- }
278
- /** @param menu the MenuStackItem to put on the stack. */
279
- push(menu) {
280
- this._elements.push(menu);
281
- }
282
- /**
283
- * Pop items off of the stack up to and including `lastItem` and emit each on the close
284
- * observable. If the stack is empty or `lastItem` is not on the stack it does nothing.
285
- * @param lastItem the last item to pop off the stack.
286
- * @param focusNext the event to emit on the `empty` observable if the method call resulted in an
287
- * empty stack. Does not emit if the stack was initially empty or if `lastItem` was not on the
288
- * stack.
289
- */
290
- close(lastItem, focusNext) {
291
- if (this._elements.indexOf(lastItem) >= 0) {
292
- let poppedElement;
293
- do {
294
- poppedElement = this._elements.pop();
295
- this._close.next(poppedElement);
296
- } while (poppedElement !== lastItem);
297
- if (this.isEmpty()) {
298
- this._empty.next(focusNext);
299
- }
300
- }
375
+ /** Injection token used for an implementation of MenuStack. */
376
+ const MENU_TRIGGER = new InjectionToken('cdk-menu-trigger');
377
+ class MenuTrigger {
378
+ constructor(injector, menuStack) {
379
+ this.injector = injector;
380
+ this.menuStack = menuStack;
381
+ /** Emits when the attached menu is requested to open */
382
+ this.opened = new EventEmitter();
383
+ /** Emits when the attached menu is requested to close */
384
+ this.closed = new EventEmitter();
385
+ /** A reference to the overlay which manages the triggered menu */
386
+ this._overlayRef = null;
387
+ /** Emits when this trigger is destroyed. */
388
+ this._destroyed = new Subject();
389
+ /** Emits when the outside pointer events listener on the overlay should be stopped. */
390
+ this._stopOutsideClicksListener = merge(this.closed, this._destroyed);
301
391
  }
302
- /**
303
- * Pop items off of the stack up to but excluding `lastItem` and emit each on the close
304
- * observable. If the stack is empty or `lastItem` is not on the stack it does nothing.
305
- * @param lastItem the element which should be left on the stack
306
- * @return whether or not an item was removed from the stack
307
- */
308
- closeSubMenuOf(lastItem) {
309
- let removed = false;
310
- if (this._elements.indexOf(lastItem) >= 0) {
311
- removed = this.peek() !== lastItem;
312
- while (this.peek() !== lastItem) {
313
- this._close.next(this._elements.pop());
314
- }
315
- }
316
- return removed;
392
+ ngOnDestroy() {
393
+ this._destroyOverlay();
394
+ this._destroyed.next();
395
+ this._destroyed.complete();
317
396
  }
318
- /**
319
- * Pop off all MenuStackItems and emit each one on the `close` observable one by one.
320
- * @param focusNext the event to emit on the `empty` observable once the stack is emptied. Does
321
- * not emit if the stack was initially empty.
322
- */
323
- closeAll(focusNext) {
324
- if (!this.isEmpty()) {
325
- while (!this.isEmpty()) {
326
- const menuStackItem = this._elements.pop();
327
- if (menuStackItem) {
328
- this._close.next(menuStackItem);
329
- }
330
- }
331
- this._empty.next(focusNext);
332
- }
397
+ /** Whether the attached menu is open. */
398
+ isOpen() {
399
+ var _a;
400
+ return !!((_a = this._overlayRef) === null || _a === void 0 ? void 0 : _a.hasAttached());
333
401
  }
334
- /** Return true if this stack is empty. */
335
- isEmpty() {
336
- return !this._elements.length;
402
+ registerChildMenu(child) {
403
+ this.childMenu = child;
337
404
  }
338
- /** Return the length of the stack. */
339
- length() {
340
- return this._elements.length;
405
+ getChildMenuInjector() {
406
+ this._childMenuInjector =
407
+ this._childMenuInjector ||
408
+ Injector.create({
409
+ providers: [
410
+ { provide: MENU_TRIGGER, useValue: this },
411
+ { provide: MENU_STACK, useValue: this.menuStack },
412
+ ],
413
+ parent: this.injector,
414
+ });
415
+ return this._childMenuInjector;
341
416
  }
342
- /** Get the top most element on the stack. */
343
- peek() {
344
- return this._elements[this._elements.length - 1];
417
+ /** Destroy and unset the overlay reference it if exists */
418
+ _destroyOverlay() {
419
+ if (this._overlayRef) {
420
+ this._overlayRef.dispose();
421
+ this._overlayRef = null;
422
+ }
345
423
  }
346
424
  }
347
- /** NoopMenuStack is a placeholder MenuStack used for inline menus. */
348
- class NoopMenuStack extends MenuStack {
349
- /** Noop push - does not add elements to the MenuStack. */
350
- push(_) { }
351
- }
425
+ MenuTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: MenuTrigger, deps: [{ token: i0.Injector }, { token: MENU_STACK }], target: i0.ɵɵFactoryTarget.Directive });
426
+ MenuTrigger.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: MenuTrigger, ngImport: i0 });
427
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: MenuTrigger, decorators: [{
428
+ type: Directive
429
+ }], ctorParameters: function () {
430
+ return [{ type: i0.Injector }, { type: MenuStack, decorators: [{
431
+ type: Inject,
432
+ args: [MENU_STACK]
433
+ }] }];
434
+ } });
352
435
 
353
436
  /**
354
437
  * @license
@@ -381,8 +464,9 @@ function isClickInsideMenuOverlay(target) {
381
464
  * The directive must be placed along with the `cdkMenuItem` directive in order to enable full
382
465
  * functionality.
383
466
  */
384
- class CdkMenuItemTrigger {
385
- constructor(_elementRef, _viewContainerRef, _overlay, _ngZone, _parentMenu, _menuAim, _directionality) {
467
+ class CdkMenuItemTrigger extends MenuTrigger {
468
+ constructor(injector, _elementRef, _viewContainerRef, _overlay, _ngZone, menuStack, _parentMenu, _menuAim, _directionality) {
469
+ super(injector, menuStack);
386
470
  this._elementRef = _elementRef;
387
471
  this._viewContainerRef = _viewContainerRef;
388
472
  this._overlay = _overlay;
@@ -390,46 +474,16 @@ class CdkMenuItemTrigger {
390
474
  this._parentMenu = _parentMenu;
391
475
  this._menuAim = _menuAim;
392
476
  this._directionality = _directionality;
393
- /** Emits when the attached menu is requested to open */
394
- this.opened = new EventEmitter();
395
- /** Emits when the attached menu is requested to close */
396
- this.closed = new EventEmitter();
397
- /** The menu stack for this trigger and its sub-menus. */
398
- this._menuStack = new MenuStack();
399
- /** A reference to the overlay which manages the triggered menu */
400
- this._overlayRef = null;
401
- /** Emits when this trigger is destroyed. */
402
- this._destroyed = new Subject();
403
- /** Emits when the outside pointer events listener on the overlay should be stopped. */
404
- this._stopOutsideClicksListener = merge(this.closed, this._destroyed);
405
477
  this._registerCloseHandler();
406
478
  this._subscribeToMouseEnter();
407
479
  }
408
- /** Template reference variable to the menu this trigger opens */
409
- get menuPanel() {
410
- return this._menuPanel;
411
- }
412
- set menuPanel(panel) {
413
- // If the provided panel already has a stack, that means it already has a trigger configured.
414
- // Note however that there are some edge cases where two triggers **may** share the same menu,
415
- // e.g. two triggers in two separate menus.
416
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && (panel === null || panel === void 0 ? void 0 : panel._menuStack)) {
417
- throwExistingMenuStackError();
418
- }
419
- this._menuPanel = panel;
420
- if (this._menuPanel) {
421
- this._menuPanel._menuStack = this._getMenuStack();
422
- }
423
- }
424
480
  /** Open/close the attached menu if the trigger has been configured with one */
425
481
  toggle() {
426
- if (this.hasMenu()) {
427
- this.isMenuOpen() ? this.closeMenu() : this.openMenu();
428
- }
482
+ this.isOpen() ? this.close() : this.open();
429
483
  }
430
484
  /** Open the attached menu. */
431
- openMenu() {
432
- if (!this.isMenuOpen()) {
485
+ open() {
486
+ if (!this.isOpen()) {
433
487
  this.opened.next();
434
488
  this._overlayRef = this._overlayRef || this._overlay.create(this._getOverlayConfig());
435
489
  this._overlayRef.attach(this._getPortal());
@@ -437,28 +491,19 @@ class CdkMenuItemTrigger {
437
491
  }
438
492
  }
439
493
  /** Close the opened menu. */
440
- closeMenu() {
441
- if (this.isMenuOpen()) {
494
+ close() {
495
+ if (this.isOpen()) {
442
496
  this.closed.next();
443
497
  this._overlayRef.detach();
444
498
  }
445
499
  this._closeSiblingTriggers();
446
500
  }
447
- /** Return true if the trigger has an attached menu */
448
- hasMenu() {
449
- return !!this.menuPanel;
450
- }
451
- /** Whether the menu this button is a trigger for is open */
452
- isMenuOpen() {
453
- return this._overlayRef ? this._overlayRef.hasAttached() : false;
454
- }
455
501
  /**
456
502
  * Get a reference to the rendered Menu if the Menu is open and it is visible in the DOM.
457
503
  * @return the menu if it is open, otherwise undefined.
458
504
  */
459
505
  getMenu() {
460
- var _a;
461
- return (_a = this.menuPanel) === null || _a === void 0 ? void 0 : _a._menu;
506
+ return this.childMenu;
462
507
  }
463
508
  /**
464
509
  * Subscribe to the mouseenter events and close any sibling menu items if this element is moused
@@ -468,11 +513,11 @@ class CdkMenuItemTrigger {
468
513
  // Closes any sibling menu items and opens the menu associated with this trigger.
469
514
  const toggleMenus = () => this._ngZone.run(() => {
470
515
  this._closeSiblingTriggers();
471
- this.openMenu();
516
+ this.open();
472
517
  });
473
518
  this._ngZone.runOutsideAngular(() => {
474
519
  fromEvent(this._elementRef.nativeElement, 'mouseenter')
475
- .pipe(filter(() => { var _a; return !((_a = this._getMenuStack()) === null || _a === void 0 ? void 0 : _a.isEmpty()) && !this.isMenuOpen(); }), takeUntil(this._destroyed))
520
+ .pipe(filter(() => !this.menuStack.isEmpty() && !this.isOpen()), takeUntil(this._destroyed))
476
521
  .subscribe(() => {
477
522
  if (this._menuAim) {
478
523
  this._menuAim.toggle(toggleMenus);
@@ -489,47 +534,37 @@ class CdkMenuItemTrigger {
489
534
  * @param event the keyboard event to handle
490
535
  */
491
536
  _toggleOnKeydown(event) {
492
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
537
+ var _a, _b, _c, _d, _e, _f, _g;
493
538
  const keyCode = event.keyCode;
494
539
  switch (keyCode) {
495
540
  case SPACE:
496
541
  case ENTER:
497
542
  event.preventDefault();
498
543
  this.toggle();
499
- (_b = (_a = this.menuPanel) === null || _a === void 0 ? void 0 : _a._menu) === null || _b === void 0 ? void 0 : _b.focusFirstItem('keyboard');
544
+ (_a = this.childMenu) === null || _a === void 0 ? void 0 : _a.focusFirstItem('keyboard');
500
545
  break;
501
546
  case RIGHT_ARROW:
502
- if (this._parentMenu && this._isParentVertical()) {
547
+ if (this._parentMenu && this._isParentVertical() && ((_b = this._directionality) === null || _b === void 0 ? void 0 : _b.value) !== 'rtl') {
503
548
  event.preventDefault();
504
- if (((_c = this._directionality) === null || _c === void 0 ? void 0 : _c.value) === 'rtl') {
505
- this._getMenuStack().close(this._parentMenu, 2 /* currentItem */);
506
- }
507
- else {
508
- this.openMenu();
509
- (_e = (_d = this.menuPanel) === null || _d === void 0 ? void 0 : _d._menu) === null || _e === void 0 ? void 0 : _e.focusFirstItem('keyboard');
510
- }
549
+ this.open();
550
+ (_c = this.childMenu) === null || _c === void 0 ? void 0 : _c.focusFirstItem('keyboard');
511
551
  }
512
552
  break;
513
553
  case LEFT_ARROW:
514
- if (this._parentMenu && this._isParentVertical()) {
554
+ if (this._parentMenu && this._isParentVertical() && ((_d = this._directionality) === null || _d === void 0 ? void 0 : _d.value) === 'rtl') {
515
555
  event.preventDefault();
516
- if (((_f = this._directionality) === null || _f === void 0 ? void 0 : _f.value) === 'rtl') {
517
- this.openMenu();
518
- (_h = (_g = this.menuPanel) === null || _g === void 0 ? void 0 : _g._menu) === null || _h === void 0 ? void 0 : _h.focusFirstItem('keyboard');
519
- }
520
- else {
521
- this._getMenuStack().close(this._parentMenu, 2 /* currentItem */);
522
- }
556
+ this.open();
557
+ (_e = this.childMenu) === null || _e === void 0 ? void 0 : _e.focusFirstItem('keyboard');
523
558
  }
524
559
  break;
525
560
  case DOWN_ARROW:
526
561
  case UP_ARROW:
527
562
  if (!this._isParentVertical()) {
528
563
  event.preventDefault();
529
- this.openMenu();
564
+ this.open();
530
565
  keyCode === DOWN_ARROW
531
- ? (_k = (_j = this.menuPanel) === null || _j === void 0 ? void 0 : _j._menu) === null || _k === void 0 ? void 0 : _k.focusFirstItem('keyboard')
532
- : (_m = (_l = this.menuPanel) === null || _l === void 0 ? void 0 : _l._menu) === null || _m === void 0 ? void 0 : _m.focusLastItem('keyboard');
566
+ ? (_f = this.childMenu) === null || _f === void 0 ? void 0 : _f.focusFirstItem('keyboard')
567
+ : (_g = this.childMenu) === null || _g === void 0 ? void 0 : _g.focusLastItem('keyboard');
533
568
  }
534
569
  break;
535
570
  }
@@ -537,17 +572,17 @@ class CdkMenuItemTrigger {
537
572
  /** Close out any sibling menu trigger menus. */
538
573
  _closeSiblingTriggers() {
539
574
  if (this._parentMenu) {
540
- const menuStack = this._getMenuStack();
541
575
  // If nothing was removed from the stack and the last element is not the parent item
542
576
  // that means that the parent menu is a menu bar since we don't put the menu bar on the
543
577
  // stack
544
- const isParentMenuBar = !menuStack.closeSubMenuOf(this._parentMenu) && menuStack.peek() !== this._parentMenu;
578
+ const isParentMenuBar = !this.menuStack.closeSubMenuOf(this._parentMenu) &&
579
+ this.menuStack.peek() !== this._parentMenu;
545
580
  if (isParentMenuBar) {
546
- menuStack.closeAll();
581
+ this.menuStack.closeAll();
547
582
  }
548
583
  }
549
584
  else {
550
- this._getMenuStack().closeAll();
585
+ this.menuStack.closeAll();
551
586
  }
552
587
  }
553
588
  /** Get the configuration object used to create the overlay */
@@ -567,32 +602,22 @@ class CdkMenuItemTrigger {
567
602
  }
568
603
  /** Determine and return where to position the opened menu relative to the menu item */
569
604
  _getOverlayPositions() {
570
- // TODO: use a common positioning config from (possibly) cdk/overlay
571
- return !this._parentMenu || this._parentMenu.orientation === 'horizontal'
572
- ? [
573
- { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },
574
- { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' },
575
- { originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top' },
576
- { originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom' },
577
- ]
578
- : [
579
- { originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'top' },
580
- { originX: 'end', originY: 'bottom', overlayX: 'start', overlayY: 'bottom' },
581
- { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top' },
582
- { originX: 'start', originY: 'bottom', overlayX: 'end', overlayY: 'bottom' },
583
- ];
605
+ var _a;
606
+ return ((_a = this.menuPosition) !== null && _a !== void 0 ? _a : (!this._parentMenu || this._parentMenu.orientation === 'horizontal'
607
+ ? STANDARD_DROPDOWN_BELOW_POSITIONS
608
+ : STANDARD_DROPDOWN_ADJACENT_POSITIONS));
584
609
  }
585
610
  /**
586
611
  * Get the portal to be attached to the overlay which contains the menu. Allows for the menu
587
612
  * content to change dynamically and be reflected in the application.
588
613
  */
589
614
  _getPortal() {
590
- var _a, _b;
591
- const hasMenuContentChanged = ((_a = this.menuPanel) === null || _a === void 0 ? void 0 : _a._templateRef) !== ((_b = this._panelContent) === null || _b === void 0 ? void 0 : _b.templateRef);
592
- if (this.menuPanel && (!this._panelContent || hasMenuContentChanged)) {
593
- this._panelContent = new TemplatePortal(this.menuPanel._templateRef, this._viewContainerRef);
615
+ var _a;
616
+ const hasMenuContentChanged = this._menuTemplateRef !== ((_a = this._menuPortal) === null || _a === void 0 ? void 0 : _a.templateRef);
617
+ if (this._menuTemplateRef && (!this._menuPortal || hasMenuContentChanged)) {
618
+ this._menuPortal = new TemplatePortal(this._menuTemplateRef, this._viewContainerRef, undefined, this.getChildMenuInjector());
594
619
  }
595
- return this._panelContent;
620
+ return this._menuPortal;
596
621
  }
597
622
  /**
598
623
  * @return true if if the enclosing parent menu is configured in a vertical orientation.
@@ -607,40 +632,13 @@ class CdkMenuItemTrigger {
607
632
  */
608
633
  _registerCloseHandler() {
609
634
  if (!this._parentMenu) {
610
- this._menuStack.closed.pipe(takeUntil(this._destroyed)).subscribe(item => {
611
- var _a;
612
- if (item === ((_a = this._menuPanel) === null || _a === void 0 ? void 0 : _a._menu)) {
613
- this.closeMenu();
635
+ this.menuStack.closed.pipe(takeUntil(this._destroyed)).subscribe(item => {
636
+ if (item === this.childMenu) {
637
+ this.close();
614
638
  }
615
639
  });
616
640
  }
617
641
  }
618
- /** Get the menu stack for this trigger - either from the parent or this trigger. */
619
- _getMenuStack() {
620
- var _a;
621
- // We use a function since at the construction of the MenuItemTrigger the parent Menu won't have
622
- // its menu stack set. Therefore we need to reference the menu stack from the parent each time
623
- // we want to use it.
624
- return ((_a = this._parentMenu) === null || _a === void 0 ? void 0 : _a._menuStack) || this._menuStack;
625
- }
626
- ngOnDestroy() {
627
- this._destroyOverlay();
628
- this._resetPanelMenuStack();
629
- this._destroyed.next();
630
- this._destroyed.complete();
631
- }
632
- /** Set the menu panels menu stack back to null. */
633
- _resetPanelMenuStack() {
634
- // If a CdkMenuTrigger is placed in a submenu, each time the trigger is rendered (its parent
635
- // menu is opened) the panel setter for CdkMenuPanel is called. From the first render onward,
636
- // the attached CdkMenuPanel has the MenuStack set. Since we throw an error if a panel already
637
- // has a stack set, we want to reset the attached stack here to prevent the error from being
638
- // thrown if the trigger re-configures its attached panel (in the case where there is a 1:1
639
- // relationship between the panel and trigger).
640
- if (this._menuPanel) {
641
- this._menuPanel._menuStack = null;
642
- }
643
- }
644
642
  /**
645
643
  * Subscribe to the overlays outside pointer events stream and handle closing out the stack if a
646
644
  * click occurs outside the menus.
@@ -652,36 +650,41 @@ class CdkMenuItemTrigger {
652
650
  .pipe(takeUntil(this._stopOutsideClicksListener))
653
651
  .subscribe(event => {
654
652
  if (!isClickInsideMenuOverlay(event.target)) {
655
- this._getMenuStack().closeAll();
653
+ this.menuStack.closeAll();
656
654
  }
657
655
  });
658
656
  }
659
657
  }
660
- /** Destroy and unset the overlay reference it if exists */
661
- _destroyOverlay() {
662
- if (this._overlayRef) {
663
- this._overlayRef.dispose();
664
- this._overlayRef = null;
665
- }
666
- }
667
658
  }
668
- CdkMenuItemTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuItemTrigger, deps: [{ token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: i1.Overlay }, { token: i0.NgZone }, { token: CDK_MENU, optional: true }, { token: MENU_AIM, optional: true }, { token: i2.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
669
- CdkMenuItemTrigger.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkMenuItemTrigger, selector: "[cdkMenuTriggerFor]", inputs: { menuPanel: ["cdkMenuTriggerFor", "menuPanel"] }, outputs: { opened: "cdkMenuOpened", closed: "cdkMenuClosed" }, host: { attributes: { "aria-haspopup": "menu" }, listeners: { "keydown": "_toggleOnKeydown($event)", "click": "toggle()" }, properties: { "attr.aria-expanded": "isMenuOpen()" }, classAttribute: "cdk-menu-trigger" }, exportAs: ["cdkMenuTriggerFor"], ngImport: i0 });
670
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuItemTrigger, decorators: [{
659
+ CdkMenuItemTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemTrigger, deps: [{ token: i0.Injector }, { token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: i1.Overlay }, { token: i0.NgZone }, { token: MENU_STACK }, { token: CDK_MENU, optional: true }, { token: MENU_AIM, optional: true }, { token: i1$1.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
660
+ CdkMenuItemTrigger.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuItemTrigger, selector: "[cdkMenuTriggerFor]", inputs: { _menuTemplateRef: ["cdkMenuTriggerFor", "_menuTemplateRef"], menuPosition: ["cdkMenuPosition", "menuPosition"] }, outputs: { opened: "cdkMenuOpened", closed: "cdkMenuClosed" }, host: { attributes: { "aria-haspopup": "menu" }, listeners: { "keydown": "_toggleOnKeydown($event)", "click": "toggle()" }, properties: { "attr.aria-expanded": "isOpen()" }, classAttribute: "cdk-menu-trigger" }, providers: [
661
+ { provide: MENU_TRIGGER, useExisting: CdkMenuItemTrigger },
662
+ PARENT_OR_NEW_MENU_STACK_PROVIDER,
663
+ ], exportAs: ["cdkMenuTriggerFor"], usesInheritance: true, ngImport: i0 });
664
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemTrigger, decorators: [{
671
665
  type: Directive,
672
666
  args: [{
673
667
  selector: '[cdkMenuTriggerFor]',
674
668
  exportAs: 'cdkMenuTriggerFor',
675
669
  host: {
676
- '(keydown)': '_toggleOnKeydown($event)',
677
- '(click)': 'toggle()',
678
670
  'class': 'cdk-menu-trigger',
679
671
  'aria-haspopup': 'menu',
680
- '[attr.aria-expanded]': 'isMenuOpen()',
672
+ '(keydown)': '_toggleOnKeydown($event)',
673
+ '(click)': 'toggle()',
674
+ '[attr.aria-expanded]': 'isOpen()',
681
675
  },
676
+ inputs: ['_menuTemplateRef: cdkMenuTriggerFor', 'menuPosition: cdkMenuPosition'],
677
+ outputs: ['opened: cdkMenuOpened', 'closed: cdkMenuClosed'],
678
+ providers: [
679
+ { provide: MENU_TRIGGER, useExisting: CdkMenuItemTrigger },
680
+ PARENT_OR_NEW_MENU_STACK_PROVIDER,
681
+ ],
682
682
  }]
683
683
  }], ctorParameters: function () {
684
- return [{ type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: i1.Overlay }, { type: i0.NgZone }, { type: undefined, decorators: [{
684
+ return [{ type: i0.Injector }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: i1.Overlay }, { type: i0.NgZone }, { type: MenuStack, decorators: [{
685
+ type: Inject,
686
+ args: [MENU_STACK]
687
+ }] }, { type: undefined, decorators: [{
685
688
  type: Optional
686
689
  }, {
687
690
  type: Inject,
@@ -691,19 +694,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
691
694
  }, {
692
695
  type: Inject,
693
696
  args: [MENU_AIM]
694
- }] }, { type: i2.Directionality, decorators: [{
697
+ }] }, { type: i1$1.Directionality, decorators: [{
695
698
  type: Optional
696
699
  }] }];
697
- }, propDecorators: { menuPanel: [{
698
- type: Input,
699
- args: ['cdkMenuTriggerFor']
700
- }], opened: [{
701
- type: Output,
702
- args: ['cdkMenuOpened']
703
- }], closed: [{
704
- type: Output,
705
- args: ['cdkMenuClosed']
706
- }] } });
700
+ } });
707
701
 
708
702
  /**
709
703
  * @license
@@ -712,26 +706,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
712
706
  * Use of this source code is governed by an MIT-style license that can be
713
707
  * found in the LICENSE file at https://angular.io/license
714
708
  */
715
- // TODO refactor this to be configurable allowing for custom elements to be removed
716
- /** Removes all icons from within the given element. */
717
- function removeIcons(element) {
718
- for (const icon of Array.from(element.querySelectorAll('mat-icon, .material-icons'))) {
719
- icon.remove();
720
- }
721
- }
722
709
  /**
723
710
  * Directive which provides the ability for an element to be focused and navigated to using the
724
711
  * keyboard when residing in a CdkMenu, CdkMenuBar, or CdkMenuGroup. It performs user defined
725
712
  * behavior when clicked.
726
713
  */
727
714
  class CdkMenuItem {
728
- constructor(_elementRef, _ngZone, _parentMenu, _menuAim, _dir,
715
+ constructor(_elementRef, _ngZone, _menuStack, _parentMenu, _menuAim, _dir,
729
716
  /** Reference to the CdkMenuItemTrigger directive if one is added to the same element */
730
717
  // `CdkMenuItem` is commonly used in combination with a `CdkMenuItemTrigger`.
731
718
  // tslint:disable-next-line: lightweight-tokens
732
719
  _menuTrigger) {
733
720
  this._elementRef = _elementRef;
734
721
  this._ngZone = _ngZone;
722
+ this._menuStack = _menuStack;
735
723
  this._parentMenu = _parentMenu;
736
724
  this._menuAim = _menuAim;
737
725
  this._dir = _dir;
@@ -776,12 +764,11 @@ class CdkMenuItem {
776
764
  * is not in a menu bar.
777
765
  */
778
766
  _setTabIndex(event) {
779
- var _a;
780
767
  if (this.disabled) {
781
768
  return;
782
769
  }
783
770
  // don't set the tabindex if there are no open sibling or parent menus
784
- if (!event || !((_a = this._getMenuStack()) === null || _a === void 0 ? void 0 : _a.isEmpty())) {
771
+ if (!event || !this._menuStack.isEmpty()) {
785
772
  this._tabindex = 0;
786
773
  }
787
774
  }
@@ -794,21 +781,19 @@ class CdkMenuItem {
794
781
  * on the cdkMenuItemTriggered emitter and close all open menus.
795
782
  */
796
783
  trigger() {
797
- var _a;
798
784
  if (!this.disabled && !this.hasMenu()) {
799
785
  this.triggered.next();
800
- (_a = this._getMenuStack()) === null || _a === void 0 ? void 0 : _a.closeAll();
786
+ this._menuStack.closeAll();
801
787
  }
802
788
  }
803
789
  /** Whether the menu item opens a menu. */
804
790
  hasMenu() {
805
- var _a;
806
- return !!((_a = this._menuTrigger) === null || _a === void 0 ? void 0 : _a.hasMenu());
791
+ return !!this._menuTrigger;
807
792
  }
808
793
  /** Return true if this MenuItem has an attached menu and it is open. */
809
794
  isMenuOpen() {
810
795
  var _a;
811
- return !!((_a = this._menuTrigger) === null || _a === void 0 ? void 0 : _a.isMenuOpen());
796
+ return !!((_a = this._menuTrigger) === null || _a === void 0 ? void 0 : _a.isOpen());
812
797
  }
813
798
  /**
814
799
  * Get a reference to the rendered Menu if the Menu is open and it is visible in the DOM.
@@ -825,11 +810,7 @@ class CdkMenuItem {
825
810
  /** Get the label for this element which is required by the FocusableOption interface. */
826
811
  getLabel() {
827
812
  var _a;
828
- // TODO cloning the tree may be expensive; implement a better method
829
- // we know that the current node is an element type
830
- const clone = this._elementRef.nativeElement.cloneNode(true);
831
- removeIcons(clone);
832
- return ((_a = clone.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
813
+ return this.typeahead || ((_a = this._elementRef.nativeElement.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
833
814
  }
834
815
  /**
835
816
  * Handles keyboard events for the menu item, specifically either triggering the user defined
@@ -838,7 +819,7 @@ class CdkMenuItem {
838
819
  * @param event the keyboard event to handle
839
820
  */
840
821
  _onKeydown(event) {
841
- var _a, _b, _c, _d, _e, _f;
822
+ var _a, _b;
842
823
  switch (event.keyCode) {
843
824
  case SPACE:
844
825
  case ENTER:
@@ -846,19 +827,35 @@ class CdkMenuItem {
846
827
  this.trigger();
847
828
  break;
848
829
  case RIGHT_ARROW:
849
- if (this._parentMenu && this._isParentVertical() && !this.hasMenu()) {
850
- event.preventDefault();
851
- ((_a = this._dir) === null || _a === void 0 ? void 0 : _a.value) === 'rtl'
852
- ? (_b = this._getMenuStack()) === null || _b === void 0 ? void 0 : _b.close(this._parentMenu, 1 /* previousItem */)
853
- : (_c = this._getMenuStack()) === null || _c === void 0 ? void 0 : _c.closeAll(0 /* nextItem */);
830
+ if (this._parentMenu && this._isParentVertical()) {
831
+ if (((_a = this._dir) === null || _a === void 0 ? void 0 : _a.value) === 'rtl') {
832
+ if (this._menuStack.hasInlineMenu() || this._menuStack.length() > 1) {
833
+ event.preventDefault();
834
+ this._menuStack.close(this._parentMenu, 1 /* previousItem */);
835
+ }
836
+ }
837
+ else if (!this.hasMenu()) {
838
+ if (this._menuStack.hasInlineMenu()) {
839
+ event.preventDefault();
840
+ this._menuStack.closeAll(0 /* nextItem */);
841
+ }
842
+ }
854
843
  }
855
844
  break;
856
845
  case LEFT_ARROW:
857
- if (this._parentMenu && this._isParentVertical() && !this.hasMenu()) {
858
- event.preventDefault();
859
- ((_d = this._dir) === null || _d === void 0 ? void 0 : _d.value) === 'rtl'
860
- ? (_e = this._getMenuStack()) === null || _e === void 0 ? void 0 : _e.closeAll(0 /* nextItem */)
861
- : (_f = this._getMenuStack()) === null || _f === void 0 ? void 0 : _f.close(this._parentMenu, 1 /* previousItem */);
846
+ if (this._parentMenu && this._isParentVertical()) {
847
+ if (((_b = this._dir) === null || _b === void 0 ? void 0 : _b.value) !== 'rtl') {
848
+ if (this._menuStack.hasInlineMenu() || this._menuStack.length() > 1) {
849
+ event.preventDefault();
850
+ this._menuStack.close(this._parentMenu, 1 /* previousItem */);
851
+ }
852
+ }
853
+ else if (!this.hasMenu()) {
854
+ if (this._menuStack.hasInlineMenu()) {
855
+ event.preventDefault();
856
+ this._menuStack.closeAll(0 /* nextItem */);
857
+ }
858
+ }
862
859
  }
863
860
  break;
864
861
  }
@@ -869,9 +866,9 @@ class CdkMenuItem {
869
866
  */
870
867
  _setupMouseEnter() {
871
868
  if (!this._isStandaloneItem()) {
872
- const closeOpenSiblings = () => this._ngZone.run(() => { var _a; return (_a = this._getMenuStack()) === null || _a === void 0 ? void 0 : _a.closeSubMenuOf(this._parentMenu); });
869
+ const closeOpenSiblings = () => this._ngZone.run(() => this._menuStack.closeSubMenuOf(this._parentMenu));
873
870
  this._ngZone.runOutsideAngular(() => fromEvent(this._elementRef.nativeElement, 'mouseenter')
874
- .pipe(filter(() => { var _a; return !((_a = this._getMenuStack()) === null || _a === void 0 ? void 0 : _a.isEmpty()) && !this.hasMenu(); }), takeUntil(this._destroyed))
871
+ .pipe(filter(() => !this._menuStack.isEmpty() && !this.hasMenu()), takeUntil(this._destroyed))
875
872
  .subscribe(() => {
876
873
  if (this._menuAim) {
877
874
  this._menuAim.toggle(closeOpenSiblings);
@@ -890,21 +887,13 @@ class CdkMenuItem {
890
887
  var _a;
891
888
  return ((_a = this._parentMenu) === null || _a === void 0 ? void 0 : _a.orientation) === 'vertical';
892
889
  }
893
- /** Get the MenuStack from the parent menu. */
894
- _getMenuStack() {
895
- var _a;
896
- // We use a function since at the construction of the MenuItemTrigger the parent Menu won't have
897
- // its menu stack set. Therefore we need to reference the menu stack from the parent each time
898
- // we want to use it.
899
- return (_a = this._parentMenu) === null || _a === void 0 ? void 0 : _a._menuStack;
900
- }
901
890
  ngOnDestroy() {
902
891
  this._destroyed.next();
903
892
  }
904
893
  }
905
- CdkMenuItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuItem, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: CDK_MENU, optional: true }, { token: MENU_AIM, optional: true }, { token: i2.Directionality, optional: true }, { token: CdkMenuItemTrigger, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
906
- CdkMenuItem.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkMenuItem, selector: "[cdkMenuItem]", inputs: { disabled: "disabled" }, outputs: { triggered: "cdkMenuItemTriggered" }, host: { attributes: { "type": "button", "role": "menuitem" }, listeners: { "blur": "_resetTabIndex()", "mouseout": "_resetTabIndex()", "focus": "_setTabIndex()", "mouseenter": "_setTabIndex($event)", "click": "trigger()", "keydown": "_onKeydown($event)" }, properties: { "tabindex": "_tabindex", "attr.aria-disabled": "disabled || null" }, classAttribute: "cdk-menu-item" }, exportAs: ["cdkMenuItem"], ngImport: i0 });
907
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuItem, decorators: [{
894
+ CdkMenuItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItem, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: MENU_STACK }, { token: CDK_MENU, optional: true }, { token: MENU_AIM, optional: true }, { token: i1$1.Directionality, optional: true }, { token: CdkMenuItemTrigger, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
895
+ CdkMenuItem.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuItem, selector: "[cdkMenuItem]", inputs: { disabled: "disabled", typeahead: "typeahead" }, outputs: { triggered: "cdkMenuItemTriggered" }, host: { attributes: { "type": "button", "role": "menuitem" }, listeners: { "blur": "_resetTabIndex()", "mouseout": "_resetTabIndex()", "focus": "_setTabIndex()", "mouseenter": "_setTabIndex($event)", "click": "trigger()", "keydown": "_onKeydown($event)" }, properties: { "tabindex": "_tabindex", "attr.aria-disabled": "disabled || null" }, classAttribute: "cdk-menu-item" }, exportAs: ["cdkMenuItem"], ngImport: i0 });
896
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItem, decorators: [{
908
897
  type: Directive,
909
898
  args: [{
910
899
  selector: '[cdkMenuItem]',
@@ -924,7 +913,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
924
913
  },
925
914
  }]
926
915
  }], ctorParameters: function () {
927
- return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: undefined, decorators: [{
916
+ return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: MenuStack, decorators: [{
917
+ type: Inject,
918
+ args: [MENU_STACK]
919
+ }] }, { type: undefined, decorators: [{
928
920
  type: Optional
929
921
  }, {
930
922
  type: Inject,
@@ -934,7 +926,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
934
926
  }, {
935
927
  type: Inject,
936
928
  args: [MENU_AIM]
937
- }] }, { type: i2.Directionality, decorators: [{
929
+ }] }, { type: i1$1.Directionality, decorators: [{
938
930
  type: Optional
939
931
  }] }, { type: CdkMenuItemTrigger, decorators: [{
940
932
  type: Self
@@ -943,6 +935,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
943
935
  }] }];
944
936
  }, propDecorators: { disabled: [{
945
937
  type: Input
938
+ }], typeahead: [{
939
+ type: Input
946
940
  }], triggered: [{
947
941
  type: Output,
948
942
  args: ['cdkMenuItemTriggered']
@@ -986,9 +980,9 @@ class CdkMenuItemSelectable extends CdkMenuItem {
986
980
  }
987
981
  }
988
982
  }
989
- CdkMenuItemSelectable.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuItemSelectable, deps: null, target: i0.ɵɵFactoryTarget.Directive });
990
- CdkMenuItemSelectable.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkMenuItemSelectable, inputs: { checked: "checked", name: "name", id: "id" }, outputs: { toggled: "cdkMenuItemToggled" }, usesInheritance: true, ngImport: i0 });
991
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuItemSelectable, decorators: [{
983
+ CdkMenuItemSelectable.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemSelectable, deps: null, target: i0.ɵɵFactoryTarget.Directive });
984
+ CdkMenuItemSelectable.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuItemSelectable, inputs: { checked: "checked", name: "name", id: "id" }, outputs: { toggled: "cdkMenuItemToggled" }, usesInheritance: true, ngImport: i0 });
985
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemSelectable, decorators: [{
992
986
  type: Directive
993
987
  }], propDecorators: { toggled: [{
994
988
  type: Output,
@@ -1022,6 +1016,10 @@ class CdkMenuGroup {
1022
1016
  ngAfterContentInit() {
1023
1017
  this._registerMenuSelectionListeners();
1024
1018
  }
1019
+ ngOnDestroy() {
1020
+ this._selectableChanges.next();
1021
+ this._selectableChanges.complete();
1022
+ }
1025
1023
  /**
1026
1024
  * Register the child selectable elements with the change emitter and ensure any new child
1027
1025
  * elements do so as well.
@@ -1039,14 +1037,10 @@ class CdkMenuGroup {
1039
1037
  .pipe(takeUntil(this._selectableChanges))
1040
1038
  .subscribe(() => this.change.next(selectable));
1041
1039
  }
1042
- ngOnDestroy() {
1043
- this._selectableChanges.next();
1044
- this._selectableChanges.complete();
1045
- }
1046
1040
  }
1047
- CdkMenuGroup.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1048
- CdkMenuGroup.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkMenuGroup, selector: "[cdkMenuGroup]", outputs: { change: "change" }, host: { attributes: { "role": "group" }, classAttribute: "cdk-menu-group" }, providers: [{ provide: UniqueSelectionDispatcher, useClass: UniqueSelectionDispatcher }], queries: [{ propertyName: "_selectableItems", predicate: CdkMenuItemSelectable, descendants: true }], exportAs: ["cdkMenuGroup"], ngImport: i0 });
1049
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuGroup, decorators: [{
1041
+ CdkMenuGroup.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1042
+ CdkMenuGroup.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuGroup, selector: "[cdkMenuGroup]", outputs: { change: "change" }, host: { attributes: { "role": "group" }, classAttribute: "cdk-menu-group" }, providers: [{ provide: UniqueSelectionDispatcher, useClass: UniqueSelectionDispatcher }], queries: [{ propertyName: "_selectableItems", predicate: CdkMenuItemSelectable, descendants: true }], exportAs: ["cdkMenuGroup"], ngImport: i0 });
1043
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuGroup, decorators: [{
1050
1044
  type: Directive,
1051
1045
  args: [{
1052
1046
  selector: '[cdkMenuGroup]',
@@ -1090,62 +1084,148 @@ class PointerFocusTracker {
1090
1084
  this.activeElement = undefined;
1091
1085
  });
1092
1086
  }
1093
- /**
1094
- * Gets a stream of pointer (mouse) entries into the given items.
1095
- * This should typically run outside the Angular zone.
1096
- */
1097
- _getItemPointerEntries() {
1098
- return defer(() => this._items.changes.pipe(startWith(this._items), mergeMap((list) => list.map(element => fromEvent(element._elementRef.nativeElement, 'mouseenter').pipe(mapTo(element), takeUntil(this._items.changes)))), mergeAll()));
1087
+ /**
1088
+ * Gets a stream of pointer (mouse) entries into the given items.
1089
+ * This should typically run outside the Angular zone.
1090
+ */
1091
+ _getItemPointerEntries() {
1092
+ return defer(() => this._items.changes.pipe(startWith(this._items), mergeMap((list) => list.map(element => fromEvent(element._elementRef.nativeElement, 'mouseenter').pipe(mapTo(element), takeUntil(this._items.changes)))), mergeAll()));
1093
+ }
1094
+ /**
1095
+ * Gets a stream of pointer (mouse) exits out of the given items.
1096
+ * This should typically run outside the Angular zone.
1097
+ */
1098
+ _getItemPointerExits() {
1099
+ return defer(() => this._items.changes.pipe(startWith(this._items), mergeMap((list) => list.map(element => fromEvent(element._elementRef.nativeElement, 'mouseout').pipe(mapTo(element), takeUntil(this._items.changes)))), mergeAll()));
1100
+ }
1101
+ /** Stop the managers listeners. */
1102
+ destroy() {
1103
+ this._destroyed.next();
1104
+ this._destroyed.complete();
1105
+ }
1106
+ }
1107
+
1108
+ /**
1109
+ * @license
1110
+ * Copyright Google LLC All Rights Reserved.
1111
+ *
1112
+ * Use of this source code is governed by an MIT-style license that can be
1113
+ * found in the LICENSE file at https://angular.io/license
1114
+ */
1115
+ class CdkMenuBase extends CdkMenuGroup {
1116
+ constructor(_elementRef, menuStack, dir) {
1117
+ super();
1118
+ this._elementRef = _elementRef;
1119
+ this.menuStack = menuStack;
1120
+ this.dir = dir;
1121
+ /**
1122
+ * Sets the aria-orientation attribute and determines where menus will be opened.
1123
+ * Does not affect styling/layout.
1124
+ */
1125
+ this.orientation = 'vertical';
1126
+ /** Emits when the MenuBar is destroyed. */
1127
+ this.destroyed = new Subject();
1128
+ }
1129
+ ngAfterContentInit() {
1130
+ super.ngAfterContentInit();
1131
+ this._setKeyManager();
1132
+ this._subscribeToMenuOpen();
1133
+ this._subscribeToMenuStackClosed();
1134
+ }
1135
+ ngOnDestroy() {
1136
+ super.ngOnDestroy();
1137
+ this.destroyed.next();
1138
+ this.destroyed.complete();
1139
+ }
1140
+ /** Place focus on the first MenuItem in the menu and set the focus origin. */
1141
+ focusFirstItem(focusOrigin = 'program') {
1142
+ this.keyManager.setFocusOrigin(focusOrigin);
1143
+ this.keyManager.setFirstItemActive();
1144
+ }
1145
+ /** Place focus on the last MenuItem in the menu and set the focus origin. */
1146
+ focusLastItem(focusOrigin = 'program') {
1147
+ this.keyManager.setFocusOrigin(focusOrigin);
1148
+ this.keyManager.setLastItemActive();
1149
+ }
1150
+ /** Return true if this menu has been configured in a horizontal orientation. */
1151
+ isHorizontal() {
1152
+ return this.orientation === 'horizontal';
1153
+ }
1154
+ /** Return true if the MenuBar has an open submenu. */
1155
+ hasOpenSubmenu() {
1156
+ return !!this.openItem;
1099
1157
  }
1100
1158
  /**
1101
- * Gets a stream of pointer (mouse) exits out of the given items.
1102
- * This should typically run outside the Angular zone.
1159
+ * Close the open menu if the current active item opened the requested MenuStackItem.
1160
+ * @param item the MenuStackItem requested to be closed.
1103
1161
  */
1104
- _getItemPointerExits() {
1105
- return defer(() => this._items.changes.pipe(startWith(this._items), mergeMap((list) => list.map(element => fromEvent(element._elementRef.nativeElement, 'mouseout').pipe(mapTo(element), takeUntil(this._items.changes)))), mergeAll()));
1106
- }
1107
- /** Stop the managers listeners. */
1108
- destroy() {
1109
- this._destroyed.next();
1110
- this._destroyed.complete();
1162
+ closeOpenMenu(menu) {
1163
+ var _a, _b, _c;
1164
+ const keyManager = this.keyManager;
1165
+ const trigger = this.openItem;
1166
+ if (menu === ((_a = trigger === null || trigger === void 0 ? void 0 : trigger.getMenuTrigger()) === null || _a === void 0 ? void 0 : _a.getMenu())) {
1167
+ (_b = trigger === null || trigger === void 0 ? void 0 : trigger.getMenuTrigger()) === null || _b === void 0 ? void 0 : _b.close();
1168
+ // If the user has moused over a sibling item we want to focus the element under mouse focus
1169
+ // not the trigger which previously opened the now closed menu.
1170
+ if (trigger) {
1171
+ keyManager.setActiveItem(((_c = this.pointerTracker) === null || _c === void 0 ? void 0 : _c.activeElement) || trigger);
1172
+ }
1173
+ }
1111
1174
  }
1112
- }
1113
-
1114
- /**
1115
- * @license
1116
- * Copyright Google LLC All Rights Reserved.
1117
- *
1118
- * Use of this source code is governed by an MIT-style license that can be
1119
- * found in the LICENSE file at https://angular.io/license
1120
- */
1121
- /**
1122
- * Directive applied to an ng-template which wraps a CdkMenu and provides a reference to the
1123
- * child element it wraps which allows for opening of the CdkMenu in an overlay.
1124
- */
1125
- class CdkMenuPanel {
1126
- constructor(_templateRef) {
1127
- this._templateRef = _templateRef;
1175
+ /** Setup the FocusKeyManager with the correct orientation for the menu. */
1176
+ _setKeyManager() {
1177
+ var _a;
1178
+ this.keyManager = new FocusKeyManager(this.items).withWrap().withTypeAhead().withHomeAndEnd();
1179
+ if (this.isHorizontal()) {
1180
+ this.keyManager.withHorizontalOrientation(((_a = this.dir) === null || _a === void 0 ? void 0 : _a.value) || 'ltr');
1181
+ }
1182
+ else {
1183
+ this.keyManager.withVerticalOrientation();
1184
+ }
1128
1185
  }
1129
1186
  /**
1130
- * Set the Menu component on the menu panel. Since we cannot use ContentChild to fetch the
1131
- * child Menu component, the child Menu must register its self with the parent MenuPanel.
1187
+ * Subscribe to the menu trigger's open events in order to track the trigger which opened the menu
1188
+ * and stop tracking it when the menu is closed.
1132
1189
  */
1133
- _registerMenu(child) {
1134
- var _a;
1135
- this._menu = child;
1136
- // The ideal solution would be to affect the CdkMenuPanel injector from the CdkMenuTrigger and
1137
- // inject the menu stack reference into the child menu and menu items, however this isn't
1138
- // possible at this time.
1139
- this._menu._menuStack = this._menuStack;
1140
- (_a = this._menuStack) === null || _a === void 0 ? void 0 : _a.push(child);
1190
+ _subscribeToMenuOpen() {
1191
+ const exitCondition = merge(this.items.changes, this.destroyed);
1192
+ this.items.changes
1193
+ .pipe(startWith(this.items), mergeMap((list) => list
1194
+ .filter(item => item.hasMenu())
1195
+ .map(item => item.getMenuTrigger().opened.pipe(mapTo(item), takeUntil(exitCondition)))), mergeAll(), switchMap((item) => {
1196
+ this.openItem = item;
1197
+ return item.getMenuTrigger().closed;
1198
+ }), takeUntil(this.destroyed))
1199
+ .subscribe(() => (this.openItem = undefined));
1200
+ }
1201
+ /** Subscribe to the MenuStack close and empty observables. */
1202
+ _subscribeToMenuStackClosed() {
1203
+ this.menuStack.closed
1204
+ .pipe(takeUntil(this.destroyed))
1205
+ .subscribe(item => this.closeOpenMenu(item));
1141
1206
  }
1142
1207
  }
1143
- CdkMenuPanel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuPanel, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
1144
- CdkMenuPanel.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkMenuPanel, selector: "ng-template[cdkMenuPanel]", exportAs: ["cdkMenuPanel"], ngImport: i0 });
1145
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuPanel, decorators: [{
1208
+ CdkMenuBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuBase, deps: [{ token: i0.ElementRef }, { token: MENU_STACK }, { token: i1$1.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1209
+ CdkMenuBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuBase, host: { listeners: { "focus": "focusFirstItem()" }, properties: { "attr.aria-orientation": "orientation" } }, queries: [{ propertyName: "items", predicate: CdkMenuItem, descendants: true }], usesInheritance: true, ngImport: i0 });
1210
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuBase, decorators: [{
1146
1211
  type: Directive,
1147
- args: [{ selector: 'ng-template[cdkMenuPanel]', exportAs: 'cdkMenuPanel' }]
1148
- }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
1212
+ args: [{
1213
+ host: {
1214
+ '[attr.aria-orientation]': 'orientation',
1215
+ '(focus)': 'focusFirstItem()',
1216
+ },
1217
+ }]
1218
+ }], ctorParameters: function () {
1219
+ return [{ type: i0.ElementRef }, { type: MenuStack, decorators: [{
1220
+ type: Inject,
1221
+ args: [MENU_STACK]
1222
+ }] }, { type: i1$1.Directionality, decorators: [{
1223
+ type: Optional
1224
+ }] }];
1225
+ }, propDecorators: { items: [{
1226
+ type: ContentChildren,
1227
+ args: [CdkMenuItem, { descendants: true }]
1228
+ }] } });
1149
1229
 
1150
1230
  /**
1151
1231
  * @license
@@ -1161,60 +1241,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
1161
1241
  *
1162
1242
  * It also acts as a RadioGroup for elements marked with role `menuitemradio`.
1163
1243
  */
1164
- class CdkMenu extends CdkMenuGroup {
1165
- constructor(_ngZone, _elementRef, _menuAim, _dir,
1166
- // `CdkMenuPanel` is always used in combination with a `CdkMenu`.
1167
- // tslint:disable-next-line: lightweight-tokens
1168
- _menuPanel) {
1169
- super();
1244
+ class CdkMenu extends CdkMenuBase {
1245
+ constructor(_ngZone, elementRef, menuStack, _parentTrigger, _menuAim, dir) {
1246
+ var _a;
1247
+ super(elementRef, menuStack, dir);
1170
1248
  this._ngZone = _ngZone;
1171
- this._elementRef = _elementRef;
1249
+ this._parentTrigger = _parentTrigger;
1172
1250
  this._menuAim = _menuAim;
1173
- this._dir = _dir;
1174
- this._menuPanel = _menuPanel;
1175
- /**
1176
- * Sets the aria-orientation attribute and determines where menus will be opened.
1177
- * Does not affect styling/layout.
1178
- */
1179
- this.orientation = 'vertical';
1180
1251
  /** Event emitted when the menu is closed. */
1181
1252
  this.closed = new EventEmitter();
1182
- // We provide a default MenuStack implementation in case the menu is an inline menu.
1183
- // For Menus part of a MenuBar nested within a MenuPanel this will be overwritten
1184
- // to the correct parent MenuStack.
1185
- /** Track the Menus making up the open menu stack. */
1186
- this._menuStack = new NoopMenuStack();
1187
- }
1188
- ngOnInit() {
1189
- this._registerWithParentPanel();
1253
+ this.destroyed.subscribe(this.closed);
1254
+ if (!this._isInline()) {
1255
+ this.menuStack.push(this);
1256
+ }
1257
+ (_a = this._parentTrigger) === null || _a === void 0 ? void 0 : _a.registerChildMenu(this);
1190
1258
  }
1191
1259
  ngAfterContentInit() {
1192
1260
  var _a;
1193
1261
  super.ngAfterContentInit();
1194
1262
  this._completeChangeEmitter();
1195
- this._setKeyManager();
1196
- this._subscribeToMenuOpen();
1197
- this._subscribeToMenuStack();
1263
+ this._subscribeToMenuStackEmptied();
1198
1264
  this._subscribeToMouseManager();
1199
- (_a = this._menuAim) === null || _a === void 0 ? void 0 : _a.initialize(this, this._pointerTracker);
1265
+ (_a = this._menuAim) === null || _a === void 0 ? void 0 : _a.initialize(this, this.pointerTracker);
1200
1266
  }
1201
- /** Place focus on the first MenuItem in the menu and set the focus origin. */
1202
- focusFirstItem(focusOrigin = 'program') {
1203
- this._keyManager.setFocusOrigin(focusOrigin);
1204
- this._keyManager.setFirstItemActive();
1205
- }
1206
- /** Place focus on the last MenuItem in the menu and set the focus origin. */
1207
- focusLastItem(focusOrigin = 'program') {
1208
- this._keyManager.setFocusOrigin(focusOrigin);
1209
- this._keyManager.setLastItemActive();
1267
+ ngOnDestroy() {
1268
+ var _a;
1269
+ super.ngOnDestroy();
1270
+ this.closed.complete();
1271
+ (_a = this.pointerTracker) === null || _a === void 0 ? void 0 : _a.destroy();
1210
1272
  }
1211
1273
  /** Handle keyboard events for the Menu. */
1212
1274
  _handleKeyEvent(event) {
1213
- const keyManager = this._keyManager;
1275
+ const keyManager = this.keyManager;
1214
1276
  switch (event.keyCode) {
1215
1277
  case LEFT_ARROW:
1216
1278
  case RIGHT_ARROW:
1217
- if (this._isHorizontal()) {
1279
+ if (this.isHorizontal()) {
1218
1280
  event.preventDefault();
1219
1281
  keyManager.setFocusOrigin('keyboard');
1220
1282
  keyManager.onKeydown(event);
@@ -1222,7 +1284,7 @@ class CdkMenu extends CdkMenuGroup {
1222
1284
  break;
1223
1285
  case UP_ARROW:
1224
1286
  case DOWN_ARROW:
1225
- if (!this._isHorizontal()) {
1287
+ if (!this.isHorizontal()) {
1226
1288
  event.preventDefault();
1227
1289
  keyManager.setFocusOrigin('keyboard');
1228
1290
  keyManager.onKeydown(event);
@@ -1231,32 +1293,23 @@ class CdkMenu extends CdkMenuGroup {
1231
1293
  case ESCAPE:
1232
1294
  if (!hasModifierKey(event)) {
1233
1295
  event.preventDefault();
1234
- this._menuStack.close(this, 2 /* currentItem */);
1296
+ this.menuStack.close(this, 2 /* currentItem */);
1235
1297
  }
1236
1298
  break;
1237
1299
  case TAB:
1238
- this._menuStack.closeAll();
1300
+ this.menuStack.closeAll();
1239
1301
  break;
1240
1302
  default:
1241
1303
  keyManager.onKeydown(event);
1242
1304
  }
1243
1305
  }
1244
- /** Register this menu with its enclosing parent menu panel */
1245
- _registerWithParentPanel() {
1246
- var _a;
1247
- (_a = this._getMenuPanel()) === null || _a === void 0 ? void 0 : _a._registerMenu(this);
1248
- }
1249
- /**
1250
- * Get the enclosing CdkMenuPanel defaulting to the injected reference over the developer
1251
- * provided reference.
1252
- */
1253
- _getMenuPanel() {
1254
- return this._menuPanel || this._explicitPanel;
1255
- }
1256
1306
  /**
1257
1307
  * Complete the change emitter if there are any nested MenuGroups or register to complete the
1258
1308
  * change emitter if a MenuGroup is rendered at some point
1259
1309
  */
1310
+ // TODO(mmalerba): This doesnt' quite work. It causes change events to stop
1311
+ // firing for radio items directly in the menu if a second group of options
1312
+ // is added in a menu-group.
1260
1313
  _completeChangeEmitter() {
1261
1314
  if (this._hasNestedGroups()) {
1262
1315
  this.change.complete();
@@ -1273,61 +1326,21 @@ class CdkMenu extends CdkMenuGroup {
1273
1326
  // order to ensure that we return true iff there are child CdkMenuGroup elements.
1274
1327
  return this._nestedGroups.length > 0 && !(this._nestedGroups.first instanceof CdkMenu);
1275
1328
  }
1276
- /** Setup the FocusKeyManager with the correct orientation for the menu. */
1277
- _setKeyManager() {
1278
- var _a;
1279
- this._keyManager = new FocusKeyManager(this._allItems)
1280
- .withWrap()
1281
- .withTypeAhead()
1282
- .withHomeAndEnd();
1283
- if (this._isHorizontal()) {
1284
- this._keyManager.withHorizontalOrientation(((_a = this._dir) === null || _a === void 0 ? void 0 : _a.value) || 'ltr');
1285
- }
1286
- else {
1287
- this._keyManager.withVerticalOrientation();
1288
- }
1289
- }
1290
1329
  /**
1291
1330
  * Set the PointerFocusTracker and ensure that when mouse focus changes the key manager is updated
1292
1331
  * with the latest menu item under mouse focus.
1293
1332
  */
1294
1333
  _subscribeToMouseManager() {
1295
1334
  this._ngZone.runOutsideAngular(() => {
1296
- this._pointerTracker = new PointerFocusTracker(this._allItems);
1297
- this._pointerTracker.entered
1335
+ this.pointerTracker = new PointerFocusTracker(this.items);
1336
+ this.pointerTracker.entered
1298
1337
  .pipe(takeUntil(this.closed))
1299
- .subscribe(item => this._keyManager.setActiveItem(item));
1338
+ .subscribe(item => this.keyManager.setActiveItem(item));
1300
1339
  });
1301
1340
  }
1302
- /** Subscribe to the MenuStack close and empty observables. */
1303
- _subscribeToMenuStack() {
1304
- this._menuStack.closed
1305
- .pipe(takeUntil(this.closed))
1306
- .subscribe(item => this._closeOpenMenu(item));
1307
- this._menuStack.emptied
1308
- .pipe(takeUntil(this.closed))
1309
- .subscribe(event => this._toggleMenuFocus(event));
1310
- }
1311
- /**
1312
- * Close the open menu if the current active item opened the requested MenuStackItem.
1313
- * @param item the MenuStackItem requested to be closed.
1314
- */
1315
- _closeOpenMenu(menu) {
1316
- var _a, _b, _c;
1317
- const keyManager = this._keyManager;
1318
- const trigger = this._openItem;
1319
- if (menu === ((_a = trigger === null || trigger === void 0 ? void 0 : trigger.getMenuTrigger()) === null || _a === void 0 ? void 0 : _a.getMenu())) {
1320
- (_b = trigger === null || trigger === void 0 ? void 0 : trigger.getMenuTrigger()) === null || _b === void 0 ? void 0 : _b.closeMenu();
1321
- // If the user has moused over a sibling item we want to focus the element under mouse focus
1322
- // not the trigger which previously opened the now closed menu.
1323
- if (trigger) {
1324
- keyManager.setActiveItem(((_c = this._pointerTracker) === null || _c === void 0 ? void 0 : _c.activeElement) || trigger);
1325
- }
1326
- }
1327
- }
1328
1341
  /** Set focus the either the current, previous or next item based on the FocusNext event. */
1329
1342
  _toggleMenuFocus(event) {
1330
- const keyManager = this._keyManager;
1343
+ const keyManager = this.keyManager;
1331
1344
  switch (event) {
1332
1345
  case 0 /* nextItem */:
1333
1346
  keyManager.setFocusOrigin('keyboard');
@@ -1345,98 +1358,67 @@ class CdkMenu extends CdkMenuGroup {
1345
1358
  break;
1346
1359
  }
1347
1360
  }
1348
- // TODO(andy9775): remove duplicate logic between menu an menu bar
1349
- /**
1350
- * Subscribe to the menu trigger's open events in order to track the trigger which opened the menu
1351
- * and stop tracking it when the menu is closed.
1352
- */
1353
- _subscribeToMenuOpen() {
1354
- const exitCondition = merge(this._allItems.changes, this.closed);
1355
- this._allItems.changes
1356
- .pipe(startWith(this._allItems), mergeMap((list) => list
1357
- .filter(item => item.hasMenu())
1358
- .map(item => item.getMenuTrigger().opened.pipe(mapTo(item), takeUntil(exitCondition)))), mergeAll(), switchMap((item) => {
1359
- this._openItem = item;
1360
- return item.getMenuTrigger().closed;
1361
- }), takeUntil(this.closed))
1362
- .subscribe(() => (this._openItem = undefined));
1363
- }
1364
- /** Return true if this menu has been configured in a horizontal orientation. */
1365
- _isHorizontal() {
1366
- return this.orientation === 'horizontal';
1367
- }
1368
1361
  /**
1369
1362
  * Return true if this menu is an inline menu. That is, it does not exist in a pop-up and is
1370
1363
  * always visible in the dom.
1371
1364
  */
1372
1365
  _isInline() {
1373
- // NoopMenuStack is the default. If this menu is not inline than the NoopMenuStack is replaced
1374
- // automatically.
1375
- return this._menuStack instanceof NoopMenuStack;
1366
+ return !this._parentTrigger;
1376
1367
  }
1377
- ngOnDestroy() {
1378
- var _a;
1379
- super.ngOnDestroy();
1380
- this._emitClosedEvent();
1381
- (_a = this._pointerTracker) === null || _a === void 0 ? void 0 : _a.destroy();
1382
- }
1383
- /** Emit and complete the closed event emitter */
1384
- _emitClosedEvent() {
1385
- this.closed.next();
1386
- this.closed.complete();
1368
+ _subscribeToMenuStackEmptied() {
1369
+ this.menuStack.emptied
1370
+ .pipe(takeUntil(this.destroyed))
1371
+ .subscribe(event => this._toggleMenuFocus(event));
1387
1372
  }
1388
1373
  }
1389
- CdkMenu.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenu, deps: [{ token: i0.NgZone }, { token: i0.ElementRef }, { token: MENU_AIM, optional: true, self: true }, { token: i2.Directionality, optional: true }, { token: CdkMenuPanel, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1390
- CdkMenu.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkMenu, selector: "[cdkMenu]", inputs: { orientation: ["cdkMenuOrientation", "orientation"], _explicitPanel: ["cdkMenuPanel", "_explicitPanel"] }, outputs: { closed: "closed" }, host: { attributes: { "role": "menu" }, listeners: { "focus": "focusFirstItem()", "keydown": "_handleKeyEvent($event)" }, properties: { "tabindex": "_isInline() ? 0 : null", "class.cdk-menu-inline": "_isInline()", "attr.aria-orientation": "orientation" }, classAttribute: "cdk-menu" }, providers: [
1374
+ CdkMenu.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenu, deps: [{ token: i0.NgZone }, { token: i0.ElementRef }, { token: MENU_STACK }, { token: MENU_TRIGGER, optional: true }, { token: MENU_AIM, optional: true, self: true }, { token: i1$1.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1375
+ CdkMenu.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenu, selector: "[cdkMenu]", outputs: { closed: "closed" }, host: { attributes: { "role": "menu" }, listeners: { "keydown": "_handleKeyEvent($event)" }, properties: { "tabindex": "_isInline() ? 0 : null", "class.cdk-menu-inline": "_isInline()" }, classAttribute: "cdk-menu" }, providers: [
1391
1376
  { provide: CdkMenuGroup, useExisting: CdkMenu },
1392
1377
  { provide: CDK_MENU, useExisting: CdkMenu },
1393
- ], queries: [{ propertyName: "_nestedGroups", predicate: CdkMenuGroup, descendants: true }, { propertyName: "_allItems", predicate: CdkMenuItem, descendants: true }], exportAs: ["cdkMenu"], usesInheritance: true, ngImport: i0 });
1394
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenu, decorators: [{
1378
+ PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER,
1379
+ ], queries: [{ propertyName: "_nestedGroups", predicate: CdkMenuGroup, descendants: true }], exportAs: ["cdkMenu"], usesInheritance: true, ngImport: i0 });
1380
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenu, decorators: [{
1395
1381
  type: Directive,
1396
1382
  args: [{
1397
1383
  selector: '[cdkMenu]',
1398
1384
  exportAs: 'cdkMenu',
1399
1385
  host: {
1400
- '[tabindex]': '_isInline() ? 0 : null',
1401
1386
  'role': 'menu',
1402
1387
  'class': 'cdk-menu',
1388
+ '[tabindex]': '_isInline() ? 0 : null',
1403
1389
  '[class.cdk-menu-inline]': '_isInline()',
1404
- '[attr.aria-orientation]': 'orientation',
1405
- '(focus)': 'focusFirstItem()',
1406
1390
  '(keydown)': '_handleKeyEvent($event)',
1407
1391
  },
1408
1392
  providers: [
1409
1393
  { provide: CdkMenuGroup, useExisting: CdkMenu },
1410
1394
  { provide: CDK_MENU, useExisting: CdkMenu },
1395
+ PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER,
1411
1396
  ],
1412
1397
  }]
1413
1398
  }], ctorParameters: function () {
1414
- return [{ type: i0.NgZone }, { type: i0.ElementRef }, { type: undefined, decorators: [{
1399
+ return [{ type: i0.NgZone }, { type: i0.ElementRef }, { type: MenuStack, decorators: [{
1400
+ type: Inject,
1401
+ args: [MENU_STACK]
1402
+ }] }, { type: MenuTrigger, decorators: [{
1403
+ type: Optional
1404
+ }, {
1405
+ type: Inject,
1406
+ args: [MENU_TRIGGER]
1407
+ }] }, { type: undefined, decorators: [{
1415
1408
  type: Self
1416
1409
  }, {
1417
1410
  type: Optional
1418
1411
  }, {
1419
1412
  type: Inject,
1420
1413
  args: [MENU_AIM]
1421
- }] }, { type: i2.Directionality, decorators: [{
1422
- type: Optional
1423
- }] }, { type: CdkMenuPanel, decorators: [{
1414
+ }] }, { type: i1$1.Directionality, decorators: [{
1424
1415
  type: Optional
1425
1416
  }] }];
1426
- }, propDecorators: { orientation: [{
1427
- type: Input,
1428
- args: ['cdkMenuOrientation']
1429
- }], closed: [{
1417
+ }, propDecorators: { closed: [{
1430
1418
  type: Output
1431
1419
  }], _nestedGroups: [{
1432
1420
  type: ContentChildren,
1433
1421
  args: [CdkMenuGroup, { descendants: true }]
1434
- }], _allItems: [{
1435
- type: ContentChildren,
1436
- args: [CdkMenuItem, { descendants: true }]
1437
- }], _explicitPanel: [{
1438
- type: Input,
1439
- args: ['cdkMenuPanel']
1440
1422
  }] } });
1441
1423
 
1442
1424
  /**
@@ -1452,40 +1434,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
1452
1434
  * this directive is applied to should contain components marked with CdkMenuItem.
1453
1435
  *
1454
1436
  */
1455
- class CdkMenuBar extends CdkMenuGroup {
1456
- constructor(_menuStack, _ngZone, _elementRef, _menuAim, _dir) {
1457
- super();
1458
- this._menuStack = _menuStack;
1437
+ class CdkMenuBar extends CdkMenuBase {
1438
+ constructor(_ngZone, elementRef, menuStack, _menuAim, dir) {
1439
+ super(elementRef, menuStack, dir);
1459
1440
  this._ngZone = _ngZone;
1460
- this._elementRef = _elementRef;
1461
1441
  this._menuAim = _menuAim;
1462
- this._dir = _dir;
1463
- /**
1464
- * Sets the aria-orientation attribute and determines where menus will be opened.
1465
- * Does not affect styling/layout.
1466
- */
1467
1442
  this.orientation = 'horizontal';
1468
- /** Emits when the MenuBar is destroyed. */
1469
- this._destroyed = new Subject();
1470
1443
  }
1471
1444
  ngAfterContentInit() {
1472
1445
  var _a;
1473
1446
  super.ngAfterContentInit();
1474
- this._setKeyManager();
1475
- this._subscribeToMenuOpen();
1476
- this._subscribeToMenuStack();
1447
+ this._subscribeToMenuStackEmptied();
1477
1448
  this._subscribeToMouseManager();
1478
- (_a = this._menuAim) === null || _a === void 0 ? void 0 : _a.initialize(this, this._pointerTracker);
1449
+ (_a = this._menuAim) === null || _a === void 0 ? void 0 : _a.initialize(this, this.pointerTracker);
1479
1450
  }
1480
- /** Place focus on the first MenuItem in the menu and set the focus origin. */
1481
- focusFirstItem(focusOrigin = 'program') {
1482
- this._keyManager.setFocusOrigin(focusOrigin);
1483
- this._keyManager.setFirstItemActive();
1484
- }
1485
- /** Place focus on the last MenuItem in the menu and set the focus origin. */
1486
- focusLastItem(focusOrigin = 'program') {
1487
- this._keyManager.setFocusOrigin(focusOrigin);
1488
- this._keyManager.setLastItemActive();
1451
+ ngOnDestroy() {
1452
+ var _a;
1453
+ super.ngOnDestroy();
1454
+ (_a = this.pointerTracker) === null || _a === void 0 ? void 0 : _a.destroy();
1489
1455
  }
1490
1456
  /**
1491
1457
  * Handle keyboard events, specifically changing the focused element and/or toggling the active
@@ -1494,7 +1460,7 @@ class CdkMenuBar extends CdkMenuGroup {
1494
1460
  */
1495
1461
  _handleKeyEvent(event) {
1496
1462
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1497
- const keyManager = this._keyManager;
1463
+ const keyManager = this.keyManager;
1498
1464
  switch (event.keyCode) {
1499
1465
  case UP_ARROW:
1500
1466
  case DOWN_ARROW:
@@ -1504,100 +1470,60 @@ class CdkMenuBar extends CdkMenuGroup {
1504
1470
  // For a horizontal menu if the left/right keys were clicked, or a vertical menu if the
1505
1471
  // up/down keys were clicked: if the current menu is open, close it then focus and open the
1506
1472
  // next menu.
1507
- if ((this._isHorizontal() && horizontalArrows) ||
1508
- (!this._isHorizontal() && !horizontalArrows)) {
1473
+ if ((this.isHorizontal() && horizontalArrows) ||
1474
+ (!this.isHorizontal() && !horizontalArrows)) {
1509
1475
  event.preventDefault();
1510
1476
  const prevIsOpen = (_a = keyManager.activeItem) === null || _a === void 0 ? void 0 : _a.isMenuOpen();
1511
- (_c = (_b = keyManager.activeItem) === null || _b === void 0 ? void 0 : _b.getMenuTrigger()) === null || _c === void 0 ? void 0 : _c.closeMenu();
1477
+ (_c = (_b = keyManager.activeItem) === null || _b === void 0 ? void 0 : _b.getMenuTrigger()) === null || _c === void 0 ? void 0 : _c.close();
1512
1478
  keyManager.setFocusOrigin('keyboard');
1513
1479
  keyManager.onKeydown(event);
1514
1480
  if (prevIsOpen) {
1515
- (_e = (_d = keyManager.activeItem) === null || _d === void 0 ? void 0 : _d.getMenuTrigger()) === null || _e === void 0 ? void 0 : _e.openMenu();
1481
+ (_e = (_d = keyManager.activeItem) === null || _d === void 0 ? void 0 : _d.getMenuTrigger()) === null || _e === void 0 ? void 0 : _e.open();
1516
1482
  }
1517
1483
  }
1518
1484
  break;
1519
1485
  case ESCAPE:
1520
1486
  event.preventDefault();
1521
- (_g = (_f = keyManager.activeItem) === null || _f === void 0 ? void 0 : _f.getMenuTrigger()) === null || _g === void 0 ? void 0 : _g.closeMenu();
1487
+ (_g = (_f = keyManager.activeItem) === null || _f === void 0 ? void 0 : _f.getMenuTrigger()) === null || _g === void 0 ? void 0 : _g.close();
1522
1488
  break;
1523
1489
  case TAB:
1524
- (_j = (_h = keyManager.activeItem) === null || _h === void 0 ? void 0 : _h.getMenuTrigger()) === null || _j === void 0 ? void 0 : _j.closeMenu();
1490
+ (_j = (_h = keyManager.activeItem) === null || _h === void 0 ? void 0 : _h.getMenuTrigger()) === null || _j === void 0 ? void 0 : _j.close();
1525
1491
  break;
1526
1492
  default:
1527
1493
  keyManager.onKeydown(event);
1528
1494
  }
1529
1495
  }
1530
- /** Setup the FocusKeyManager with the correct orientation for the menu bar. */
1531
- _setKeyManager() {
1532
- var _a;
1533
- this._keyManager = new FocusKeyManager(this._allItems)
1534
- .withWrap()
1535
- .withTypeAhead()
1536
- .withHomeAndEnd();
1537
- if (this._isHorizontal()) {
1538
- this._keyManager.withHorizontalOrientation(((_a = this._dir) === null || _a === void 0 ? void 0 : _a.value) || 'ltr');
1539
- }
1540
- else {
1541
- this._keyManager.withVerticalOrientation();
1542
- }
1543
- }
1544
1496
  /**
1545
1497
  * Set the PointerFocusTracker and ensure that when mouse focus changes the key manager is updated
1546
1498
  * with the latest menu item under mouse focus.
1547
1499
  */
1548
1500
  _subscribeToMouseManager() {
1549
1501
  this._ngZone.runOutsideAngular(() => {
1550
- this._pointerTracker = new PointerFocusTracker(this._allItems);
1551
- this._pointerTracker.entered.pipe(takeUntil(this._destroyed)).subscribe(item => {
1552
- if (this._hasOpenSubmenu()) {
1553
- this._keyManager.setActiveItem(item);
1502
+ this.pointerTracker = new PointerFocusTracker(this.items);
1503
+ this.pointerTracker.entered.pipe(takeUntil(this.destroyed)).subscribe(item => {
1504
+ if (this.hasOpenSubmenu()) {
1505
+ this.keyManager.setActiveItem(item);
1554
1506
  }
1555
1507
  });
1556
1508
  });
1557
1509
  }
1558
- /** Subscribe to the MenuStack close and empty observables. */
1559
- _subscribeToMenuStack() {
1560
- this._menuStack.closed
1561
- .pipe(takeUntil(this._destroyed))
1562
- .subscribe(item => this._closeOpenMenu(item));
1563
- this._menuStack.emptied
1564
- .pipe(takeUntil(this._destroyed))
1565
- .subscribe(event => this._toggleOpenMenu(event));
1566
- }
1567
- /**
1568
- * Close the open menu if the current active item opened the requested MenuStackItem.
1569
- * @param item the MenuStackItem requested to be closed.
1570
- */
1571
- _closeOpenMenu(menu) {
1572
- var _a, _b, _c;
1573
- const trigger = this._openItem;
1574
- const keyManager = this._keyManager;
1575
- if (menu === ((_a = trigger === null || trigger === void 0 ? void 0 : trigger.getMenuTrigger()) === null || _a === void 0 ? void 0 : _a.getMenu())) {
1576
- (_b = trigger === null || trigger === void 0 ? void 0 : trigger.getMenuTrigger()) === null || _b === void 0 ? void 0 : _b.closeMenu();
1577
- // If the user has moused over a sibling item we want to focus the element under mouse focus
1578
- // not the trigger which previously opened the now closed menu.
1579
- if (trigger) {
1580
- keyManager.setActiveItem(((_c = this._pointerTracker) === null || _c === void 0 ? void 0 : _c.activeElement) || trigger);
1581
- }
1582
- }
1583
- }
1584
1510
  /**
1585
1511
  * Set focus to either the current, previous or next item based on the FocusNext event, then
1586
1512
  * open the previous or next item.
1587
1513
  */
1588
1514
  _toggleOpenMenu(event) {
1589
1515
  var _a, _b, _c, _d;
1590
- const keyManager = this._keyManager;
1516
+ const keyManager = this.keyManager;
1591
1517
  switch (event) {
1592
1518
  case 0 /* nextItem */:
1593
1519
  keyManager.setFocusOrigin('keyboard');
1594
1520
  keyManager.setNextItemActive();
1595
- (_b = (_a = keyManager.activeItem) === null || _a === void 0 ? void 0 : _a.getMenuTrigger()) === null || _b === void 0 ? void 0 : _b.openMenu();
1521
+ (_b = (_a = keyManager.activeItem) === null || _a === void 0 ? void 0 : _a.getMenuTrigger()) === null || _b === void 0 ? void 0 : _b.open();
1596
1522
  break;
1597
1523
  case 1 /* previousItem */:
1598
1524
  keyManager.setFocusOrigin('keyboard');
1599
1525
  keyManager.setPreviousItemActive();
1600
- (_d = (_c = keyManager.activeItem) === null || _c === void 0 ? void 0 : _c.getMenuTrigger()) === null || _d === void 0 ? void 0 : _d.openMenu();
1526
+ (_d = (_c = keyManager.activeItem) === null || _c === void 0 ? void 0 : _c.getMenuTrigger()) === null || _d === void 0 ? void 0 : _d.open();
1601
1527
  break;
1602
1528
  case 2 /* currentItem */:
1603
1529
  if (keyManager.activeItem) {
@@ -1607,46 +1533,18 @@ class CdkMenuBar extends CdkMenuGroup {
1607
1533
  break;
1608
1534
  }
1609
1535
  }
1610
- /**
1611
- * @return true if the menu bar is configured to be horizontal.
1612
- */
1613
- _isHorizontal() {
1614
- return this.orientation === 'horizontal';
1615
- }
1616
- /**
1617
- * Subscribe to the menu trigger's open events in order to track the trigger which opened the menu
1618
- * and stop tracking it when the menu is closed.
1619
- */
1620
- _subscribeToMenuOpen() {
1621
- const exitCondition = merge(this._allItems.changes, this._destroyed);
1622
- this._allItems.changes
1623
- .pipe(startWith(this._allItems), mergeMap((list) => list
1624
- .filter(item => item.hasMenu())
1625
- .map(item => item.getMenuTrigger().opened.pipe(mapTo(item), takeUntil(exitCondition)))), mergeAll(), switchMap((item) => {
1626
- this._openItem = item;
1627
- return item.getMenuTrigger().closed;
1628
- }), takeUntil(this._destroyed))
1629
- .subscribe(() => (this._openItem = undefined));
1630
- }
1631
- /** Return true if the MenuBar has an open submenu. */
1632
- _hasOpenSubmenu() {
1633
- return !!this._openItem;
1634
- }
1635
- ngOnDestroy() {
1536
+ _subscribeToMenuStackEmptied() {
1636
1537
  var _a;
1637
- super.ngOnDestroy();
1638
- this._destroyed.next();
1639
- this._destroyed.complete();
1640
- (_a = this._pointerTracker) === null || _a === void 0 ? void 0 : _a.destroy();
1538
+ (_a = this.menuStack) === null || _a === void 0 ? void 0 : _a.emptied.pipe(takeUntil(this.destroyed)).subscribe(event => this._toggleOpenMenu(event));
1641
1539
  }
1642
1540
  }
1643
- CdkMenuBar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuBar, deps: [{ token: MenuStack }, { token: i0.NgZone }, { token: i0.ElementRef }, { token: MENU_AIM, optional: true, self: true }, { token: i2.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1644
- CdkMenuBar.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkMenuBar, selector: "[cdkMenuBar]", inputs: { orientation: ["cdkMenuBarOrientation", "orientation"] }, host: { attributes: { "role": "menubar", "tabindex": "0" }, listeners: { "focus": "focusFirstItem()", "keydown": "_handleKeyEvent($event)" }, properties: { "attr.aria-orientation": "orientation" }, classAttribute: "cdk-menu-bar" }, providers: [
1541
+ CdkMenuBar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuBar, deps: [{ token: i0.NgZone }, { token: i0.ElementRef }, { token: MENU_STACK }, { token: MENU_AIM, optional: true, self: true }, { token: i1$1.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1542
+ CdkMenuBar.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuBar, selector: "[cdkMenuBar]", host: { attributes: { "role": "menubar", "tabindex": "0" }, listeners: { "keydown": "_handleKeyEvent($event)" }, classAttribute: "cdk-menu-bar" }, providers: [
1645
1543
  { provide: CdkMenuGroup, useExisting: CdkMenuBar },
1646
1544
  { provide: CDK_MENU, useExisting: CdkMenuBar },
1647
- { provide: MenuStack, useClass: MenuStack },
1648
- ], queries: [{ propertyName: "_allItems", predicate: CdkMenuItem, descendants: true }], exportAs: ["cdkMenuBar"], usesInheritance: true, ngImport: i0 });
1649
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuBar, decorators: [{
1545
+ { provide: MENU_STACK, useFactory: () => MenuStack.inline() },
1546
+ ], exportAs: ["cdkMenuBar"], usesInheritance: true, ngImport: i0 });
1547
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuBar, decorators: [{
1650
1548
  type: Directive,
1651
1549
  args: [{
1652
1550
  selector: '[cdkMenuBar]',
@@ -1655,34 +1553,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
1655
1553
  'role': 'menubar',
1656
1554
  'class': 'cdk-menu-bar',
1657
1555
  'tabindex': '0',
1658
- '[attr.aria-orientation]': 'orientation',
1659
- '(focus)': 'focusFirstItem()',
1660
1556
  '(keydown)': '_handleKeyEvent($event)',
1661
1557
  },
1662
1558
  providers: [
1663
1559
  { provide: CdkMenuGroup, useExisting: CdkMenuBar },
1664
1560
  { provide: CDK_MENU, useExisting: CdkMenuBar },
1665
- { provide: MenuStack, useClass: MenuStack },
1561
+ { provide: MENU_STACK, useFactory: () => MenuStack.inline() },
1666
1562
  ],
1667
1563
  }]
1668
1564
  }], ctorParameters: function () {
1669
- return [{ type: MenuStack }, { type: i0.NgZone }, { type: i0.ElementRef }, { type: undefined, decorators: [{
1565
+ return [{ type: i0.NgZone }, { type: i0.ElementRef }, { type: MenuStack, decorators: [{
1566
+ type: Inject,
1567
+ args: [MENU_STACK]
1568
+ }] }, { type: undefined, decorators: [{
1670
1569
  type: Self
1671
1570
  }, {
1672
1571
  type: Optional
1673
1572
  }, {
1674
1573
  type: Inject,
1675
1574
  args: [MENU_AIM]
1676
- }] }, { type: i2.Directionality, decorators: [{
1575
+ }] }, { type: i1$1.Directionality, decorators: [{
1677
1576
  type: Optional
1678
1577
  }] }];
1679
- }, propDecorators: { orientation: [{
1680
- type: Input,
1681
- args: ['cdkMenuBarOrientation']
1682
- }], _allItems: [{
1683
- type: ContentChildren,
1684
- args: [CdkMenuItem, { descendants: true }]
1685
- }] } });
1578
+ } });
1686
1579
 
1687
1580
  /**
1688
1581
  * A directive providing behavior for the "menuitemradio" ARIA role, which behaves similarly to
@@ -1690,12 +1583,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
1690
1583
  * or `CdkMenuGroup` comprise a radio group with unique selection enforced.
1691
1584
  */
1692
1585
  class CdkMenuItemRadio extends CdkMenuItemSelectable {
1693
- constructor(_selectionDispatcher, element, ngZone, parentMenu, menuAim, dir,
1586
+ constructor(_selectionDispatcher, element, ngZone, menuStack, parentMenu, menuAim, dir,
1694
1587
  /** Reference to the CdkMenuItemTrigger directive if one is added to the same element */
1695
1588
  // `CdkMenuItemRadio` is commonly used in combination with a `CdkMenuItemTrigger`.
1696
1589
  // tslint:disable-next-line: lightweight-tokens
1697
1590
  menuTrigger) {
1698
- super(element, ngZone, parentMenu, menuAim, dir, menuTrigger);
1591
+ super(element, ngZone, menuStack, parentMenu, menuAim, dir, menuTrigger);
1699
1592
  this._selectionDispatcher = _selectionDispatcher;
1700
1593
  this._registerDispatcherListener();
1701
1594
  }
@@ -1715,12 +1608,12 @@ class CdkMenuItemRadio extends CdkMenuItemSelectable {
1715
1608
  this._removeDispatcherListener();
1716
1609
  }
1717
1610
  }
1718
- CdkMenuItemRadio.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuItemRadio, deps: [{ token: i1$1.UniqueSelectionDispatcher }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: CDK_MENU, optional: true }, { token: MENU_AIM, optional: true }, { token: i2.Directionality, optional: true }, { token: CdkMenuItemTrigger, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
1719
- CdkMenuItemRadio.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkMenuItemRadio, selector: "[cdkMenuItemRadio]", host: { attributes: { "type": "button", "role": "menuitemradio" }, properties: { "tabindex": "_tabindex", "attr.aria-checked": "checked || null", "attr.aria-disabled": "disabled || null" } }, providers: [
1611
+ CdkMenuItemRadio.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemRadio, deps: [{ token: i1$2.UniqueSelectionDispatcher }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: MENU_STACK }, { token: CDK_MENU, optional: true }, { token: MENU_AIM, optional: true }, { token: i1$1.Directionality, optional: true }, { token: CdkMenuItemTrigger, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
1612
+ CdkMenuItemRadio.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuItemRadio, selector: "[cdkMenuItemRadio]", host: { attributes: { "type": "button", "role": "menuitemradio" }, properties: { "tabindex": "_tabindex", "attr.aria-checked": "checked || null", "attr.aria-disabled": "disabled || null" } }, providers: [
1720
1613
  { provide: CdkMenuItemSelectable, useExisting: CdkMenuItemRadio },
1721
1614
  { provide: CdkMenuItem, useExisting: CdkMenuItemSelectable },
1722
1615
  ], exportAs: ["cdkMenuItemRadio"], usesInheritance: true, ngImport: i0 });
1723
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuItemRadio, decorators: [{
1616
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemRadio, decorators: [{
1724
1617
  type: Directive,
1725
1618
  args: [{
1726
1619
  selector: '[cdkMenuItemRadio]',
@@ -1738,7 +1631,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
1738
1631
  ],
1739
1632
  }]
1740
1633
  }], ctorParameters: function () {
1741
- return [{ type: i1$1.UniqueSelectionDispatcher }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: undefined, decorators: [{
1634
+ return [{ type: i1$2.UniqueSelectionDispatcher }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: MenuStack, decorators: [{
1635
+ type: Inject,
1636
+ args: [MENU_STACK]
1637
+ }] }, { type: undefined, decorators: [{
1742
1638
  type: Optional
1743
1639
  }, {
1744
1640
  type: Inject,
@@ -1748,7 +1644,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
1748
1644
  }, {
1749
1645
  type: Inject,
1750
1646
  args: [MENU_AIM]
1751
- }] }, { type: i2.Directionality, decorators: [{
1647
+ }] }, { type: i1$1.Directionality, decorators: [{
1752
1648
  type: Optional
1753
1649
  }] }, { type: CdkMenuItemTrigger, decorators: [{
1754
1650
  type: Self
@@ -1777,12 +1673,12 @@ class CdkMenuItemCheckbox extends CdkMenuItemSelectable {
1777
1673
  }
1778
1674
  }
1779
1675
  }
1780
- CdkMenuItemCheckbox.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuItemCheckbox, deps: null, target: i0.ɵɵFactoryTarget.Directive });
1781
- CdkMenuItemCheckbox.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkMenuItemCheckbox, selector: "[cdkMenuItemCheckbox]", host: { attributes: { "type": "button", "role": "menuitemcheckbox" }, properties: { "tabindex": "_tabindex", "attr.aria-checked": "checked || null", "attr.aria-disabled": "disabled || null" } }, providers: [
1676
+ CdkMenuItemCheckbox.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemCheckbox, deps: null, target: i0.ɵɵFactoryTarget.Directive });
1677
+ CdkMenuItemCheckbox.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuItemCheckbox, selector: "[cdkMenuItemCheckbox]", host: { attributes: { "type": "button", "role": "menuitemcheckbox" }, properties: { "tabindex": "_tabindex", "attr.aria-checked": "checked || null", "attr.aria-disabled": "disabled || null" } }, providers: [
1782
1678
  { provide: CdkMenuItemSelectable, useExisting: CdkMenuItemCheckbox },
1783
1679
  { provide: CdkMenuItem, useExisting: CdkMenuItemSelectable },
1784
1680
  ], exportAs: ["cdkMenuItemCheckbox"], usesInheritance: true, ngImport: i0 });
1785
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuItemCheckbox, decorators: [{
1681
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemCheckbox, decorators: [{
1786
1682
  type: Directive,
1787
1683
  args: [{
1788
1684
  selector: '[cdkMenuItemCheckbox]',
@@ -1808,6 +1704,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
1808
1704
  * Use of this source code is governed by an MIT-style license that can be
1809
1705
  * found in the LICENSE file at https://angular.io/license
1810
1706
  */
1707
+ // In cases where the first menu item in the context menu is a trigger the submenu opens on a
1708
+ // hover event. We offset the context menu 2px by default to prevent this from occurring.
1709
+ const CONTEXT_MENU_POSITIONS = STANDARD_DROPDOWN_BELOW_POSITIONS.map(position => {
1710
+ const offsetX = position.overlayX === 'start' ? 2 : -2;
1711
+ const offsetY = position.overlayY === 'top' ? 2 : -2;
1712
+ return Object.assign(Object.assign({}, position), { offsetX, offsetY });
1713
+ });
1811
1714
  /** Tracks the last open context menu trigger across the entire application. */
1812
1715
  class ContextMenuTracker {
1813
1716
  /**
@@ -1822,54 +1725,27 @@ class ContextMenuTracker {
1822
1725
  }
1823
1726
  }
1824
1727
  }
1825
- ContextMenuTracker.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: ContextMenuTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1826
- ContextMenuTracker.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: ContextMenuTracker, providedIn: 'root' });
1827
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: ContextMenuTracker, decorators: [{
1728
+ ContextMenuTracker.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: ContextMenuTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1729
+ ContextMenuTracker.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: ContextMenuTracker, providedIn: 'root' });
1730
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: ContextMenuTracker, decorators: [{
1828
1731
  type: Injectable,
1829
1732
  args: [{ providedIn: 'root' }]
1830
1733
  }] });
1831
- /** Injection token for the ContextMenu options object. */
1832
- const CDK_CONTEXT_MENU_DEFAULT_OPTIONS = new InjectionToken('cdk-context-menu-default-options');
1833
1734
  /**
1834
1735
  * A directive which when placed on some element opens a the Menu it is bound to when a user
1835
1736
  * right-clicks within that element. It is aware of nested Context Menus and the lowest level
1836
1737
  * non-disabled context menu will trigger.
1837
1738
  */
1838
- class CdkContextMenuTrigger {
1839
- constructor(_viewContainerRef, _overlay, _contextMenuTracker, _options, _directionality) {
1739
+ class CdkContextMenuTrigger extends MenuTrigger {
1740
+ constructor(injector, _viewContainerRef, _overlay, _contextMenuTracker, menuStack, _directionality) {
1741
+ super(injector, menuStack);
1840
1742
  this._viewContainerRef = _viewContainerRef;
1841
1743
  this._overlay = _overlay;
1842
1744
  this._contextMenuTracker = _contextMenuTracker;
1843
- this._options = _options;
1844
1745
  this._directionality = _directionality;
1845
- /** Emits when the attached menu is requested to open. */
1846
- this.opened = new EventEmitter();
1847
- /** Emits when the attached menu is requested to close. */
1848
- this.closed = new EventEmitter();
1849
1746
  this._disabled = false;
1850
- /** A reference to the overlay which manages the triggered menu. */
1851
- this._overlayRef = null;
1852
- /** Emits when the element is destroyed. */
1853
- this._destroyed = new Subject();
1854
- /** The menu stack for this trigger and its associated menus. */
1855
- this._menuStack = new MenuStack();
1856
- /** Emits when the outside pointer events listener on the overlay should be stopped. */
1857
- this._stopOutsideClicksListener = merge(this.closed, this._destroyed);
1858
1747
  this._setMenuStackListener();
1859
1748
  }
1860
- /** Template reference variable to the menu to open on right click. */
1861
- get menuPanel() {
1862
- return this._menuPanel;
1863
- }
1864
- set menuPanel(panel) {
1865
- if ((typeof ngDevMode === 'undefined' || ngDevMode) && panel._menuStack) {
1866
- throwExistingMenuStackError();
1867
- }
1868
- this._menuPanel = panel;
1869
- if (this._menuPanel) {
1870
- this._menuPanel._menuStack = this._menuStack;
1871
- }
1872
- }
1873
1749
  /** Whether the context menu should be disabled. */
1874
1750
  get disabled() {
1875
1751
  return this._disabled;
@@ -1891,7 +1767,7 @@ class CdkContextMenuTrigger {
1891
1767
  else if (this.isOpen()) {
1892
1768
  // since we're moving this menu we need to close any submenus first otherwise they end up
1893
1769
  // disconnected from this one.
1894
- this._menuStack.closeSubMenuOf(this._menuPanel._menu);
1770
+ this.menuStack.closeSubMenuOf(this.childMenu);
1895
1771
  this._overlayRef.getConfig().positionStrategy.setOrigin(coordinates);
1896
1772
  this._overlayRef.updatePosition();
1897
1773
  }
@@ -1910,7 +1786,7 @@ class CdkContextMenuTrigger {
1910
1786
  }
1911
1787
  /** Close the opened menu. */
1912
1788
  close() {
1913
- this._menuStack.closeAll();
1789
+ this.menuStack.closeAll();
1914
1790
  }
1915
1791
  /**
1916
1792
  * Open the context menu and close any previously open menus.
@@ -1929,21 +1805,16 @@ class CdkContextMenuTrigger {
1929
1805
  this._open({ x: event.clientX, y: event.clientY }, true);
1930
1806
  // A context menu can be triggered via a mouse right click or a keyboard shortcut.
1931
1807
  if (event.button === 2) {
1932
- (_a = this._menuPanel._menu) === null || _a === void 0 ? void 0 : _a.focusFirstItem('mouse');
1808
+ (_a = this.childMenu) === null || _a === void 0 ? void 0 : _a.focusFirstItem('mouse');
1933
1809
  }
1934
1810
  else if (event.button === 0) {
1935
- (_b = this._menuPanel._menu) === null || _b === void 0 ? void 0 : _b.focusFirstItem('keyboard');
1811
+ (_b = this.childMenu) === null || _b === void 0 ? void 0 : _b.focusFirstItem('keyboard');
1936
1812
  }
1937
1813
  else {
1938
- (_c = this._menuPanel._menu) === null || _c === void 0 ? void 0 : _c.focusFirstItem('program');
1814
+ (_c = this.childMenu) === null || _c === void 0 ? void 0 : _c.focusFirstItem('program');
1939
1815
  }
1940
1816
  }
1941
1817
  }
1942
- /** Whether the attached menu is open. */
1943
- isOpen() {
1944
- var _a;
1945
- return !!((_a = this._overlayRef) === null || _a === void 0 ? void 0 : _a.hasAttached());
1946
- }
1947
1818
  /**
1948
1819
  * Get the configuration object used to create the overlay.
1949
1820
  * @param coordinates the location to place the opened menu
@@ -1960,24 +1831,11 @@ class CdkContextMenuTrigger {
1960
1831
  * @param coordinates the location to place the opened menu
1961
1832
  */
1962
1833
  _getOverlayPositionStrategy(coordinates) {
1834
+ var _a;
1963
1835
  return this._overlay
1964
1836
  .position()
1965
1837
  .flexibleConnectedTo(coordinates)
1966
- .withDefaultOffsetX(this._options.offsetX)
1967
- .withDefaultOffsetY(this._options.offsetY)
1968
- .withPositions(this._getOverlayPositions());
1969
- }
1970
- /**
1971
- * Determine and return where to position the opened menu relative to the mouse location.
1972
- */
1973
- _getOverlayPositions() {
1974
- // TODO: this should be configurable through the injected context menu options
1975
- return [
1976
- { originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'top' },
1977
- { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top' },
1978
- { originX: 'end', originY: 'bottom', overlayX: 'start', overlayY: 'bottom' },
1979
- { originX: 'start', originY: 'bottom', overlayX: 'end', overlayY: 'bottom' },
1980
- ];
1838
+ .withPositions((_a = this.menuPosition) !== null && _a !== void 0 ? _a : CONTEXT_MENU_POSITIONS);
1981
1839
  }
1982
1840
  /**
1983
1841
  * Get the portal to be attached to the overlay which contains the menu. Allows for the menu
@@ -1985,16 +1843,16 @@ class CdkContextMenuTrigger {
1985
1843
  */
1986
1844
  _getMenuContent() {
1987
1845
  var _a;
1988
- const hasMenuContentChanged = this.menuPanel._templateRef !== ((_a = this._panelContent) === null || _a === void 0 ? void 0 : _a.templateRef);
1989
- if (this.menuPanel && (!this._panelContent || hasMenuContentChanged)) {
1990
- this._panelContent = new TemplatePortal(this.menuPanel._templateRef, this._viewContainerRef);
1846
+ const hasMenuContentChanged = this._menuTemplateRef !== ((_a = this._menuPortal) === null || _a === void 0 ? void 0 : _a.templateRef);
1847
+ if (this._menuTemplateRef && (!this._menuPortal || hasMenuContentChanged)) {
1848
+ this._menuPortal = new TemplatePortal(this._menuTemplateRef, this._viewContainerRef, undefined, this.getChildMenuInjector());
1991
1849
  }
1992
- return this._panelContent;
1850
+ return this._menuPortal;
1993
1851
  }
1994
1852
  /** Subscribe to the menu stack close events and close this menu when requested. */
1995
1853
  _setMenuStackListener() {
1996
- this._menuStack.closed.pipe(takeUntil(this._destroyed)).subscribe(item => {
1997
- if (item === this._menuPanel._menu && this.isOpen()) {
1854
+ this.menuStack.closed.pipe(takeUntil(this._destroyed)).subscribe(item => {
1855
+ if (item === this.childMenu && this.isOpen()) {
1998
1856
  this.closed.next();
1999
1857
  this._overlayRef.detach();
2000
1858
  }
@@ -2015,44 +1873,18 @@ class CdkContextMenuTrigger {
2015
1873
  }
2016
1874
  outsideClicks.pipe(takeUntil(this._stopOutsideClicksListener)).subscribe(event => {
2017
1875
  if (!isClickInsideMenuOverlay(event.target)) {
2018
- this._menuStack.closeAll();
1876
+ this.menuStack.closeAll();
2019
1877
  }
2020
1878
  });
2021
1879
  }
2022
1880
  }
2023
- ngOnDestroy() {
2024
- this._destroyOverlay();
2025
- this._resetPanelMenuStack();
2026
- this._destroyed.next();
2027
- this._destroyed.complete();
2028
- }
2029
- /** Destroy and unset the overlay reference it if exists. */
2030
- _destroyOverlay() {
2031
- if (this._overlayRef) {
2032
- this._overlayRef.dispose();
2033
- this._overlayRef = null;
2034
- }
2035
- }
2036
- /** Set the menu panels menu stack back to null. */
2037
- _resetPanelMenuStack() {
2038
- // If a ContextMenuTrigger is placed in a conditionally rendered view, each time the trigger is
2039
- // rendered the panel setter for ContextMenuTrigger is called. From the first render onward,
2040
- // the attached CdkMenuPanel has the MenuStack set. Since we throw an error if a panel already
2041
- // has a stack set, we want to reset the attached stack here to prevent the error from being
2042
- // thrown if the trigger re-configures its attached panel (in the case where there is a 1:1
2043
- // relationship between the panel and trigger).
2044
- if (this._menuPanel) {
2045
- this._menuPanel._menuStack = null;
2046
- }
2047
- }
2048
1881
  }
2049
- CdkContextMenuTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkContextMenuTrigger, deps: [{ token: i0.ViewContainerRef }, { token: i1.Overlay }, { token: ContextMenuTracker }, { token: CDK_CONTEXT_MENU_DEFAULT_OPTIONS }, { token: i2.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
2050
- CdkContextMenuTrigger.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.5", type: CdkContextMenuTrigger, selector: "[cdkContextMenuTriggerFor]", inputs: { menuPanel: ["cdkContextMenuTriggerFor", "menuPanel"], disabled: ["cdkContextMenuDisabled", "disabled"] }, outputs: { opened: "cdkContextMenuOpened", closed: "cdkContextMenuClosed" }, host: { listeners: { "contextmenu": "_openOnContextMenu($event)" } }, providers: [
2051
- // In cases where the first menu item in the context menu is a trigger the submenu opens on a
2052
- // hover event. Offsetting the opened context menu by 2px prevents this from occurring.
2053
- { provide: CDK_CONTEXT_MENU_DEFAULT_OPTIONS, useValue: { offsetX: 2, offsetY: 2 } },
2054
- ], exportAs: ["cdkContextMenuTriggerFor"], ngImport: i0 });
2055
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkContextMenuTrigger, decorators: [{
1882
+ CdkContextMenuTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkContextMenuTrigger, deps: [{ token: i0.Injector }, { token: i0.ViewContainerRef }, { token: i1.Overlay }, { token: ContextMenuTracker }, { token: MENU_STACK }, { token: i1$1.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1883
+ CdkContextMenuTrigger.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkContextMenuTrigger, selector: "[cdkContextMenuTriggerFor]", inputs: { _menuTemplateRef: ["cdkContextMenuTriggerFor", "_menuTemplateRef"], menuPosition: ["cdkContextMenuPosition", "menuPosition"], disabled: ["cdkContextMenuDisabled", "disabled"] }, outputs: { opened: "cdkContextMenuOpened", closed: "cdkContextMenuClosed" }, host: { listeners: { "contextmenu": "_openOnContextMenu($event)" } }, providers: [
1884
+ { provide: MENU_TRIGGER, useExisting: CdkContextMenuTrigger },
1885
+ { provide: MENU_STACK, useClass: MenuStack },
1886
+ ], exportAs: ["cdkContextMenuTriggerFor"], usesInheritance: true, ngImport: i0 });
1887
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkContextMenuTrigger, decorators: [{
2056
1888
  type: Directive,
2057
1889
  args: [{
2058
1890
  selector: '[cdkContextMenuTriggerFor]',
@@ -2060,29 +1892,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
2060
1892
  host: {
2061
1893
  '(contextmenu)': '_openOnContextMenu($event)',
2062
1894
  },
1895
+ inputs: ['_menuTemplateRef: cdkContextMenuTriggerFor', 'menuPosition: cdkContextMenuPosition'],
1896
+ outputs: ['opened: cdkContextMenuOpened', 'closed: cdkContextMenuClosed'],
2063
1897
  providers: [
2064
- // In cases where the first menu item in the context menu is a trigger the submenu opens on a
2065
- // hover event. Offsetting the opened context menu by 2px prevents this from occurring.
2066
- { provide: CDK_CONTEXT_MENU_DEFAULT_OPTIONS, useValue: { offsetX: 2, offsetY: 2 } },
1898
+ { provide: MENU_TRIGGER, useExisting: CdkContextMenuTrigger },
1899
+ { provide: MENU_STACK, useClass: MenuStack },
2067
1900
  ],
2068
1901
  }]
2069
1902
  }], ctorParameters: function () {
2070
- return [{ type: i0.ViewContainerRef }, { type: i1.Overlay }, { type: ContextMenuTracker }, { type: undefined, decorators: [{
1903
+ return [{ type: i0.Injector }, { type: i0.ViewContainerRef }, { type: i1.Overlay }, { type: ContextMenuTracker }, { type: MenuStack, decorators: [{
2071
1904
  type: Inject,
2072
- args: [CDK_CONTEXT_MENU_DEFAULT_OPTIONS]
2073
- }] }, { type: i2.Directionality, decorators: [{
1905
+ args: [MENU_STACK]
1906
+ }] }, { type: i1$1.Directionality, decorators: [{
2074
1907
  type: Optional
2075
1908
  }] }];
2076
- }, propDecorators: { menuPanel: [{
2077
- type: Input,
2078
- args: ['cdkContextMenuTriggerFor']
2079
- }], opened: [{
2080
- type: Output,
2081
- args: ['cdkContextMenuOpened']
2082
- }], closed: [{
2083
- type: Output,
2084
- args: ['cdkContextMenuClosed']
2085
- }], disabled: [{
1909
+ }, propDecorators: { disabled: [{
2086
1910
  type: Input,
2087
1911
  args: ['cdkContextMenuDisabled']
2088
1912
  }] } });
@@ -2097,7 +1921,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
2097
1921
  const EXPORTED_DECLARATIONS = [
2098
1922
  CdkMenuBar,
2099
1923
  CdkMenu,
2100
- CdkMenuPanel,
2101
1924
  CdkMenuItem,
2102
1925
  CdkMenuItemRadio,
2103
1926
  CdkMenuItemCheckbox,
@@ -2108,10 +1931,9 @@ const EXPORTED_DECLARATIONS = [
2108
1931
  ];
2109
1932
  class CdkMenuModule {
2110
1933
  }
2111
- CdkMenuModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2112
- CdkMenuModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuModule, declarations: [CdkMenuBar,
1934
+ CdkMenuModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1935
+ CdkMenuModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuModule, declarations: [CdkMenuBar,
2113
1936
  CdkMenu,
2114
- CdkMenuPanel,
2115
1937
  CdkMenuItem,
2116
1938
  CdkMenuItemRadio,
2117
1939
  CdkMenuItemCheckbox,
@@ -2120,7 +1942,6 @@ CdkMenuModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version:
2120
1942
  CdkContextMenuTrigger,
2121
1943
  CdkTargetMenuAim], imports: [OverlayModule], exports: [CdkMenuBar,
2122
1944
  CdkMenu,
2123
- CdkMenuPanel,
2124
1945
  CdkMenuItem,
2125
1946
  CdkMenuItemRadio,
2126
1947
  CdkMenuItemCheckbox,
@@ -2128,8 +1949,8 @@ CdkMenuModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version:
2128
1949
  CdkMenuGroup,
2129
1950
  CdkContextMenuTrigger,
2130
1951
  CdkTargetMenuAim] });
2131
- CdkMenuModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuModule, imports: [[OverlayModule]] });
2132
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5", ngImport: i0, type: CdkMenuModule, decorators: [{
1952
+ CdkMenuModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuModule, imports: [[OverlayModule]] });
1953
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuModule, decorators: [{
2133
1954
  type: NgModule,
2134
1955
  args: [{
2135
1956
  imports: [OverlayModule],
@@ -2158,5 +1979,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.5",
2158
1979
  * Generated bundle index. Do not edit.
2159
1980
  */
2160
1981
 
2161
- export { CDK_CONTEXT_MENU_DEFAULT_OPTIONS, CDK_MENU, CdkContextMenuTrigger, CdkMenu, CdkMenuBar, CdkMenuGroup, CdkMenuItem, CdkMenuItemCheckbox, CdkMenuItemRadio, CdkMenuItemTrigger, CdkMenuModule, CdkMenuPanel, CdkTargetMenuAim, ContextMenuTracker, MENU_AIM, MenuStack, TargetMenuAim, isClickInsideMenuOverlay };
1982
+ export { CDK_MENU, CdkContextMenuTrigger, CdkMenu, CdkMenuBar, CdkMenuGroup, CdkMenuItem, CdkMenuItemCheckbox, CdkMenuItemRadio, CdkMenuItemTrigger, CdkMenuModule, CdkTargetMenuAim, ContextMenuTracker, MENU_AIM, MENU_STACK, MENU_TRIGGER, MenuStack, MenuTrigger, TargetMenuAim, isClickInsideMenuOverlay };
2162
1983
  //# sourceMappingURL=menu.mjs.map