@angular/cdk-experimental 14.0.0-next.1 → 14.0.0-next.10

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 (133) 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 +4 -4
  7. package/esm2020/column-resize/column-resize-directives/column-resize.mjs +4 -4
  8. package/esm2020/column-resize/column-resize-directives/default-enabled-column-resize-flex.mjs +4 -4
  9. package/esm2020/column-resize/column-resize-directives/default-enabled-column-resize.mjs +4 -4
  10. package/esm2020/column-resize/column-resize-module.mjs +9 -9
  11. package/esm2020/column-resize/column-resize-notifier.mjs +7 -7
  12. package/esm2020/column-resize/column-resize.mjs +6 -5
  13. package/esm2020/column-resize/column-size-store.mjs +4 -4
  14. package/esm2020/column-resize/event-dispatcher.mjs +4 -4
  15. package/esm2020/column-resize/overlay-handle.mjs +4 -4
  16. package/esm2020/column-resize/resizable.mjs +4 -4
  17. package/esm2020/column-resize/resize-strategy.mjs +10 -10
  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 +29 -12
  24. package/esm2020/dialog/dialog-module.mjs +5 -5
  25. package/esm2020/dialog/dialog.mjs +5 -5
  26. package/esm2020/listbox/listbox-module.mjs +5 -5
  27. package/esm2020/listbox/listbox.mjs +26 -44
  28. package/esm2020/menu/context-menu-trigger.mjs +227 -0
  29. package/esm2020/menu/menu-aim.mjs +24 -19
  30. package/esm2020/menu/menu-bar.mjs +72 -165
  31. package/esm2020/menu/menu-base.mjs +203 -0
  32. package/esm2020/menu/menu-errors.mjs +1 -9
  33. package/esm2020/menu/menu-group.mjs +7 -45
  34. package/esm2020/menu/menu-interface.mjs +1 -1
  35. package/esm2020/menu/menu-item-checkbox.mjs +11 -11
  36. package/esm2020/menu/menu-item-radio.mjs +50 -26
  37. package/esm2020/menu/menu-item-selectable.mjs +18 -33
  38. package/esm2020/menu/menu-item.mjs +133 -88
  39. package/esm2020/menu/menu-module.mjs +12 -14
  40. package/esm2020/menu/menu-stack.mjs +69 -19
  41. package/esm2020/menu/menu-trigger-base.mjs +114 -0
  42. package/esm2020/menu/menu-trigger.mjs +302 -0
  43. package/esm2020/menu/menu.mjs +75 -208
  44. package/esm2020/menu/pointer-focus-tracker.mjs +11 -9
  45. package/esm2020/menu/public-api.mjs +10 -7
  46. package/esm2020/popover-edit/edit-event-dispatcher.mjs +4 -4
  47. package/esm2020/popover-edit/edit-ref.mjs +4 -4
  48. package/esm2020/popover-edit/edit-services.mjs +4 -4
  49. package/esm2020/popover-edit/focus-dispatcher.mjs +4 -4
  50. package/esm2020/popover-edit/focus-escape-notifier.mjs +4 -4
  51. package/esm2020/popover-edit/lens-directives.mjs +10 -10
  52. package/esm2020/popover-edit/popover-edit-module.mjs +5 -5
  53. package/esm2020/popover-edit/popover-edit-position-strategy-factory.mjs +7 -7
  54. package/esm2020/popover-edit/table-directives.mjs +16 -16
  55. package/esm2020/scrolling/auto-size-virtual-scroll.mjs +4 -4
  56. package/esm2020/scrolling/scrolling-module.mjs +5 -5
  57. package/esm2020/selection/row-selection.mjs +4 -4
  58. package/esm2020/selection/select-all.mjs +4 -4
  59. package/esm2020/selection/selection-column.mjs +4 -4
  60. package/esm2020/selection/selection-module.mjs +5 -5
  61. package/esm2020/selection/selection-toggle.mjs +4 -4
  62. package/esm2020/selection/selection.mjs +4 -4
  63. package/esm2020/table-scroll-container/table-scroll-container-module.mjs +5 -5
  64. package/esm2020/table-scroll-container/table-scroll-container.mjs +4 -4
  65. package/esm2020/version.mjs +1 -1
  66. package/fesm2015/cdk-experimental.mjs +1 -1
  67. package/fesm2015/cdk-experimental.mjs.map +1 -1
  68. package/fesm2015/column-resize.mjs +52 -51
  69. package/fesm2015/column-resize.mjs.map +1 -1
  70. package/fesm2015/combobox.mjs +63 -106
  71. package/fesm2015/combobox.mjs.map +1 -1
  72. package/fesm2015/dialog.mjs +37 -19
  73. package/fesm2015/dialog.mjs.map +1 -1
  74. package/fesm2015/listbox.mjs +31 -47
  75. package/fesm2015/listbox.mjs.map +1 -1
  76. package/fesm2015/menu.mjs +1109 -1140
  77. package/fesm2015/menu.mjs.map +1 -1
  78. package/fesm2015/popover-edit.mjs +49 -49
  79. package/fesm2015/popover-edit.mjs.map +1 -1
  80. package/fesm2015/scrolling.mjs +7 -7
  81. package/fesm2015/scrolling.mjs.map +1 -1
  82. package/fesm2015/selection.mjs +19 -19
  83. package/fesm2015/selection.mjs.map +1 -1
  84. package/fesm2015/table-scroll-container.mjs +7 -7
  85. package/fesm2015/table-scroll-container.mjs.map +1 -1
  86. package/fesm2020/cdk-experimental.mjs +1 -1
  87. package/fesm2020/cdk-experimental.mjs.map +1 -1
  88. package/fesm2020/column-resize.mjs +52 -51
  89. package/fesm2020/column-resize.mjs.map +1 -1
  90. package/fesm2020/combobox.mjs +62 -103
  91. package/fesm2020/combobox.mjs.map +1 -1
  92. package/fesm2020/dialog.mjs +36 -19
  93. package/fesm2020/dialog.mjs.map +1 -1
  94. package/fesm2020/listbox.mjs +29 -46
  95. package/fesm2020/listbox.mjs.map +1 -1
  96. package/fesm2020/menu.mjs +1031 -1054
  97. package/fesm2020/menu.mjs.map +1 -1
  98. package/fesm2020/popover-edit.mjs +49 -49
  99. package/fesm2020/popover-edit.mjs.map +1 -1
  100. package/fesm2020/scrolling.mjs +7 -7
  101. package/fesm2020/scrolling.mjs.map +1 -1
  102. package/fesm2020/selection.mjs +19 -19
  103. package/fesm2020/selection.mjs.map +1 -1
  104. package/fesm2020/table-scroll-container.mjs +7 -7
  105. package/fesm2020/table-scroll-container.mjs.map +1 -1
  106. package/listbox/listbox.d.ts +16 -13
  107. package/menu/context-menu-trigger.d.ts +98 -0
  108. package/menu/menu-aim.d.ts +20 -9
  109. package/menu/menu-bar.d.ts +24 -60
  110. package/menu/menu-base.d.ts +104 -0
  111. package/menu/menu-errors.d.ts +0 -5
  112. package/menu/menu-group.d.ts +3 -28
  113. package/menu/menu-interface.d.ts +7 -5
  114. package/menu/menu-item-checkbox.d.ts +8 -2
  115. package/menu/menu-item-radio.d.ts +32 -8
  116. package/menu/menu-item-selectable.d.ts +4 -14
  117. package/menu/menu-item.d.ts +64 -24
  118. package/menu/menu-module.d.ts +10 -10
  119. package/menu/menu-stack.d.ts +64 -20
  120. package/menu/menu-trigger-base.d.ts +77 -0
  121. package/menu/menu-trigger.d.ts +104 -0
  122. package/menu/menu.d.ts +34 -87
  123. package/menu/pointer-focus-tracker.d.ts +7 -4
  124. package/menu/public-api.d.ts +9 -6
  125. package/package.json +3 -3
  126. package/combobox/combobox-panel.d.ts +0 -27
  127. package/esm2020/combobox/combobox-panel.mjs +0 -48
  128. package/esm2020/menu/context-menu.mjs +0 -294
  129. package/esm2020/menu/menu-item-trigger.mjs +0 -361
  130. package/esm2020/menu/menu-panel.mjs +0 -37
  131. package/menu/context-menu.d.ts +0 -123
  132. package/menu/menu-item-trigger.d.ts +0 -119
  133. package/menu/menu-panel.d.ts +0 -30
package/fesm2015/menu.mjs CHANGED
@@ -1,16 +1,43 @@
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 { Directive, InjectionToken, Optional, SkipSelf, Inject, Injectable, 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';
6
- 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';
4
+ import { OverlayConfig, STANDARD_DROPDOWN_BELOW_POSITIONS, STANDARD_DROPDOWN_ADJACENT_POSITIONS, OverlayModule } from '@angular/cdk/overlay';
5
+ import { UP_ARROW, hasModifierKey, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, ENTER, SPACE, TAB, ESCAPE } from '@angular/cdk/keycodes';
6
+ import { startWith, debounceTime, distinctUntilChanged, filter, takeUntil, mergeMap, mapTo, mergeAll, switchMap, skip } from 'rxjs/operators';
7
+ import * as i1$2 from '@angular/cdk/collections';
10
8
  import { UniqueSelectionDispatcher } from '@angular/cdk/collections';
11
- import { coerceBooleanProperty } from '@angular/cdk/coercion';
12
- import * as i2 from '@angular/cdk/bidi';
9
+ import { Subject, fromEvent, merge, defer, partition } from 'rxjs';
13
10
  import { TemplatePortal } from '@angular/cdk/portal';
11
+ import { FocusKeyManager } from '@angular/cdk/a11y';
12
+ import { coerceBooleanProperty } from '@angular/cdk/coercion';
13
+ import * as i1$1 from '@angular/cdk/bidi';
14
+
15
+ /**
16
+ * @license
17
+ * Copyright Google LLC All Rights Reserved.
18
+ *
19
+ * Use of this source code is governed by an MIT-style license that can be
20
+ * found in the LICENSE file at https://angular.io/license
21
+ */
22
+ /**
23
+ * A grouping container for `CdkMenuItemRadio` instances, similar to a `role="radiogroup"` element.
24
+ */
25
+ class CdkMenuGroup {
26
+ }
27
+ CdkMenuGroup.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
28
+ CdkMenuGroup.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuGroup, selector: "[cdkMenuGroup]", host: { attributes: { "role": "group" }, classAttribute: "cdk-menu-group" }, providers: [{ provide: UniqueSelectionDispatcher, useClass: UniqueSelectionDispatcher }], exportAs: ["cdkMenuGroup"], ngImport: i0 });
29
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuGroup, decorators: [{
30
+ type: Directive,
31
+ args: [{
32
+ selector: '[cdkMenuGroup]',
33
+ exportAs: 'cdkMenuGroup',
34
+ host: {
35
+ 'role': 'group',
36
+ 'class': 'cdk-menu-group',
37
+ },
38
+ providers: [{ provide: UniqueSelectionDispatcher, useClass: UniqueSelectionDispatcher }],
39
+ }]
40
+ }] });
14
41
 
15
42
  /**
16
43
  * @license
@@ -29,14 +56,158 @@ const CDK_MENU = new InjectionToken('cdk-menu');
29
56
  * Use of this source code is governed by an MIT-style license that can be
30
57
  * found in the LICENSE file at https://angular.io/license
31
58
  */
59
+ /** Injection token used for an implementation of MenuStack. */
60
+ const MENU_STACK = new InjectionToken('cdk-menu-stack');
61
+ /** Provider that provides the parent menu stack, or a new menu stack if there is no parent one. */
62
+ const PARENT_OR_NEW_MENU_STACK_PROVIDER = {
63
+ provide: MENU_STACK,
64
+ deps: [[new Optional(), new SkipSelf(), new Inject(MENU_STACK)]],
65
+ useFactory: (parentMenuStack) => parentMenuStack || new MenuStack(),
66
+ };
67
+ /** Provider that provides the parent menu stack, or a new inline menu stack if there is no parent one. */
68
+ const PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER = (orientation) => ({
69
+ provide: MENU_STACK,
70
+ deps: [[new Optional(), new SkipSelf(), new Inject(MENU_STACK)]],
71
+ useFactory: (parentMenuStack) => parentMenuStack || MenuStack.inline(orientation),
72
+ });
73
+ /** The next available menu stack ID. */
74
+ let nextId$2 = 0;
32
75
  /**
33
- * Throws an exception when a menu panel already has a menu stack.
34
- * @docs-private
76
+ * MenuStack allows subscribers to listen for close events (when a MenuStackItem is popped off
77
+ * of the stack) in order to perform closing actions. Upon the MenuStack being empty it emits
78
+ * from the `empty` observable specifying the next focus action which the listener should perform
79
+ * as requested by the closer.
35
80
  */
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.');
81
+ class MenuStack {
82
+ constructor() {
83
+ /** The ID of this menu stack. */
84
+ this.id = `${nextId$2++}`;
85
+ /** All MenuStackItems tracked by this MenuStack. */
86
+ this._elements = [];
87
+ /** Emits the element which was popped off of the stack when requested by a closer. */
88
+ this._close = new Subject();
89
+ /** Emits once the MenuStack has become empty after popping off elements. */
90
+ this._empty = new Subject();
91
+ /** Emits whether any menu in the menu stack has focus. */
92
+ this._hasFocus = new Subject();
93
+ /** Observable which emits the MenuStackItem which has been requested to close. */
94
+ this.closed = this._close;
95
+ /** Observable which emits whether any menu in the menu stack has focus. */
96
+ this.hasFocus = this._hasFocus.pipe(startWith(false), debounceTime(0), distinctUntilChanged());
97
+ /**
98
+ * Observable which emits when the MenuStack is empty after popping off the last element. It
99
+ * emits a FocusNext event which specifies the action the closer has requested the listener
100
+ * perform.
101
+ */
102
+ this.emptied = this._empty;
103
+ /**
104
+ * Whether the inline menu associated with this menu stack is vertical or horizontal.
105
+ * `null` indicates there is no inline menu associated with this menu stack.
106
+ */
107
+ this._inlineMenuOrientation = null;
108
+ }
109
+ /** Creates a menu stack that originates from an inline menu. */
110
+ static inline(orientation) {
111
+ const stack = new MenuStack();
112
+ stack._inlineMenuOrientation = orientation;
113
+ return stack;
114
+ }
115
+ /**
116
+ * Adds an item to the menu stack.
117
+ * @param menu the MenuStackItem to put on the stack.
118
+ */
119
+ push(menu) {
120
+ this._elements.push(menu);
121
+ }
122
+ /**
123
+ * Pop items off of the stack up to and including `lastItem` and emit each on the close
124
+ * observable. If the stack is empty or `lastItem` is not on the stack it does nothing.
125
+ * @param lastItem the last item to pop off the stack.
126
+ * @param options Options that configure behavior on close.
127
+ */
128
+ close(lastItem, options) {
129
+ const { focusNextOnEmpty, focusParentTrigger } = Object.assign({}, options);
130
+ if (this._elements.indexOf(lastItem) >= 0) {
131
+ let poppedElement;
132
+ do {
133
+ poppedElement = this._elements.pop();
134
+ this._close.next({ item: poppedElement, focusParentTrigger });
135
+ } while (poppedElement !== lastItem);
136
+ if (this.isEmpty()) {
137
+ this._empty.next(focusNextOnEmpty);
138
+ }
139
+ }
140
+ }
141
+ /**
142
+ * Pop items off of the stack up to but excluding `lastItem` and emit each on the close
143
+ * observable. If the stack is empty or `lastItem` is not on the stack it does nothing.
144
+ * @param lastItem the element which should be left on the stack
145
+ * @return whether or not an item was removed from the stack
146
+ */
147
+ closeSubMenuOf(lastItem) {
148
+ let removed = false;
149
+ if (this._elements.indexOf(lastItem) >= 0) {
150
+ removed = this.peek() !== lastItem;
151
+ while (this.peek() !== lastItem) {
152
+ this._close.next({ item: this._elements.pop() });
153
+ }
154
+ }
155
+ return removed;
156
+ }
157
+ /**
158
+ * Pop off all MenuStackItems and emit each one on the `close` observable one by one.
159
+ * @param options Options that configure behavior on close.
160
+ */
161
+ closeAll(options) {
162
+ const { focusNextOnEmpty, focusParentTrigger } = Object.assign({}, options);
163
+ if (!this.isEmpty()) {
164
+ while (!this.isEmpty()) {
165
+ const menuStackItem = this._elements.pop();
166
+ if (menuStackItem) {
167
+ this._close.next({ item: menuStackItem, focusParentTrigger });
168
+ }
169
+ }
170
+ this._empty.next(focusNextOnEmpty);
171
+ }
172
+ }
173
+ /** Return true if this stack is empty. */
174
+ isEmpty() {
175
+ return !this._elements.length;
176
+ }
177
+ /** Return the length of the stack. */
178
+ length() {
179
+ return this._elements.length;
180
+ }
181
+ /** Get the top most element on the stack. */
182
+ peek() {
183
+ return this._elements[this._elements.length - 1];
184
+ }
185
+ /** Whether the menu stack is associated with an inline menu. */
186
+ hasInlineMenu() {
187
+ return this._inlineMenuOrientation != null;
188
+ }
189
+ /** The orientation of the associated inline menu. */
190
+ inlineMenuOrientation() {
191
+ return this._inlineMenuOrientation;
192
+ }
193
+ /** Sets whether the menu stack contains the focused element. */
194
+ setHasFocus(hasFocus) {
195
+ this._hasFocus.next(hasFocus);
196
+ }
39
197
  }
198
+ MenuStack.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: MenuStack, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
199
+ MenuStack.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: MenuStack });
200
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: MenuStack, decorators: [{
201
+ type: Injectable
202
+ }] });
203
+
204
+ /**
205
+ * @license
206
+ * Copyright Google LLC All Rights Reserved.
207
+ *
208
+ * Use of this source code is governed by an MIT-style license that can be
209
+ * found in the LICENSE file at https://angular.io/license
210
+ */
40
211
  /**
41
212
  * Throws an exception when an instance of the PointerFocusTracker is not provided.
42
213
  * @docs-private
@@ -84,7 +255,6 @@ function getYIntercept(point, slope) {
84
255
  * @param submenuPoints the submenu DOMRect points.
85
256
  * @param m the slope of the trajectory line.
86
257
  * @param b the y intercept of the trajectory line.
87
- *
88
258
  * @return true if any point on the line falls within the submenu.
89
259
  */
90
260
  function isWithinSubmenu(submenuPoints, m, b) {
@@ -108,14 +278,24 @@ function isWithinSubmenu(submenuPoints, m, b) {
108
278
  * to submenu.
109
279
  */
110
280
  class TargetMenuAim {
111
- constructor(_ngZone) {
281
+ constructor(
282
+ /** The Angular zone. */
283
+ _ngZone) {
112
284
  this._ngZone = _ngZone;
113
285
  /** The last NUM_POINTS mouse move events. */
114
286
  this._points = [];
115
287
  /** Emits when this service is destroyed. */
116
288
  this._destroyed = new Subject();
117
289
  }
118
- /** Set the Menu and its PointerFocusTracker. */
290
+ ngOnDestroy() {
291
+ this._destroyed.next();
292
+ this._destroyed.complete();
293
+ }
294
+ /**
295
+ * Set the Menu and its PointerFocusTracker.
296
+ * @param menu The menu that this menu aim service controls.
297
+ * @param pointerTracker The `PointerFocusTracker` for the given menu.
298
+ */
119
299
  initialize(menu, pointerTracker) {
120
300
  this._menu = menu;
121
301
  this._pointerTracker = pointerTracker;
@@ -152,6 +332,8 @@ class TargetMenuAim {
152
332
  *
153
333
  * The delayed toggle handler executes the `doToggle` callback after some period of time iff the
154
334
  * users mouse is on an item in the current menu.
335
+ *
336
+ * @param doToggle the function called when the user is not moving towards the submenu.
155
337
  */
156
338
  _startTimeout(doToggle) {
157
339
  // If the users mouse is moving towards a submenu we don't want to immediately resolve.
@@ -189,7 +371,7 @@ class TargetMenuAim {
189
371
  /** Get the bounding DOMRect for the open submenu. */
190
372
  _getSubmenuBounds() {
191
373
  var _a, _b, _c;
192
- return (_c = (_b = (_a = this._pointerTracker) === null || _a === void 0 ? void 0 : _a.previousElement) === null || _b === void 0 ? void 0 : _b.getMenu()) === null || _c === void 0 ? void 0 : _c._elementRef.nativeElement.getBoundingClientRect();
374
+ return (_c = (_b = (_a = this._pointerTracker) === null || _a === void 0 ? void 0 : _a.previousElement) === null || _b === void 0 ? void 0 : _b.getMenu()) === null || _c === void 0 ? void 0 : _c.nativeElement.getBoundingClientRect();
193
375
  }
194
376
  /**
195
377
  * Check if a reference to the PointerFocusTracker and menu element is provided.
@@ -208,7 +390,7 @@ class TargetMenuAim {
208
390
  /** Subscribe to the root menus mouse move events and update the tracked mouse points. */
209
391
  _subscribeToMouseMoves() {
210
392
  this._ngZone.runOutsideAngular(() => {
211
- fromEvent(this._menu._elementRef.nativeElement, 'mousemove')
393
+ fromEvent(this._menu.nativeElement, 'mousemove')
212
394
  .pipe(filter((_, index) => index % MOUSE_MOVE_SAMPLE_FREQUENCY === 0), takeUntil(this._destroyed))
213
395
  .subscribe((event) => {
214
396
  this._points.push({ x: event.clientX, y: event.clientY });
@@ -218,25 +400,21 @@ class TargetMenuAim {
218
400
  });
219
401
  });
220
402
  }
221
- ngOnDestroy() {
222
- this._destroyed.next();
223
- this._destroyed.complete();
224
- }
225
403
  }
226
- TargetMenuAim.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: TargetMenuAim, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
227
- TargetMenuAim.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: TargetMenuAim });
228
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: TargetMenuAim, decorators: [{
404
+ 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 });
405
+ TargetMenuAim.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: TargetMenuAim });
406
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: TargetMenuAim, decorators: [{
229
407
  type: Injectable
230
408
  }], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
231
409
  /**
232
- * CdkTargetMenuAim is a provider for the TargetMenuAim service. It should be added to an
410
+ * CdkTargetMenuAim is a provider for the TargetMenuAim service. It can be added to an
233
411
  * element with either the `cdkMenu` or `cdkMenuBar` directive and child menu items.
234
412
  */
235
413
  class CdkTargetMenuAim {
236
414
  }
237
- CdkTargetMenuAim.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkTargetMenuAim, deps: [], target: i0.ɵɵFactoryTarget.Directive });
238
- CdkTargetMenuAim.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.0", type: CdkTargetMenuAim, selector: "[cdkTargetMenuAim]", providers: [{ provide: MENU_AIM, useClass: TargetMenuAim }], exportAs: ["cdkTargetMenuAim"], ngImport: i0 });
239
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkTargetMenuAim, decorators: [{
415
+ CdkTargetMenuAim.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkTargetMenuAim, deps: [], target: i0.ɵɵFactoryTarget.Directive });
416
+ 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 });
417
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkTargetMenuAim, decorators: [{
240
418
  type: Directive,
241
419
  args: [{
242
420
  selector: '[cdkTargetMenuAim]',
@@ -252,103 +430,111 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
252
430
  * Use of this source code is governed by an MIT-style license that can be
253
431
  * found in the LICENSE file at https://angular.io/license
254
432
  */
433
+ /** Injection token used for an implementation of MenuStack. */
434
+ const MENU_TRIGGER = new InjectionToken('cdk-menu-trigger');
255
435
  /**
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.
436
+ * Abstract directive that implements shared logic common to all menu triggers.
437
+ * This class can be extended to create custom menu trigger types.
260
438
  */
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;
439
+ class CdkMenuTriggerBase {
440
+ constructor(
441
+ /** The DI injector for this component */
442
+ injector,
443
+ /** The view container ref for this component */
444
+ viewContainerRef,
445
+ /** The menu stack this menu is part of. */
446
+ menuStack) {
447
+ this.injector = injector;
448
+ this.viewContainerRef = viewContainerRef;
449
+ this.menuStack = menuStack;
450
+ /** Emits when the attached menu is requested to open */
451
+ this.opened = new EventEmitter();
452
+ /** Emits when the attached menu is requested to close */
453
+ this.closed = new EventEmitter();
454
+ /** A reference to the overlay which manages the triggered menu */
455
+ this.overlayRef = null;
456
+ /** Emits when this trigger is destroyed. */
457
+ this.destroyed = new Subject();
458
+ /** Emits when the outside pointer events listener on the overlay should be stopped. */
459
+ this.stopOutsideClicksListener = merge(this.closed, this.destroyed);
277
460
  }
278
- /** @param menu the MenuStackItem to put on the stack. */
279
- push(menu) {
280
- this._elements.push(menu);
461
+ ngOnDestroy() {
462
+ this._destroyOverlay();
463
+ this.destroyed.next();
464
+ this.destroyed.complete();
281
465
  }
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
- }
466
+ /** Whether the attached menu is open. */
467
+ isOpen() {
468
+ var _a;
469
+ return !!((_a = this.overlayRef) === null || _a === void 0 ? void 0 : _a.hasAttached());
470
+ }
471
+ /** Registers a child menu as having been opened by this trigger. */
472
+ registerChildMenu(child) {
473
+ this.childMenu = child;
301
474
  }
302
475
  /**
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
476
+ * Get the portal to be attached to the overlay which contains the menu. Allows for the menu
477
+ * content to change dynamically and be reflected in the application.
307
478
  */
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
- }
479
+ getMenuContentPortal() {
480
+ var _a;
481
+ const hasMenuContentChanged = this.menuTemplateRef !== ((_a = this._menuPortal) === null || _a === void 0 ? void 0 : _a.templateRef);
482
+ if (this.menuTemplateRef && (!this._menuPortal || hasMenuContentChanged)) {
483
+ this._menuPortal = new TemplatePortal(this.menuTemplateRef, this.viewContainerRef, undefined, this._getChildMenuInjector());
315
484
  }
316
- return removed;
485
+ return this._menuPortal;
317
486
  }
318
487
  /**
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.
488
+ * Whether the given element is inside the scope of this trigger's menu stack.
489
+ * @param element The element to check.
490
+ * @return Whether the element is inside the scope of this trigger's menu stack.
322
491
  */
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
- }
492
+ isElementInsideMenuStack(element) {
493
+ var _a;
494
+ for (let el = element; el; el = (_a = el === null || el === void 0 ? void 0 : el.parentElement) !== null && _a !== void 0 ? _a : null) {
495
+ if (el.getAttribute('data-cdk-menu-stack-id') === this.menuStack.id) {
496
+ return true;
330
497
  }
331
- this._empty.next(focusNext);
332
498
  }
499
+ return false;
333
500
  }
334
- /** Return true if this stack is empty. */
335
- isEmpty() {
336
- return !this._elements.length;
337
- }
338
- /** Return the length of the stack. */
339
- length() {
340
- return this._elements.length;
501
+ /** Destroy and unset the overlay reference it if exists */
502
+ _destroyOverlay() {
503
+ if (this.overlayRef) {
504
+ this.overlayRef.dispose();
505
+ this.overlayRef = null;
506
+ }
341
507
  }
342
- /** Get the top most element on the stack. */
343
- peek() {
344
- return this._elements[this._elements.length - 1];
508
+ /** Gets the injector to use when creating a child menu. */
509
+ _getChildMenuInjector() {
510
+ this._childMenuInjector =
511
+ this._childMenuInjector ||
512
+ Injector.create({
513
+ providers: [
514
+ { provide: MENU_TRIGGER, useValue: this },
515
+ { provide: MENU_STACK, useValue: this.menuStack },
516
+ ],
517
+ parent: this.injector,
518
+ });
519
+ return this._childMenuInjector;
345
520
  }
346
521
  }
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
- }
522
+ CdkMenuTriggerBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuTriggerBase, deps: [{ token: i0.Injector }, { token: i0.ViewContainerRef }, { token: MENU_STACK }], target: i0.ɵɵFactoryTarget.Directive });
523
+ CdkMenuTriggerBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuTriggerBase, host: { properties: { "attr.aria-controls": "childMenu?.id", "attr.data-cdk-menu-stack-id": "menuStack.id" } }, ngImport: i0 });
524
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuTriggerBase, decorators: [{
525
+ type: Directive,
526
+ args: [{
527
+ host: {
528
+ '[attr.aria-controls]': 'childMenu?.id',
529
+ '[attr.data-cdk-menu-stack-id]': 'menuStack.id',
530
+ },
531
+ }]
532
+ }], ctorParameters: function () {
533
+ return [{ type: i0.Injector }, { type: i0.ViewContainerRef }, { type: MenuStack, decorators: [{
534
+ type: Inject,
535
+ args: [MENU_STACK]
536
+ }] }];
537
+ } });
352
538
 
353
539
  /**
354
540
  * @license
@@ -358,199 +544,169 @@ class NoopMenuStack extends MenuStack {
358
544
  * found in the LICENSE file at https://angular.io/license
359
545
  */
360
546
  /**
361
- * Whether the target element is a menu item to be ignored by the overlay background click handler.
362
- */
363
- function isClickInsideMenuOverlay(target) {
364
- while (target === null || target === void 0 ? void 0 : target.parentElement) {
365
- const isOpenTrigger = target.getAttribute('aria-expanded') === 'true' &&
366
- target.classList.contains('cdk-menu-trigger');
367
- const isOverlayMenu = target.classList.contains('cdk-menu') && !target.classList.contains('cdk-menu-inline');
368
- if (isOpenTrigger || isOverlayMenu) {
369
- return true;
370
- }
371
- target = target.parentElement;
372
- }
373
- return false;
374
- }
375
- /**
376
- * A directive to be combined with CdkMenuItem which opens the Menu it is bound to. If the
377
- * element is in a top level MenuBar it will open the menu on click, or if a sibling is already
378
- * opened it will open on hover. If it is inside of a Menu it will open the attached Submenu on
379
- * hover regardless of its sibling state.
380
- *
381
- * The directive must be placed along with the `cdkMenuItem` directive in order to enable full
382
- * functionality.
547
+ * A directive that turns its host element into a trigger for a popup menu.
548
+ * It can be combined with cdkMenuItem to create sub-menus. If the element is in a top level
549
+ * MenuBar it will open the menu on click, or if a sibling is already opened it will open on hover.
550
+ * If it is inside of a Menu it will open the attached Submenu on hover regardless of its sibling
551
+ * state.
383
552
  */
384
- class CdkMenuItemTrigger {
385
- constructor(_elementRef, _viewContainerRef, _overlay, _ngZone, _parentMenu, _menuAim, _directionality) {
553
+ class CdkMenuTrigger extends CdkMenuTriggerBase {
554
+ constructor(
555
+ /** The DI injector for this component. */
556
+ injector,
557
+ /** The host element. */
558
+ _elementRef,
559
+ /** The view container ref for this component. */
560
+ viewContainerRef,
561
+ /** The CDK overlay service. */
562
+ _overlay,
563
+ /** The Angular zone. */
564
+ _ngZone,
565
+ /** The menu stack this trigger belongs to. */
566
+ menuStack,
567
+ /** The parent menu this trigger belongs to. */
568
+ _parentMenu,
569
+ /** The menu aim service used by this menu. */
570
+ _menuAim,
571
+ /** The directionality of the page. */
572
+ _directionality) {
573
+ super(injector, viewContainerRef, menuStack);
386
574
  this._elementRef = _elementRef;
387
- this._viewContainerRef = _viewContainerRef;
388
575
  this._overlay = _overlay;
389
576
  this._ngZone = _ngZone;
390
577
  this._parentMenu = _parentMenu;
391
578
  this._menuAim = _menuAim;
392
579
  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
580
  this._registerCloseHandler();
581
+ this._subscribeToMenuStackClosed();
406
582
  this._subscribeToMouseEnter();
583
+ this._subscribeToMenuStackHasFocus();
407
584
  }
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
- /** Open/close the attached menu if the trigger has been configured with one */
585
+ /** Toggle the attached menu. */
425
586
  toggle() {
426
- if (this.hasMenu()) {
427
- this.isMenuOpen() ? this.closeMenu() : this.openMenu();
428
- }
587
+ this.isOpen() ? this.close() : this.open();
429
588
  }
430
589
  /** Open the attached menu. */
431
- openMenu() {
432
- if (!this.isMenuOpen()) {
590
+ open() {
591
+ if (!this.isOpen()) {
433
592
  this.opened.next();
434
- this._overlayRef = this._overlayRef || this._overlay.create(this._getOverlayConfig());
435
- this._overlayRef.attach(this._getPortal());
593
+ this.overlayRef = this.overlayRef || this._overlay.create(this._getOverlayConfig());
594
+ this.overlayRef.attach(this.getMenuContentPortal());
436
595
  this._subscribeToOutsideClicks();
437
596
  }
438
597
  }
439
598
  /** Close the opened menu. */
440
- closeMenu() {
441
- if (this.isMenuOpen()) {
599
+ close() {
600
+ if (this.isOpen()) {
442
601
  this.closed.next();
443
- this._overlayRef.detach();
602
+ this.overlayRef.detach();
444
603
  }
445
604
  this._closeSiblingTriggers();
446
605
  }
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
606
  /**
456
- * Get a reference to the rendered Menu if the Menu is open and it is visible in the DOM.
457
- * @return the menu if it is open, otherwise undefined.
607
+ * Get a reference to the rendered Menu if the Menu is open and rendered in the DOM.
458
608
  */
459
609
  getMenu() {
460
- var _a;
461
- return (_a = this.menuPanel) === null || _a === void 0 ? void 0 : _a._menu;
610
+ return this.childMenu;
462
611
  }
463
612
  /**
464
- * Subscribe to the mouseenter events and close any sibling menu items if this element is moused
465
- * into.
466
- */
467
- _subscribeToMouseEnter() {
468
- // Closes any sibling menu items and opens the menu associated with this trigger.
469
- const toggleMenus = () => this._ngZone.run(() => {
470
- this._closeSiblingTriggers();
471
- this.openMenu();
472
- });
473
- this._ngZone.runOutsideAngular(() => {
474
- 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))
476
- .subscribe(() => {
477
- if (this._menuAim) {
478
- this._menuAim.toggle(toggleMenus);
479
- }
480
- else {
481
- toggleMenus();
482
- }
483
- });
484
- });
485
- }
486
- /**
487
- * Handles keyboard events for the menu item, specifically opening/closing the attached menu and
488
- * focusing the appropriate submenu item.
489
- * @param event the keyboard event to handle
613
+ * Handles keyboard events for the menu item.
614
+ * @param event The keyboard event to handle
490
615
  */
491
616
  _toggleOnKeydown(event) {
492
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
617
+ var _a, _b, _c, _d, _e, _f, _g, _h;
618
+ const isParentVertical = ((_a = this._parentMenu) === null || _a === void 0 ? void 0 : _a.orientation) === 'vertical';
493
619
  const keyCode = event.keyCode;
494
620
  switch (keyCode) {
495
621
  case SPACE:
496
622
  case ENTER:
497
- event.preventDefault();
498
- this.toggle();
499
- (_b = (_a = this.menuPanel) === null || _a === void 0 ? void 0 : _a._menu) === null || _b === void 0 ? void 0 : _b.focusFirstItem('keyboard');
623
+ if (!hasModifierKey(event)) {
624
+ event.preventDefault();
625
+ this.toggle();
626
+ (_b = this.childMenu) === null || _b === void 0 ? void 0 : _b.focusFirstItem('keyboard');
627
+ }
500
628
  break;
501
629
  case RIGHT_ARROW:
502
- if (this._parentMenu && this._isParentVertical()) {
503
- 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');
630
+ if (!hasModifierKey(event)) {
631
+ if (this._parentMenu && isParentVertical && ((_c = this._directionality) === null || _c === void 0 ? void 0 : _c.value) !== 'rtl') {
632
+ event.preventDefault();
633
+ this.open();
634
+ (_d = this.childMenu) === null || _d === void 0 ? void 0 : _d.focusFirstItem('keyboard');
510
635
  }
511
636
  }
512
637
  break;
513
638
  case LEFT_ARROW:
514
- if (this._parentMenu && this._isParentVertical()) {
515
- 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 */);
639
+ if (!hasModifierKey(event)) {
640
+ if (this._parentMenu && isParentVertical && ((_e = this._directionality) === null || _e === void 0 ? void 0 : _e.value) === 'rtl') {
641
+ event.preventDefault();
642
+ this.open();
643
+ (_f = this.childMenu) === null || _f === void 0 ? void 0 : _f.focusFirstItem('keyboard');
522
644
  }
523
645
  }
524
646
  break;
525
647
  case DOWN_ARROW:
526
648
  case UP_ARROW:
527
- if (!this._isParentVertical()) {
528
- event.preventDefault();
529
- this.openMenu();
530
- 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');
649
+ if (!hasModifierKey(event)) {
650
+ if (!isParentVertical) {
651
+ event.preventDefault();
652
+ this.open();
653
+ keyCode === DOWN_ARROW
654
+ ? (_g = this.childMenu) === null || _g === void 0 ? void 0 : _g.focusFirstItem('keyboard')
655
+ : (_h = this.childMenu) === null || _h === void 0 ? void 0 : _h.focusLastItem('keyboard');
656
+ }
533
657
  }
534
658
  break;
535
659
  }
536
660
  }
661
+ /**
662
+ * Sets whether the trigger's menu stack has focus.
663
+ * @param hasFocus Whether the menu stack has focus.
664
+ */
665
+ _setHasFocus(hasFocus) {
666
+ if (!this._parentMenu) {
667
+ this.menuStack.setHasFocus(hasFocus);
668
+ }
669
+ }
670
+ /**
671
+ * Subscribe to the mouseenter events and close any sibling menu items if this element is moused
672
+ * into.
673
+ */
674
+ _subscribeToMouseEnter() {
675
+ // Closes any sibling menu items and opens the menu associated with this trigger.
676
+ const toggleMenus = () => this._ngZone.run(() => {
677
+ this._closeSiblingTriggers();
678
+ this.open();
679
+ });
680
+ this._ngZone.runOutsideAngular(() => {
681
+ fromEvent(this._elementRef.nativeElement, 'mouseenter')
682
+ .pipe(filter(() => !this.menuStack.isEmpty() && !this.isOpen()), takeUntil(this.destroyed))
683
+ .subscribe(() => {
684
+ if (this._menuAim) {
685
+ this._menuAim.toggle(toggleMenus);
686
+ }
687
+ else {
688
+ toggleMenus();
689
+ }
690
+ });
691
+ });
692
+ }
537
693
  /** Close out any sibling menu trigger menus. */
538
694
  _closeSiblingTriggers() {
539
695
  if (this._parentMenu) {
540
- const menuStack = this._getMenuStack();
541
696
  // If nothing was removed from the stack and the last element is not the parent item
542
697
  // that means that the parent menu is a menu bar since we don't put the menu bar on the
543
698
  // stack
544
- const isParentMenuBar = !menuStack.closeSubMenuOf(this._parentMenu) && menuStack.peek() !== this._parentMenu;
699
+ const isParentMenuBar = !this.menuStack.closeSubMenuOf(this._parentMenu) &&
700
+ this.menuStack.peek() !== this._parentMenu;
545
701
  if (isParentMenuBar) {
546
- menuStack.closeAll();
702
+ this.menuStack.closeAll();
547
703
  }
548
704
  }
549
705
  else {
550
- this._getMenuStack().closeAll();
706
+ this.menuStack.closeAll();
551
707
  }
552
708
  }
553
- /** Get the configuration object used to create the overlay */
709
+ /** Get the configuration object used to create the overlay. */
554
710
  _getOverlayConfig() {
555
711
  return new OverlayConfig({
556
712
  positionStrategy: this._getOverlayPositionStrategy(),
@@ -558,48 +714,19 @@ class CdkMenuItemTrigger {
558
714
  direction: this._directionality,
559
715
  });
560
716
  }
561
- /** Build the position strategy for the overlay which specifies where to place the menu */
717
+ /** Build the position strategy for the overlay which specifies where to place the menu. */
562
718
  _getOverlayPositionStrategy() {
563
719
  return this._overlay
564
720
  .position()
565
721
  .flexibleConnectedTo(this._elementRef)
566
722
  .withPositions(this._getOverlayPositions());
567
723
  }
568
- /** Determine and return where to position the opened menu relative to the menu item */
724
+ /** Get the preferred positions for the opened menu relative to the menu item. */
569
725
  _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
- ];
584
- }
585
- /**
586
- * Get the portal to be attached to the overlay which contains the menu. Allows for the menu
587
- * content to change dynamically and be reflected in the application.
588
- */
589
- _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);
594
- }
595
- return this._panelContent;
596
- }
597
- /**
598
- * @return true if if the enclosing parent menu is configured in a vertical orientation.
599
- */
600
- _isParentVertical() {
601
726
  var _a;
602
- return ((_a = this._parentMenu) === null || _a === void 0 ? void 0 : _a.orientation) === 'vertical';
727
+ return ((_a = this.menuPosition) !== null && _a !== void 0 ? _a : (!this._parentMenu || this._parentMenu.orientation === 'horizontal'
728
+ ? STANDARD_DROPDOWN_BELOW_POSITIONS
729
+ : STANDARD_DROPDOWN_ADJACENT_POSITIONS));
603
730
  }
604
731
  /**
605
732
  * Subscribe to the MenuStack close events if this is a standalone trigger and close out the menu
@@ -607,81 +734,85 @@ class CdkMenuItemTrigger {
607
734
  */
608
735
  _registerCloseHandler() {
609
736
  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();
737
+ this.menuStack.closed.pipe(takeUntil(this.destroyed)).subscribe(({ item }) => {
738
+ if (item === this.childMenu) {
739
+ this.close();
614
740
  }
615
741
  });
616
742
  }
617
743
  }
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
744
  /**
645
745
  * Subscribe to the overlays outside pointer events stream and handle closing out the stack if a
646
746
  * click occurs outside the menus.
647
747
  */
648
748
  _subscribeToOutsideClicks() {
649
- if (this._overlayRef) {
650
- this._overlayRef
749
+ if (this.overlayRef) {
750
+ this.overlayRef
651
751
  .outsidePointerEvents()
652
- .pipe(takeUntil(this._stopOutsideClicksListener))
752
+ .pipe(filter(e => e.target != this._elementRef.nativeElement &&
753
+ !this._elementRef.nativeElement.contains(e.target)), takeUntil(this.stopOutsideClicksListener))
653
754
  .subscribe(event => {
654
- if (!isClickInsideMenuOverlay(event.target)) {
655
- this._getMenuStack().closeAll();
755
+ if (!this.isElementInsideMenuStack(event.target)) {
756
+ this.menuStack.closeAll();
757
+ }
758
+ else {
759
+ this._closeSiblingTriggers();
656
760
  }
657
761
  });
658
762
  }
659
763
  }
660
- /** Destroy and unset the overlay reference it if exists */
661
- _destroyOverlay() {
662
- if (this._overlayRef) {
663
- this._overlayRef.dispose();
664
- this._overlayRef = null;
764
+ /** Subscribe to the MenuStack hasFocus events. */
765
+ _subscribeToMenuStackHasFocus() {
766
+ if (!this._parentMenu) {
767
+ this.menuStack.hasFocus.pipe(takeUntil(this.destroyed)).subscribe(hasFocus => {
768
+ if (!hasFocus) {
769
+ this.menuStack.closeAll();
770
+ }
771
+ });
772
+ }
773
+ }
774
+ /** Subscribe to the MenuStack closed events. */
775
+ _subscribeToMenuStackClosed() {
776
+ if (!this._parentMenu) {
777
+ this.menuStack.closed.subscribe(({ focusParentTrigger }) => {
778
+ if (focusParentTrigger && !this.menuStack.length()) {
779
+ this._elementRef.nativeElement.focus();
780
+ }
781
+ });
665
782
  }
666
783
  }
667
784
  }
668
- CdkMenuItemTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", 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: "13.2.0", 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: "13.2.0", ngImport: i0, type: CdkMenuItemTrigger, decorators: [{
785
+ CdkMenuTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuTrigger, 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 });
786
+ CdkMenuTrigger.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: { menuTemplateRef: ["cdkMenuTriggerFor", "menuTemplateRef"], menuPosition: ["cdkMenuPosition", "menuPosition"] }, outputs: { opened: "cdkMenuOpened", closed: "cdkMenuClosed" }, host: { attributes: { "aria-haspopup": "menu" }, listeners: { "focusin": "_setHasFocus(true)", "focusout": "_setHasFocus(false)", "keydown": "_toggleOnKeydown($event)", "click": "toggle()" }, properties: { "attr.aria-expanded": "isOpen()" }, classAttribute: "cdk-menu-trigger" }, providers: [
787
+ { provide: MENU_TRIGGER, useExisting: CdkMenuTrigger },
788
+ PARENT_OR_NEW_MENU_STACK_PROVIDER,
789
+ ], exportAs: ["cdkMenuTriggerFor"], usesInheritance: true, ngImport: i0 });
790
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuTrigger, decorators: [{
671
791
  type: Directive,
672
792
  args: [{
673
793
  selector: '[cdkMenuTriggerFor]',
674
794
  exportAs: 'cdkMenuTriggerFor',
675
795
  host: {
676
- '(keydown)': '_toggleOnKeydown($event)',
677
- '(click)': 'toggle()',
678
796
  'class': 'cdk-menu-trigger',
679
797
  'aria-haspopup': 'menu',
680
- '[attr.aria-expanded]': 'isMenuOpen()',
798
+ '[attr.aria-expanded]': 'isOpen()',
799
+ '(focusin)': '_setHasFocus(true)',
800
+ '(focusout)': '_setHasFocus(false)',
801
+ '(keydown)': '_toggleOnKeydown($event)',
802
+ '(click)': 'toggle()',
681
803
  },
804
+ inputs: ['menuTemplateRef: cdkMenuTriggerFor', 'menuPosition: cdkMenuPosition'],
805
+ outputs: ['opened: cdkMenuOpened', 'closed: cdkMenuClosed'],
806
+ providers: [
807
+ { provide: MENU_TRIGGER, useExisting: CdkMenuTrigger },
808
+ PARENT_OR_NEW_MENU_STACK_PROVIDER,
809
+ ],
682
810
  }]
683
811
  }], ctorParameters: function () {
684
- return [{ type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: i1.Overlay }, { type: i0.NgZone }, { type: undefined, decorators: [{
812
+ return [{ type: i0.Injector }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: i1.Overlay }, { type: i0.NgZone }, { type: MenuStack, decorators: [{
813
+ type: Inject,
814
+ args: [MENU_STACK]
815
+ }] }, { type: undefined, decorators: [{
685
816
  type: Optional
686
817
  }, {
687
818
  type: Inject,
@@ -691,19 +822,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
691
822
  }, {
692
823
  type: Inject,
693
824
  args: [MENU_AIM]
694
- }] }, { type: i2.Directionality, decorators: [{
825
+ }] }, { type: i1$1.Directionality, decorators: [{
695
826
  type: Optional
696
827
  }] }];
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
- }] } });
828
+ } });
707
829
 
708
830
  /**
709
831
  * @license
@@ -712,26 +834,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
712
834
  * Use of this source code is governed by an MIT-style license that can be
713
835
  * found in the LICENSE file at https://angular.io/license
714
836
  */
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
837
  /**
723
838
  * Directive which provides the ability for an element to be focused and navigated to using the
724
839
  * keyboard when residing in a CdkMenu, CdkMenuBar, or CdkMenuGroup. It performs user defined
725
840
  * behavior when clicked.
726
841
  */
727
842
  class CdkMenuItem {
728
- constructor(_elementRef, _ngZone, _parentMenu, _menuAim, _dir,
843
+ constructor(
844
+ /** The host element for this item. */
845
+ _elementRef,
846
+ /** The Angular zone. */
847
+ _ngZone,
848
+ /** The menu stack this item belongs to. */
849
+ _menuStack,
850
+ /** The parent menu this item belongs to. */
851
+ _parentMenu,
852
+ /** The menu aim service used for this item. */
853
+ _menuAim,
854
+ /** The directionality of the page. */
855
+ _dir,
729
856
  /** Reference to the CdkMenuItemTrigger directive if one is added to the same element */
730
- // `CdkMenuItem` is commonly used in combination with a `CdkMenuItemTrigger`.
731
857
  // tslint:disable-next-line: lightweight-tokens
732
858
  _menuTrigger) {
733
859
  this._elementRef = _elementRef;
734
860
  this._ngZone = _ngZone;
861
+ this._menuStack = _menuStack;
735
862
  this._parentMenu = _parentMenu;
736
863
  this._menuAim = _menuAim;
737
864
  this._dir = _dir;
@@ -742,13 +869,17 @@ class CdkMenuItem {
742
869
  * event.
743
870
  */
744
871
  this.triggered = new EventEmitter();
872
+ /** Whether the menu item opens a menu. */
873
+ this.hasMenu = !!this._menuTrigger;
745
874
  /**
746
875
  * The tabindex for this menu item managed internally and used for implementing roving a
747
876
  * tab index.
748
877
  */
749
878
  this._tabindex = -1;
879
+ /** Whether the item should close the menu if triggered by the spacebar. */
880
+ this.closeOnSpacebarTrigger = true;
750
881
  /** Emits when the menu item is destroyed. */
751
- this._destroyed = new Subject();
882
+ this.destroyed = new Subject();
752
883
  this._setupMouseEnter();
753
884
  if (this._isStandaloneItem()) {
754
885
  this._tabindex = 0;
@@ -761,54 +892,33 @@ class CdkMenuItem {
761
892
  set disabled(value) {
762
893
  this._disabled = coerceBooleanProperty(value);
763
894
  }
895
+ ngOnDestroy() {
896
+ this.destroyed.next();
897
+ this.destroyed.complete();
898
+ }
764
899
  /** Place focus on the element. */
765
900
  focus() {
766
901
  this._elementRef.nativeElement.focus();
767
902
  }
768
- /** Reset the _tabindex to -1. */
769
- _resetTabIndex() {
770
- if (!this._isStandaloneItem()) {
771
- this._tabindex = -1;
772
- }
773
- }
774
- /**
775
- * Set the tab index to 0 if not disabled and it's a focus event, or a mouse enter if this element
776
- * is not in a menu bar.
777
- */
778
- _setTabIndex(event) {
779
- var _a;
780
- if (this.disabled) {
781
- return;
782
- }
783
- // 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())) {
785
- this._tabindex = 0;
786
- }
787
- }
788
- /** Whether this menu item is standalone or within a menu or menu bar. */
789
- _isStandaloneItem() {
790
- return !this._parentMenu;
791
- }
792
903
  /**
793
904
  * If the menu item is not disabled and the element does not have a menu trigger attached, emit
794
905
  * on the cdkMenuItemTriggered emitter and close all open menus.
906
+ * @param options Options the configure how the item is triggered
907
+ * - keepOpen: specifies that the menu should be kept open after triggering the item.
795
908
  */
796
- trigger() {
797
- var _a;
798
- if (!this.disabled && !this.hasMenu()) {
909
+ trigger(options) {
910
+ const { keepOpen } = Object.assign({}, options);
911
+ if (!this.disabled && !this.hasMenu) {
799
912
  this.triggered.next();
800
- (_a = this._getMenuStack()) === null || _a === void 0 ? void 0 : _a.closeAll();
913
+ if (!keepOpen) {
914
+ this._menuStack.closeAll({ focusParentTrigger: true });
915
+ }
801
916
  }
802
917
  }
803
- /** Whether the menu item opens a menu. */
804
- hasMenu() {
805
- var _a;
806
- return !!((_a = this._menuTrigger) === null || _a === void 0 ? void 0 : _a.hasMenu());
807
- }
808
918
  /** Return true if this MenuItem has an attached menu and it is open. */
809
919
  isMenuOpen() {
810
920
  var _a;
811
- return !!((_a = this._menuTrigger) === null || _a === void 0 ? void 0 : _a.isMenuOpen());
921
+ return !!((_a = this._menuTrigger) === null || _a === void 0 ? void 0 : _a.isOpen());
812
922
  }
813
923
  /**
814
924
  * Get a reference to the rendered Menu if the Menu is open and it is visible in the DOM.
@@ -818,18 +928,33 @@ class CdkMenuItem {
818
928
  var _a;
819
929
  return (_a = this._menuTrigger) === null || _a === void 0 ? void 0 : _a.getMenu();
820
930
  }
821
- /** Get the MenuItemTrigger associated with this element. */
931
+ /** Get the CdkMenuTrigger associated with this element. */
822
932
  getMenuTrigger() {
823
933
  return this._menuTrigger;
824
934
  }
825
935
  /** Get the label for this element which is required by the FocusableOption interface. */
826
936
  getLabel() {
827
937
  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()) || '';
938
+ return this.typeaheadLabel || ((_a = this._elementRef.nativeElement.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
939
+ }
940
+ /** Reset the tabindex to -1. */
941
+ _resetTabIndex() {
942
+ if (!this._isStandaloneItem()) {
943
+ this._tabindex = -1;
944
+ }
945
+ }
946
+ /**
947
+ * Set the tab index to 0 if not disabled and it's a focus event, or a mouse enter if this element
948
+ * is not in a menu bar.
949
+ */
950
+ _setTabIndex(event) {
951
+ if (this.disabled) {
952
+ return;
953
+ }
954
+ // don't set the tabindex if there are no open sibling or parent menus
955
+ if (!event || !this._menuStack.isEmpty()) {
956
+ this._tabindex = 0;
957
+ }
833
958
  }
834
959
  /**
835
960
  * Handles keyboard events for the menu item, specifically either triggering the user defined
@@ -838,40 +963,83 @@ class CdkMenuItem {
838
963
  * @param event the keyboard event to handle
839
964
  */
840
965
  _onKeydown(event) {
841
- var _a, _b, _c, _d, _e, _f;
966
+ var _a, _b;
842
967
  switch (event.keyCode) {
843
968
  case SPACE:
844
969
  case ENTER:
845
- event.preventDefault();
846
- this.trigger();
970
+ if (!hasModifierKey(event)) {
971
+ event.preventDefault();
972
+ this.trigger({ keepOpen: event.keyCode === SPACE && !this.closeOnSpacebarTrigger });
973
+ }
847
974
  break;
848
975
  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 */);
976
+ if (!hasModifierKey(event)) {
977
+ if (this._parentMenu && this._isParentVertical()) {
978
+ if (((_a = this._dir) === null || _a === void 0 ? void 0 : _a.value) !== 'rtl') {
979
+ this._forwardArrowPressed(event);
980
+ }
981
+ else {
982
+ this._backArrowPressed(event);
983
+ }
984
+ }
854
985
  }
855
986
  break;
856
987
  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 */);
988
+ if (!hasModifierKey(event)) {
989
+ if (this._parentMenu && this._isParentVertical()) {
990
+ if (((_b = this._dir) === null || _b === void 0 ? void 0 : _b.value) !== 'rtl') {
991
+ this._backArrowPressed(event);
992
+ }
993
+ else {
994
+ this._forwardArrowPressed(event);
995
+ }
996
+ }
862
997
  }
863
998
  break;
864
999
  }
865
1000
  }
1001
+ /** Whether this menu item is standalone or within a menu or menu bar. */
1002
+ _isStandaloneItem() {
1003
+ return !this._parentMenu;
1004
+ }
1005
+ /**
1006
+ * Handles the user pressing the back arrow key.
1007
+ * @param event The keyboard event.
1008
+ */
1009
+ _backArrowPressed(event) {
1010
+ const parentMenu = this._parentMenu;
1011
+ if (this._menuStack.hasInlineMenu() || this._menuStack.length() > 1) {
1012
+ event.preventDefault();
1013
+ this._menuStack.close(parentMenu, {
1014
+ focusNextOnEmpty: this._menuStack.inlineMenuOrientation() === 'horizontal'
1015
+ ? 1 /* previousItem */
1016
+ : 2 /* currentItem */,
1017
+ focusParentTrigger: true,
1018
+ });
1019
+ }
1020
+ }
1021
+ /**
1022
+ * Handles the user pressing the forward arrow key.
1023
+ * @param event The keyboard event.
1024
+ */
1025
+ _forwardArrowPressed(event) {
1026
+ if (!this.hasMenu && this._menuStack.inlineMenuOrientation() === 'horizontal') {
1027
+ event.preventDefault();
1028
+ this._menuStack.closeAll({
1029
+ focusNextOnEmpty: 0 /* nextItem */,
1030
+ focusParentTrigger: true,
1031
+ });
1032
+ }
1033
+ }
866
1034
  /**
867
1035
  * Subscribe to the mouseenter events and close any sibling menu items if this element is moused
868
1036
  * into.
869
1037
  */
870
1038
  _setupMouseEnter() {
871
1039
  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); });
1040
+ const closeOpenSiblings = () => this._ngZone.run(() => this._menuStack.closeSubMenuOf(this._parentMenu));
873
1041
  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))
1042
+ .pipe(filter(() => !this._menuStack.isEmpty() && !this.hasMenu), takeUntil(this.destroyed))
875
1043
  .subscribe(() => {
876
1044
  if (this._menuAim) {
877
1045
  this._menuAim.toggle(closeOpenSiblings);
@@ -890,41 +1058,30 @@ class CdkMenuItem {
890
1058
  var _a;
891
1059
  return ((_a = this._parentMenu) === null || _a === void 0 ? void 0 : _a.orientation) === 'vertical';
892
1060
  }
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
- ngOnDestroy() {
902
- this._destroyed.next();
903
- }
904
1061
  }
905
- CdkMenuItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", 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: "13.2.0", 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: "13.2.0", ngImport: i0, type: CdkMenuItem, decorators: [{
1062
+ 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: CdkMenuTrigger, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
1063
+ CdkMenuItem.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuItem, selector: "[cdkMenuItem]", inputs: { disabled: ["cdkMenuItemDisabled", "disabled"], typeaheadLabel: ["cdkMenuitemTypeaheadLabel", "typeaheadLabel"] }, outputs: { triggered: "cdkMenuItemTriggered" }, host: { attributes: { "role": "menuitem" }, listeners: { "blur": "_resetTabIndex()", "focus": "_setTabIndex()", "click": "trigger()", "keydown": "_onKeydown($event)" }, properties: { "tabindex": "_tabindex", "attr.aria-disabled": "disabled || null" }, classAttribute: "cdk-menu-item" }, exportAs: ["cdkMenuItem"], ngImport: i0 });
1064
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItem, decorators: [{
908
1065
  type: Directive,
909
1066
  args: [{
910
1067
  selector: '[cdkMenuItem]',
911
1068
  exportAs: 'cdkMenuItem',
912
1069
  host: {
913
- '[tabindex]': '_tabindex',
914
- 'type': 'button',
915
1070
  'role': 'menuitem',
916
1071
  'class': 'cdk-menu-item',
1072
+ '[tabindex]': '_tabindex',
917
1073
  '[attr.aria-disabled]': 'disabled || null',
918
1074
  '(blur)': '_resetTabIndex()',
919
- '(mouseout)': '_resetTabIndex()',
920
1075
  '(focus)': '_setTabIndex()',
921
- '(mouseenter)': '_setTabIndex($event)',
922
1076
  '(click)': 'trigger()',
923
1077
  '(keydown)': '_onKeydown($event)',
924
1078
  },
925
1079
  }]
926
1080
  }], ctorParameters: function () {
927
- return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: undefined, decorators: [{
1081
+ return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: MenuStack, decorators: [{
1082
+ type: Inject,
1083
+ args: [MENU_STACK]
1084
+ }] }, { type: undefined, decorators: [{
928
1085
  type: Optional
929
1086
  }, {
930
1087
  type: Inject,
@@ -934,136 +1091,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
934
1091
  }, {
935
1092
  type: Inject,
936
1093
  args: [MENU_AIM]
937
- }] }, { type: i2.Directionality, decorators: [{
1094
+ }] }, { type: i1$1.Directionality, decorators: [{
938
1095
  type: Optional
939
- }] }, { type: CdkMenuItemTrigger, decorators: [{
1096
+ }] }, { type: CdkMenuTrigger, decorators: [{
940
1097
  type: Self
941
1098
  }, {
942
1099
  type: Optional
943
1100
  }] }];
944
1101
  }, propDecorators: { disabled: [{
945
- type: Input
1102
+ type: Input,
1103
+ args: ['cdkMenuItemDisabled']
1104
+ }], typeaheadLabel: [{
1105
+ type: Input,
1106
+ args: ['cdkMenuitemTypeaheadLabel']
946
1107
  }], triggered: [{
947
1108
  type: Output,
948
1109
  args: ['cdkMenuItemTriggered']
949
1110
  }] } });
950
1111
 
951
- /**
952
- * @license
953
- * Copyright Google LLC All Rights Reserved.
954
- *
955
- * Use of this source code is governed by an MIT-style license that can be
956
- * found in the LICENSE file at https://angular.io/license
957
- */
958
- /** Counter used to set a unique id and name for a selectable item */
959
- let nextId = 0;
960
- /**
961
- * Base class providing checked state for MenuItems along with outputting a clicked event when the
962
- * element is triggered. It provides functionality for selectable elements.
963
- */
964
- class CdkMenuItemSelectable extends CdkMenuItem {
965
- constructor() {
966
- super(...arguments);
967
- /** Event emitted when the selectable item is clicked */
968
- this.toggled = new EventEmitter();
969
- this._checked = false;
970
- /** The name of the selectable element with a default value */
971
- this.name = `cdk-selectable-item-${nextId++}`;
972
- /** The id of the selectable element with a default value */
973
- this.id = `cdk-selectable-item-${nextId++}`;
974
- }
975
- /** Whether the element is checked */
976
- get checked() {
977
- return this._checked;
978
- }
979
- set checked(value) {
980
- this._checked = coerceBooleanProperty(value);
981
- }
982
- /** If the element is not disabled emit the click event */
983
- trigger() {
984
- if (!this.disabled) {
985
- this.toggled.next(this);
986
- }
987
- }
988
- }
989
- CdkMenuItemSelectable.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuItemSelectable, deps: null, target: i0.ɵɵFactoryTarget.Directive });
990
- CdkMenuItemSelectable.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.0", type: CdkMenuItemSelectable, inputs: { checked: "checked", name: "name", id: "id" }, outputs: { toggled: "cdkMenuItemToggled" }, usesInheritance: true, ngImport: i0 });
991
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuItemSelectable, decorators: [{
992
- type: Directive
993
- }], propDecorators: { toggled: [{
994
- type: Output,
995
- args: ['cdkMenuItemToggled']
996
- }], checked: [{
997
- type: Input
998
- }], name: [{
999
- type: Input
1000
- }], id: [{
1001
- type: Input
1002
- }] } });
1003
-
1004
- /**
1005
- * @license
1006
- * Copyright Google LLC All Rights Reserved.
1007
- *
1008
- * Use of this source code is governed by an MIT-style license that can be
1009
- * found in the LICENSE file at https://angular.io/license
1010
- */
1011
- /**
1012
- * Directive which acts as a grouping container for `CdkMenuItem` instances with
1013
- * `role="menuitemradio"`, similar to a `role="radiogroup"` element.
1014
- */
1015
- class CdkMenuGroup {
1016
- constructor() {
1017
- /** Emits the element when checkbox or radiobutton state changed */
1018
- this.change = new EventEmitter();
1019
- /** Emits when the _selectableItems QueryList triggers a change */
1020
- this._selectableChanges = new EventEmitter();
1021
- }
1022
- ngAfterContentInit() {
1023
- this._registerMenuSelectionListeners();
1024
- }
1025
- /**
1026
- * Register the child selectable elements with the change emitter and ensure any new child
1027
- * elements do so as well.
1028
- */
1029
- _registerMenuSelectionListeners() {
1030
- this._selectableItems.forEach(selectable => this._registerClickListener(selectable));
1031
- this._selectableItems.changes.subscribe((selectableItems) => {
1032
- this._selectableChanges.next();
1033
- selectableItems.forEach(selectable => this._registerClickListener(selectable));
1034
- });
1035
- }
1036
- /** Register each selectable to emit on the change Emitter when clicked */
1037
- _registerClickListener(selectable) {
1038
- selectable.toggled
1039
- .pipe(takeUntil(this._selectableChanges))
1040
- .subscribe(() => this.change.next(selectable));
1041
- }
1042
- ngOnDestroy() {
1043
- this._selectableChanges.next();
1044
- this._selectableChanges.complete();
1045
- }
1046
- }
1047
- CdkMenuGroup.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1048
- CdkMenuGroup.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.0", 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: "13.2.0", ngImport: i0, type: CdkMenuGroup, decorators: [{
1050
- type: Directive,
1051
- args: [{
1052
- selector: '[cdkMenuGroup]',
1053
- exportAs: 'cdkMenuGroup',
1054
- host: {
1055
- 'role': 'group',
1056
- 'class': 'cdk-menu-group',
1057
- },
1058
- providers: [{ provide: UniqueSelectionDispatcher, useClass: UniqueSelectionDispatcher }],
1059
- }]
1060
- }], propDecorators: { change: [{
1061
- type: Output
1062
- }], _selectableItems: [{
1063
- type: ContentChildren,
1064
- args: [CdkMenuItemSelectable, { descendants: true }]
1065
- }] } });
1066
-
1067
1112
  /**
1068
1113
  * @license
1069
1114
  * Copyright Google LLC All Rights Reserved.
@@ -1076,7 +1121,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
1076
1121
  * observables which emit when the users mouse enters and leaves a tracked element.
1077
1122
  */
1078
1123
  class PointerFocusTracker {
1079
- constructor(_items) {
1124
+ constructor(
1125
+ /** The list of items being tracked. */
1126
+ _items) {
1080
1127
  this._items = _items;
1081
1128
  /** Emits when an element is moused into. */
1082
1129
  this.entered = this._getItemPointerEntries();
@@ -1090,6 +1137,11 @@ class PointerFocusTracker {
1090
1137
  this.activeElement = undefined;
1091
1138
  });
1092
1139
  }
1140
+ /** Stop the managers listeners. */
1141
+ destroy() {
1142
+ this._destroyed.next();
1143
+ this._destroyed.complete();
1144
+ }
1093
1145
  /**
1094
1146
  * Gets a stream of pointer (mouse) entries into the given items.
1095
1147
  * This should typically run outside the Angular zone.
@@ -1104,48 +1156,7 @@ class PointerFocusTracker {
1104
1156
  _getItemPointerExits() {
1105
1157
  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
1158
  }
1107
- /** Stop the managers listeners. */
1108
- destroy() {
1109
- this._destroyed.next();
1110
- this._destroyed.complete();
1111
- }
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;
1128
- }
1129
- /**
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.
1132
- */
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);
1141
- }
1142
1159
  }
1143
- CdkMenuPanel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuPanel, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
1144
- CdkMenuPanel.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.0", type: CdkMenuPanel, selector: "ng-template[cdkMenuPanel]", exportAs: ["cdkMenuPanel"], ngImport: i0 });
1145
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuPanel, decorators: [{
1146
- type: Directive,
1147
- args: [{ selector: 'ng-template[cdkMenuPanel]', exportAs: 'cdkMenuPanel' }]
1148
- }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
1149
1160
 
1150
1161
  /**
1151
1162
  * @license
@@ -1154,181 +1165,282 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
1154
1165
  * Use of this source code is governed by an MIT-style license that can be
1155
1166
  * found in the LICENSE file at https://angular.io/license
1156
1167
  */
1168
+ /** Counter used to create unique IDs for menus. */
1169
+ let nextId$1 = 0;
1157
1170
  /**
1158
- * Directive which configures the element as a Menu which should contain child elements marked as
1159
- * CdkMenuItem or CdkMenuGroup. Sets the appropriate role and aria-attributes for a menu and
1160
- * contains accessible keyboard and mouse handling logic.
1161
- *
1162
- * It also acts as a RadioGroup for elements marked with role `menuitemradio`.
1171
+ * Abstract directive that implements shared logic common to all menus.
1172
+ * This class can be extended to create custom menu types.
1163
1173
  */
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) {
1174
+ class CdkMenuBase extends CdkMenuGroup {
1175
+ constructor(
1176
+ /** The host element. */
1177
+ elementRef,
1178
+ /** The Angular zone. */
1179
+ ngZone,
1180
+ /** The stack of menus this menu belongs to. */
1181
+ menuStack,
1182
+ /** The menu aim service used by this menu. */
1183
+ menuAim,
1184
+ /** The directionality of the current page. */
1185
+ dir) {
1169
1186
  super();
1170
- this._ngZone = _ngZone;
1171
- this._elementRef = _elementRef;
1172
- 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
- */
1187
+ this.ngZone = ngZone;
1188
+ this.menuStack = menuStack;
1189
+ this.menuAim = menuAim;
1190
+ this.dir = dir;
1191
+ /** The id of the menu's host element. */
1192
+ this.id = `cdk-menu-${nextId$1++}`;
1193
+ /** The direction items in the menu flow. */
1179
1194
  this.orientation = 'vertical';
1180
- /** Event emitted when the menu is closed. */
1181
- 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();
1195
+ /** Whether the menu is displayed inline (i.e. always present vs a conditional popup that the user triggers with a trigger element). */
1196
+ this.isInline = false;
1197
+ /** Emits when the MenuBar is destroyed. */
1198
+ this.destroyed = new Subject();
1199
+ /** Whether this menu's menu stack has focus. */
1200
+ this._menuStackHasFocus = false;
1201
+ this.nativeElement = elementRef.nativeElement;
1190
1202
  }
1191
1203
  ngAfterContentInit() {
1192
- var _a;
1193
- super.ngAfterContentInit();
1194
- this._completeChangeEmitter();
1204
+ if (!this.isInline) {
1205
+ this.menuStack.push(this);
1206
+ }
1195
1207
  this._setKeyManager();
1208
+ this._subscribeToMenuStackHasFocus();
1196
1209
  this._subscribeToMenuOpen();
1197
- this._subscribeToMenuStack();
1198
- this._subscribeToMouseManager();
1199
- (_a = this._menuAim) === null || _a === void 0 ? void 0 : _a.initialize(this, this._pointerTracker);
1210
+ this._subscribeToMenuStackClosed();
1211
+ this._setUpPointerTracker();
1200
1212
  }
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();
1210
- }
1211
- /** Handle keyboard events for the Menu. */
1212
- _handleKeyEvent(event) {
1213
- const keyManager = this._keyManager;
1214
- switch (event.keyCode) {
1215
- case LEFT_ARROW:
1216
- case RIGHT_ARROW:
1217
- if (this._isHorizontal()) {
1218
- event.preventDefault();
1219
- keyManager.setFocusOrigin('keyboard');
1220
- keyManager.onKeydown(event);
1221
- }
1222
- break;
1223
- case UP_ARROW:
1224
- case DOWN_ARROW:
1225
- if (!this._isHorizontal()) {
1226
- event.preventDefault();
1227
- keyManager.setFocusOrigin('keyboard');
1228
- keyManager.onKeydown(event);
1229
- }
1230
- break;
1231
- case ESCAPE:
1232
- if (!hasModifierKey(event)) {
1233
- event.preventDefault();
1234
- this._menuStack.close(this, 2 /* currentItem */);
1235
- }
1236
- break;
1237
- case TAB:
1238
- this._menuStack.closeAll();
1239
- break;
1240
- default:
1241
- keyManager.onKeydown(event);
1242
- }
1243
- }
1244
- /** Register this menu with its enclosing parent menu panel */
1245
- _registerWithParentPanel() {
1213
+ ngOnDestroy() {
1246
1214
  var _a;
1247
- (_a = this._getMenuPanel()) === null || _a === void 0 ? void 0 : _a._registerMenu(this);
1215
+ this.destroyed.next();
1216
+ this.destroyed.complete();
1217
+ (_a = this.pointerTracker) === null || _a === void 0 ? void 0 : _a.destroy();
1248
1218
  }
1249
1219
  /**
1250
- * Get the enclosing CdkMenuPanel defaulting to the injected reference over the developer
1251
- * provided reference.
1220
+ * Place focus on the first MenuItem in the menu and set the focus origin.
1221
+ * @param focusOrigin The origin input mode of the focus event.
1252
1222
  */
1253
- _getMenuPanel() {
1254
- return this._menuPanel || this._explicitPanel;
1223
+ focusFirstItem(focusOrigin = 'program') {
1224
+ this.keyManager.setFocusOrigin(focusOrigin);
1225
+ this.keyManager.setFirstItemActive();
1255
1226
  }
1256
1227
  /**
1257
- * Complete the change emitter if there are any nested MenuGroups or register to complete the
1258
- * change emitter if a MenuGroup is rendered at some point
1228
+ * Place focus on the last MenuItem in the menu and set the focus origin.
1229
+ * @param focusOrigin The origin input mode of the focus event.
1259
1230
  */
1260
- _completeChangeEmitter() {
1261
- if (this._hasNestedGroups()) {
1262
- this.change.complete();
1263
- }
1264
- else {
1265
- this._nestedGroups.changes.pipe(take(1)).subscribe(() => this.change.complete());
1266
- }
1231
+ focusLastItem(focusOrigin = 'program') {
1232
+ this.keyManager.setFocusOrigin(focusOrigin);
1233
+ this.keyManager.setLastItemActive();
1234
+ }
1235
+ /** Gets the tabindex for this menu. */
1236
+ _getTabIndex() {
1237
+ const tabindexIfInline = this._menuStackHasFocus ? -1 : 0;
1238
+ return this.isInline ? tabindexIfInline : null;
1267
1239
  }
1268
- /** Return true if there are nested CdkMenuGroup elements within the Menu */
1269
- _hasNestedGroups() {
1270
- // view engine has a bug where @ContentChildren will return the current element
1271
- // along with children if the selectors match - not just the children.
1272
- // Here, if there is at least one element, we check to see if the first element is a CdkMenu in
1273
- // order to ensure that we return true iff there are child CdkMenuGroup elements.
1274
- return this._nestedGroups.length > 0 && !(this._nestedGroups.first instanceof CdkMenu);
1240
+ /**
1241
+ * Close the open menu if the current active item opened the requested MenuStackItem.
1242
+ * @param menu The menu requested to be closed.
1243
+ * @param options Options to configure the behavior on close.
1244
+ * - `focusParentTrigger` Whether to focus the parent trigger after closing the menu.
1245
+ */
1246
+ closeOpenMenu(menu, options) {
1247
+ var _a, _b;
1248
+ const { focusParentTrigger } = Object.assign({}, options);
1249
+ const keyManager = this.keyManager;
1250
+ const trigger = this.triggerItem;
1251
+ if (menu === ((_a = trigger === null || trigger === void 0 ? void 0 : trigger.getMenuTrigger()) === null || _a === void 0 ? void 0 : _a.getMenu())) {
1252
+ (_b = trigger === null || trigger === void 0 ? void 0 : trigger.getMenuTrigger()) === null || _b === void 0 ? void 0 : _b.close();
1253
+ // If the user has moused over a sibling item we want to focus the element under mouse focus
1254
+ // not the trigger which previously opened the now closed menu.
1255
+ if (focusParentTrigger) {
1256
+ if (trigger) {
1257
+ keyManager.setActiveItem(trigger);
1258
+ }
1259
+ else {
1260
+ keyManager.setFirstItemActive();
1261
+ }
1262
+ }
1263
+ }
1275
1264
  }
1276
1265
  /** Setup the FocusKeyManager with the correct orientation for the menu. */
1277
1266
  _setKeyManager() {
1278
1267
  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');
1268
+ this.keyManager = new FocusKeyManager(this.items).withWrap().withTypeAhead().withHomeAndEnd();
1269
+ if (this.orientation === 'horizontal') {
1270
+ this.keyManager.withHorizontalOrientation(((_a = this.dir) === null || _a === void 0 ? void 0 : _a.value) || 'ltr');
1285
1271
  }
1286
1272
  else {
1287
- this._keyManager.withVerticalOrientation();
1273
+ this.keyManager.withVerticalOrientation();
1274
+ }
1275
+ }
1276
+ /**
1277
+ * Subscribe to the menu trigger's open events in order to track the trigger which opened the menu
1278
+ * and stop tracking it when the menu is closed.
1279
+ */
1280
+ _subscribeToMenuOpen() {
1281
+ const exitCondition = merge(this.items.changes, this.destroyed);
1282
+ this.items.changes
1283
+ .pipe(startWith(this.items), mergeMap((list) => list
1284
+ .filter(item => item.hasMenu)
1285
+ .map(item => item.getMenuTrigger().opened.pipe(mapTo(item), takeUntil(exitCondition)))), mergeAll(), switchMap((item) => {
1286
+ this.triggerItem = item;
1287
+ return item.getMenuTrigger().closed;
1288
+ }), takeUntil(this.destroyed))
1289
+ .subscribe(() => (this.triggerItem = undefined));
1290
+ }
1291
+ /** Subscribe to the MenuStack close events. */
1292
+ _subscribeToMenuStackClosed() {
1293
+ this.menuStack.closed
1294
+ .pipe(takeUntil(this.destroyed))
1295
+ .subscribe(({ item, focusParentTrigger }) => this.closeOpenMenu(item, { focusParentTrigger }));
1296
+ }
1297
+ /** Subscribe to the MenuStack hasFocus events. */
1298
+ _subscribeToMenuStackHasFocus() {
1299
+ if (this.isInline) {
1300
+ this.menuStack.hasFocus.pipe(takeUntil(this.destroyed)).subscribe(hasFocus => {
1301
+ this._menuStackHasFocus = hasFocus;
1302
+ });
1288
1303
  }
1289
1304
  }
1290
1305
  /**
1291
1306
  * Set the PointerFocusTracker and ensure that when mouse focus changes the key manager is updated
1292
1307
  * with the latest menu item under mouse focus.
1293
1308
  */
1294
- _subscribeToMouseManager() {
1295
- this._ngZone.runOutsideAngular(() => {
1296
- this._pointerTracker = new PointerFocusTracker(this._allItems);
1297
- this._pointerTracker.entered
1298
- .pipe(takeUntil(this.closed))
1299
- .subscribe(item => this._keyManager.setActiveItem(item));
1300
- });
1309
+ _setUpPointerTracker() {
1310
+ if (this.menuAim) {
1311
+ this.ngZone.runOutsideAngular(() => {
1312
+ this.pointerTracker = new PointerFocusTracker(this.items);
1313
+ });
1314
+ this.menuAim.initialize(this, this.pointerTracker);
1315
+ }
1316
+ }
1317
+ }
1318
+ CdkMenuBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuBase, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: MENU_STACK }, { token: MENU_AIM, optional: true, self: true }, { token: i1$1.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1319
+ CdkMenuBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuBase, inputs: { id: "id" }, host: { attributes: { "role": "menu" }, listeners: { "focus": "focusFirstItem()", "focusin": "menuStack.setHasFocus(true)", "focusout": "menuStack.setHasFocus(false)" }, properties: { "tabindex": "_getTabIndex()", "id": "id", "attr.aria-orientation": "orientation", "attr.data-cdk-menu-stack-id": "menuStack.id" } }, queries: [{ propertyName: "items", predicate: CdkMenuItem, descendants: true }], usesInheritance: true, ngImport: i0 });
1320
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuBase, decorators: [{
1321
+ type: Directive,
1322
+ args: [{
1323
+ host: {
1324
+ 'role': 'menu',
1325
+ 'class': '',
1326
+ '[tabindex]': '_getTabIndex()',
1327
+ '[id]': 'id',
1328
+ '[attr.aria-orientation]': 'orientation',
1329
+ '[attr.data-cdk-menu-stack-id]': 'menuStack.id',
1330
+ '(focus)': 'focusFirstItem()',
1331
+ '(focusin)': 'menuStack.setHasFocus(true)',
1332
+ '(focusout)': 'menuStack.setHasFocus(false)',
1333
+ },
1334
+ }]
1335
+ }], ctorParameters: function () {
1336
+ return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: MenuStack, decorators: [{
1337
+ type: Inject,
1338
+ args: [MENU_STACK]
1339
+ }] }, { type: undefined, decorators: [{
1340
+ type: Self
1341
+ }, {
1342
+ type: Optional
1343
+ }, {
1344
+ type: Inject,
1345
+ args: [MENU_AIM]
1346
+ }] }, { type: i1$1.Directionality, decorators: [{
1347
+ type: Optional
1348
+ }] }];
1349
+ }, propDecorators: { id: [{
1350
+ type: Input
1351
+ }], items: [{
1352
+ type: ContentChildren,
1353
+ args: [CdkMenuItem, { descendants: true }]
1354
+ }] } });
1355
+
1356
+ /**
1357
+ * @license
1358
+ * Copyright Google LLC All Rights Reserved.
1359
+ *
1360
+ * Use of this source code is governed by an MIT-style license that can be
1361
+ * found in the LICENSE file at https://angular.io/license
1362
+ */
1363
+ /**
1364
+ * Directive which configures the element as a Menu which should contain child elements marked as
1365
+ * CdkMenuItem or CdkMenuGroup. Sets the appropriate role and aria-attributes for a menu and
1366
+ * contains accessible keyboard and mouse handling logic.
1367
+ *
1368
+ * It also acts as a RadioGroup for elements marked with role `menuitemradio`.
1369
+ */
1370
+ class CdkMenu extends CdkMenuBase {
1371
+ constructor(
1372
+ /** The host element. */
1373
+ elementRef,
1374
+ /** The Angular zone. */
1375
+ ngZone,
1376
+ /** The menu stack this menu is part of. */
1377
+ menuStack,
1378
+ /** The trigger that opened this menu. */
1379
+ _parentTrigger,
1380
+ /** The menu aim service used by this menu. */
1381
+ menuAim,
1382
+ /** The directionality of the page. */
1383
+ dir) {
1384
+ var _a;
1385
+ super(elementRef, ngZone, menuStack, menuAim, dir);
1386
+ this._parentTrigger = _parentTrigger;
1387
+ /** Event emitted when the menu is closed. */
1388
+ this.closed = new EventEmitter();
1389
+ /** The direction items in the menu flow. */
1390
+ this.orientation = 'vertical';
1391
+ /** Whether the menu is displayed inline (i.e. always present vs a conditional popup that the user triggers with a trigger element). */
1392
+ this.isInline = !this._parentTrigger;
1393
+ this.destroyed.subscribe(this.closed);
1394
+ (_a = this._parentTrigger) === null || _a === void 0 ? void 0 : _a.registerChildMenu(this);
1395
+ }
1396
+ ngAfterContentInit() {
1397
+ super.ngAfterContentInit();
1398
+ this._subscribeToMenuStackEmptied();
1301
1399
  }
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));
1400
+ ngOnDestroy() {
1401
+ super.ngOnDestroy();
1402
+ this.closed.complete();
1310
1403
  }
1311
1404
  /**
1312
- * Close the open menu if the current active item opened the requested MenuStackItem.
1313
- * @param item the MenuStackItem requested to be closed.
1405
+ * Handle keyboard events for the Menu.
1406
+ * @param event The keyboard event to be handled.
1314
1407
  */
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
- }
1408
+ _handleKeyEvent(event) {
1409
+ const keyManager = this.keyManager;
1410
+ switch (event.keyCode) {
1411
+ case LEFT_ARROW:
1412
+ case RIGHT_ARROW:
1413
+ if (!hasModifierKey(event)) {
1414
+ event.preventDefault();
1415
+ keyManager.setFocusOrigin('keyboard');
1416
+ keyManager.onKeydown(event);
1417
+ }
1418
+ break;
1419
+ case ESCAPE:
1420
+ if (!hasModifierKey(event)) {
1421
+ event.preventDefault();
1422
+ this.menuStack.close(this, {
1423
+ focusNextOnEmpty: 2 /* currentItem */,
1424
+ focusParentTrigger: true,
1425
+ });
1426
+ }
1427
+ break;
1428
+ case TAB:
1429
+ if (!hasModifierKey(event, 'altKey', 'metaKey', 'ctrlKey')) {
1430
+ this.menuStack.closeAll({ focusParentTrigger: true });
1431
+ }
1432
+ break;
1433
+ default:
1434
+ keyManager.onKeydown(event);
1326
1435
  }
1327
1436
  }
1328
- /** Set focus the either the current, previous or next item based on the FocusNext event. */
1329
- _toggleMenuFocus(event) {
1330
- const keyManager = this._keyManager;
1331
- switch (event) {
1437
+ /**
1438
+ * Set focus the either the current, previous or next item based on the FocusNext event.
1439
+ * @param focusNext The element to focus.
1440
+ */
1441
+ _toggleMenuFocus(focusNext) {
1442
+ const keyManager = this.keyManager;
1443
+ switch (focusNext) {
1332
1444
  case 0 /* nextItem */:
1333
1445
  keyManager.setFocusOrigin('keyboard');
1334
1446
  keyManager.setNextItemActive();
@@ -1345,98 +1457,57 @@ class CdkMenu extends CdkMenuGroup {
1345
1457
  break;
1346
1458
  }
1347
1459
  }
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
- /**
1369
- * Return true if this menu is an inline menu. That is, it does not exist in a pop-up and is
1370
- * always visible in the dom.
1371
- */
1372
- _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;
1376
- }
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();
1460
+ /** Subscribe to the MenuStack emptied events. */
1461
+ _subscribeToMenuStackEmptied() {
1462
+ this.menuStack.emptied
1463
+ .pipe(takeUntil(this.destroyed))
1464
+ .subscribe(event => this._toggleMenuFocus(event));
1387
1465
  }
1388
1466
  }
1389
- CdkMenu.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", 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: "13.2.0", 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: [
1467
+ CdkMenu.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenu, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { 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 });
1468
+ 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: { "class.cdk-menu-inline": "isInline" }, classAttribute: "cdk-menu" }, providers: [
1391
1469
  { provide: CdkMenuGroup, useExisting: CdkMenu },
1392
1470
  { 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: "13.2.0", ngImport: i0, type: CdkMenu, decorators: [{
1471
+ PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER('vertical'),
1472
+ ], exportAs: ["cdkMenu"], usesInheritance: true, ngImport: i0 });
1473
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenu, decorators: [{
1395
1474
  type: Directive,
1396
1475
  args: [{
1397
1476
  selector: '[cdkMenu]',
1398
1477
  exportAs: 'cdkMenu',
1399
1478
  host: {
1400
- '[tabindex]': '_isInline() ? 0 : null',
1401
1479
  'role': 'menu',
1402
1480
  'class': 'cdk-menu',
1403
- '[class.cdk-menu-inline]': '_isInline()',
1404
- '[attr.aria-orientation]': 'orientation',
1405
- '(focus)': 'focusFirstItem()',
1481
+ '[class.cdk-menu-inline]': 'isInline',
1406
1482
  '(keydown)': '_handleKeyEvent($event)',
1407
1483
  },
1408
1484
  providers: [
1409
1485
  { provide: CdkMenuGroup, useExisting: CdkMenu },
1410
1486
  { provide: CDK_MENU, useExisting: CdkMenu },
1487
+ PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER('vertical'),
1411
1488
  ],
1412
1489
  }]
1413
1490
  }], ctorParameters: function () {
1414
- return [{ type: i0.NgZone }, { type: i0.ElementRef }, { type: undefined, decorators: [{
1491
+ return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: MenuStack, decorators: [{
1492
+ type: Inject,
1493
+ args: [MENU_STACK]
1494
+ }] }, { type: CdkMenuTriggerBase, decorators: [{
1495
+ type: Optional
1496
+ }, {
1497
+ type: Inject,
1498
+ args: [MENU_TRIGGER]
1499
+ }] }, { type: undefined, decorators: [{
1415
1500
  type: Self
1416
1501
  }, {
1417
1502
  type: Optional
1418
1503
  }, {
1419
1504
  type: Inject,
1420
1505
  args: [MENU_AIM]
1421
- }] }, { type: i2.Directionality, decorators: [{
1422
- type: Optional
1423
- }] }, { type: CdkMenuPanel, decorators: [{
1506
+ }] }, { type: i1$1.Directionality, decorators: [{
1424
1507
  type: Optional
1425
1508
  }] }];
1426
- }, propDecorators: { orientation: [{
1427
- type: Input,
1428
- args: ['cdkMenuOrientation']
1429
- }], closed: [{
1509
+ }, propDecorators: { closed: [{
1430
1510
  type: Output
1431
- }], _nestedGroups: [{
1432
- type: ContentChildren,
1433
- args: [CdkMenuGroup, { descendants: true }]
1434
- }], _allItems: [{
1435
- type: ContentChildren,
1436
- args: [CdkMenuItem, { descendants: true }]
1437
- }], _explicitPanel: [{
1438
- type: Input,
1439
- args: ['cdkMenuPanel']
1440
1511
  }] } });
1441
1512
 
1442
1513
  /**
@@ -1452,152 +1523,90 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
1452
1523
  * this directive is applied to should contain components marked with CdkMenuItem.
1453
1524
  *
1454
1525
  */
1455
- class CdkMenuBar extends CdkMenuGroup {
1456
- constructor(_menuStack, _ngZone, _elementRef, _menuAim, _dir) {
1457
- super();
1458
- this._menuStack = _menuStack;
1459
- this._ngZone = _ngZone;
1460
- this._elementRef = _elementRef;
1461
- 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
- */
1526
+ class CdkMenuBar extends CdkMenuBase {
1527
+ constructor(
1528
+ /** The host element. */
1529
+ elementRef,
1530
+ /** The Angular zone. */
1531
+ ngZone,
1532
+ /** The menu stack this menu is part of. */
1533
+ menuStack,
1534
+ /** The menu aim service used by this menu. */
1535
+ menuAim,
1536
+ /** The directionality of the page. */
1537
+ dir) {
1538
+ super(elementRef, ngZone, menuStack, menuAim, dir);
1539
+ /** The direction items in the menu flow. */
1467
1540
  this.orientation = 'horizontal';
1468
- /** Emits when the MenuBar is destroyed. */
1469
- this._destroyed = new Subject();
1541
+ /** Whether the menu is displayed inline (i.e. always present vs a conditional popup that the user triggers with a trigger element). */
1542
+ this.isInline = true;
1470
1543
  }
1471
1544
  ngAfterContentInit() {
1472
- var _a;
1473
1545
  super.ngAfterContentInit();
1474
- this._setKeyManager();
1475
- this._subscribeToMenuOpen();
1476
- this._subscribeToMenuStack();
1477
- this._subscribeToMouseManager();
1478
- (_a = this._menuAim) === null || _a === void 0 ? void 0 : _a.initialize(this, this._pointerTracker);
1479
- }
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();
1546
+ this._subscribeToMenuStackEmptied();
1489
1547
  }
1490
1548
  /**
1491
- * Handle keyboard events, specifically changing the focused element and/or toggling the active
1492
- * items menu.
1493
- * @param event the KeyboardEvent to handle.
1549
+ * Handle keyboard events for the Menu.
1550
+ * @param event The keyboard event to be handled.
1494
1551
  */
1495
1552
  _handleKeyEvent(event) {
1496
1553
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1497
- const keyManager = this._keyManager;
1554
+ const keyManager = this.keyManager;
1498
1555
  switch (event.keyCode) {
1499
1556
  case UP_ARROW:
1500
1557
  case DOWN_ARROW:
1501
1558
  case LEFT_ARROW:
1502
1559
  case RIGHT_ARROW:
1503
- const horizontalArrows = event.keyCode === LEFT_ARROW || event.keyCode === RIGHT_ARROW;
1504
- // For a horizontal menu if the left/right keys were clicked, or a vertical menu if the
1505
- // up/down keys were clicked: if the current menu is open, close it then focus and open the
1506
- // next menu.
1507
- if ((this._isHorizontal() && horizontalArrows) ||
1508
- (!this._isHorizontal() && !horizontalArrows)) {
1509
- event.preventDefault();
1510
- 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();
1512
- keyManager.setFocusOrigin('keyboard');
1513
- keyManager.onKeydown(event);
1514
- if (prevIsOpen) {
1515
- (_e = (_d = keyManager.activeItem) === null || _d === void 0 ? void 0 : _d.getMenuTrigger()) === null || _e === void 0 ? void 0 : _e.openMenu();
1560
+ if (!hasModifierKey(event)) {
1561
+ const horizontalArrows = event.keyCode === LEFT_ARROW || event.keyCode === RIGHT_ARROW;
1562
+ // For a horizontal menu if the left/right keys were clicked, or a vertical menu if the
1563
+ // up/down keys were clicked: if the current menu is open, close it then focus and open the
1564
+ // next menu.
1565
+ if (horizontalArrows) {
1566
+ event.preventDefault();
1567
+ const prevIsOpen = (_a = keyManager.activeItem) === null || _a === void 0 ? void 0 : _a.isMenuOpen();
1568
+ (_c = (_b = keyManager.activeItem) === null || _b === void 0 ? void 0 : _b.getMenuTrigger()) === null || _c === void 0 ? void 0 : _c.close();
1569
+ keyManager.setFocusOrigin('keyboard');
1570
+ keyManager.onKeydown(event);
1571
+ if (prevIsOpen) {
1572
+ (_e = (_d = keyManager.activeItem) === null || _d === void 0 ? void 0 : _d.getMenuTrigger()) === null || _e === void 0 ? void 0 : _e.open();
1573
+ }
1516
1574
  }
1517
1575
  }
1518
1576
  break;
1519
1577
  case ESCAPE:
1520
- event.preventDefault();
1521
- (_g = (_f = keyManager.activeItem) === null || _f === void 0 ? void 0 : _f.getMenuTrigger()) === null || _g === void 0 ? void 0 : _g.closeMenu();
1578
+ if (!hasModifierKey(event)) {
1579
+ event.preventDefault();
1580
+ (_g = (_f = keyManager.activeItem) === null || _f === void 0 ? void 0 : _f.getMenuTrigger()) === null || _g === void 0 ? void 0 : _g.close();
1581
+ }
1522
1582
  break;
1523
1583
  case TAB:
1524
- (_j = (_h = keyManager.activeItem) === null || _h === void 0 ? void 0 : _h.getMenuTrigger()) === null || _j === void 0 ? void 0 : _j.closeMenu();
1584
+ if (!hasModifierKey(event, 'altKey', 'metaKey', 'ctrlKey')) {
1585
+ (_j = (_h = keyManager.activeItem) === null || _h === void 0 ? void 0 : _h.getMenuTrigger()) === null || _j === void 0 ? void 0 : _j.close();
1586
+ }
1525
1587
  break;
1526
1588
  default:
1527
1589
  keyManager.onKeydown(event);
1528
1590
  }
1529
1591
  }
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
- /**
1545
- * Set the PointerFocusTracker and ensure that when mouse focus changes the key manager is updated
1546
- * with the latest menu item under mouse focus.
1547
- */
1548
- _subscribeToMouseManager() {
1549
- 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);
1554
- }
1555
- });
1556
- });
1557
- }
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
1592
  /**
1585
1593
  * Set focus to either the current, previous or next item based on the FocusNext event, then
1586
1594
  * open the previous or next item.
1595
+ * @param focusNext The element to focus.
1587
1596
  */
1588
- _toggleOpenMenu(event) {
1597
+ _toggleOpenMenu(focusNext) {
1589
1598
  var _a, _b, _c, _d;
1590
- const keyManager = this._keyManager;
1591
- switch (event) {
1599
+ const keyManager = this.keyManager;
1600
+ switch (focusNext) {
1592
1601
  case 0 /* nextItem */:
1593
1602
  keyManager.setFocusOrigin('keyboard');
1594
1603
  keyManager.setNextItemActive();
1595
- (_b = (_a = keyManager.activeItem) === null || _a === void 0 ? void 0 : _a.getMenuTrigger()) === null || _b === void 0 ? void 0 : _b.openMenu();
1604
+ (_b = (_a = keyManager.activeItem) === null || _a === void 0 ? void 0 : _a.getMenuTrigger()) === null || _b === void 0 ? void 0 : _b.open();
1596
1605
  break;
1597
1606
  case 1 /* previousItem */:
1598
1607
  keyManager.setFocusOrigin('keyboard');
1599
1608
  keyManager.setPreviousItemActive();
1600
- (_d = (_c = keyManager.activeItem) === null || _c === void 0 ? void 0 : _c.getMenuTrigger()) === null || _d === void 0 ? void 0 : _d.openMenu();
1609
+ (_d = (_c = keyManager.activeItem) === null || _c === void 0 ? void 0 : _c.getMenuTrigger()) === null || _d === void 0 ? void 0 : _d.open();
1601
1610
  break;
1602
1611
  case 2 /* currentItem */:
1603
1612
  if (keyManager.activeItem) {
@@ -1607,46 +1616,19 @@ class CdkMenuBar extends CdkMenuGroup {
1607
1616
  break;
1608
1617
  }
1609
1618
  }
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() {
1619
+ /** Subscribe to the MenuStack emptied events. */
1620
+ _subscribeToMenuStackEmptied() {
1636
1621
  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();
1622
+ (_a = this.menuStack) === null || _a === void 0 ? void 0 : _a.emptied.pipe(takeUntil(this.destroyed)).subscribe(event => this._toggleOpenMenu(event));
1641
1623
  }
1642
1624
  }
1643
- CdkMenuBar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", 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: "13.2.0", 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: [
1625
+ CdkMenuBar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuBar, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: MENU_STACK }, { token: MENU_AIM, optional: true, self: true }, { token: i1$1.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1626
+ CdkMenuBar.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuBar, selector: "[cdkMenuBar]", host: { attributes: { "role": "menubar" }, listeners: { "keydown": "_handleKeyEvent($event)" }, classAttribute: "cdk-menu-bar" }, providers: [
1645
1627
  { provide: CdkMenuGroup, useExisting: CdkMenuBar },
1646
1628
  { 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: "13.2.0", ngImport: i0, type: CdkMenuBar, decorators: [{
1629
+ { provide: MENU_STACK, useFactory: () => MenuStack.inline('horizontal') },
1630
+ ], exportAs: ["cdkMenuBar"], usesInheritance: true, ngImport: i0 });
1631
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuBar, decorators: [{
1650
1632
  type: Directive,
1651
1633
  args: [{
1652
1634
  selector: '[cdkMenuBar]',
@@ -1654,83 +1636,134 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
1654
1636
  host: {
1655
1637
  'role': 'menubar',
1656
1638
  'class': 'cdk-menu-bar',
1657
- 'tabindex': '0',
1658
- '[attr.aria-orientation]': 'orientation',
1659
- '(focus)': 'focusFirstItem()',
1660
1639
  '(keydown)': '_handleKeyEvent($event)',
1661
1640
  },
1662
1641
  providers: [
1663
1642
  { provide: CdkMenuGroup, useExisting: CdkMenuBar },
1664
1643
  { provide: CDK_MENU, useExisting: CdkMenuBar },
1665
- { provide: MenuStack, useClass: MenuStack },
1644
+ { provide: MENU_STACK, useFactory: () => MenuStack.inline('horizontal') },
1666
1645
  ],
1667
1646
  }]
1668
1647
  }], ctorParameters: function () {
1669
- return [{ type: MenuStack }, { type: i0.NgZone }, { type: i0.ElementRef }, { type: undefined, decorators: [{
1648
+ return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: MenuStack, decorators: [{
1649
+ type: Inject,
1650
+ args: [MENU_STACK]
1651
+ }] }, { type: undefined, decorators: [{
1670
1652
  type: Self
1671
1653
  }, {
1672
1654
  type: Optional
1673
1655
  }, {
1674
1656
  type: Inject,
1675
1657
  args: [MENU_AIM]
1676
- }] }, { type: i2.Directionality, decorators: [{
1658
+ }] }, { type: i1$1.Directionality, decorators: [{
1677
1659
  type: Optional
1678
1660
  }] }];
1679
- }, propDecorators: { orientation: [{
1661
+ } });
1662
+
1663
+ /**
1664
+ * @license
1665
+ * Copyright Google LLC All Rights Reserved.
1666
+ *
1667
+ * Use of this source code is governed by an MIT-style license that can be
1668
+ * found in the LICENSE file at https://angular.io/license
1669
+ */
1670
+ /** Base class providing checked state for selectable MenuItems. */
1671
+ class CdkMenuItemSelectable extends CdkMenuItem {
1672
+ constructor() {
1673
+ super(...arguments);
1674
+ this._checked = false;
1675
+ /** Whether the item should close the menu if triggered by the spacebar. */
1676
+ this.closeOnSpacebarTrigger = false;
1677
+ }
1678
+ /** Whether the element is checked */
1679
+ get checked() {
1680
+ return this._checked;
1681
+ }
1682
+ set checked(value) {
1683
+ this._checked = coerceBooleanProperty(value);
1684
+ }
1685
+ }
1686
+ CdkMenuItemSelectable.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemSelectable, deps: null, target: i0.ɵɵFactoryTarget.Directive });
1687
+ CdkMenuItemSelectable.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuItemSelectable, inputs: { checked: ["cdkMenuItemChecked", "checked"] }, host: { properties: { "attr.aria-checked": "!!checked", "attr.aria-disabled": "disabled || null" } }, usesInheritance: true, ngImport: i0 });
1688
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemSelectable, decorators: [{
1689
+ type: Directive,
1690
+ args: [{
1691
+ host: {
1692
+ '[attr.aria-checked]': '!!checked',
1693
+ '[attr.aria-disabled]': 'disabled || null',
1694
+ },
1695
+ }]
1696
+ }], propDecorators: { checked: [{
1680
1697
  type: Input,
1681
- args: ['cdkMenuBarOrientation']
1682
- }], _allItems: [{
1683
- type: ContentChildren,
1684
- args: [CdkMenuItem, { descendants: true }]
1698
+ args: ['cdkMenuItemChecked']
1685
1699
  }] } });
1686
1700
 
1701
+ /** Counter used to set a unique id and name for a selectable item */
1702
+ let nextId = 0;
1687
1703
  /**
1688
1704
  * A directive providing behavior for the "menuitemradio" ARIA role, which behaves similarly to
1689
1705
  * a conventional radio-button. Any sibling `CdkMenuItemRadio` instances within the same `CdkMenu`
1690
1706
  * or `CdkMenuGroup` comprise a radio group with unique selection enforced.
1691
1707
  */
1692
1708
  class CdkMenuItemRadio extends CdkMenuItemSelectable {
1693
- constructor(_selectionDispatcher, element, ngZone, parentMenu, menuAim, dir,
1709
+ constructor(
1710
+ /** The host element for this radio item. */
1711
+ element,
1712
+ /** The Angular zone. */
1713
+ ngZone,
1714
+ /** The unique selection dispatcher for this radio's `CdkMenuGroup`. */
1715
+ _selectionDispatcher,
1716
+ /** The menu stack this item belongs to. */
1717
+ menuStack,
1718
+ /** The parent menu for this item. */
1719
+ parentMenu,
1720
+ /** The menu aim used for this item. */
1721
+ menuAim,
1722
+ /** The directionality of the page. */
1723
+ dir,
1694
1724
  /** Reference to the CdkMenuItemTrigger directive if one is added to the same element */
1695
- // `CdkMenuItemRadio` is commonly used in combination with a `CdkMenuItemTrigger`.
1696
1725
  // tslint:disable-next-line: lightweight-tokens
1697
1726
  menuTrigger) {
1698
- super(element, ngZone, parentMenu, menuAim, dir, menuTrigger);
1727
+ super(element, ngZone, menuStack, parentMenu, menuAim, dir, menuTrigger);
1699
1728
  this._selectionDispatcher = _selectionDispatcher;
1729
+ /** An ID to identify this radio item to the `UniqueSelectionDisptcher`. */
1730
+ this._id = `${nextId++}`;
1700
1731
  this._registerDispatcherListener();
1701
1732
  }
1702
- /** Configure the unique selection dispatcher listener in order to toggle the checked state */
1703
- _registerDispatcherListener() {
1704
- this._removeDispatcherListener = this._selectionDispatcher.listen((id, name) => (this.checked = this.id === id && this.name === name));
1733
+ ngOnDestroy() {
1734
+ super.ngOnDestroy();
1735
+ this._removeDispatcherListener();
1705
1736
  }
1706
- /** Toggles the checked state of the radio-button. */
1707
- trigger() {
1708
- super.trigger();
1737
+ /**
1738
+ * Toggles the checked state of the radio-button.
1739
+ * @param options Options the configure how the item is triggered
1740
+ * - keepOpen: specifies that the menu should be kept open after triggering the item.
1741
+ */
1742
+ trigger(options) {
1743
+ super.trigger(options);
1709
1744
  if (!this.disabled) {
1710
- this._selectionDispatcher.notify(this.id, this.name);
1745
+ this._selectionDispatcher.notify(this._id, '');
1711
1746
  }
1712
1747
  }
1713
- ngOnDestroy() {
1714
- super.ngOnDestroy();
1715
- this._removeDispatcherListener();
1748
+ /** Configure the unique selection dispatcher listener in order to toggle the checked state */
1749
+ _registerDispatcherListener() {
1750
+ this._removeDispatcherListener = this._selectionDispatcher.listen((id) => {
1751
+ this.checked = this._id === id;
1752
+ });
1716
1753
  }
1717
1754
  }
1718
- CdkMenuItemRadio.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", 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: "13.2.0", type: CdkMenuItemRadio, selector: "[cdkMenuItemRadio]", host: { attributes: { "type": "button", "role": "menuitemradio" }, properties: { "tabindex": "_tabindex", "attr.aria-checked": "checked || null", "attr.aria-disabled": "disabled || null" } }, providers: [
1755
+ CdkMenuItemRadio.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemRadio, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: i1$2.UniqueSelectionDispatcher }, { token: MENU_STACK }, { token: CDK_MENU, optional: true }, { token: MENU_AIM, optional: true }, { token: i1$1.Directionality, optional: true }, { token: CdkMenuTrigger, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
1756
+ CdkMenuItemRadio.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuItemRadio, selector: "[cdkMenuItemRadio]", host: { attributes: { "role": "menuitemradio" } }, providers: [
1720
1757
  { provide: CdkMenuItemSelectable, useExisting: CdkMenuItemRadio },
1721
1758
  { provide: CdkMenuItem, useExisting: CdkMenuItemSelectable },
1722
1759
  ], exportAs: ["cdkMenuItemRadio"], usesInheritance: true, ngImport: i0 });
1723
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuItemRadio, decorators: [{
1760
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemRadio, decorators: [{
1724
1761
  type: Directive,
1725
1762
  args: [{
1726
1763
  selector: '[cdkMenuItemRadio]',
1727
1764
  exportAs: 'cdkMenuItemRadio',
1728
1765
  host: {
1729
- '[tabindex]': '_tabindex',
1730
- 'type': 'button',
1731
1766
  'role': 'menuitemradio',
1732
- '[attr.aria-checked]': 'checked || null',
1733
- '[attr.aria-disabled]': 'disabled || null',
1734
1767
  },
1735
1768
  providers: [
1736
1769
  { provide: CdkMenuItemSelectable, useExisting: CdkMenuItemRadio },
@@ -1738,7 +1771,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
1738
1771
  ],
1739
1772
  }]
1740
1773
  }], ctorParameters: function () {
1741
- return [{ type: i1$1.UniqueSelectionDispatcher }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: undefined, decorators: [{
1774
+ return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: i1$2.UniqueSelectionDispatcher }, { type: MenuStack, decorators: [{
1775
+ type: Inject,
1776
+ args: [MENU_STACK]
1777
+ }] }, { type: undefined, decorators: [{
1742
1778
  type: Optional
1743
1779
  }, {
1744
1780
  type: Inject,
@@ -1748,9 +1784,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
1748
1784
  }, {
1749
1785
  type: Inject,
1750
1786
  args: [MENU_AIM]
1751
- }] }, { type: i2.Directionality, decorators: [{
1787
+ }] }, { type: i1$1.Directionality, decorators: [{
1752
1788
  type: Optional
1753
- }] }, { type: CdkMenuItemTrigger, decorators: [{
1789
+ }] }, { type: CdkMenuTrigger, decorators: [{
1754
1790
  type: Self
1755
1791
  }, {
1756
1792
  type: Optional
@@ -1769,30 +1805,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
1769
1805
  * conventional checkbox.
1770
1806
  */
1771
1807
  class CdkMenuItemCheckbox extends CdkMenuItemSelectable {
1772
- /** Toggle the checked state of the checkbox. */
1773
- trigger() {
1774
- super.trigger();
1808
+ /**
1809
+ * Toggle the checked state of the checkbox.
1810
+ * @param options Options the configure how the item is triggered
1811
+ * - keepOpen: specifies that the menu should be kept open after triggering the item.
1812
+ */
1813
+ trigger(options) {
1814
+ super.trigger(options);
1775
1815
  if (!this.disabled) {
1776
1816
  this.checked = !this.checked;
1777
1817
  }
1778
1818
  }
1779
1819
  }
1780
- CdkMenuItemCheckbox.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuItemCheckbox, deps: null, target: i0.ɵɵFactoryTarget.Directive });
1781
- CdkMenuItemCheckbox.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.0", type: CdkMenuItemCheckbox, selector: "[cdkMenuItemCheckbox]", host: { attributes: { "type": "button", "role": "menuitemcheckbox" }, properties: { "tabindex": "_tabindex", "attr.aria-checked": "checked || null", "attr.aria-disabled": "disabled || null" } }, providers: [
1820
+ CdkMenuItemCheckbox.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemCheckbox, deps: null, target: i0.ɵɵFactoryTarget.Directive });
1821
+ CdkMenuItemCheckbox.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: CdkMenuItemCheckbox, selector: "[cdkMenuItemCheckbox]", host: { attributes: { "role": "menuitemcheckbox" } }, providers: [
1782
1822
  { provide: CdkMenuItemSelectable, useExisting: CdkMenuItemCheckbox },
1783
1823
  { provide: CdkMenuItem, useExisting: CdkMenuItemSelectable },
1784
1824
  ], exportAs: ["cdkMenuItemCheckbox"], usesInheritance: true, ngImport: i0 });
1785
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuItemCheckbox, decorators: [{
1825
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuItemCheckbox, decorators: [{
1786
1826
  type: Directive,
1787
1827
  args: [{
1788
1828
  selector: '[cdkMenuItemCheckbox]',
1789
1829
  exportAs: 'cdkMenuItemCheckbox',
1790
1830
  host: {
1791
- '[tabindex]': '_tabindex',
1792
- 'type': 'button',
1793
1831
  'role': 'menuitemcheckbox',
1794
- '[attr.aria-checked]': 'checked || null',
1795
- '[attr.aria-disabled]': 'disabled || null',
1796
1832
  },
1797
1833
  providers: [
1798
1834
  { provide: CdkMenuItemSelectable, useExisting: CdkMenuItemCheckbox },
@@ -1808,11 +1844,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
1808
1844
  * Use of this source code is governed by an MIT-style license that can be
1809
1845
  * found in the LICENSE file at https://angular.io/license
1810
1846
  */
1847
+ /** The preferred menu positions for the context menu. */
1848
+ const CONTEXT_MENU_POSITIONS = STANDARD_DROPDOWN_BELOW_POSITIONS.map(position => {
1849
+ // In cases where the first menu item in the context menu is a trigger the submenu opens on a
1850
+ // hover event. We offset the context menu 2px by default to prevent this from occurring.
1851
+ const offsetX = position.overlayX === 'start' ? 2 : -2;
1852
+ const offsetY = position.overlayY === 'top' ? 2 : -2;
1853
+ return Object.assign(Object.assign({}, position), { offsetX, offsetY });
1854
+ });
1811
1855
  /** Tracks the last open context menu trigger across the entire application. */
1812
1856
  class ContextMenuTracker {
1813
1857
  /**
1814
1858
  * Close the previous open context menu and set the given one as being open.
1815
- * @param trigger the trigger for the currently open Context Menu.
1859
+ * @param trigger The trigger for the currently open Context Menu.
1816
1860
  */
1817
1861
  update(trigger) {
1818
1862
  var _a;
@@ -1822,55 +1866,38 @@ class ContextMenuTracker {
1822
1866
  }
1823
1867
  }
1824
1868
  }
1825
- ContextMenuTracker.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ContextMenuTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1826
- ContextMenuTracker.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ContextMenuTracker, providedIn: 'root' });
1827
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ContextMenuTracker, decorators: [{
1869
+ ContextMenuTracker.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: ContextMenuTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1870
+ ContextMenuTracker.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: ContextMenuTracker, providedIn: 'root' });
1871
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: ContextMenuTracker, decorators: [{
1828
1872
  type: Injectable,
1829
1873
  args: [{ providedIn: 'root' }]
1830
1874
  }] });
1831
- /** Injection token for the ContextMenu options object. */
1832
- const CDK_CONTEXT_MENU_DEFAULT_OPTIONS = new InjectionToken('cdk-context-menu-default-options');
1833
1875
  /**
1834
- * A directive which when placed on some element opens a the Menu it is bound to when a user
1835
- * right-clicks within that element. It is aware of nested Context Menus and the lowest level
1836
- * non-disabled context menu will trigger.
1876
+ * A directive that opens a menu when a user right-clicks within its host element.
1877
+ * It is aware of nested context menus and will trigger only the lowest level non-disabled context menu.
1837
1878
  */
1838
- class CdkContextMenuTrigger {
1839
- constructor(_viewContainerRef, _overlay, _contextMenuTracker, _options, _directionality) {
1840
- this._viewContainerRef = _viewContainerRef;
1879
+ class CdkContextMenuTrigger extends CdkMenuTriggerBase {
1880
+ constructor(
1881
+ /** The DI injector for this component */
1882
+ injector,
1883
+ /** The view container ref for this component */
1884
+ viewContainerRef,
1885
+ /** The CDK overlay service */
1886
+ _overlay,
1887
+ /** The app's context menu tracking registry */
1888
+ _contextMenuTracker,
1889
+ /** The menu stack this menu is part of. */
1890
+ menuStack,
1891
+ /** The directionality of the current page */
1892
+ _directionality) {
1893
+ super(injector, viewContainerRef, menuStack);
1841
1894
  this._overlay = _overlay;
1842
1895
  this._contextMenuTracker = _contextMenuTracker;
1843
- this._options = _options;
1844
1896
  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
1897
  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
- this._setMenuStackListener();
1898
+ this._setMenuStackCloseListener();
1859
1899
  }
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
- /** Whether the context menu should be disabled. */
1900
+ /** Whether the context menu is disabled. */
1874
1901
  get disabled() {
1875
1902
  return this._disabled;
1876
1903
  }
@@ -1884,36 +1911,12 @@ class CdkContextMenuTrigger {
1884
1911
  open(coordinates) {
1885
1912
  this._open(coordinates, false);
1886
1913
  }
1887
- _open(coordinates, ignoreFirstOutsideAuxClick) {
1888
- if (this.disabled) {
1889
- return;
1890
- }
1891
- else if (this.isOpen()) {
1892
- // since we're moving this menu we need to close any submenus first otherwise they end up
1893
- // disconnected from this one.
1894
- this._menuStack.closeSubMenuOf(this._menuPanel._menu);
1895
- this._overlayRef.getConfig().positionStrategy.setOrigin(coordinates);
1896
- this._overlayRef.updatePosition();
1897
- }
1898
- else {
1899
- this.opened.next();
1900
- if (this._overlayRef) {
1901
- this._overlayRef.getConfig().positionStrategy.setOrigin(coordinates);
1902
- this._overlayRef.updatePosition();
1903
- }
1904
- else {
1905
- this._overlayRef = this._overlay.create(this._getOverlayConfig(coordinates));
1906
- }
1907
- this._overlayRef.attach(this._getMenuContent());
1908
- this._subscribeToOutsideClicks(ignoreFirstOutsideAuxClick);
1909
- }
1910
- }
1911
- /** Close the opened menu. */
1914
+ /** Close the currently opened context menu. */
1912
1915
  close() {
1913
- this._menuStack.closeAll();
1916
+ this.menuStack.closeAll();
1914
1917
  }
1915
1918
  /**
1916
- * Open the context menu and close any previously open menus.
1919
+ * Open the context menu and closes any previously open menus.
1917
1920
  * @param event the mouse event which opens the context menu.
1918
1921
  */
1919
1922
  _openOnContextMenu(event) {
@@ -1929,21 +1932,16 @@ class CdkContextMenuTrigger {
1929
1932
  this._open({ x: event.clientX, y: event.clientY }, true);
1930
1933
  // A context menu can be triggered via a mouse right click or a keyboard shortcut.
1931
1934
  if (event.button === 2) {
1932
- (_a = this._menuPanel._menu) === null || _a === void 0 ? void 0 : _a.focusFirstItem('mouse');
1935
+ (_a = this.childMenu) === null || _a === void 0 ? void 0 : _a.focusFirstItem('mouse');
1933
1936
  }
1934
1937
  else if (event.button === 0) {
1935
- (_b = this._menuPanel._menu) === null || _b === void 0 ? void 0 : _b.focusFirstItem('keyboard');
1938
+ (_b = this.childMenu) === null || _b === void 0 ? void 0 : _b.focusFirstItem('keyboard');
1936
1939
  }
1937
1940
  else {
1938
- (_c = this._menuPanel._menu) === null || _c === void 0 ? void 0 : _c.focusFirstItem('program');
1941
+ (_c = this.childMenu) === null || _c === void 0 ? void 0 : _c.focusFirstItem('program');
1939
1942
  }
1940
1943
  }
1941
1944
  }
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
1945
  /**
1948
1946
  * Get the configuration object used to create the overlay.
1949
1947
  * @param coordinates the location to place the opened menu
@@ -1956,133 +1954,105 @@ class CdkContextMenuTrigger {
1956
1954
  });
1957
1955
  }
1958
1956
  /**
1959
- * Build the position strategy for the overlay which specifies where to place the menu.
1957
+ * Get the position strategy for the overlay which specifies where to place the menu.
1960
1958
  * @param coordinates the location to place the opened menu
1961
1959
  */
1962
1960
  _getOverlayPositionStrategy(coordinates) {
1961
+ var _a;
1963
1962
  return this._overlay
1964
1963
  .position()
1965
1964
  .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
- ];
1981
- }
1982
- /**
1983
- * Get the portal to be attached to the overlay which contains the menu. Allows for the menu
1984
- * content to change dynamically and be reflected in the application.
1985
- */
1986
- _getMenuContent() {
1987
- 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);
1991
- }
1992
- return this._panelContent;
1965
+ .withPositions((_a = this.menuPosition) !== null && _a !== void 0 ? _a : CONTEXT_MENU_POSITIONS);
1993
1966
  }
1994
1967
  /** Subscribe to the menu stack close events and close this menu when requested. */
1995
- _setMenuStackListener() {
1996
- this._menuStack.closed.pipe(takeUntil(this._destroyed)).subscribe(item => {
1997
- if (item === this._menuPanel._menu && this.isOpen()) {
1968
+ _setMenuStackCloseListener() {
1969
+ this.menuStack.closed.pipe(takeUntil(this.destroyed)).subscribe(({ item }) => {
1970
+ if (item === this.childMenu && this.isOpen()) {
1998
1971
  this.closed.next();
1999
- this._overlayRef.detach();
1972
+ this.overlayRef.detach();
2000
1973
  }
2001
1974
  });
2002
1975
  }
2003
1976
  /**
2004
1977
  * Subscribe to the overlays outside pointer events stream and handle closing out the stack if a
2005
1978
  * click occurs outside the menus.
1979
+ * @param ignoreFirstAuxClick Whether to ignore the first auxclick event outside the menu.
2006
1980
  */
2007
1981
  _subscribeToOutsideClicks(ignoreFirstAuxClick) {
2008
- if (this._overlayRef) {
2009
- let outsideClicks = this._overlayRef.outsidePointerEvents();
1982
+ if (this.overlayRef) {
1983
+ let outsideClicks = this.overlayRef.outsidePointerEvents();
2010
1984
  // If the menu was triggered by the `contextmenu` event, skip the first `auxclick` event
2011
1985
  // because it fires when the mouse is released on the same click that opened the menu.
2012
1986
  if (ignoreFirstAuxClick) {
2013
1987
  const [auxClicks, nonAuxClicks] = partition(outsideClicks, ({ type }) => type === 'auxclick');
2014
1988
  outsideClicks = merge(nonAuxClicks, auxClicks.pipe(skip(1)));
2015
1989
  }
2016
- outsideClicks.pipe(takeUntil(this._stopOutsideClicksListener)).subscribe(event => {
2017
- if (!isClickInsideMenuOverlay(event.target)) {
2018
- this._menuStack.closeAll();
1990
+ outsideClicks.pipe(takeUntil(this.stopOutsideClicksListener)).subscribe(event => {
1991
+ if (!this.isElementInsideMenuStack(event.target)) {
1992
+ this.menuStack.closeAll();
2019
1993
  }
2020
1994
  });
2021
1995
  }
2022
1996
  }
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;
1997
+ /**
1998
+ * Open the attached menu at the specified location.
1999
+ * @param coordinates where to open the context menu
2000
+ * @param ignoreFirstOutsideAuxClick Whether to ignore the first auxclick outside the menu after opening.
2001
+ */
2002
+ _open(coordinates, ignoreFirstOutsideAuxClick) {
2003
+ if (this.disabled) {
2004
+ return;
2034
2005
  }
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;
2006
+ if (this.isOpen()) {
2007
+ // since we're moving this menu we need to close any submenus first otherwise they end up
2008
+ // disconnected from this one.
2009
+ this.menuStack.closeSubMenuOf(this.childMenu);
2010
+ this.overlayRef.getConfig().positionStrategy.setOrigin(coordinates);
2011
+ this.overlayRef.updatePosition();
2012
+ }
2013
+ else {
2014
+ this.opened.next();
2015
+ if (this.overlayRef) {
2016
+ this.overlayRef.getConfig().positionStrategy.setOrigin(coordinates);
2017
+ this.overlayRef.updatePosition();
2018
+ }
2019
+ else {
2020
+ this.overlayRef = this._overlay.create(this._getOverlayConfig(coordinates));
2021
+ }
2022
+ this.overlayRef.attach(this.getMenuContentPortal());
2023
+ this._subscribeToOutsideClicks(ignoreFirstOutsideAuxClick);
2046
2024
  }
2047
2025
  }
2048
2026
  }
2049
- CdkContextMenuTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", 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: "13.2.0", 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: "13.2.0", ngImport: i0, type: CdkContextMenuTrigger, decorators: [{
2027
+ 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 });
2028
+ 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)" }, properties: { "attr.data-cdk-menu-stack-id": "null" } }, providers: [
2029
+ { provide: MENU_TRIGGER, useExisting: CdkContextMenuTrigger },
2030
+ { provide: MENU_STACK, useClass: MenuStack },
2031
+ ], exportAs: ["cdkContextMenuTriggerFor"], usesInheritance: true, ngImport: i0 });
2032
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkContextMenuTrigger, decorators: [{
2056
2033
  type: Directive,
2057
2034
  args: [{
2058
2035
  selector: '[cdkContextMenuTriggerFor]',
2059
2036
  exportAs: 'cdkContextMenuTriggerFor',
2060
2037
  host: {
2038
+ '[attr.data-cdk-menu-stack-id]': 'null',
2061
2039
  '(contextmenu)': '_openOnContextMenu($event)',
2062
2040
  },
2041
+ inputs: ['menuTemplateRef: cdkContextMenuTriggerFor', 'menuPosition: cdkContextMenuPosition'],
2042
+ outputs: ['opened: cdkContextMenuOpened', 'closed: cdkContextMenuClosed'],
2063
2043
  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 } },
2044
+ { provide: MENU_TRIGGER, useExisting: CdkContextMenuTrigger },
2045
+ { provide: MENU_STACK, useClass: MenuStack },
2067
2046
  ],
2068
2047
  }]
2069
2048
  }], ctorParameters: function () {
2070
- return [{ type: i0.ViewContainerRef }, { type: i1.Overlay }, { type: ContextMenuTracker }, { type: undefined, decorators: [{
2049
+ return [{ type: i0.Injector }, { type: i0.ViewContainerRef }, { type: i1.Overlay }, { type: ContextMenuTracker }, { type: MenuStack, decorators: [{
2071
2050
  type: Inject,
2072
- args: [CDK_CONTEXT_MENU_DEFAULT_OPTIONS]
2073
- }] }, { type: i2.Directionality, decorators: [{
2051
+ args: [MENU_STACK]
2052
+ }] }, { type: i1$1.Directionality, decorators: [{
2074
2053
  type: Optional
2075
2054
  }] }];
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: [{
2055
+ }, propDecorators: { disabled: [{
2086
2056
  type: Input,
2087
2057
  args: ['cdkContextMenuDisabled']
2088
2058
  }] } });
@@ -2094,42 +2064,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
2094
2064
  * Use of this source code is governed by an MIT-style license that can be
2095
2065
  * found in the LICENSE file at https://angular.io/license
2096
2066
  */
2067
+ /** The list of components and directives that should be declared and exported from this module. */
2097
2068
  const EXPORTED_DECLARATIONS = [
2098
2069
  CdkMenuBar,
2099
2070
  CdkMenu,
2100
- CdkMenuPanel,
2101
2071
  CdkMenuItem,
2102
2072
  CdkMenuItemRadio,
2103
2073
  CdkMenuItemCheckbox,
2104
- CdkMenuItemTrigger,
2074
+ CdkMenuTrigger,
2105
2075
  CdkMenuGroup,
2106
2076
  CdkContextMenuTrigger,
2107
2077
  CdkTargetMenuAim,
2108
2078
  ];
2079
+ /** Module that declares components and directives for the CDK menu. */
2109
2080
  class CdkMenuModule {
2110
2081
  }
2111
- CdkMenuModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2112
- CdkMenuModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuModule, declarations: [CdkMenuBar,
2082
+ CdkMenuModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2083
+ CdkMenuModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuModule, declarations: [CdkMenuBar,
2113
2084
  CdkMenu,
2114
- CdkMenuPanel,
2115
2085
  CdkMenuItem,
2116
2086
  CdkMenuItemRadio,
2117
2087
  CdkMenuItemCheckbox,
2118
- CdkMenuItemTrigger,
2088
+ CdkMenuTrigger,
2119
2089
  CdkMenuGroup,
2120
2090
  CdkContextMenuTrigger,
2121
2091
  CdkTargetMenuAim], imports: [OverlayModule], exports: [CdkMenuBar,
2122
2092
  CdkMenu,
2123
- CdkMenuPanel,
2124
2093
  CdkMenuItem,
2125
2094
  CdkMenuItemRadio,
2126
2095
  CdkMenuItemCheckbox,
2127
- CdkMenuItemTrigger,
2096
+ CdkMenuTrigger,
2128
2097
  CdkMenuGroup,
2129
2098
  CdkContextMenuTrigger,
2130
2099
  CdkTargetMenuAim] });
2131
- CdkMenuModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuModule, imports: [[OverlayModule]] });
2132
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CdkMenuModule, decorators: [{
2100
+ CdkMenuModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuModule, imports: [[OverlayModule]] });
2101
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkMenuModule, decorators: [{
2133
2102
  type: NgModule,
2134
2103
  args: [{
2135
2104
  imports: [OverlayModule],
@@ -2158,5 +2127,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImpor
2158
2127
  * Generated bundle index. Do not edit.
2159
2128
  */
2160
2129
 
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 };
2130
+ export { CDK_MENU, CdkContextMenuTrigger, CdkMenu, CdkMenuBar, CdkMenuBase, CdkMenuGroup, CdkMenuItem, CdkMenuItemCheckbox, CdkMenuItemRadio, CdkMenuItemSelectable, CdkMenuModule, CdkMenuTrigger, CdkMenuTriggerBase, CdkTargetMenuAim, ContextMenuTracker, MENU_AIM, MENU_STACK, MENU_TRIGGER, MenuStack, PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER, PARENT_OR_NEW_MENU_STACK_PROVIDER, PointerFocusTracker, TargetMenuAim };
2162
2131
  //# sourceMappingURL=menu.mjs.map