@angular/material 21.0.0-next.9 → 21.0.0-rc.0

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 (202) hide show
  1. package/core/tokens/_classes.scss +1 -1
  2. package/core/tokens/m2/_md-sys-color.scss +17 -17
  3. package/fesm2022/_animation-chunk.mjs +10 -16
  4. package/fesm2022/_animation-chunk.mjs.map +1 -1
  5. package/fesm2022/_date-formats-chunk.mjs +68 -164
  6. package/fesm2022/_date-formats-chunk.mjs.map +1 -1
  7. package/fesm2022/_date-range-input-harness-chunk.mjs +284 -463
  8. package/fesm2022/_date-range-input-harness-chunk.mjs.map +1 -1
  9. package/fesm2022/_error-options-chunk.mjs +56 -19
  10. package/fesm2022/_error-options-chunk.mjs.map +1 -1
  11. package/fesm2022/_error-state-chunk.mjs +24 -31
  12. package/fesm2022/_error-state-chunk.mjs.map +1 -1
  13. package/fesm2022/_form-field-chunk.mjs +1224 -1017
  14. package/fesm2022/_form-field-chunk.mjs.map +1 -1
  15. package/fesm2022/_icon-button-chunk.mjs +243 -187
  16. package/fesm2022/_icon-button-chunk.mjs.map +1 -1
  17. package/fesm2022/_icon-registry-chunk.mjs +350 -575
  18. package/fesm2022/_icon-registry-chunk.mjs.map +1 -1
  19. package/fesm2022/_input-harness-chunk.mjs +56 -107
  20. package/fesm2022/_input-harness-chunk.mjs.map +1 -1
  21. package/fesm2022/_input-value-accessor-chunk.mjs +0 -6
  22. package/fesm2022/_input-value-accessor-chunk.mjs.map +1 -1
  23. package/fesm2022/_internal-form-field-chunk.mjs +59 -19
  24. package/fesm2022/_internal-form-field-chunk.mjs.map +1 -1
  25. package/fesm2022/_line-chunk.mjs +83 -43
  26. package/fesm2022/_line-chunk.mjs.map +1 -1
  27. package/fesm2022/_option-chunk.mjs +348 -311
  28. package/fesm2022/_option-chunk.mjs.map +1 -1
  29. package/fesm2022/_option-harness-chunk.mjs +23 -39
  30. package/fesm2022/_option-harness-chunk.mjs.map +1 -1
  31. package/fesm2022/_option-module-chunk.mjs +36 -10
  32. package/fesm2022/_option-module-chunk.mjs.map +1 -1
  33. package/fesm2022/_pseudo-checkbox-chunk.mjs +79 -44
  34. package/fesm2022/_pseudo-checkbox-chunk.mjs.map +1 -1
  35. package/fesm2022/_pseudo-checkbox-module-chunk.mjs +36 -10
  36. package/fesm2022/_pseudo-checkbox-module-chunk.mjs.map +1 -1
  37. package/fesm2022/_public-api-chunk.mjs +71 -134
  38. package/fesm2022/_public-api-chunk.mjs.map +1 -1
  39. package/fesm2022/_ripple-chunk.mjs +504 -600
  40. package/fesm2022/_ripple-chunk.mjs.map +1 -1
  41. package/fesm2022/_ripple-loader-chunk.mjs +120 -138
  42. package/fesm2022/_ripple-loader-chunk.mjs.map +1 -1
  43. package/fesm2022/_ripple-module-chunk.mjs +36 -10
  44. package/fesm2022/_ripple-module-chunk.mjs.map +1 -1
  45. package/fesm2022/_structural-styles-chunk.mjs +37 -10
  46. package/fesm2022/_structural-styles-chunk.mjs.map +1 -1
  47. package/fesm2022/_tooltip-chunk.mjs +810 -888
  48. package/fesm2022/_tooltip-chunk.mjs.map +1 -1
  49. package/fesm2022/autocomplete-testing.mjs +62 -86
  50. package/fesm2022/autocomplete-testing.mjs.map +1 -1
  51. package/fesm2022/autocomplete.mjs +965 -1126
  52. package/fesm2022/autocomplete.mjs.map +1 -1
  53. package/fesm2022/badge-testing.mjs +38 -54
  54. package/fesm2022/badge-testing.mjs.map +1 -1
  55. package/fesm2022/badge.mjs +321 -272
  56. package/fesm2022/badge.mjs.map +1 -1
  57. package/fesm2022/bottom-sheet-testing.mjs +10 -24
  58. package/fesm2022/bottom-sheet-testing.mjs.map +1 -1
  59. package/fesm2022/bottom-sheet.mjs +349 -344
  60. package/fesm2022/bottom-sheet.mjs.map +1 -1
  61. package/fesm2022/button-testing.mjs +60 -94
  62. package/fesm2022/button-testing.mjs.map +1 -1
  63. package/fesm2022/button-toggle-testing.mjs +76 -125
  64. package/fesm2022/button-toggle-testing.mjs.map +1 -1
  65. package/fesm2022/button-toggle.mjs +752 -662
  66. package/fesm2022/button-toggle.mjs.map +1 -1
  67. package/fesm2022/button.mjs +263 -158
  68. package/fesm2022/button.mjs.map +1 -1
  69. package/fesm2022/card-testing.mjs +19 -33
  70. package/fesm2022/card-testing.mjs.map +1 -1
  71. package/fesm2022/card.mjs +576 -272
  72. package/fesm2022/card.mjs.map +1 -1
  73. package/fesm2022/checkbox-testing.mjs +71 -123
  74. package/fesm2022/checkbox-testing.mjs.map +1 -1
  75. package/fesm2022/checkbox.mjs +515 -477
  76. package/fesm2022/checkbox.mjs.map +1 -1
  77. package/fesm2022/chips-testing.mjs +201 -344
  78. package/fesm2022/chips-testing.mjs.map +1 -1
  79. package/fesm2022/chips.mjs +2552 -2289
  80. package/fesm2022/chips.mjs.map +1 -1
  81. package/fesm2022/core-testing.mjs +14 -28
  82. package/fesm2022/core-testing.mjs.map +1 -1
  83. package/fesm2022/core.mjs +357 -328
  84. package/fesm2022/core.mjs.map +1 -1
  85. package/fesm2022/datepicker-testing.mjs +15 -25
  86. package/fesm2022/datepicker-testing.mjs.map +1 -1
  87. package/fesm2022/datepicker.mjs +4826 -4563
  88. package/fesm2022/datepicker.mjs.map +1 -1
  89. package/fesm2022/dialog-testing.mjs +93 -129
  90. package/fesm2022/dialog-testing.mjs.map +1 -1
  91. package/fesm2022/dialog.mjs +810 -829
  92. package/fesm2022/dialog.mjs.map +1 -1
  93. package/fesm2022/divider-testing.mjs +10 -11
  94. package/fesm2022/divider-testing.mjs.map +1 -1
  95. package/fesm2022/divider.mjs +119 -43
  96. package/fesm2022/divider.mjs.map +1 -1
  97. package/fesm2022/expansion-testing.mjs +74 -130
  98. package/fesm2022/expansion-testing.mjs.map +1 -1
  99. package/fesm2022/expansion.mjs +703 -515
  100. package/fesm2022/expansion.mjs.map +1 -1
  101. package/fesm2022/form-field-testing-control.mjs +16 -33
  102. package/fesm2022/form-field-testing-control.mjs.map +1 -1
  103. package/fesm2022/form-field-testing.mjs +118 -179
  104. package/fesm2022/form-field-testing.mjs.map +1 -1
  105. package/fesm2022/form-field.mjs +36 -10
  106. package/fesm2022/form-field.mjs.map +1 -1
  107. package/fesm2022/grid-list-testing.mjs +65 -113
  108. package/fesm2022/grid-list-testing.mjs.map +1 -1
  109. package/fesm2022/grid-list.mjs +559 -494
  110. package/fesm2022/grid-list.mjs.map +1 -1
  111. package/fesm2022/icon-testing.mjs +148 -127
  112. package/fesm2022/icon-testing.mjs.map +1 -1
  113. package/fesm2022/icon.mjs +325 -351
  114. package/fesm2022/icon.mjs.map +1 -1
  115. package/fesm2022/input-testing.mjs +59 -99
  116. package/fesm2022/input-testing.mjs.map +1 -1
  117. package/fesm2022/input.mjs +457 -520
  118. package/fesm2022/input.mjs.map +1 -1
  119. package/fesm2022/list-testing.mjs +251 -434
  120. package/fesm2022/list-testing.mjs.map +1 -1
  121. package/fesm2022/list.mjs +1522 -1204
  122. package/fesm2022/list.mjs.map +1 -1
  123. package/fesm2022/material.mjs +0 -5
  124. package/fesm2022/material.mjs.map +1 -1
  125. package/fesm2022/menu-testing.mjs +159 -228
  126. package/fesm2022/menu-testing.mjs.map +1 -1
  127. package/fesm2022/menu.mjs +1338 -1343
  128. package/fesm2022/menu.mjs.map +1 -1
  129. package/fesm2022/paginator-testing.mjs +55 -79
  130. package/fesm2022/paginator-testing.mjs.map +1 -1
  131. package/fesm2022/paginator.mjs +381 -309
  132. package/fesm2022/paginator.mjs.map +1 -1
  133. package/fesm2022/progress-bar-testing.mjs +12 -21
  134. package/fesm2022/progress-bar-testing.mjs.map +1 -1
  135. package/fesm2022/progress-bar.mjs +224 -169
  136. package/fesm2022/progress-bar.mjs.map +1 -1
  137. package/fesm2022/progress-spinner-testing.mjs +13 -23
  138. package/fesm2022/progress-spinner-testing.mjs.map +1 -1
  139. package/fesm2022/progress-spinner.mjs +235 -160
  140. package/fesm2022/progress-spinner.mjs.map +1 -1
  141. package/fesm2022/radio-testing.mjs +133 -208
  142. package/fesm2022/radio-testing.mjs.map +1 -1
  143. package/fesm2022/radio.mjs +712 -679
  144. package/fesm2022/radio.mjs.map +1 -1
  145. package/fesm2022/select-testing.mjs +83 -117
  146. package/fesm2022/select-testing.mjs.map +1 -1
  147. package/fesm2022/select.mjs +1116 -1246
  148. package/fesm2022/select.mjs.map +1 -1
  149. package/fesm2022/sidenav-testing.mjs +54 -120
  150. package/fesm2022/sidenav-testing.mjs.map +1 -1
  151. package/fesm2022/sidenav.mjs +1078 -995
  152. package/fesm2022/sidenav.mjs.map +1 -1
  153. package/fesm2022/slide-toggle-testing.mjs +57 -92
  154. package/fesm2022/slide-toggle-testing.mjs.map +1 -1
  155. package/fesm2022/slide-toggle.mjs +369 -279
  156. package/fesm2022/slide-toggle.mjs.map +1 -1
  157. package/fesm2022/slider-testing.mjs +90 -138
  158. package/fesm2022/slider-testing.mjs.map +1 -1
  159. package/fesm2022/slider.mjs +1651 -1716
  160. package/fesm2022/slider.mjs.map +1 -1
  161. package/fesm2022/snack-bar-testing.mjs +40 -87
  162. package/fesm2022/snack-bar-testing.mjs.map +1 -1
  163. package/fesm2022/snack-bar.mjs +763 -714
  164. package/fesm2022/snack-bar.mjs.map +1 -1
  165. package/fesm2022/sort-testing.mjs +45 -66
  166. package/fesm2022/sort-testing.mjs.map +1 -1
  167. package/fesm2022/sort.mjs +419 -344
  168. package/fesm2022/sort.mjs.map +1 -1
  169. package/fesm2022/stepper-testing.mjs +78 -154
  170. package/fesm2022/stepper-testing.mjs.map +1 -1
  171. package/fesm2022/stepper.mjs +790 -498
  172. package/fesm2022/stepper.mjs.map +1 -1
  173. package/fesm2022/table-testing.mjs +120 -213
  174. package/fesm2022/table-testing.mjs.map +1 -1
  175. package/fesm2022/table.mjs +1026 -684
  176. package/fesm2022/table.mjs.map +1 -1
  177. package/fesm2022/tabs-testing.mjs +125 -197
  178. package/fesm2022/tabs-testing.mjs.map +1 -1
  179. package/fesm2022/tabs.mjs +2351 -2028
  180. package/fesm2022/tabs.mjs.map +1 -1
  181. package/fesm2022/timepicker-testing.mjs +113 -172
  182. package/fesm2022/timepicker-testing.mjs.map +1 -1
  183. package/fesm2022/timepicker.mjs +1019 -826
  184. package/fesm2022/timepicker.mjs.map +1 -1
  185. package/fesm2022/toolbar-testing.mjs +16 -27
  186. package/fesm2022/toolbar-testing.mjs.map +1 -1
  187. package/fesm2022/toolbar.mjs +163 -78
  188. package/fesm2022/toolbar.mjs.map +1 -1
  189. package/fesm2022/tooltip-testing.mjs +41 -52
  190. package/fesm2022/tooltip-testing.mjs.map +1 -1
  191. package/fesm2022/tooltip.mjs +36 -10
  192. package/fesm2022/tooltip.mjs.map +1 -1
  193. package/fesm2022/tree-testing.mjs +86 -162
  194. package/fesm2022/tree-testing.mjs.map +1 -1
  195. package/fesm2022/tree.mjs +638 -466
  196. package/fesm2022/tree.mjs.map +1 -1
  197. package/package.json +2 -2
  198. package/schematics/ng-add/index.js +1 -1
  199. package/types/expansion.d.ts +4 -2
  200. package/types/menu-testing.d.ts +2 -0
  201. package/types/select.d.ts +1 -1
  202. package/types/timepicker.d.ts +1 -0
package/fesm2022/menu.mjs CHANGED
@@ -17,1404 +17,1399 @@ import { MatRippleModule } from './_ripple-module-chunk.mjs';
17
17
  import '@angular/cdk/coercion';
18
18
  import '@angular/cdk/layout';
19
19
 
20
- /**
21
- * Injection token used to provide the parent menu to menu-specific components.
22
- * @docs-private
23
- */
24
20
  const MAT_MENU_PANEL = new InjectionToken('MAT_MENU_PANEL');
25
21
 
26
- /**
27
- * Single item inside a `mat-menu`. Provides the menu item styling and accessibility treatment.
28
- */
29
22
  class MatMenuItem {
30
- _elementRef = inject(ElementRef);
31
- _document = inject(DOCUMENT);
32
- _focusMonitor = inject(FocusMonitor);
33
- _parentMenu = inject(MAT_MENU_PANEL, { optional: true });
34
- _changeDetectorRef = inject(ChangeDetectorRef);
35
- /** ARIA role for the menu item. */
36
- role = 'menuitem';
37
- /** Whether the menu item is disabled. */
38
- disabled = false;
39
- /** Whether ripples are disabled on the menu item. */
40
- disableRipple = false;
41
- /** Stream that emits when the menu item is hovered. */
42
- _hovered = new Subject();
43
- /** Stream that emits when the menu item is focused. */
44
- _focused = new Subject();
45
- /** Whether the menu item is highlighted. */
46
- _highlighted = false;
47
- /** Whether the menu item acts as a trigger for a sub-menu. */
48
- _triggersSubmenu = false;
49
- constructor() {
50
- inject(_CdkPrivateStyleLoader).load(_StructuralStylesLoader);
51
- this._parentMenu?.addItem?.(this);
52
- }
53
- /** Focuses the menu item. */
54
- focus(origin, options) {
55
- if (this._focusMonitor && origin) {
56
- this._focusMonitor.focusVia(this._getHostElement(), origin, options);
57
- }
58
- else {
59
- this._getHostElement().focus(options);
60
- }
61
- this._focused.next(this);
62
- }
63
- ngAfterViewInit() {
64
- if (this._focusMonitor) {
65
- // Start monitoring the element, so it gets the appropriate focused classes. We want
66
- // to show the focus style for menu items only when the focus was not caused by a
67
- // mouse or touch interaction.
68
- this._focusMonitor.monitor(this._elementRef, false);
69
- }
70
- }
71
- ngOnDestroy() {
72
- if (this._focusMonitor) {
73
- this._focusMonitor.stopMonitoring(this._elementRef);
74
- }
75
- if (this._parentMenu && this._parentMenu.removeItem) {
76
- this._parentMenu.removeItem(this);
77
- }
78
- this._hovered.complete();
79
- this._focused.complete();
80
- }
81
- /** Used to set the `tabindex`. */
82
- _getTabIndex() {
83
- return this.disabled ? '-1' : '0';
84
- }
85
- /** Returns the host DOM element. */
86
- _getHostElement() {
87
- return this._elementRef.nativeElement;
88
- }
89
- /** Prevents the default element actions if it is disabled. */
90
- _checkDisabled(event) {
91
- if (this.disabled) {
92
- event.preventDefault();
93
- event.stopPropagation();
94
- }
95
- }
96
- /** Emits to the hover stream. */
97
- _handleMouseEnter() {
98
- this._hovered.next(this);
99
- }
100
- /** Gets the label to be used when determining whether the option should be focused. */
101
- getLabel() {
102
- const clone = this._elementRef.nativeElement.cloneNode(true);
103
- const icons = clone.querySelectorAll('mat-icon, .material-icons');
104
- // Strip away icons, so they don't show up in the text.
105
- for (let i = 0; i < icons.length; i++) {
106
- icons[i].remove();
107
- }
108
- return clone.textContent?.trim() || '';
109
- }
110
- _setHighlighted(isHighlighted) {
111
- // We need to mark this for check for the case where the content is coming from a
112
- // `matMenuContent` whose change detection tree is at the declaration position,
113
- // not the insertion position. See #23175.
114
- this._highlighted = isHighlighted;
115
- this._changeDetectorRef.markForCheck();
116
- }
117
- _setTriggersSubmenu(triggersSubmenu) {
118
- this._triggersSubmenu = triggersSubmenu;
119
- this._changeDetectorRef.markForCheck();
120
- }
121
- _hasFocus() {
122
- return this._document && this._document.activeElement === this._getHostElement();
123
- }
124
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
125
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.0-next.2", type: MatMenuItem, isStandalone: true, selector: "[mat-menu-item]", inputs: { role: "role", disabled: ["disabled", "disabled", booleanAttribute], disableRipple: ["disableRipple", "disableRipple", booleanAttribute] }, host: { listeners: { "click": "_checkDisabled($event)", "mouseenter": "_handleMouseEnter()" }, properties: { "attr.role": "role", "class.mat-mdc-menu-item-highlighted": "_highlighted", "class.mat-mdc-menu-item-submenu-trigger": "_triggersSubmenu", "attr.tabindex": "_getTabIndex()", "attr.aria-disabled": "disabled", "attr.disabled": "disabled || null" }, classAttribute: "mat-mdc-menu-item mat-focus-indicator" }, exportAs: ["matMenuItem"], ngImport: i0, template: "<ng-content select=\"mat-icon, [matMenuItemIcon]\"></ng-content>\n<span class=\"mat-mdc-menu-item-text\"><ng-content></ng-content></span>\n<div class=\"mat-mdc-menu-ripple\" matRipple\n [matRippleDisabled]=\"disableRipple || disabled\"\n [matRippleTrigger]=\"_getHostElement()\">\n</div>\n\n@if (_triggersSubmenu) {\n <svg\n class=\"mat-mdc-menu-submenu-icon\"\n viewBox=\"0 0 5 10\"\n focusable=\"false\"\n aria-hidden=\"true\"><polygon points=\"0,0 5,5 0,10\"/></svg>\n}\n", dependencies: [{ kind: "directive", type: MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23
+ _elementRef = inject(ElementRef);
24
+ _document = inject(DOCUMENT);
25
+ _focusMonitor = inject(FocusMonitor);
26
+ _parentMenu = inject(MAT_MENU_PANEL, {
27
+ optional: true
28
+ });
29
+ _changeDetectorRef = inject(ChangeDetectorRef);
30
+ role = 'menuitem';
31
+ disabled = false;
32
+ disableRipple = false;
33
+ _hovered = new Subject();
34
+ _focused = new Subject();
35
+ _highlighted = false;
36
+ _triggersSubmenu = false;
37
+ constructor() {
38
+ inject(_CdkPrivateStyleLoader).load(_StructuralStylesLoader);
39
+ this._parentMenu?.addItem?.(this);
40
+ }
41
+ focus(origin, options) {
42
+ if (this._focusMonitor && origin) {
43
+ this._focusMonitor.focusVia(this._getHostElement(), origin, options);
44
+ } else {
45
+ this._getHostElement().focus(options);
46
+ }
47
+ this._focused.next(this);
48
+ }
49
+ ngAfterViewInit() {
50
+ if (this._focusMonitor) {
51
+ this._focusMonitor.monitor(this._elementRef, false);
52
+ }
53
+ }
54
+ ngOnDestroy() {
55
+ if (this._focusMonitor) {
56
+ this._focusMonitor.stopMonitoring(this._elementRef);
57
+ }
58
+ if (this._parentMenu && this._parentMenu.removeItem) {
59
+ this._parentMenu.removeItem(this);
60
+ }
61
+ this._hovered.complete();
62
+ this._focused.complete();
63
+ }
64
+ _getTabIndex() {
65
+ return this.disabled ? '-1' : '0';
66
+ }
67
+ _getHostElement() {
68
+ return this._elementRef.nativeElement;
69
+ }
70
+ _checkDisabled(event) {
71
+ if (this.disabled) {
72
+ event.preventDefault();
73
+ event.stopPropagation();
74
+ }
75
+ }
76
+ _handleMouseEnter() {
77
+ this._hovered.next(this);
78
+ }
79
+ getLabel() {
80
+ const clone = this._elementRef.nativeElement.cloneNode(true);
81
+ const icons = clone.querySelectorAll('mat-icon, .material-icons');
82
+ for (let i = 0; i < icons.length; i++) {
83
+ icons[i].remove();
84
+ }
85
+ return clone.textContent?.trim() || '';
86
+ }
87
+ _setHighlighted(isHighlighted) {
88
+ this._highlighted = isHighlighted;
89
+ this._changeDetectorRef.markForCheck();
90
+ }
91
+ _setTriggersSubmenu(triggersSubmenu) {
92
+ this._triggersSubmenu = triggersSubmenu;
93
+ this._changeDetectorRef.markForCheck();
94
+ }
95
+ _hasFocus() {
96
+ return this._document && this._document.activeElement === this._getHostElement();
97
+ }
98
+ static ɵfac = i0.ɵɵngDeclareFactory({
99
+ minVersion: "12.0.0",
100
+ version: "20.2.0-next.2",
101
+ ngImport: i0,
102
+ type: MatMenuItem,
103
+ deps: [],
104
+ target: i0.ɵɵFactoryTarget.Component
105
+ });
106
+ static ɵcmp = i0.ɵɵngDeclareComponent({
107
+ minVersion: "17.0.0",
108
+ version: "20.2.0-next.2",
109
+ type: MatMenuItem,
110
+ isStandalone: true,
111
+ selector: "[mat-menu-item]",
112
+ inputs: {
113
+ role: "role",
114
+ disabled: ["disabled", "disabled", booleanAttribute],
115
+ disableRipple: ["disableRipple", "disableRipple", booleanAttribute]
116
+ },
117
+ host: {
118
+ listeners: {
119
+ "click": "_checkDisabled($event)",
120
+ "mouseenter": "_handleMouseEnter()"
121
+ },
122
+ properties: {
123
+ "attr.role": "role",
124
+ "class.mat-mdc-menu-item-highlighted": "_highlighted",
125
+ "class.mat-mdc-menu-item-submenu-trigger": "_triggersSubmenu",
126
+ "attr.tabindex": "_getTabIndex()",
127
+ "attr.aria-disabled": "disabled",
128
+ "attr.disabled": "disabled || null"
129
+ },
130
+ classAttribute: "mat-mdc-menu-item mat-focus-indicator"
131
+ },
132
+ exportAs: ["matMenuItem"],
133
+ ngImport: i0,
134
+ template: "<ng-content select=\"mat-icon, [matMenuItemIcon]\"></ng-content>\n<span class=\"mat-mdc-menu-item-text\"><ng-content></ng-content></span>\n<div class=\"mat-mdc-menu-ripple\" matRipple\n [matRippleDisabled]=\"disableRipple || disabled\"\n [matRippleTrigger]=\"_getHostElement()\">\n</div>\n\n@if (_triggersSubmenu) {\n <svg\n class=\"mat-mdc-menu-submenu-icon\"\n viewBox=\"0 0 5 10\"\n focusable=\"false\"\n aria-hidden=\"true\"><polygon points=\"0,0 5,5 0,10\"/></svg>\n}\n",
135
+ dependencies: [{
136
+ kind: "directive",
137
+ type: MatRipple,
138
+ selector: "[mat-ripple], [matRipple]",
139
+ inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"],
140
+ exportAs: ["matRipple"]
141
+ }],
142
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
143
+ encapsulation: i0.ViewEncapsulation.None
144
+ });
126
145
  }
127
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuItem, decorators: [{
128
- type: Component,
129
- args: [{ selector: '[mat-menu-item]', exportAs: 'matMenuItem', host: {
130
- '[attr.role]': 'role',
131
- 'class': 'mat-mdc-menu-item mat-focus-indicator',
132
- '[class.mat-mdc-menu-item-highlighted]': '_highlighted',
133
- '[class.mat-mdc-menu-item-submenu-trigger]': '_triggersSubmenu',
134
- '[attr.tabindex]': '_getTabIndex()',
135
- '[attr.aria-disabled]': 'disabled',
136
- '[attr.disabled]': 'disabled || null',
137
- '(click)': '_checkDisabled($event)',
138
- '(mouseenter)': '_handleMouseEnter()',
139
- }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [MatRipple], template: "<ng-content select=\"mat-icon, [matMenuItemIcon]\"></ng-content>\n<span class=\"mat-mdc-menu-item-text\"><ng-content></ng-content></span>\n<div class=\"mat-mdc-menu-ripple\" matRipple\n [matRippleDisabled]=\"disableRipple || disabled\"\n [matRippleTrigger]=\"_getHostElement()\">\n</div>\n\n@if (_triggersSubmenu) {\n <svg\n class=\"mat-mdc-menu-submenu-icon\"\n viewBox=\"0 0 5 10\"\n focusable=\"false\"\n aria-hidden=\"true\"><polygon points=\"0,0 5,5 0,10\"/></svg>\n}\n" }]
140
- }], ctorParameters: () => [], propDecorators: { role: [{
141
- type: Input
142
- }], disabled: [{
143
- type: Input,
144
- args: [{ transform: booleanAttribute }]
145
- }], disableRipple: [{
146
- type: Input,
147
- args: [{ transform: booleanAttribute }]
148
- }] } });
146
+ i0.ɵɵngDeclareClassMetadata({
147
+ minVersion: "12.0.0",
148
+ version: "20.2.0-next.2",
149
+ ngImport: i0,
150
+ type: MatMenuItem,
151
+ decorators: [{
152
+ type: Component,
153
+ args: [{
154
+ selector: '[mat-menu-item]',
155
+ exportAs: 'matMenuItem',
156
+ host: {
157
+ '[attr.role]': 'role',
158
+ 'class': 'mat-mdc-menu-item mat-focus-indicator',
159
+ '[class.mat-mdc-menu-item-highlighted]': '_highlighted',
160
+ '[class.mat-mdc-menu-item-submenu-trigger]': '_triggersSubmenu',
161
+ '[attr.tabindex]': '_getTabIndex()',
162
+ '[attr.aria-disabled]': 'disabled',
163
+ '[attr.disabled]': 'disabled || null',
164
+ '(click)': '_checkDisabled($event)',
165
+ '(mouseenter)': '_handleMouseEnter()'
166
+ },
167
+ changeDetection: ChangeDetectionStrategy.OnPush,
168
+ encapsulation: ViewEncapsulation.None,
169
+ imports: [MatRipple],
170
+ template: "<ng-content select=\"mat-icon, [matMenuItemIcon]\"></ng-content>\n<span class=\"mat-mdc-menu-item-text\"><ng-content></ng-content></span>\n<div class=\"mat-mdc-menu-ripple\" matRipple\n [matRippleDisabled]=\"disableRipple || disabled\"\n [matRippleTrigger]=\"_getHostElement()\">\n</div>\n\n@if (_triggersSubmenu) {\n <svg\n class=\"mat-mdc-menu-submenu-icon\"\n viewBox=\"0 0 5 10\"\n focusable=\"false\"\n aria-hidden=\"true\"><polygon points=\"0,0 5,5 0,10\"/></svg>\n}\n"
171
+ }]
172
+ }],
173
+ ctorParameters: () => [],
174
+ propDecorators: {
175
+ role: [{
176
+ type: Input
177
+ }],
178
+ disabled: [{
179
+ type: Input,
180
+ args: [{
181
+ transform: booleanAttribute
182
+ }]
183
+ }],
184
+ disableRipple: [{
185
+ type: Input,
186
+ args: [{
187
+ transform: booleanAttribute
188
+ }]
189
+ }]
190
+ }
191
+ });
149
192
 
150
- /**
151
- * Throws an exception for the case when menu's x-position value isn't valid.
152
- * In other words, it doesn't match 'before' or 'after'.
153
- * @docs-private
154
- */
155
193
  function throwMatMenuInvalidPositionX() {
156
- throw Error(`xPosition value must be either 'before' or after'.
194
+ throw Error(`xPosition value must be either 'before' or after'.
157
195
  Example: <mat-menu xPosition="before" #menu="matMenu"></mat-menu>`);
158
196
  }
159
- /**
160
- * Throws an exception for the case when menu's y-position value isn't valid.
161
- * In other words, it doesn't match 'above' or 'below'.
162
- * @docs-private
163
- */
164
197
  function throwMatMenuInvalidPositionY() {
165
- throw Error(`yPosition value must be either 'above' or below'.
198
+ throw Error(`yPosition value must be either 'above' or below'.
166
199
  Example: <mat-menu yPosition="above" #menu="matMenu"></mat-menu>`);
167
200
  }
168
- /**
169
- * Throws an exception for the case when a menu is assigned
170
- * to a trigger that is placed inside the same menu.
171
- * @docs-private
172
- */
173
201
  function throwMatMenuRecursiveError() {
174
- throw Error(`matMenuTriggerFor: menu cannot contain its own trigger. Assign a menu that is ` +
175
- `not a parent of the trigger or move the trigger outside of the menu.`);
202
+ throw Error(`matMenuTriggerFor: menu cannot contain its own trigger. Assign a menu that is ` + `not a parent of the trigger or move the trigger outside of the menu.`);
176
203
  }
177
204
 
178
- /**
179
- * Injection token that can be used to reference instances of `MatMenuContent`. It serves
180
- * as alternative token to the actual `MatMenuContent` class which could cause unnecessary
181
- * retention of the class and its directive metadata.
182
- */
183
205
  const MAT_MENU_CONTENT = new InjectionToken('MatMenuContent');
184
- /** Menu content that will be rendered lazily once the menu is opened. */
185
206
  class MatMenuContent {
186
- _template = inject(TemplateRef);
187
- _appRef = inject(ApplicationRef);
188
- _injector = inject(Injector);
189
- _viewContainerRef = inject(ViewContainerRef);
190
- _document = inject(DOCUMENT);
191
- _changeDetectorRef = inject(ChangeDetectorRef);
192
- _portal;
193
- _outlet;
194
- /** Emits when the menu content has been attached. */
195
- _attached = new Subject();
196
- constructor() { }
197
- /**
198
- * Attaches the content with a particular context.
199
- * @docs-private
200
- */
201
- attach(context = {}) {
202
- if (!this._portal) {
203
- this._portal = new TemplatePortal(this._template, this._viewContainerRef);
204
- }
205
- this.detach();
206
- if (!this._outlet) {
207
- this._outlet = new DomPortalOutlet(this._document.createElement('div'), this._appRef, this._injector);
208
- }
209
- const element = this._template.elementRef.nativeElement;
210
- // Because we support opening the same menu from different triggers (which in turn have their
211
- // own `OverlayRef` panel), we have to re-insert the host element every time, otherwise we
212
- // risk it staying attached to a pane that's no longer in the DOM.
213
- element.parentNode.insertBefore(this._outlet.outletElement, element);
214
- // When `MatMenuContent` is used in an `OnPush` component, the insertion of the menu
215
- // content via `createEmbeddedView` does not cause the content to be seen as "dirty"
216
- // by Angular. This causes the `@ContentChildren` for menu items within the menu to
217
- // not be updated by Angular. By explicitly marking for check here, we tell Angular that
218
- // it needs to check for new menu items and update the `@ContentChild` in `MatMenu`.
219
- this._changeDetectorRef.markForCheck();
220
- this._portal.attach(this._outlet, context);
221
- this._attached.next();
222
- }
223
- /**
224
- * Detaches the content.
225
- * @docs-private
226
- */
227
- detach() {
228
- if (this._portal?.isAttached) {
229
- this._portal.detach();
230
- }
231
- }
232
- ngOnDestroy() {
233
- this.detach();
234
- this._outlet?.dispose();
235
- }
236
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
237
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: MatMenuContent, isStandalone: true, selector: "ng-template[matMenuContent]", providers: [{ provide: MAT_MENU_CONTENT, useExisting: MatMenuContent }], ngImport: i0 });
207
+ _template = inject(TemplateRef);
208
+ _appRef = inject(ApplicationRef);
209
+ _injector = inject(Injector);
210
+ _viewContainerRef = inject(ViewContainerRef);
211
+ _document = inject(DOCUMENT);
212
+ _changeDetectorRef = inject(ChangeDetectorRef);
213
+ _portal;
214
+ _outlet;
215
+ _attached = new Subject();
216
+ constructor() {}
217
+ attach(context = {}) {
218
+ if (!this._portal) {
219
+ this._portal = new TemplatePortal(this._template, this._viewContainerRef);
220
+ }
221
+ this.detach();
222
+ if (!this._outlet) {
223
+ this._outlet = new DomPortalOutlet(this._document.createElement('div'), this._appRef, this._injector);
224
+ }
225
+ const element = this._template.elementRef.nativeElement;
226
+ element.parentNode.insertBefore(this._outlet.outletElement, element);
227
+ this._changeDetectorRef.markForCheck();
228
+ this._portal.attach(this._outlet, context);
229
+ this._attached.next();
230
+ }
231
+ detach() {
232
+ if (this._portal?.isAttached) {
233
+ this._portal.detach();
234
+ }
235
+ }
236
+ ngOnDestroy() {
237
+ this.detach();
238
+ this._outlet?.dispose();
239
+ }
240
+ static ɵfac = i0.ɵɵngDeclareFactory({
241
+ minVersion: "12.0.0",
242
+ version: "20.2.0-next.2",
243
+ ngImport: i0,
244
+ type: MatMenuContent,
245
+ deps: [],
246
+ target: i0.ɵɵFactoryTarget.Directive
247
+ });
248
+ static ɵdir = i0.ɵɵngDeclareDirective({
249
+ minVersion: "14.0.0",
250
+ version: "20.2.0-next.2",
251
+ type: MatMenuContent,
252
+ isStandalone: true,
253
+ selector: "ng-template[matMenuContent]",
254
+ providers: [{
255
+ provide: MAT_MENU_CONTENT,
256
+ useExisting: MatMenuContent
257
+ }],
258
+ ngImport: i0
259
+ });
238
260
  }
239
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuContent, decorators: [{
240
- type: Directive,
241
- args: [{
242
- selector: 'ng-template[matMenuContent]',
243
- providers: [{ provide: MAT_MENU_CONTENT, useExisting: MatMenuContent }],
244
- }]
245
- }], ctorParameters: () => [] });
261
+ i0.ɵɵngDeclareClassMetadata({
262
+ minVersion: "12.0.0",
263
+ version: "20.2.0-next.2",
264
+ ngImport: i0,
265
+ type: MatMenuContent,
266
+ decorators: [{
267
+ type: Directive,
268
+ args: [{
269
+ selector: 'ng-template[matMenuContent]',
270
+ providers: [{
271
+ provide: MAT_MENU_CONTENT,
272
+ useExisting: MatMenuContent
273
+ }]
274
+ }]
275
+ }],
276
+ ctorParameters: () => []
277
+ });
246
278
 
247
- /** Injection token to be used to override the default options for `mat-menu`. */
248
279
  const MAT_MENU_DEFAULT_OPTIONS = new InjectionToken('mat-menu-default-options', {
249
- providedIn: 'root',
250
- factory: () => ({
251
- overlapTrigger: false,
252
- xPosition: 'after',
253
- yPosition: 'below',
254
- backdropClass: 'cdk-overlay-transparent-backdrop',
255
- }),
280
+ providedIn: 'root',
281
+ factory: () => ({
282
+ overlapTrigger: false,
283
+ xPosition: 'after',
284
+ yPosition: 'below',
285
+ backdropClass: 'cdk-overlay-transparent-backdrop'
286
+ })
256
287
  });
257
- /** Name of the enter animation `@keyframes`. */
258
288
  const ENTER_ANIMATION = '_mat-menu-enter';
259
- /** Name of the exit animation `@keyframes`. */
260
289
  const EXIT_ANIMATION = '_mat-menu-exit';
261
290
  class MatMenu {
262
- _elementRef = inject(ElementRef);
263
- _changeDetectorRef = inject(ChangeDetectorRef);
264
- _injector = inject(Injector);
265
- _keyManager;
266
- _xPosition;
267
- _yPosition;
268
- _firstItemFocusRef;
269
- _exitFallbackTimeout;
270
- /** Whether animations are currently disabled. */
271
- _animationsDisabled = _animationsDisabled();
272
- /** All items inside the menu. Includes items nested inside another menu. */
273
- _allItems;
274
- /** Only the direct descendant menu items. */
275
- _directDescendantItems = new QueryList();
276
- /** Classes to be applied to the menu panel. */
277
- _classList = {};
278
- /** Current state of the panel animation. */
279
- _panelAnimationState = 'void';
280
- /** Emits whenever an animation on the menu completes. */
281
- _animationDone = new Subject();
282
- /** Whether the menu is animating. */
283
- _isAnimating = signal(false, ...(ngDevMode ? [{ debugName: "_isAnimating" }] : []));
284
- /** Parent menu of the current menu panel. */
285
- parentMenu;
286
- /** Layout direction of the menu. */
287
- direction;
288
- /** Class or list of classes to be added to the overlay panel. */
289
- overlayPanelClass;
290
- /** Class to be added to the backdrop element. */
291
- backdropClass;
292
- /** aria-label for the menu panel. */
293
- ariaLabel;
294
- /** aria-labelledby for the menu panel. */
295
- ariaLabelledby;
296
- /** aria-describedby for the menu panel. */
297
- ariaDescribedby;
298
- /** Position of the menu in the X axis. */
299
- get xPosition() {
300
- return this._xPosition;
301
- }
302
- set xPosition(value) {
303
- if (value !== 'before' &&
304
- value !== 'after' &&
305
- (typeof ngDevMode === 'undefined' || ngDevMode)) {
306
- throwMatMenuInvalidPositionX();
307
- }
308
- this._xPosition = value;
309
- this.setPositionClasses();
310
- }
311
- /** Position of the menu in the Y axis. */
312
- get yPosition() {
313
- return this._yPosition;
314
- }
315
- set yPosition(value) {
316
- if (value !== 'above' && value !== 'below' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
317
- throwMatMenuInvalidPositionY();
318
- }
319
- this._yPosition = value;
320
- this.setPositionClasses();
321
- }
322
- /** @docs-private */
323
- templateRef;
324
- /**
325
- * List of the items inside of a menu.
326
- * @deprecated
327
- * @breaking-change 8.0.0
328
- */
329
- items;
330
- /**
331
- * Menu content that will be rendered lazily.
332
- * @docs-private
333
- */
334
- lazyContent;
335
- /** Whether the menu should overlap its trigger. */
336
- overlapTrigger;
337
- /** Whether the menu has a backdrop. */
338
- hasBackdrop;
339
- /**
340
- * This method takes classes set on the host mat-menu element and applies them on the
341
- * menu template that displays in the overlay container. Otherwise, it's difficult
342
- * to style the containing menu from outside the component.
343
- * @param classes list of class names
344
- */
345
- set panelClass(classes) {
346
- const previousPanelClass = this._previousPanelClass;
347
- const newClassList = { ...this._classList };
348
- if (previousPanelClass && previousPanelClass.length) {
349
- previousPanelClass.split(' ').forEach((className) => {
350
- newClassList[className] = false;
351
- });
352
- }
353
- this._previousPanelClass = classes;
354
- if (classes && classes.length) {
355
- classes.split(' ').forEach((className) => {
356
- newClassList[className] = true;
357
- });
358
- this._elementRef.nativeElement.className = '';
359
- }
360
- this._classList = newClassList;
361
- }
362
- _previousPanelClass;
363
- /**
364
- * This method takes classes set on the host mat-menu element and applies them on the
365
- * menu template that displays in the overlay container. Otherwise, it's difficult
366
- * to style the containing menu from outside the component.
367
- * @deprecated Use `panelClass` instead.
368
- * @breaking-change 8.0.0
369
- */
370
- get classList() {
371
- return this.panelClass;
372
- }
373
- set classList(classes) {
374
- this.panelClass = classes;
375
- }
376
- /** Event emitted when the menu is closed. */
377
- closed = new EventEmitter();
378
- /**
379
- * Event emitted when the menu is closed.
380
- * @deprecated Switch to `closed` instead
381
- * @breaking-change 8.0.0
382
- */
383
- close = this.closed;
384
- panelId = inject(_IdGenerator).getId('mat-menu-panel-');
385
- constructor() {
386
- const defaultOptions = inject(MAT_MENU_DEFAULT_OPTIONS);
387
- this.overlayPanelClass = defaultOptions.overlayPanelClass || '';
388
- this._xPosition = defaultOptions.xPosition;
389
- this._yPosition = defaultOptions.yPosition;
390
- this.backdropClass = defaultOptions.backdropClass;
391
- this.overlapTrigger = defaultOptions.overlapTrigger;
392
- this.hasBackdrop = defaultOptions.hasBackdrop;
393
- }
394
- ngOnInit() {
395
- this.setPositionClasses();
396
- }
397
- ngAfterContentInit() {
398
- this._updateDirectDescendants();
399
- this._keyManager = new FocusKeyManager(this._directDescendantItems)
400
- .withWrap()
401
- .withTypeAhead()
402
- .withHomeAndEnd();
403
- this._keyManager.tabOut.subscribe(() => this.closed.emit('tab'));
404
- // If a user manually (programmatically) focuses a menu item, we need to reflect that focus
405
- // change back to the key manager. Note that we don't need to unsubscribe here because _focused
406
- // is internal and we know that it gets completed on destroy.
407
- this._directDescendantItems.changes
408
- .pipe(startWith(this._directDescendantItems), switchMap(items => merge(...items.map((item) => item._focused))))
409
- .subscribe(focusedItem => this._keyManager.updateActiveItem(focusedItem));
410
- this._directDescendantItems.changes.subscribe((itemsList) => {
411
- // Move focus to another item, if the active item is removed from the list.
412
- // We need to debounce the callback, because multiple items might be removed
413
- // in quick succession.
414
- const manager = this._keyManager;
415
- if (this._panelAnimationState === 'enter' && manager.activeItem?._hasFocus()) {
416
- const items = itemsList.toArray();
417
- const index = Math.max(0, Math.min(items.length - 1, manager.activeItemIndex || 0));
418
- if (items[index] && !items[index].disabled) {
419
- manager.setActiveItem(index);
420
- }
421
- else {
422
- manager.setNextItemActive();
423
- }
424
- }
425
- });
426
- }
427
- ngOnDestroy() {
428
- this._keyManager?.destroy();
429
- this._directDescendantItems.destroy();
430
- this.closed.complete();
431
- this._firstItemFocusRef?.destroy();
432
- clearTimeout(this._exitFallbackTimeout);
433
- }
434
- /** Stream that emits whenever the hovered menu item changes. */
435
- _hovered() {
436
- // Coerce the `changes` property because Angular types it as `Observable<any>`
437
- const itemChanges = this._directDescendantItems.changes;
438
- return itemChanges.pipe(startWith(this._directDescendantItems), switchMap(items => merge(...items.map((item) => item._hovered))));
439
- }
440
- /*
441
- * Registers a menu item with the menu.
442
- * @docs-private
443
- * @deprecated No longer being used. To be removed.
444
- * @breaking-change 9.0.0
445
- */
446
- addItem(_item) { }
447
- /**
448
- * Removes an item from the menu.
449
- * @docs-private
450
- * @deprecated No longer being used. To be removed.
451
- * @breaking-change 9.0.0
452
- */
453
- removeItem(_item) { }
454
- /** Handle a keyboard event from the menu, delegating to the appropriate action. */
455
- _handleKeydown(event) {
456
- const keyCode = event.keyCode;
457
- const manager = this._keyManager;
458
- switch (keyCode) {
459
- case ESCAPE:
460
- if (!hasModifierKey(event)) {
461
- event.preventDefault();
462
- this.closed.emit('keydown');
463
- }
464
- break;
465
- case LEFT_ARROW:
466
- if (this.parentMenu && this.direction === 'ltr') {
467
- this.closed.emit('keydown');
468
- }
469
- break;
470
- case RIGHT_ARROW:
471
- if (this.parentMenu && this.direction === 'rtl') {
472
- this.closed.emit('keydown');
473
- }
474
- break;
475
- default:
476
- if (keyCode === UP_ARROW || keyCode === DOWN_ARROW) {
477
- manager.setFocusOrigin('keyboard');
478
- }
479
- manager.onKeydown(event);
480
- return;
291
+ _elementRef = inject(ElementRef);
292
+ _changeDetectorRef = inject(ChangeDetectorRef);
293
+ _injector = inject(Injector);
294
+ _keyManager;
295
+ _xPosition;
296
+ _yPosition;
297
+ _firstItemFocusRef;
298
+ _exitFallbackTimeout;
299
+ _animationsDisabled = _animationsDisabled();
300
+ _allItems;
301
+ _directDescendantItems = new QueryList();
302
+ _classList = {};
303
+ _panelAnimationState = 'void';
304
+ _animationDone = new Subject();
305
+ _isAnimating = signal(false, ...(ngDevMode ? [{
306
+ debugName: "_isAnimating"
307
+ }] : []));
308
+ parentMenu;
309
+ direction;
310
+ overlayPanelClass;
311
+ backdropClass;
312
+ ariaLabel;
313
+ ariaLabelledby;
314
+ ariaDescribedby;
315
+ get xPosition() {
316
+ return this._xPosition;
317
+ }
318
+ set xPosition(value) {
319
+ if (value !== 'before' && value !== 'after' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
320
+ throwMatMenuInvalidPositionX();
321
+ }
322
+ this._xPosition = value;
323
+ this.setPositionClasses();
324
+ }
325
+ get yPosition() {
326
+ return this._yPosition;
327
+ }
328
+ set yPosition(value) {
329
+ if (value !== 'above' && value !== 'below' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
330
+ throwMatMenuInvalidPositionY();
331
+ }
332
+ this._yPosition = value;
333
+ this.setPositionClasses();
334
+ }
335
+ templateRef;
336
+ items;
337
+ lazyContent;
338
+ overlapTrigger;
339
+ hasBackdrop;
340
+ set panelClass(classes) {
341
+ const previousPanelClass = this._previousPanelClass;
342
+ const newClassList = {
343
+ ...this._classList
344
+ };
345
+ if (previousPanelClass && previousPanelClass.length) {
346
+ previousPanelClass.split(' ').forEach(className => {
347
+ newClassList[className] = false;
348
+ });
349
+ }
350
+ this._previousPanelClass = classes;
351
+ if (classes && classes.length) {
352
+ classes.split(' ').forEach(className => {
353
+ newClassList[className] = true;
354
+ });
355
+ this._elementRef.nativeElement.className = '';
356
+ }
357
+ this._classList = newClassList;
358
+ }
359
+ _previousPanelClass;
360
+ get classList() {
361
+ return this.panelClass;
362
+ }
363
+ set classList(classes) {
364
+ this.panelClass = classes;
365
+ }
366
+ closed = new EventEmitter();
367
+ close = this.closed;
368
+ panelId = inject(_IdGenerator).getId('mat-menu-panel-');
369
+ constructor() {
370
+ const defaultOptions = inject(MAT_MENU_DEFAULT_OPTIONS);
371
+ this.overlayPanelClass = defaultOptions.overlayPanelClass || '';
372
+ this._xPosition = defaultOptions.xPosition;
373
+ this._yPosition = defaultOptions.yPosition;
374
+ this.backdropClass = defaultOptions.backdropClass;
375
+ this.overlapTrigger = defaultOptions.overlapTrigger;
376
+ this.hasBackdrop = defaultOptions.hasBackdrop;
377
+ }
378
+ ngOnInit() {
379
+ this.setPositionClasses();
380
+ }
381
+ ngAfterContentInit() {
382
+ this._updateDirectDescendants();
383
+ this._keyManager = new FocusKeyManager(this._directDescendantItems).withWrap().withTypeAhead().withHomeAndEnd();
384
+ this._keyManager.tabOut.subscribe(() => this.closed.emit('tab'));
385
+ this._directDescendantItems.changes.pipe(startWith(this._directDescendantItems), switchMap(items => merge(...items.map(item => item._focused)))).subscribe(focusedItem => this._keyManager.updateActiveItem(focusedItem));
386
+ this._directDescendantItems.changes.subscribe(itemsList => {
387
+ const manager = this._keyManager;
388
+ if (this._panelAnimationState === 'enter' && manager.activeItem?._hasFocus()) {
389
+ const items = itemsList.toArray();
390
+ const index = Math.max(0, Math.min(items.length - 1, manager.activeItemIndex || 0));
391
+ if (items[index] && !items[index].disabled) {
392
+ manager.setActiveItem(index);
393
+ } else {
394
+ manager.setNextItemActive();
481
395
  }
482
- }
483
- /**
484
- * Focus the first item in the menu.
485
- * @param origin Action from which the focus originated. Used to set the correct styling.
486
- */
487
- focusFirstItem(origin = 'program') {
488
- // Wait for `afterNextRender` to ensure iOS VoiceOver screen reader focuses the first item (#24735).
489
- this._firstItemFocusRef?.destroy();
490
- this._firstItemFocusRef = afterNextRender(() => {
491
- const menuPanel = this._resolvePanel();
492
- // If an item in the menuPanel is already focused, avoid overriding the focus.
493
- if (!menuPanel || !menuPanel.contains(document.activeElement)) {
494
- const manager = this._keyManager;
495
- manager.setFocusOrigin(origin).setFirstItemActive();
496
- // If there's no active item at this point, it means that all the items are disabled.
497
- // Move focus to the menuPanel panel so keyboard events like Escape still work. Also this will
498
- // give _some_ feedback to screen readers.
499
- if (!manager.activeItem && menuPanel) {
500
- menuPanel.focus();
501
- }
502
- }
503
- }, { injector: this._injector });
504
- }
505
- /**
506
- * Resets the active item in the menu. This is used when the menu is opened, allowing
507
- * the user to start from the first option when pressing the down arrow.
508
- */
509
- resetActiveItem() {
510
- this._keyManager.setActiveItem(-1);
511
- }
512
- /**
513
- * @deprecated No longer used and will be removed.
514
- * @breaking-change 21.0.0
515
- */
516
- setElevation(_depth) { }
517
- /**
518
- * Adds classes to the menu panel based on its position. Can be used by
519
- * consumers to add specific styling based on the position.
520
- * @param posX Position of the menu along the x axis.
521
- * @param posY Position of the menu along the y axis.
522
- * @docs-private
523
- */
524
- setPositionClasses(posX = this.xPosition, posY = this.yPosition) {
525
- this._classList = {
526
- ...this._classList,
527
- ['mat-menu-before']: posX === 'before',
528
- ['mat-menu-after']: posX === 'after',
529
- ['mat-menu-above']: posY === 'above',
530
- ['mat-menu-below']: posY === 'below',
531
- };
532
- this._changeDetectorRef.markForCheck();
533
- }
534
- /** Callback that is invoked when the panel animation completes. */
535
- _onAnimationDone(state) {
536
- const isExit = state === EXIT_ANIMATION;
537
- if (isExit || state === ENTER_ANIMATION) {
538
- if (isExit) {
539
- clearTimeout(this._exitFallbackTimeout);
540
- this._exitFallbackTimeout = undefined;
541
- }
542
- this._animationDone.next(isExit ? 'void' : 'enter');
543
- this._isAnimating.set(false);
396
+ }
397
+ });
398
+ }
399
+ ngOnDestroy() {
400
+ this._keyManager?.destroy();
401
+ this._directDescendantItems.destroy();
402
+ this.closed.complete();
403
+ this._firstItemFocusRef?.destroy();
404
+ clearTimeout(this._exitFallbackTimeout);
405
+ }
406
+ _hovered() {
407
+ const itemChanges = this._directDescendantItems.changes;
408
+ return itemChanges.pipe(startWith(this._directDescendantItems), switchMap(items => merge(...items.map(item => item._hovered))));
409
+ }
410
+ addItem(_item) {}
411
+ removeItem(_item) {}
412
+ _handleKeydown(event) {
413
+ const keyCode = event.keyCode;
414
+ const manager = this._keyManager;
415
+ switch (keyCode) {
416
+ case ESCAPE:
417
+ if (!hasModifierKey(event)) {
418
+ event.preventDefault();
419
+ this.closed.emit('keydown');
544
420
  }
545
- }
546
- _onAnimationStart(state) {
547
- if (state === ENTER_ANIMATION || state === EXIT_ANIMATION) {
548
- this._isAnimating.set(true);
421
+ break;
422
+ case LEFT_ARROW:
423
+ if (this.parentMenu && this.direction === 'ltr') {
424
+ this.closed.emit('keydown');
549
425
  }
550
- }
551
- _setIsOpen(isOpen) {
552
- this._panelAnimationState = isOpen ? 'enter' : 'void';
553
- if (isOpen) {
554
- if (this._keyManager.activeItemIndex === 0) {
555
- // Scroll the content element to the top as soon as the animation starts. This is necessary,
556
- // because we move focus to the first item while it's still being animated, which can throw
557
- // the browser off when it determines the scroll position. Alternatively we can move focus
558
- // when the animation is done, however moving focus asynchronously will interrupt screen
559
- // readers which are in the process of reading out the menu already. We take the `element`
560
- // from the `event` since we can't use a `ViewChild` to access the pane.
561
- const menuPanel = this._resolvePanel();
562
- if (menuPanel) {
563
- menuPanel.scrollTop = 0;
564
- }
565
- }
426
+ break;
427
+ case RIGHT_ARROW:
428
+ if (this.parentMenu && this.direction === 'rtl') {
429
+ this.closed.emit('keydown');
566
430
  }
567
- else if (!this._animationsDisabled) {
568
- // Some apps do `* { animation: none !important; }` in tests which will prevent the
569
- // `animationend` event from firing. Since the exit animation is loading-bearing for
570
- // removing the content from the DOM, add a fallback timer.
571
- this._exitFallbackTimeout = setTimeout(() => this._onAnimationDone(EXIT_ANIMATION), 200);
431
+ break;
432
+ default:
433
+ if (keyCode === UP_ARROW || keyCode === DOWN_ARROW) {
434
+ manager.setFocusOrigin('keyboard');
572
435
  }
573
- // Animation events won't fire when animations are disabled so we simulate them.
574
- if (this._animationsDisabled) {
575
- setTimeout(() => {
576
- this._onAnimationDone(isOpen ? ENTER_ANIMATION : EXIT_ANIMATION);
577
- });
436
+ manager.onKeydown(event);
437
+ return;
438
+ }
439
+ }
440
+ focusFirstItem(origin = 'program') {
441
+ this._firstItemFocusRef?.destroy();
442
+ this._firstItemFocusRef = afterNextRender(() => {
443
+ const menuPanel = this._resolvePanel();
444
+ if (!menuPanel || !menuPanel.contains(document.activeElement)) {
445
+ const manager = this._keyManager;
446
+ manager.setFocusOrigin(origin).setFirstItemActive();
447
+ if (!manager.activeItem && menuPanel) {
448
+ menuPanel.focus();
578
449
  }
579
- this._changeDetectorRef.markForCheck();
580
- }
581
- /**
582
- * Sets up a stream that will keep track of any newly-added menu items and will update the list
583
- * of direct descendants. We collect the descendants this way, because `_allItems` can include
584
- * items that are part of child menus, and using a custom way of registering items is unreliable
585
- * when it comes to maintaining the item order.
586
- */
587
- _updateDirectDescendants() {
588
- this._allItems.changes
589
- .pipe(startWith(this._allItems))
590
- .subscribe((items) => {
591
- this._directDescendantItems.reset(items.filter(item => item._parentMenu === this));
592
- this._directDescendantItems.notifyOnChanges();
593
- });
594
- }
595
- /** Gets the menu panel DOM node. */
596
- _resolvePanel() {
597
- let menuPanel = null;
598
- if (this._directDescendantItems.length) {
599
- // Because the `mat-menuPanel` is at the DOM insertion point, not inside the overlay, we don't
600
- // have a nice way of getting a hold of the menuPanel panel. We can't use a `ViewChild` either
601
- // because the panel is inside an `ng-template`. We work around it by starting from one of
602
- // the items and walking up the DOM.
603
- menuPanel = this._directDescendantItems.first._getHostElement().closest('[role="menu"]');
450
+ }
451
+ }, {
452
+ injector: this._injector
453
+ });
454
+ }
455
+ resetActiveItem() {
456
+ this._keyManager.setActiveItem(-1);
457
+ }
458
+ setElevation(_depth) {}
459
+ setPositionClasses(posX = this.xPosition, posY = this.yPosition) {
460
+ this._classList = {
461
+ ...this._classList,
462
+ ['mat-menu-before']: posX === 'before',
463
+ ['mat-menu-after']: posX === 'after',
464
+ ['mat-menu-above']: posY === 'above',
465
+ ['mat-menu-below']: posY === 'below'
466
+ };
467
+ this._changeDetectorRef.markForCheck();
468
+ }
469
+ _onAnimationDone(state) {
470
+ const isExit = state === EXIT_ANIMATION;
471
+ if (isExit || state === ENTER_ANIMATION) {
472
+ if (isExit) {
473
+ clearTimeout(this._exitFallbackTimeout);
474
+ this._exitFallbackTimeout = undefined;
475
+ }
476
+ this._animationDone.next(isExit ? 'void' : 'enter');
477
+ this._isAnimating.set(false);
478
+ }
479
+ }
480
+ _onAnimationStart(state) {
481
+ if (state === ENTER_ANIMATION || state === EXIT_ANIMATION) {
482
+ this._isAnimating.set(true);
483
+ }
484
+ }
485
+ _setIsOpen(isOpen) {
486
+ this._panelAnimationState = isOpen ? 'enter' : 'void';
487
+ if (isOpen) {
488
+ if (this._keyManager.activeItemIndex === 0) {
489
+ const menuPanel = this._resolvePanel();
490
+ if (menuPanel) {
491
+ menuPanel.scrollTop = 0;
604
492
  }
605
- return menuPanel;
606
- }
607
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
608
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "20.2.0-next.2", type: MatMenu, isStandalone: true, selector: "mat-menu", inputs: { backdropClass: "backdropClass", ariaLabel: ["aria-label", "ariaLabel"], ariaLabelledby: ["aria-labelledby", "ariaLabelledby"], ariaDescribedby: ["aria-describedby", "ariaDescribedby"], xPosition: "xPosition", yPosition: "yPosition", overlapTrigger: ["overlapTrigger", "overlapTrigger", booleanAttribute], hasBackdrop: ["hasBackdrop", "hasBackdrop", (value) => (value == null ? null : booleanAttribute(value))], panelClass: ["class", "panelClass"], classList: "classList" }, outputs: { closed: "closed", close: "close" }, host: { properties: { "attr.aria-label": "null", "attr.aria-labelledby": "null", "attr.aria-describedby": "null" } }, providers: [{ provide: MAT_MENU_PANEL, useExisting: MatMenu }], queries: [{ propertyName: "lazyContent", first: true, predicate: MAT_MENU_CONTENT, descendants: true }, { propertyName: "_allItems", predicate: MatMenuItem, descendants: true }, { propertyName: "items", predicate: MatMenuItem }], viewQueries: [{ propertyName: "templateRef", first: true, predicate: TemplateRef, descendants: true }], exportAs: ["matMenu"], ngImport: i0, template: "<ng-template>\n <div\n class=\"mat-mdc-menu-panel\"\n [id]=\"panelId\"\n [class]=\"_classList\"\n [class.mat-menu-panel-animations-disabled]=\"_animationsDisabled\"\n [class.mat-menu-panel-exit-animation]=\"_panelAnimationState === 'void'\"\n [class.mat-menu-panel-animating]=\"_isAnimating()\"\n (click)=\"closed.emit('click')\"\n tabindex=\"-1\"\n role=\"menu\"\n (animationstart)=\"_onAnimationStart($event.animationName)\"\n (animationend)=\"_onAnimationDone($event.animationName)\"\n (animationcancel)=\"_onAnimationDone($event.animationName)\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"ariaLabelledby || null\"\n [attr.aria-describedby]=\"ariaDescribedby || null\">\n <div class=\"mat-mdc-menu-content\">\n <ng-content></ng-content>\n </div>\n </div>\n</ng-template>\n", styles: ["mat-menu{display:none}.mat-mdc-menu-content{margin:0;padding:8px 0;outline:0}.mat-mdc-menu-content,.mat-mdc-menu-content .mat-mdc-menu-item .mat-mdc-menu-item-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;flex:1;white-space:normal;font-family:var(--mat-menu-item-label-text-font, var(--mat-sys-label-large-font));line-height:var(--mat-menu-item-label-text-line-height, var(--mat-sys-label-large-line-height));font-size:var(--mat-menu-item-label-text-size, var(--mat-sys-label-large-size));letter-spacing:var(--mat-menu-item-label-text-tracking, var(--mat-sys-label-large-tracking));font-weight:var(--mat-menu-item-label-text-weight, var(--mat-sys-label-large-weight))}@keyframes _mat-menu-enter{from{opacity:0;transform:scale(0.8)}to{opacity:1;transform:none}}@keyframes _mat-menu-exit{from{opacity:1}to{opacity:0}}.mat-mdc-menu-panel{min-width:112px;max-width:280px;overflow:auto;box-sizing:border-box;outline:0;animation:_mat-menu-enter 120ms cubic-bezier(0, 0, 0.2, 1);border-radius:var(--mat-menu-container-shape, var(--mat-sys-corner-extra-small));background-color:var(--mat-menu-container-color, var(--mat-sys-surface-container));box-shadow:var(--mat-menu-container-elevation-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));will-change:transform,opacity}.mat-mdc-menu-panel.mat-menu-panel-exit-animation{animation:_mat-menu-exit 100ms 25ms linear forwards}.mat-mdc-menu-panel.mat-menu-panel-animations-disabled{animation:none}.mat-mdc-menu-panel.mat-menu-panel-animating{pointer-events:none}.mat-mdc-menu-panel.mat-menu-panel-animating:has(.mat-mdc-menu-content:empty){display:none}@media(forced-colors: active){.mat-mdc-menu-panel{outline:solid 1px}}.mat-mdc-menu-panel .mat-divider{border-top-color:var(--mat-menu-divider-color, var(--mat-sys-surface-variant));margin-bottom:var(--mat-menu-divider-bottom-spacing, 8px);margin-top:var(--mat-menu-divider-top-spacing, 8px)}.mat-mdc-menu-item{display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;padding:0;cursor:pointer;width:100%;text-align:left;box-sizing:border-box;color:inherit;font-size:inherit;background:none;text-decoration:none;margin:0;min-height:48px;padding-left:var(--mat-menu-item-leading-spacing, 12px);padding-right:var(--mat-menu-item-trailing-spacing, 12px);-webkit-user-select:none;user-select:none;cursor:pointer;outline:none;border:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mat-mdc-menu-item::-moz-focus-inner{border:0}[dir=rtl] .mat-mdc-menu-item{padding-left:var(--mat-menu-item-trailing-spacing, 12px);padding-right:var(--mat-menu-item-leading-spacing, 12px)}.mat-mdc-menu-item:has(.material-icons,mat-icon,[matButtonIcon]){padding-left:var(--mat-menu-item-with-icon-leading-spacing, 12px);padding-right:var(--mat-menu-item-with-icon-trailing-spacing, 12px)}[dir=rtl] .mat-mdc-menu-item:has(.material-icons,mat-icon,[matButtonIcon]){padding-left:var(--mat-menu-item-with-icon-trailing-spacing, 12px);padding-right:var(--mat-menu-item-with-icon-leading-spacing, 12px)}.mat-mdc-menu-item,.mat-mdc-menu-item:visited,.mat-mdc-menu-item:link{color:var(--mat-menu-item-label-text-color, var(--mat-sys-on-surface))}.mat-mdc-menu-item .mat-icon-no-color,.mat-mdc-menu-item .mat-mdc-menu-submenu-icon{color:var(--mat-menu-item-icon-color, var(--mat-sys-on-surface-variant))}.mat-mdc-menu-item[disabled]{cursor:default;opacity:.38}.mat-mdc-menu-item[disabled]::after{display:block;position:absolute;content:\"\";top:0;left:0;bottom:0;right:0}.mat-mdc-menu-item:focus{outline:0}.mat-mdc-menu-item .mat-icon{flex-shrink:0;margin-right:var(--mat-menu-item-spacing, 12px);height:var(--mat-menu-item-icon-size, 24px);width:var(--mat-menu-item-icon-size, 24px)}[dir=rtl] .mat-mdc-menu-item{text-align:right}[dir=rtl] .mat-mdc-menu-item .mat-icon{margin-right:0;margin-left:var(--mat-menu-item-spacing, 12px)}.mat-mdc-menu-item:not([disabled]):hover{background-color:var(--mat-menu-item-hover-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-hover-state-layer-opacity) * 100%), transparent))}.mat-mdc-menu-item:not([disabled]).cdk-program-focused,.mat-mdc-menu-item:not([disabled]).cdk-keyboard-focused,.mat-mdc-menu-item:not([disabled]).mat-mdc-menu-item-highlighted{background-color:var(--mat-menu-item-focus-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-focus-state-layer-opacity) * 100%), transparent))}@media(forced-colors: active){.mat-mdc-menu-item{margin-top:1px}}.mat-mdc-menu-submenu-icon{width:var(--mat-menu-item-icon-size, 24px);height:10px;fill:currentColor;padding-left:var(--mat-menu-item-spacing, 12px)}[dir=rtl] .mat-mdc-menu-submenu-icon{padding-right:var(--mat-menu-item-spacing, 12px);padding-left:0}[dir=rtl] .mat-mdc-menu-submenu-icon polygon{transform:scaleX(-1);transform-origin:center}@media(forced-colors: active){.mat-mdc-menu-submenu-icon{fill:CanvasText}}.mat-mdc-menu-item .mat-mdc-menu-ripple{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
493
+ }
494
+ } else if (!this._animationsDisabled) {
495
+ this._exitFallbackTimeout = setTimeout(() => this._onAnimationDone(EXIT_ANIMATION), 200);
496
+ }
497
+ if (this._animationsDisabled) {
498
+ setTimeout(() => {
499
+ this._onAnimationDone(isOpen ? ENTER_ANIMATION : EXIT_ANIMATION);
500
+ });
501
+ }
502
+ this._changeDetectorRef.markForCheck();
503
+ }
504
+ _updateDirectDescendants() {
505
+ this._allItems.changes.pipe(startWith(this._allItems)).subscribe(items => {
506
+ this._directDescendantItems.reset(items.filter(item => item._parentMenu === this));
507
+ this._directDescendantItems.notifyOnChanges();
508
+ });
509
+ }
510
+ _resolvePanel() {
511
+ let menuPanel = null;
512
+ if (this._directDescendantItems.length) {
513
+ menuPanel = this._directDescendantItems.first._getHostElement().closest('[role="menu"]');
514
+ }
515
+ return menuPanel;
516
+ }
517
+ static ɵfac = i0.ɵɵngDeclareFactory({
518
+ minVersion: "12.0.0",
519
+ version: "20.2.0-next.2",
520
+ ngImport: i0,
521
+ type: MatMenu,
522
+ deps: [],
523
+ target: i0.ɵɵFactoryTarget.Component
524
+ });
525
+ static ɵcmp = i0.ɵɵngDeclareComponent({
526
+ minVersion: "16.1.0",
527
+ version: "20.2.0-next.2",
528
+ type: MatMenu,
529
+ isStandalone: true,
530
+ selector: "mat-menu",
531
+ inputs: {
532
+ backdropClass: "backdropClass",
533
+ ariaLabel: ["aria-label", "ariaLabel"],
534
+ ariaLabelledby: ["aria-labelledby", "ariaLabelledby"],
535
+ ariaDescribedby: ["aria-describedby", "ariaDescribedby"],
536
+ xPosition: "xPosition",
537
+ yPosition: "yPosition",
538
+ overlapTrigger: ["overlapTrigger", "overlapTrigger", booleanAttribute],
539
+ hasBackdrop: ["hasBackdrop", "hasBackdrop", value => value == null ? null : booleanAttribute(value)],
540
+ panelClass: ["class", "panelClass"],
541
+ classList: "classList"
542
+ },
543
+ outputs: {
544
+ closed: "closed",
545
+ close: "close"
546
+ },
547
+ host: {
548
+ properties: {
549
+ "attr.aria-label": "null",
550
+ "attr.aria-labelledby": "null",
551
+ "attr.aria-describedby": "null"
552
+ }
553
+ },
554
+ providers: [{
555
+ provide: MAT_MENU_PANEL,
556
+ useExisting: MatMenu
557
+ }],
558
+ queries: [{
559
+ propertyName: "lazyContent",
560
+ first: true,
561
+ predicate: MAT_MENU_CONTENT,
562
+ descendants: true
563
+ }, {
564
+ propertyName: "_allItems",
565
+ predicate: MatMenuItem,
566
+ descendants: true
567
+ }, {
568
+ propertyName: "items",
569
+ predicate: MatMenuItem
570
+ }],
571
+ viewQueries: [{
572
+ propertyName: "templateRef",
573
+ first: true,
574
+ predicate: TemplateRef,
575
+ descendants: true
576
+ }],
577
+ exportAs: ["matMenu"],
578
+ ngImport: i0,
579
+ template: "<ng-template>\n <div\n class=\"mat-mdc-menu-panel\"\n [id]=\"panelId\"\n [class]=\"_classList\"\n [class.mat-menu-panel-animations-disabled]=\"_animationsDisabled\"\n [class.mat-menu-panel-exit-animation]=\"_panelAnimationState === 'void'\"\n [class.mat-menu-panel-animating]=\"_isAnimating()\"\n (click)=\"closed.emit('click')\"\n tabindex=\"-1\"\n role=\"menu\"\n (animationstart)=\"_onAnimationStart($event.animationName)\"\n (animationend)=\"_onAnimationDone($event.animationName)\"\n (animationcancel)=\"_onAnimationDone($event.animationName)\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"ariaLabelledby || null\"\n [attr.aria-describedby]=\"ariaDescribedby || null\">\n <div class=\"mat-mdc-menu-content\">\n <ng-content></ng-content>\n </div>\n </div>\n</ng-template>\n",
580
+ styles: ["mat-menu{display:none}.mat-mdc-menu-content{margin:0;padding:8px 0;outline:0}.mat-mdc-menu-content,.mat-mdc-menu-content .mat-mdc-menu-item .mat-mdc-menu-item-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;flex:1;white-space:normal;font-family:var(--mat-menu-item-label-text-font, var(--mat-sys-label-large-font));line-height:var(--mat-menu-item-label-text-line-height, var(--mat-sys-label-large-line-height));font-size:var(--mat-menu-item-label-text-size, var(--mat-sys-label-large-size));letter-spacing:var(--mat-menu-item-label-text-tracking, var(--mat-sys-label-large-tracking));font-weight:var(--mat-menu-item-label-text-weight, var(--mat-sys-label-large-weight))}@keyframes _mat-menu-enter{from{opacity:0;transform:scale(0.8)}to{opacity:1;transform:none}}@keyframes _mat-menu-exit{from{opacity:1}to{opacity:0}}.mat-mdc-menu-panel{min-width:112px;max-width:280px;overflow:auto;box-sizing:border-box;outline:0;animation:_mat-menu-enter 120ms cubic-bezier(0, 0, 0.2, 1);border-radius:var(--mat-menu-container-shape, var(--mat-sys-corner-extra-small));background-color:var(--mat-menu-container-color, var(--mat-sys-surface-container));box-shadow:var(--mat-menu-container-elevation-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));will-change:transform,opacity}.mat-mdc-menu-panel.mat-menu-panel-exit-animation{animation:_mat-menu-exit 100ms 25ms linear forwards}.mat-mdc-menu-panel.mat-menu-panel-animations-disabled{animation:none}.mat-mdc-menu-panel.mat-menu-panel-animating{pointer-events:none}.mat-mdc-menu-panel.mat-menu-panel-animating:has(.mat-mdc-menu-content:empty){display:none}@media(forced-colors: active){.mat-mdc-menu-panel{outline:solid 1px}}.mat-mdc-menu-panel .mat-divider{border-top-color:var(--mat-menu-divider-color, var(--mat-sys-surface-variant));margin-bottom:var(--mat-menu-divider-bottom-spacing, 8px);margin-top:var(--mat-menu-divider-top-spacing, 8px)}.mat-mdc-menu-item{display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;padding:0;cursor:pointer;width:100%;text-align:left;box-sizing:border-box;color:inherit;font-size:inherit;background:none;text-decoration:none;margin:0;min-height:48px;padding-left:var(--mat-menu-item-leading-spacing, 12px);padding-right:var(--mat-menu-item-trailing-spacing, 12px);-webkit-user-select:none;user-select:none;cursor:pointer;outline:none;border:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mat-mdc-menu-item::-moz-focus-inner{border:0}[dir=rtl] .mat-mdc-menu-item{padding-left:var(--mat-menu-item-trailing-spacing, 12px);padding-right:var(--mat-menu-item-leading-spacing, 12px)}.mat-mdc-menu-item:has(.material-icons,mat-icon,[matButtonIcon]){padding-left:var(--mat-menu-item-with-icon-leading-spacing, 12px);padding-right:var(--mat-menu-item-with-icon-trailing-spacing, 12px)}[dir=rtl] .mat-mdc-menu-item:has(.material-icons,mat-icon,[matButtonIcon]){padding-left:var(--mat-menu-item-with-icon-trailing-spacing, 12px);padding-right:var(--mat-menu-item-with-icon-leading-spacing, 12px)}.mat-mdc-menu-item,.mat-mdc-menu-item:visited,.mat-mdc-menu-item:link{color:var(--mat-menu-item-label-text-color, var(--mat-sys-on-surface))}.mat-mdc-menu-item .mat-icon-no-color,.mat-mdc-menu-item .mat-mdc-menu-submenu-icon{color:var(--mat-menu-item-icon-color, var(--mat-sys-on-surface-variant))}.mat-mdc-menu-item[disabled]{cursor:default;opacity:.38}.mat-mdc-menu-item[disabled]::after{display:block;position:absolute;content:\"\";top:0;left:0;bottom:0;right:0}.mat-mdc-menu-item:focus{outline:0}.mat-mdc-menu-item .mat-icon{flex-shrink:0;margin-right:var(--mat-menu-item-spacing, 12px);height:var(--mat-menu-item-icon-size, 24px);width:var(--mat-menu-item-icon-size, 24px)}[dir=rtl] .mat-mdc-menu-item{text-align:right}[dir=rtl] .mat-mdc-menu-item .mat-icon{margin-right:0;margin-left:var(--mat-menu-item-spacing, 12px)}.mat-mdc-menu-item:not([disabled]):hover{background-color:var(--mat-menu-item-hover-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-hover-state-layer-opacity) * 100%), transparent))}.mat-mdc-menu-item:not([disabled]).cdk-program-focused,.mat-mdc-menu-item:not([disabled]).cdk-keyboard-focused,.mat-mdc-menu-item:not([disabled]).mat-mdc-menu-item-highlighted{background-color:var(--mat-menu-item-focus-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-focus-state-layer-opacity) * 100%), transparent))}@media(forced-colors: active){.mat-mdc-menu-item{margin-top:1px}}.mat-mdc-menu-submenu-icon{width:var(--mat-menu-item-icon-size, 24px);height:10px;fill:currentColor;padding-left:var(--mat-menu-item-spacing, 12px)}[dir=rtl] .mat-mdc-menu-submenu-icon{padding-right:var(--mat-menu-item-spacing, 12px);padding-left:0}[dir=rtl] .mat-mdc-menu-submenu-icon polygon{transform:scaleX(-1);transform-origin:center}@media(forced-colors: active){.mat-mdc-menu-submenu-icon{fill:CanvasText}}.mat-mdc-menu-item .mat-mdc-menu-ripple{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none}\n"],
581
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
582
+ encapsulation: i0.ViewEncapsulation.None
583
+ });
609
584
  }
610
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenu, decorators: [{
611
- type: Component,
612
- args: [{ selector: 'mat-menu', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, exportAs: 'matMenu', host: {
613
- '[attr.aria-label]': 'null',
614
- '[attr.aria-labelledby]': 'null',
615
- '[attr.aria-describedby]': 'null',
616
- }, providers: [{ provide: MAT_MENU_PANEL, useExisting: MatMenu }], template: "<ng-template>\n <div\n class=\"mat-mdc-menu-panel\"\n [id]=\"panelId\"\n [class]=\"_classList\"\n [class.mat-menu-panel-animations-disabled]=\"_animationsDisabled\"\n [class.mat-menu-panel-exit-animation]=\"_panelAnimationState === 'void'\"\n [class.mat-menu-panel-animating]=\"_isAnimating()\"\n (click)=\"closed.emit('click')\"\n tabindex=\"-1\"\n role=\"menu\"\n (animationstart)=\"_onAnimationStart($event.animationName)\"\n (animationend)=\"_onAnimationDone($event.animationName)\"\n (animationcancel)=\"_onAnimationDone($event.animationName)\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"ariaLabelledby || null\"\n [attr.aria-describedby]=\"ariaDescribedby || null\">\n <div class=\"mat-mdc-menu-content\">\n <ng-content></ng-content>\n </div>\n </div>\n</ng-template>\n", styles: ["mat-menu{display:none}.mat-mdc-menu-content{margin:0;padding:8px 0;outline:0}.mat-mdc-menu-content,.mat-mdc-menu-content .mat-mdc-menu-item .mat-mdc-menu-item-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;flex:1;white-space:normal;font-family:var(--mat-menu-item-label-text-font, var(--mat-sys-label-large-font));line-height:var(--mat-menu-item-label-text-line-height, var(--mat-sys-label-large-line-height));font-size:var(--mat-menu-item-label-text-size, var(--mat-sys-label-large-size));letter-spacing:var(--mat-menu-item-label-text-tracking, var(--mat-sys-label-large-tracking));font-weight:var(--mat-menu-item-label-text-weight, var(--mat-sys-label-large-weight))}@keyframes _mat-menu-enter{from{opacity:0;transform:scale(0.8)}to{opacity:1;transform:none}}@keyframes _mat-menu-exit{from{opacity:1}to{opacity:0}}.mat-mdc-menu-panel{min-width:112px;max-width:280px;overflow:auto;box-sizing:border-box;outline:0;animation:_mat-menu-enter 120ms cubic-bezier(0, 0, 0.2, 1);border-radius:var(--mat-menu-container-shape, var(--mat-sys-corner-extra-small));background-color:var(--mat-menu-container-color, var(--mat-sys-surface-container));box-shadow:var(--mat-menu-container-elevation-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));will-change:transform,opacity}.mat-mdc-menu-panel.mat-menu-panel-exit-animation{animation:_mat-menu-exit 100ms 25ms linear forwards}.mat-mdc-menu-panel.mat-menu-panel-animations-disabled{animation:none}.mat-mdc-menu-panel.mat-menu-panel-animating{pointer-events:none}.mat-mdc-menu-panel.mat-menu-panel-animating:has(.mat-mdc-menu-content:empty){display:none}@media(forced-colors: active){.mat-mdc-menu-panel{outline:solid 1px}}.mat-mdc-menu-panel .mat-divider{border-top-color:var(--mat-menu-divider-color, var(--mat-sys-surface-variant));margin-bottom:var(--mat-menu-divider-bottom-spacing, 8px);margin-top:var(--mat-menu-divider-top-spacing, 8px)}.mat-mdc-menu-item{display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;padding:0;cursor:pointer;width:100%;text-align:left;box-sizing:border-box;color:inherit;font-size:inherit;background:none;text-decoration:none;margin:0;min-height:48px;padding-left:var(--mat-menu-item-leading-spacing, 12px);padding-right:var(--mat-menu-item-trailing-spacing, 12px);-webkit-user-select:none;user-select:none;cursor:pointer;outline:none;border:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mat-mdc-menu-item::-moz-focus-inner{border:0}[dir=rtl] .mat-mdc-menu-item{padding-left:var(--mat-menu-item-trailing-spacing, 12px);padding-right:var(--mat-menu-item-leading-spacing, 12px)}.mat-mdc-menu-item:has(.material-icons,mat-icon,[matButtonIcon]){padding-left:var(--mat-menu-item-with-icon-leading-spacing, 12px);padding-right:var(--mat-menu-item-with-icon-trailing-spacing, 12px)}[dir=rtl] .mat-mdc-menu-item:has(.material-icons,mat-icon,[matButtonIcon]){padding-left:var(--mat-menu-item-with-icon-trailing-spacing, 12px);padding-right:var(--mat-menu-item-with-icon-leading-spacing, 12px)}.mat-mdc-menu-item,.mat-mdc-menu-item:visited,.mat-mdc-menu-item:link{color:var(--mat-menu-item-label-text-color, var(--mat-sys-on-surface))}.mat-mdc-menu-item .mat-icon-no-color,.mat-mdc-menu-item .mat-mdc-menu-submenu-icon{color:var(--mat-menu-item-icon-color, var(--mat-sys-on-surface-variant))}.mat-mdc-menu-item[disabled]{cursor:default;opacity:.38}.mat-mdc-menu-item[disabled]::after{display:block;position:absolute;content:\"\";top:0;left:0;bottom:0;right:0}.mat-mdc-menu-item:focus{outline:0}.mat-mdc-menu-item .mat-icon{flex-shrink:0;margin-right:var(--mat-menu-item-spacing, 12px);height:var(--mat-menu-item-icon-size, 24px);width:var(--mat-menu-item-icon-size, 24px)}[dir=rtl] .mat-mdc-menu-item{text-align:right}[dir=rtl] .mat-mdc-menu-item .mat-icon{margin-right:0;margin-left:var(--mat-menu-item-spacing, 12px)}.mat-mdc-menu-item:not([disabled]):hover{background-color:var(--mat-menu-item-hover-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-hover-state-layer-opacity) * 100%), transparent))}.mat-mdc-menu-item:not([disabled]).cdk-program-focused,.mat-mdc-menu-item:not([disabled]).cdk-keyboard-focused,.mat-mdc-menu-item:not([disabled]).mat-mdc-menu-item-highlighted{background-color:var(--mat-menu-item-focus-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-focus-state-layer-opacity) * 100%), transparent))}@media(forced-colors: active){.mat-mdc-menu-item{margin-top:1px}}.mat-mdc-menu-submenu-icon{width:var(--mat-menu-item-icon-size, 24px);height:10px;fill:currentColor;padding-left:var(--mat-menu-item-spacing, 12px)}[dir=rtl] .mat-mdc-menu-submenu-icon{padding-right:var(--mat-menu-item-spacing, 12px);padding-left:0}[dir=rtl] .mat-mdc-menu-submenu-icon polygon{transform:scaleX(-1);transform-origin:center}@media(forced-colors: active){.mat-mdc-menu-submenu-icon{fill:CanvasText}}.mat-mdc-menu-item .mat-mdc-menu-ripple{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none}\n"] }]
617
- }], ctorParameters: () => [], propDecorators: { _allItems: [{
618
- type: ContentChildren,
619
- args: [MatMenuItem, { descendants: true }]
620
- }], backdropClass: [{
621
- type: Input
622
- }], ariaLabel: [{
623
- type: Input,
624
- args: ['aria-label']
625
- }], ariaLabelledby: [{
626
- type: Input,
627
- args: ['aria-labelledby']
628
- }], ariaDescribedby: [{
629
- type: Input,
630
- args: ['aria-describedby']
631
- }], xPosition: [{
632
- type: Input
633
- }], yPosition: [{
634
- type: Input
635
- }], templateRef: [{
636
- type: ViewChild,
637
- args: [TemplateRef]
638
- }], items: [{
639
- type: ContentChildren,
640
- args: [MatMenuItem, { descendants: false }]
641
- }], lazyContent: [{
642
- type: ContentChild,
643
- args: [MAT_MENU_CONTENT]
644
- }], overlapTrigger: [{
645
- type: Input,
646
- args: [{ transform: booleanAttribute }]
647
- }], hasBackdrop: [{
648
- type: Input,
649
- args: [{ transform: (value) => (value == null ? null : booleanAttribute(value)) }]
650
- }], panelClass: [{
651
- type: Input,
652
- args: ['class']
653
- }], classList: [{
654
- type: Input
655
- }], closed: [{
656
- type: Output
657
- }], close: [{
658
- type: Output
659
- }] } });
585
+ i0.ɵɵngDeclareClassMetadata({
586
+ minVersion: "12.0.0",
587
+ version: "20.2.0-next.2",
588
+ ngImport: i0,
589
+ type: MatMenu,
590
+ decorators: [{
591
+ type: Component,
592
+ args: [{
593
+ selector: 'mat-menu',
594
+ changeDetection: ChangeDetectionStrategy.OnPush,
595
+ encapsulation: ViewEncapsulation.None,
596
+ exportAs: 'matMenu',
597
+ host: {
598
+ '[attr.aria-label]': 'null',
599
+ '[attr.aria-labelledby]': 'null',
600
+ '[attr.aria-describedby]': 'null'
601
+ },
602
+ providers: [{
603
+ provide: MAT_MENU_PANEL,
604
+ useExisting: MatMenu
605
+ }],
606
+ template: "<ng-template>\n <div\n class=\"mat-mdc-menu-panel\"\n [id]=\"panelId\"\n [class]=\"_classList\"\n [class.mat-menu-panel-animations-disabled]=\"_animationsDisabled\"\n [class.mat-menu-panel-exit-animation]=\"_panelAnimationState === 'void'\"\n [class.mat-menu-panel-animating]=\"_isAnimating()\"\n (click)=\"closed.emit('click')\"\n tabindex=\"-1\"\n role=\"menu\"\n (animationstart)=\"_onAnimationStart($event.animationName)\"\n (animationend)=\"_onAnimationDone($event.animationName)\"\n (animationcancel)=\"_onAnimationDone($event.animationName)\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"ariaLabelledby || null\"\n [attr.aria-describedby]=\"ariaDescribedby || null\">\n <div class=\"mat-mdc-menu-content\">\n <ng-content></ng-content>\n </div>\n </div>\n</ng-template>\n",
607
+ styles: ["mat-menu{display:none}.mat-mdc-menu-content{margin:0;padding:8px 0;outline:0}.mat-mdc-menu-content,.mat-mdc-menu-content .mat-mdc-menu-item .mat-mdc-menu-item-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;flex:1;white-space:normal;font-family:var(--mat-menu-item-label-text-font, var(--mat-sys-label-large-font));line-height:var(--mat-menu-item-label-text-line-height, var(--mat-sys-label-large-line-height));font-size:var(--mat-menu-item-label-text-size, var(--mat-sys-label-large-size));letter-spacing:var(--mat-menu-item-label-text-tracking, var(--mat-sys-label-large-tracking));font-weight:var(--mat-menu-item-label-text-weight, var(--mat-sys-label-large-weight))}@keyframes _mat-menu-enter{from{opacity:0;transform:scale(0.8)}to{opacity:1;transform:none}}@keyframes _mat-menu-exit{from{opacity:1}to{opacity:0}}.mat-mdc-menu-panel{min-width:112px;max-width:280px;overflow:auto;box-sizing:border-box;outline:0;animation:_mat-menu-enter 120ms cubic-bezier(0, 0, 0.2, 1);border-radius:var(--mat-menu-container-shape, var(--mat-sys-corner-extra-small));background-color:var(--mat-menu-container-color, var(--mat-sys-surface-container));box-shadow:var(--mat-menu-container-elevation-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));will-change:transform,opacity}.mat-mdc-menu-panel.mat-menu-panel-exit-animation{animation:_mat-menu-exit 100ms 25ms linear forwards}.mat-mdc-menu-panel.mat-menu-panel-animations-disabled{animation:none}.mat-mdc-menu-panel.mat-menu-panel-animating{pointer-events:none}.mat-mdc-menu-panel.mat-menu-panel-animating:has(.mat-mdc-menu-content:empty){display:none}@media(forced-colors: active){.mat-mdc-menu-panel{outline:solid 1px}}.mat-mdc-menu-panel .mat-divider{border-top-color:var(--mat-menu-divider-color, var(--mat-sys-surface-variant));margin-bottom:var(--mat-menu-divider-bottom-spacing, 8px);margin-top:var(--mat-menu-divider-top-spacing, 8px)}.mat-mdc-menu-item{display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;padding:0;cursor:pointer;width:100%;text-align:left;box-sizing:border-box;color:inherit;font-size:inherit;background:none;text-decoration:none;margin:0;min-height:48px;padding-left:var(--mat-menu-item-leading-spacing, 12px);padding-right:var(--mat-menu-item-trailing-spacing, 12px);-webkit-user-select:none;user-select:none;cursor:pointer;outline:none;border:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mat-mdc-menu-item::-moz-focus-inner{border:0}[dir=rtl] .mat-mdc-menu-item{padding-left:var(--mat-menu-item-trailing-spacing, 12px);padding-right:var(--mat-menu-item-leading-spacing, 12px)}.mat-mdc-menu-item:has(.material-icons,mat-icon,[matButtonIcon]){padding-left:var(--mat-menu-item-with-icon-leading-spacing, 12px);padding-right:var(--mat-menu-item-with-icon-trailing-spacing, 12px)}[dir=rtl] .mat-mdc-menu-item:has(.material-icons,mat-icon,[matButtonIcon]){padding-left:var(--mat-menu-item-with-icon-trailing-spacing, 12px);padding-right:var(--mat-menu-item-with-icon-leading-spacing, 12px)}.mat-mdc-menu-item,.mat-mdc-menu-item:visited,.mat-mdc-menu-item:link{color:var(--mat-menu-item-label-text-color, var(--mat-sys-on-surface))}.mat-mdc-menu-item .mat-icon-no-color,.mat-mdc-menu-item .mat-mdc-menu-submenu-icon{color:var(--mat-menu-item-icon-color, var(--mat-sys-on-surface-variant))}.mat-mdc-menu-item[disabled]{cursor:default;opacity:.38}.mat-mdc-menu-item[disabled]::after{display:block;position:absolute;content:\"\";top:0;left:0;bottom:0;right:0}.mat-mdc-menu-item:focus{outline:0}.mat-mdc-menu-item .mat-icon{flex-shrink:0;margin-right:var(--mat-menu-item-spacing, 12px);height:var(--mat-menu-item-icon-size, 24px);width:var(--mat-menu-item-icon-size, 24px)}[dir=rtl] .mat-mdc-menu-item{text-align:right}[dir=rtl] .mat-mdc-menu-item .mat-icon{margin-right:0;margin-left:var(--mat-menu-item-spacing, 12px)}.mat-mdc-menu-item:not([disabled]):hover{background-color:var(--mat-menu-item-hover-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-hover-state-layer-opacity) * 100%), transparent))}.mat-mdc-menu-item:not([disabled]).cdk-program-focused,.mat-mdc-menu-item:not([disabled]).cdk-keyboard-focused,.mat-mdc-menu-item:not([disabled]).mat-mdc-menu-item-highlighted{background-color:var(--mat-menu-item-focus-state-layer-color, color-mix(in srgb, var(--mat-sys-on-surface) calc(var(--mat-sys-focus-state-layer-opacity) * 100%), transparent))}@media(forced-colors: active){.mat-mdc-menu-item{margin-top:1px}}.mat-mdc-menu-submenu-icon{width:var(--mat-menu-item-icon-size, 24px);height:10px;fill:currentColor;padding-left:var(--mat-menu-item-spacing, 12px)}[dir=rtl] .mat-mdc-menu-submenu-icon{padding-right:var(--mat-menu-item-spacing, 12px);padding-left:0}[dir=rtl] .mat-mdc-menu-submenu-icon polygon{transform:scaleX(-1);transform-origin:center}@media(forced-colors: active){.mat-mdc-menu-submenu-icon{fill:CanvasText}}.mat-mdc-menu-item .mat-mdc-menu-ripple{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none}\n"]
608
+ }]
609
+ }],
610
+ ctorParameters: () => [],
611
+ propDecorators: {
612
+ _allItems: [{
613
+ type: ContentChildren,
614
+ args: [MatMenuItem, {
615
+ descendants: true
616
+ }]
617
+ }],
618
+ backdropClass: [{
619
+ type: Input
620
+ }],
621
+ ariaLabel: [{
622
+ type: Input,
623
+ args: ['aria-label']
624
+ }],
625
+ ariaLabelledby: [{
626
+ type: Input,
627
+ args: ['aria-labelledby']
628
+ }],
629
+ ariaDescribedby: [{
630
+ type: Input,
631
+ args: ['aria-describedby']
632
+ }],
633
+ xPosition: [{
634
+ type: Input
635
+ }],
636
+ yPosition: [{
637
+ type: Input
638
+ }],
639
+ templateRef: [{
640
+ type: ViewChild,
641
+ args: [TemplateRef]
642
+ }],
643
+ items: [{
644
+ type: ContentChildren,
645
+ args: [MatMenuItem, {
646
+ descendants: false
647
+ }]
648
+ }],
649
+ lazyContent: [{
650
+ type: ContentChild,
651
+ args: [MAT_MENU_CONTENT]
652
+ }],
653
+ overlapTrigger: [{
654
+ type: Input,
655
+ args: [{
656
+ transform: booleanAttribute
657
+ }]
658
+ }],
659
+ hasBackdrop: [{
660
+ type: Input,
661
+ args: [{
662
+ transform: value => value == null ? null : booleanAttribute(value)
663
+ }]
664
+ }],
665
+ panelClass: [{
666
+ type: Input,
667
+ args: ['class']
668
+ }],
669
+ classList: [{
670
+ type: Input
671
+ }],
672
+ closed: [{
673
+ type: Output
674
+ }],
675
+ close: [{
676
+ type: Output
677
+ }]
678
+ }
679
+ });
660
680
 
661
- /** Injection token that determines the scroll handling while the menu is open. */
662
681
  const MAT_MENU_SCROLL_STRATEGY = new InjectionToken('mat-menu-scroll-strategy', {
663
- providedIn: 'root',
664
- factory: () => {
665
- const injector = inject(Injector);
666
- return () => createRepositionScrollStrategy(injector);
667
- },
682
+ providedIn: 'root',
683
+ factory: () => {
684
+ const injector = inject(Injector);
685
+ return () => createRepositionScrollStrategy(injector);
686
+ }
668
687
  });
669
- /**
670
- * Default top padding of the menu panel.
671
- * @deprecated No longer being used. Will be removed.
672
- * @breaking-change 15.0.0
673
- */
674
688
  const MENU_PANEL_TOP_PADDING = 8;
675
- /** Mapping between menu panels and the last trigger that opened them. */
676
689
  const PANELS_TO_TRIGGERS = new WeakMap();
677
- /** Directive applied to an element that should trigger a `mat-menu`. */
678
690
  class MatMenuTriggerBase {
679
- _canHaveBackdrop;
680
- _element = inject(ElementRef);
681
- _viewContainerRef = inject(ViewContainerRef);
682
- _menuItemInstance = inject(MatMenuItem, { optional: true, self: true });
683
- _dir = inject(Directionality, { optional: true });
684
- _focusMonitor = inject(FocusMonitor);
685
- _ngZone = inject(NgZone);
686
- _injector = inject(Injector);
687
- _scrollStrategy = inject(MAT_MENU_SCROLL_STRATEGY);
688
- _changeDetectorRef = inject(ChangeDetectorRef);
689
- _animationsDisabled = _animationsDisabled();
690
- _portal;
691
- _overlayRef = null;
692
- _menuOpen = false;
693
- _closingActionsSubscription = Subscription.EMPTY;
694
- _menuCloseSubscription = Subscription.EMPTY;
695
- _pendingRemoval;
696
- /**
697
- * We're specifically looking for a `MatMenu` here since the generic `MatMenuPanel`
698
- * interface lacks some functionality around nested menus and animations.
699
- */
700
- _parentMaterialMenu;
701
- /**
702
- * Cached value of the padding of the parent menu panel.
703
- * Used to offset sub-menus to compensate for the padding.
704
- */
705
- _parentInnerPadding;
706
- // Tracking input type is necessary so it's possible to only auto-focus
707
- // the first item of the list when the menu is opened via the keyboard
708
- _openedBy = undefined;
709
- /** Menu currently assigned to the trigger. */
710
- get _menu() {
711
- return this._menuInternal;
712
- }
713
- set _menu(menu) {
714
- if (menu === this._menuInternal) {
715
- return;
716
- }
717
- this._menuInternal = menu;
718
- this._menuCloseSubscription.unsubscribe();
719
- if (menu) {
720
- if (menu === this._parentMaterialMenu && (typeof ngDevMode === 'undefined' || ngDevMode)) {
721
- throwMatMenuRecursiveError();
722
- }
723
- this._menuCloseSubscription = menu.close.subscribe((reason) => {
724
- this._destroyMenu(reason);
725
- // If a click closed the menu, we should close the entire chain of nested menus.
726
- if ((reason === 'click' || reason === 'tab') && this._parentMaterialMenu) {
727
- this._parentMaterialMenu.closed.emit(reason);
728
- }
729
- });
730
- }
731
- this._menuItemInstance?._setTriggersSubmenu(this._triggersSubmenu());
732
- }
733
- _menuInternal;
734
- constructor(_canHaveBackdrop) {
735
- this._canHaveBackdrop = _canHaveBackdrop;
736
- const parentMenu = inject(MAT_MENU_PANEL, { optional: true });
737
- this._parentMaterialMenu = parentMenu instanceof MatMenu ? parentMenu : undefined;
738
- }
739
- ngOnDestroy() {
740
- if (this._menu && this._ownsMenu(this._menu)) {
741
- PANELS_TO_TRIGGERS.delete(this._menu);
742
- }
743
- this._pendingRemoval?.unsubscribe();
744
- this._menuCloseSubscription.unsubscribe();
745
- this._closingActionsSubscription.unsubscribe();
746
- if (this._overlayRef) {
747
- this._overlayRef.dispose();
748
- this._overlayRef = null;
749
- }
750
- }
751
- /** Whether the menu is open. */
752
- get menuOpen() {
753
- return this._menuOpen;
754
- }
755
- /** The text direction of the containing app. */
756
- get dir() {
757
- return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
758
- }
759
- /** Whether the menu triggers a sub-menu or a top-level one. */
760
- _triggersSubmenu() {
761
- return !!(this._menuItemInstance && this._parentMaterialMenu && this._menu);
762
- }
763
- _closeMenu() {
764
- this._menu?.close.emit();
765
- }
766
- /** Internal method to open menu providing option to auto focus on first item. */
767
- _openMenu(autoFocus) {
768
- const menu = this._menu;
769
- if (this._menuOpen || !menu) {
770
- return;
771
- }
772
- this._pendingRemoval?.unsubscribe();
773
- const previousTrigger = PANELS_TO_TRIGGERS.get(menu);
774
- PANELS_TO_TRIGGERS.set(menu, this);
775
- // If the same menu is currently attached to another trigger,
776
- // we need to close it so it doesn't end up in a broken state.
777
- if (previousTrigger && previousTrigger !== this) {
778
- previousTrigger._closeMenu();
691
+ _canHaveBackdrop;
692
+ _element = inject(ElementRef);
693
+ _viewContainerRef = inject(ViewContainerRef);
694
+ _menuItemInstance = inject(MatMenuItem, {
695
+ optional: true,
696
+ self: true
697
+ });
698
+ _dir = inject(Directionality, {
699
+ optional: true
700
+ });
701
+ _focusMonitor = inject(FocusMonitor);
702
+ _ngZone = inject(NgZone);
703
+ _injector = inject(Injector);
704
+ _scrollStrategy = inject(MAT_MENU_SCROLL_STRATEGY);
705
+ _changeDetectorRef = inject(ChangeDetectorRef);
706
+ _animationsDisabled = _animationsDisabled();
707
+ _portal;
708
+ _overlayRef = null;
709
+ _menuOpen = false;
710
+ _closingActionsSubscription = Subscription.EMPTY;
711
+ _menuCloseSubscription = Subscription.EMPTY;
712
+ _pendingRemoval;
713
+ _parentMaterialMenu;
714
+ _parentInnerPadding;
715
+ _openedBy = undefined;
716
+ get _menu() {
717
+ return this._menuInternal;
718
+ }
719
+ set _menu(menu) {
720
+ if (menu === this._menuInternal) {
721
+ return;
722
+ }
723
+ this._menuInternal = menu;
724
+ this._menuCloseSubscription.unsubscribe();
725
+ if (menu) {
726
+ if (menu === this._parentMaterialMenu && (typeof ngDevMode === 'undefined' || ngDevMode)) {
727
+ throwMatMenuRecursiveError();
728
+ }
729
+ this._menuCloseSubscription = menu.close.subscribe(reason => {
730
+ this._destroyMenu(reason);
731
+ if ((reason === 'click' || reason === 'tab') && this._parentMaterialMenu) {
732
+ this._parentMaterialMenu.closed.emit(reason);
779
733
  }
780
- const overlayRef = this._createOverlay(menu);
781
- const overlayConfig = overlayRef.getConfig();
782
- const positionStrategy = overlayConfig.positionStrategy;
783
- this._setPosition(menu, positionStrategy);
784
- if (this._canHaveBackdrop) {
785
- overlayConfig.hasBackdrop =
786
- menu.hasBackdrop == null ? !this._triggersSubmenu() : menu.hasBackdrop;
734
+ });
735
+ }
736
+ this._menuItemInstance?._setTriggersSubmenu(this._triggersSubmenu());
737
+ }
738
+ _menuInternal;
739
+ constructor(_canHaveBackdrop) {
740
+ this._canHaveBackdrop = _canHaveBackdrop;
741
+ const parentMenu = inject(MAT_MENU_PANEL, {
742
+ optional: true
743
+ });
744
+ this._parentMaterialMenu = parentMenu instanceof MatMenu ? parentMenu : undefined;
745
+ }
746
+ ngOnDestroy() {
747
+ if (this._menu && this._ownsMenu(this._menu)) {
748
+ PANELS_TO_TRIGGERS.delete(this._menu);
749
+ }
750
+ this._pendingRemoval?.unsubscribe();
751
+ this._menuCloseSubscription.unsubscribe();
752
+ this._closingActionsSubscription.unsubscribe();
753
+ if (this._overlayRef) {
754
+ this._overlayRef.dispose();
755
+ this._overlayRef = null;
756
+ }
757
+ }
758
+ get menuOpen() {
759
+ return this._menuOpen;
760
+ }
761
+ get dir() {
762
+ return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
763
+ }
764
+ _triggersSubmenu() {
765
+ return !!(this._menuItemInstance && this._parentMaterialMenu && this._menu);
766
+ }
767
+ _closeMenu() {
768
+ this._menu?.close.emit();
769
+ }
770
+ _openMenu(autoFocus) {
771
+ const menu = this._menu;
772
+ if (this._menuOpen || !menu) {
773
+ return;
774
+ }
775
+ this._pendingRemoval?.unsubscribe();
776
+ const previousTrigger = PANELS_TO_TRIGGERS.get(menu);
777
+ PANELS_TO_TRIGGERS.set(menu, this);
778
+ if (previousTrigger && previousTrigger !== this) {
779
+ previousTrigger._closeMenu();
780
+ }
781
+ const overlayRef = this._createOverlay(menu);
782
+ const overlayConfig = overlayRef.getConfig();
783
+ const positionStrategy = overlayConfig.positionStrategy;
784
+ this._setPosition(menu, positionStrategy);
785
+ if (this._canHaveBackdrop) {
786
+ overlayConfig.hasBackdrop = menu.hasBackdrop == null ? !this._triggersSubmenu() : menu.hasBackdrop;
787
+ } else {
788
+ overlayConfig.hasBackdrop = false;
789
+ }
790
+ if (!overlayRef.hasAttached()) {
791
+ overlayRef.attach(this._getPortal(menu));
792
+ menu.lazyContent?.attach(this.menuData);
793
+ }
794
+ this._closingActionsSubscription = this._menuClosingActions().subscribe(() => this._closeMenu());
795
+ menu.parentMenu = this._triggersSubmenu() ? this._parentMaterialMenu : undefined;
796
+ menu.direction = this.dir;
797
+ if (autoFocus) {
798
+ menu.focusFirstItem(this._openedBy || 'program');
799
+ }
800
+ this._setIsMenuOpen(true);
801
+ if (menu instanceof MatMenu) {
802
+ menu._setIsOpen(true);
803
+ menu._directDescendantItems.changes.pipe(takeUntil(menu.close)).subscribe(() => {
804
+ positionStrategy.withLockedPosition(false).reapplyLastPosition();
805
+ positionStrategy.withLockedPosition(true);
806
+ });
807
+ }
808
+ }
809
+ focus(origin, options) {
810
+ if (this._focusMonitor && origin) {
811
+ this._focusMonitor.focusVia(this._element, origin, options);
812
+ } else {
813
+ this._element.nativeElement.focus(options);
814
+ }
815
+ }
816
+ _destroyMenu(reason) {
817
+ const overlayRef = this._overlayRef;
818
+ const menu = this._menu;
819
+ if (!overlayRef || !this.menuOpen) {
820
+ return;
821
+ }
822
+ this._closingActionsSubscription.unsubscribe();
823
+ this._pendingRemoval?.unsubscribe();
824
+ if (menu instanceof MatMenu && this._ownsMenu(menu)) {
825
+ this._pendingRemoval = menu._animationDone.pipe(take(1)).subscribe(() => {
826
+ overlayRef.detach();
827
+ if (!PANELS_TO_TRIGGERS.has(menu)) {
828
+ menu.lazyContent?.detach();
787
829
  }
788
- else {
789
- overlayConfig.hasBackdrop = false;
830
+ });
831
+ menu._setIsOpen(false);
832
+ } else {
833
+ overlayRef.detach();
834
+ menu?.lazyContent?.detach();
835
+ }
836
+ if (menu && this._ownsMenu(menu)) {
837
+ PANELS_TO_TRIGGERS.delete(menu);
838
+ }
839
+ if (this.restoreFocus && (reason === 'keydown' || !this._openedBy || !this._triggersSubmenu())) {
840
+ this.focus(this._openedBy);
841
+ }
842
+ this._openedBy = undefined;
843
+ this._setIsMenuOpen(false);
844
+ }
845
+ _setIsMenuOpen(isOpen) {
846
+ if (isOpen !== this._menuOpen) {
847
+ this._menuOpen = isOpen;
848
+ this._menuOpen ? this.menuOpened.emit() : this.menuClosed.emit();
849
+ if (this._triggersSubmenu()) {
850
+ this._menuItemInstance._setHighlighted(isOpen);
851
+ }
852
+ this._changeDetectorRef.markForCheck();
853
+ }
854
+ }
855
+ _createOverlay(menu) {
856
+ if (!this._overlayRef) {
857
+ const config = this._getOverlayConfig(menu);
858
+ this._subscribeToPositions(menu, config.positionStrategy);
859
+ this._overlayRef = createOverlayRef(this._injector, config);
860
+ this._overlayRef.keydownEvents().subscribe(event => {
861
+ if (this._menu instanceof MatMenu) {
862
+ this._menu._handleKeydown(event);
790
863
  }
791
- // We need the `hasAttached` check for the case where the user kicked off a removal animation,
792
- // but re-entered the menu. Re-attaching the same portal will trigger an error otherwise.
793
- if (!overlayRef.hasAttached()) {
794
- overlayRef.attach(this._getPortal(menu));
795
- menu.lazyContent?.attach(this.menuData);
796
- }
797
- this._closingActionsSubscription = this._menuClosingActions().subscribe(() => this._closeMenu());
798
- menu.parentMenu = this._triggersSubmenu() ? this._parentMaterialMenu : undefined;
799
- menu.direction = this.dir;
800
- if (autoFocus) {
801
- menu.focusFirstItem(this._openedBy || 'program');
802
- }
803
- this._setIsMenuOpen(true);
804
- if (menu instanceof MatMenu) {
805
- menu._setIsOpen(true);
806
- menu._directDescendantItems.changes.pipe(takeUntil(menu.close)).subscribe(() => {
807
- // Re-adjust the position without locking when the amount of items
808
- // changes so that the overlay is allowed to pick a new optimal position.
809
- positionStrategy.withLockedPosition(false).reapplyLastPosition();
810
- positionStrategy.withLockedPosition(true);
811
- });
812
- }
813
- }
814
- /**
815
- * Focuses the menu trigger.
816
- * @param origin Source of the menu trigger's focus.
817
- */
818
- focus(origin, options) {
819
- if (this._focusMonitor && origin) {
820
- this._focusMonitor.focusVia(this._element, origin, options);
821
- }
822
- else {
823
- this._element.nativeElement.focus(options);
824
- }
825
- }
826
- /** Closes the menu and does the necessary cleanup. */
827
- _destroyMenu(reason) {
828
- const overlayRef = this._overlayRef;
829
- const menu = this._menu;
830
- if (!overlayRef || !this.menuOpen) {
831
- return;
832
- }
833
- this._closingActionsSubscription.unsubscribe();
834
- this._pendingRemoval?.unsubscribe();
835
- // Note that we don't wait for the animation to finish if another trigger took
836
- // over the menu, because the panel will end up empty which looks glitchy.
837
- if (menu instanceof MatMenu && this._ownsMenu(menu)) {
838
- this._pendingRemoval = menu._animationDone.pipe(take(1)).subscribe(() => {
839
- overlayRef.detach();
840
- // Only detach the lazy content if no other trigger took over the menu, otherwise we may
841
- // detach something we no longer own. Note that we don't use `this._ownsMenu` here,
842
- // because the current trigger relinquishes ownership as soon as the closing sequence
843
- // is kicked off whereas the animation takes some time to play out.
844
- if (!PANELS_TO_TRIGGERS.has(menu)) {
845
- menu.lazyContent?.detach();
846
- }
847
- });
848
- menu._setIsOpen(false);
849
- }
850
- else {
851
- overlayRef.detach();
852
- menu?.lazyContent?.detach();
853
- }
854
- if (menu && this._ownsMenu(menu)) {
855
- PANELS_TO_TRIGGERS.delete(menu);
856
- }
857
- // Always restore focus if the user is navigating using the keyboard or the menu was opened
858
- // programmatically. We don't restore for non-root triggers, because it can prevent focus
859
- // from making it back to the root trigger when closing a long chain of menus by clicking
860
- // on the backdrop.
861
- if (this.restoreFocus &&
862
- (reason === 'keydown' || !this._openedBy || !this._triggersSubmenu())) {
863
- this.focus(this._openedBy);
864
- }
865
- this._openedBy = undefined;
866
- this._setIsMenuOpen(false);
867
- }
868
- // set state rather than toggle to support triggers sharing a menu
869
- _setIsMenuOpen(isOpen) {
870
- if (isOpen !== this._menuOpen) {
871
- this._menuOpen = isOpen;
872
- this._menuOpen ? this.menuOpened.emit() : this.menuClosed.emit();
873
- if (this._triggersSubmenu()) {
874
- this._menuItemInstance._setHighlighted(isOpen);
875
- }
876
- this._changeDetectorRef.markForCheck();
877
- }
878
- }
879
- /**
880
- * This method creates the overlay from the provided menu's template and saves its
881
- * OverlayRef so that it can be attached to the DOM when openMenu is called.
882
- */
883
- _createOverlay(menu) {
884
- if (!this._overlayRef) {
885
- const config = this._getOverlayConfig(menu);
886
- this._subscribeToPositions(menu, config.positionStrategy);
887
- this._overlayRef = createOverlayRef(this._injector, config);
888
- this._overlayRef.keydownEvents().subscribe(event => {
889
- if (this._menu instanceof MatMenu) {
890
- this._menu._handleKeydown(event);
891
- }
892
- });
893
- }
894
- return this._overlayRef;
895
- }
896
- /**
897
- * This method builds the configuration object needed to create the overlay, the OverlayState.
898
- * @returns OverlayConfig
899
- */
900
- _getOverlayConfig(menu) {
901
- return new OverlayConfig({
902
- positionStrategy: createFlexibleConnectedPositionStrategy(this._injector, this._getOverlayOrigin())
903
- .withLockedPosition()
904
- .withGrowAfterOpen()
905
- .withTransformOriginOn('.mat-menu-panel, .mat-mdc-menu-panel'),
906
- backdropClass: menu.backdropClass || 'cdk-overlay-transparent-backdrop',
907
- panelClass: menu.overlayPanelClass,
908
- scrollStrategy: this._scrollStrategy(),
909
- direction: this._dir || 'ltr',
910
- disableAnimations: this._animationsDisabled,
864
+ });
865
+ }
866
+ return this._overlayRef;
867
+ }
868
+ _getOverlayConfig(menu) {
869
+ return new OverlayConfig({
870
+ positionStrategy: createFlexibleConnectedPositionStrategy(this._injector, this._getOverlayOrigin()).withLockedPosition().withGrowAfterOpen().withTransformOriginOn('.mat-menu-panel, .mat-mdc-menu-panel'),
871
+ backdropClass: menu.backdropClass || 'cdk-overlay-transparent-backdrop',
872
+ panelClass: menu.overlayPanelClass,
873
+ scrollStrategy: this._scrollStrategy(),
874
+ direction: this._dir || 'ltr',
875
+ disableAnimations: this._animationsDisabled
876
+ });
877
+ }
878
+ _subscribeToPositions(menu, position) {
879
+ if (menu.setPositionClasses) {
880
+ position.positionChanges.subscribe(change => {
881
+ this._ngZone.run(() => {
882
+ const posX = change.connectionPair.overlayX === 'start' ? 'after' : 'before';
883
+ const posY = change.connectionPair.overlayY === 'top' ? 'below' : 'above';
884
+ menu.setPositionClasses(posX, posY);
911
885
  });
912
- }
913
- /**
914
- * Listens to changes in the position of the overlay and sets the correct classes
915
- * on the menu based on the new position. This ensures the animation origin is always
916
- * correct, even if a fallback position is used for the overlay.
917
- */
918
- _subscribeToPositions(menu, position) {
919
- if (menu.setPositionClasses) {
920
- position.positionChanges.subscribe(change => {
921
- this._ngZone.run(() => {
922
- const posX = change.connectionPair.overlayX === 'start' ? 'after' : 'before';
923
- const posY = change.connectionPair.overlayY === 'top' ? 'below' : 'above';
924
- menu.setPositionClasses(posX, posY);
925
- });
926
- });
927
- }
928
- }
929
- /**
930
- * Sets the appropriate positions on a position strategy
931
- * so the overlay connects with the trigger correctly.
932
- * @param positionStrategy Strategy whose position to update.
933
- */
934
- _setPosition(menu, positionStrategy) {
935
- let [originX, originFallbackX] = menu.xPosition === 'before' ? ['end', 'start'] : ['start', 'end'];
936
- let [overlayY, overlayFallbackY] = menu.yPosition === 'above' ? ['bottom', 'top'] : ['top', 'bottom'];
937
- let [originY, originFallbackY] = [overlayY, overlayFallbackY];
938
- let [overlayX, overlayFallbackX] = [originX, originFallbackX];
939
- let offsetY = 0;
940
- if (this._triggersSubmenu()) {
941
- // When the menu is a sub-menu, it should always align itself
942
- // to the edges of the trigger, instead of overlapping it.
943
- overlayFallbackX = originX = menu.xPosition === 'before' ? 'start' : 'end';
944
- originFallbackX = overlayX = originX === 'end' ? 'start' : 'end';
945
- if (this._parentMaterialMenu) {
946
- if (this._parentInnerPadding == null) {
947
- const firstItem = this._parentMaterialMenu.items.first;
948
- this._parentInnerPadding = firstItem ? firstItem._getHostElement().offsetTop : 0;
949
- }
950
- offsetY = overlayY === 'bottom' ? this._parentInnerPadding : -this._parentInnerPadding;
951
- }
886
+ });
887
+ }
888
+ }
889
+ _setPosition(menu, positionStrategy) {
890
+ let [originX, originFallbackX] = menu.xPosition === 'before' ? ['end', 'start'] : ['start', 'end'];
891
+ let [overlayY, overlayFallbackY] = menu.yPosition === 'above' ? ['bottom', 'top'] : ['top', 'bottom'];
892
+ let [originY, originFallbackY] = [overlayY, overlayFallbackY];
893
+ let [overlayX, overlayFallbackX] = [originX, originFallbackX];
894
+ let offsetY = 0;
895
+ if (this._triggersSubmenu()) {
896
+ overlayFallbackX = originX = menu.xPosition === 'before' ? 'start' : 'end';
897
+ originFallbackX = overlayX = originX === 'end' ? 'start' : 'end';
898
+ if (this._parentMaterialMenu) {
899
+ if (this._parentInnerPadding == null) {
900
+ const firstItem = this._parentMaterialMenu.items.first;
901
+ this._parentInnerPadding = firstItem ? firstItem._getHostElement().offsetTop : 0;
952
902
  }
953
- else if (!menu.overlapTrigger) {
954
- originY = overlayY === 'top' ? 'bottom' : 'top';
955
- originFallbackY = overlayFallbackY === 'top' ? 'bottom' : 'top';
956
- }
957
- positionStrategy.withPositions([
958
- { originX, originY, overlayX, overlayY, offsetY },
959
- { originX: originFallbackX, originY, overlayX: overlayFallbackX, overlayY, offsetY },
960
- {
961
- originX,
962
- originY: originFallbackY,
963
- overlayX,
964
- overlayY: overlayFallbackY,
965
- offsetY: -offsetY,
966
- },
967
- {
968
- originX: originFallbackX,
969
- originY: originFallbackY,
970
- overlayX: overlayFallbackX,
971
- overlayY: overlayFallbackY,
972
- offsetY: -offsetY,
973
- },
974
- ]);
975
- }
976
- /** Returns a stream that emits whenever an action that should close the menu occurs. */
977
- _menuClosingActions() {
978
- const outsideClicks = this._getOutsideClickStream(this._overlayRef);
979
- const detachments = this._overlayRef.detachments();
980
- const parentClose = this._parentMaterialMenu ? this._parentMaterialMenu.closed : of();
981
- const hover = this._parentMaterialMenu
982
- ? this._parentMaterialMenu
983
- ._hovered()
984
- .pipe(filter(active => this._menuOpen && active !== this._menuItemInstance))
985
- : of();
986
- return merge(outsideClicks, parentClose, hover, detachments);
987
- }
988
- /** Gets the portal that should be attached to the overlay. */
989
- _getPortal(menu) {
990
- // Note that we can avoid this check by keeping the portal on the menu panel.
991
- // While it would be cleaner, we'd have to introduce another required method on
992
- // `MatMenuPanel`, making it harder to consume.
993
- if (!this._portal || this._portal.templateRef !== menu.templateRef) {
994
- this._portal = new TemplatePortal(menu.templateRef, this._viewContainerRef);
995
- }
996
- return this._portal;
997
- }
998
- /**
999
- * Determines whether the trigger owns a specific menu panel, at the current point in time.
1000
- * This allows us to distinguish the case where the same panel is passed into multiple triggers
1001
- * and multiple are open at a time.
1002
- */
1003
- _ownsMenu(menu) {
1004
- return PANELS_TO_TRIGGERS.get(menu) === this;
1005
- }
1006
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuTriggerBase, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive });
1007
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: MatMenuTriggerBase, isStandalone: true, ngImport: i0 });
903
+ offsetY = overlayY === 'bottom' ? this._parentInnerPadding : -this._parentInnerPadding;
904
+ }
905
+ } else if (!menu.overlapTrigger) {
906
+ originY = overlayY === 'top' ? 'bottom' : 'top';
907
+ originFallbackY = overlayFallbackY === 'top' ? 'bottom' : 'top';
908
+ }
909
+ positionStrategy.withPositions([{
910
+ originX,
911
+ originY,
912
+ overlayX,
913
+ overlayY,
914
+ offsetY
915
+ }, {
916
+ originX: originFallbackX,
917
+ originY,
918
+ overlayX: overlayFallbackX,
919
+ overlayY,
920
+ offsetY
921
+ }, {
922
+ originX,
923
+ originY: originFallbackY,
924
+ overlayX,
925
+ overlayY: overlayFallbackY,
926
+ offsetY: -offsetY
927
+ }, {
928
+ originX: originFallbackX,
929
+ originY: originFallbackY,
930
+ overlayX: overlayFallbackX,
931
+ overlayY: overlayFallbackY,
932
+ offsetY: -offsetY
933
+ }]);
934
+ }
935
+ _menuClosingActions() {
936
+ const outsideClicks = this._getOutsideClickStream(this._overlayRef);
937
+ const detachments = this._overlayRef.detachments();
938
+ const parentClose = this._parentMaterialMenu ? this._parentMaterialMenu.closed : of();
939
+ const hover = this._parentMaterialMenu ? this._parentMaterialMenu._hovered().pipe(filter(active => this._menuOpen && active !== this._menuItemInstance)) : of();
940
+ return merge(outsideClicks, parentClose, hover, detachments);
941
+ }
942
+ _getPortal(menu) {
943
+ if (!this._portal || this._portal.templateRef !== menu.templateRef) {
944
+ this._portal = new TemplatePortal(menu.templateRef, this._viewContainerRef);
945
+ }
946
+ return this._portal;
947
+ }
948
+ _ownsMenu(menu) {
949
+ return PANELS_TO_TRIGGERS.get(menu) === this;
950
+ }
951
+ static ɵfac = i0.ɵɵngDeclareFactory({
952
+ minVersion: "12.0.0",
953
+ version: "20.2.0-next.2",
954
+ ngImport: i0,
955
+ type: MatMenuTriggerBase,
956
+ deps: "invalid",
957
+ target: i0.ɵɵFactoryTarget.Directive
958
+ });
959
+ static ɵdir = i0.ɵɵngDeclareDirective({
960
+ minVersion: "14.0.0",
961
+ version: "20.2.0-next.2",
962
+ type: MatMenuTriggerBase,
963
+ isStandalone: true,
964
+ ngImport: i0
965
+ });
1008
966
  }
1009
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuTriggerBase, decorators: [{
1010
- type: Directive
1011
- }], ctorParameters: () => [{ type: undefined }] });
967
+ i0.ɵɵngDeclareClassMetadata({
968
+ minVersion: "12.0.0",
969
+ version: "20.2.0-next.2",
970
+ ngImport: i0,
971
+ type: MatMenuTriggerBase,
972
+ decorators: [{
973
+ type: Directive
974
+ }],
975
+ ctorParameters: () => [{
976
+ type: undefined
977
+ }]
978
+ });
1012
979
 
1013
- /** Directive applied to an element that should trigger a `mat-menu`. */
1014
980
  class MatMenuTrigger extends MatMenuTriggerBase {
1015
- _cleanupTouchstart;
1016
- _hoverSubscription = Subscription.EMPTY;
1017
- /**
1018
- * @deprecated
1019
- * @breaking-change 8.0.0
1020
- */
1021
- get _deprecatedMatMenuTriggerFor() {
1022
- return this.menu;
1023
- }
1024
- set _deprecatedMatMenuTriggerFor(v) {
1025
- this.menu = v;
1026
- }
1027
- /** References the menu instance that the trigger is associated with. */
1028
- get menu() {
1029
- return this._menu;
1030
- }
1031
- set menu(menu) {
1032
- this._menu = menu;
1033
- }
1034
- /** Data to be passed along to any lazily-rendered content. */
1035
- menuData;
1036
- /**
1037
- * Whether focus should be restored when the menu is closed.
1038
- * Note that disabling this option can have accessibility implications
1039
- * and it's up to you to manage focus, if you decide to turn it off.
1040
- */
1041
- restoreFocus = true;
1042
- /** Event emitted when the associated menu is opened. */
1043
- menuOpened = new EventEmitter();
1044
- /**
1045
- * Event emitted when the associated menu is opened.
1046
- * @deprecated Switch to `menuOpened` instead
1047
- * @breaking-change 8.0.0
1048
- */
1049
- // tslint:disable-next-line:no-output-on-prefix
1050
- onMenuOpen = this.menuOpened;
1051
- /** Event emitted when the associated menu is closed. */
1052
- menuClosed = new EventEmitter();
1053
- /**
1054
- * Event emitted when the associated menu is closed.
1055
- * @deprecated Switch to `menuClosed` instead
1056
- * @breaking-change 8.0.0
1057
- */
1058
- // tslint:disable-next-line:no-output-on-prefix
1059
- onMenuClose = this.menuClosed;
1060
- constructor() {
1061
- super(true);
1062
- const renderer = inject(Renderer2);
1063
- this._cleanupTouchstart = renderer.listen(this._element.nativeElement, 'touchstart', (event) => {
1064
- if (!isFakeTouchstartFromScreenReader(event)) {
1065
- this._openedBy = 'touch';
1066
- }
1067
- }, { passive: true });
1068
- }
1069
- /** Whether the menu triggers a sub-menu or a top-level one. */
1070
- triggersSubmenu() {
1071
- return super._triggersSubmenu();
1072
- }
1073
- /** Toggles the menu between the open and closed states. */
1074
- toggleMenu() {
1075
- return this.menuOpen ? this.closeMenu() : this.openMenu();
1076
- }
1077
- /** Opens the menu. */
1078
- openMenu() {
1079
- this._openMenu(true);
1080
- }
1081
- /** Closes the menu. */
1082
- closeMenu() {
1083
- this._closeMenu();
1084
- }
1085
- /**
1086
- * Updates the position of the menu to ensure that it fits all options within the viewport.
1087
- */
1088
- updatePosition() {
1089
- this._overlayRef?.updatePosition();
1090
- }
1091
- ngAfterContentInit() {
1092
- this._handleHover();
1093
- }
1094
- ngOnDestroy() {
1095
- super.ngOnDestroy();
1096
- this._cleanupTouchstart();
1097
- this._hoverSubscription.unsubscribe();
1098
- }
1099
- _getOverlayOrigin() {
1100
- return this._element;
1101
- }
1102
- _getOutsideClickStream(overlayRef) {
1103
- return overlayRef.backdropClick();
1104
- }
1105
- /** Handles mouse presses on the trigger. */
1106
- _handleMousedown(event) {
1107
- if (!isFakeMousedownFromScreenReader(event)) {
1108
- // Since right or middle button clicks won't trigger the `click` event,
1109
- // we shouldn't consider the menu as opened by mouse in those cases.
1110
- this._openedBy = event.button === 0 ? 'mouse' : undefined;
1111
- // Since clicking on the trigger won't close the menu if it opens a sub-menu,
1112
- // we should prevent focus from moving onto it via click to avoid the
1113
- // highlight from lingering on the menu item.
1114
- if (this.triggersSubmenu()) {
1115
- event.preventDefault();
1116
- }
1117
- }
1118
- }
1119
- /** Handles key presses on the trigger. */
1120
- _handleKeydown(event) {
1121
- const keyCode = event.keyCode;
1122
- // Pressing enter on the trigger will trigger the click handler later.
1123
- if (keyCode === ENTER || keyCode === SPACE) {
1124
- this._openedBy = 'keyboard';
1125
- }
1126
- if (this.triggersSubmenu() &&
1127
- ((keyCode === RIGHT_ARROW && this.dir === 'ltr') ||
1128
- (keyCode === LEFT_ARROW && this.dir === 'rtl'))) {
1129
- this._openedBy = 'keyboard';
1130
- this.openMenu();
1131
- }
1132
- }
1133
- /** Handles click events on the trigger. */
1134
- _handleClick(event) {
1135
- if (this.triggersSubmenu()) {
1136
- // Stop event propagation to avoid closing the parent menu.
1137
- event.stopPropagation();
1138
- this.openMenu();
1139
- }
1140
- else {
1141
- this.toggleMenu();
1142
- }
1143
- }
1144
- /** Handles the cases where the user hovers over the trigger. */
1145
- _handleHover() {
1146
- // Subscribe to changes in the hovered item in order to toggle the panel.
1147
- if (this.triggersSubmenu() && this._parentMaterialMenu) {
1148
- this._hoverSubscription = this._parentMaterialMenu._hovered().subscribe(active => {
1149
- if (active === this._menuItemInstance &&
1150
- !active.disabled &&
1151
- // Ignore hover events if the parent menu is in the process of being closed (see #31956).
1152
- this._parentMaterialMenu?._panelAnimationState !== 'void') {
1153
- this._openedBy = 'mouse';
1154
- // Open the menu, but do NOT auto-focus on first item when just hovering.
1155
- // When VoiceOver is enabled, this is particularly confusing as the focus will
1156
- // cause another hover event, and continue opening sub-menus without interaction.
1157
- this._openMenu(false);
1158
- }
1159
- });
981
+ _cleanupTouchstart;
982
+ _hoverSubscription = Subscription.EMPTY;
983
+ get _deprecatedMatMenuTriggerFor() {
984
+ return this.menu;
985
+ }
986
+ set _deprecatedMatMenuTriggerFor(v) {
987
+ this.menu = v;
988
+ }
989
+ get menu() {
990
+ return this._menu;
991
+ }
992
+ set menu(menu) {
993
+ this._menu = menu;
994
+ }
995
+ menuData;
996
+ restoreFocus = true;
997
+ menuOpened = new EventEmitter();
998
+ onMenuOpen = this.menuOpened;
999
+ menuClosed = new EventEmitter();
1000
+ onMenuClose = this.menuClosed;
1001
+ constructor() {
1002
+ super(true);
1003
+ const renderer = inject(Renderer2);
1004
+ this._cleanupTouchstart = renderer.listen(this._element.nativeElement, 'touchstart', event => {
1005
+ if (!isFakeTouchstartFromScreenReader(event)) {
1006
+ this._openedBy = 'touch';
1007
+ }
1008
+ }, {
1009
+ passive: true
1010
+ });
1011
+ }
1012
+ triggersSubmenu() {
1013
+ return super._triggersSubmenu();
1014
+ }
1015
+ toggleMenu() {
1016
+ return this.menuOpen ? this.closeMenu() : this.openMenu();
1017
+ }
1018
+ openMenu() {
1019
+ this._openMenu(true);
1020
+ }
1021
+ closeMenu() {
1022
+ this._closeMenu();
1023
+ }
1024
+ updatePosition() {
1025
+ this._overlayRef?.updatePosition();
1026
+ }
1027
+ ngAfterContentInit() {
1028
+ this._handleHover();
1029
+ }
1030
+ ngOnDestroy() {
1031
+ super.ngOnDestroy();
1032
+ this._cleanupTouchstart();
1033
+ this._hoverSubscription.unsubscribe();
1034
+ }
1035
+ _getOverlayOrigin() {
1036
+ return this._element;
1037
+ }
1038
+ _getOutsideClickStream(overlayRef) {
1039
+ return overlayRef.backdropClick();
1040
+ }
1041
+ _handleMousedown(event) {
1042
+ if (!isFakeMousedownFromScreenReader(event)) {
1043
+ this._openedBy = event.button === 0 ? 'mouse' : undefined;
1044
+ if (this.triggersSubmenu()) {
1045
+ event.preventDefault();
1046
+ }
1047
+ }
1048
+ }
1049
+ _handleKeydown(event) {
1050
+ const keyCode = event.keyCode;
1051
+ if (keyCode === ENTER || keyCode === SPACE) {
1052
+ this._openedBy = 'keyboard';
1053
+ }
1054
+ if (this.triggersSubmenu() && (keyCode === RIGHT_ARROW && this.dir === 'ltr' || keyCode === LEFT_ARROW && this.dir === 'rtl')) {
1055
+ this._openedBy = 'keyboard';
1056
+ this.openMenu();
1057
+ }
1058
+ }
1059
+ _handleClick(event) {
1060
+ if (this.triggersSubmenu()) {
1061
+ event.stopPropagation();
1062
+ this.openMenu();
1063
+ } else {
1064
+ this.toggleMenu();
1065
+ }
1066
+ }
1067
+ _handleHover() {
1068
+ if (this.triggersSubmenu() && this._parentMaterialMenu) {
1069
+ this._hoverSubscription = this._parentMaterialMenu._hovered().subscribe(active => {
1070
+ if (active === this._menuItemInstance && !active.disabled && this._parentMaterialMenu?._panelAnimationState !== 'void') {
1071
+ this._openedBy = 'mouse';
1072
+ this._openMenu(false);
1160
1073
  }
1161
- }
1162
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1163
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: MatMenuTrigger, isStandalone: true, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: { _deprecatedMatMenuTriggerFor: ["mat-menu-trigger-for", "_deprecatedMatMenuTriggerFor"], menu: ["matMenuTriggerFor", "menu"], menuData: ["matMenuTriggerData", "menuData"], restoreFocus: ["matMenuTriggerRestoreFocus", "restoreFocus"] }, outputs: { menuOpened: "menuOpened", onMenuOpen: "onMenuOpen", menuClosed: "menuClosed", onMenuClose: "onMenuClose" }, host: { listeners: { "click": "_handleClick($event)", "mousedown": "_handleMousedown($event)", "keydown": "_handleKeydown($event)" }, properties: { "attr.aria-haspopup": "menu ? \"menu\" : null", "attr.aria-expanded": "menuOpen", "attr.aria-controls": "menuOpen ? menu?.panelId : null" }, classAttribute: "mat-mdc-menu-trigger" }, exportAs: ["matMenuTrigger"], usesInheritance: true, ngImport: i0 });
1074
+ });
1075
+ }
1076
+ }
1077
+ static ɵfac = i0.ɵɵngDeclareFactory({
1078
+ minVersion: "12.0.0",
1079
+ version: "20.2.0-next.2",
1080
+ ngImport: i0,
1081
+ type: MatMenuTrigger,
1082
+ deps: [],
1083
+ target: i0.ɵɵFactoryTarget.Directive
1084
+ });
1085
+ static ɵdir = i0.ɵɵngDeclareDirective({
1086
+ minVersion: "14.0.0",
1087
+ version: "20.2.0-next.2",
1088
+ type: MatMenuTrigger,
1089
+ isStandalone: true,
1090
+ selector: "[mat-menu-trigger-for], [matMenuTriggerFor]",
1091
+ inputs: {
1092
+ _deprecatedMatMenuTriggerFor: ["mat-menu-trigger-for", "_deprecatedMatMenuTriggerFor"],
1093
+ menu: ["matMenuTriggerFor", "menu"],
1094
+ menuData: ["matMenuTriggerData", "menuData"],
1095
+ restoreFocus: ["matMenuTriggerRestoreFocus", "restoreFocus"]
1096
+ },
1097
+ outputs: {
1098
+ menuOpened: "menuOpened",
1099
+ onMenuOpen: "onMenuOpen",
1100
+ menuClosed: "menuClosed",
1101
+ onMenuClose: "onMenuClose"
1102
+ },
1103
+ host: {
1104
+ listeners: {
1105
+ "click": "_handleClick($event)",
1106
+ "mousedown": "_handleMousedown($event)",
1107
+ "keydown": "_handleKeydown($event)"
1108
+ },
1109
+ properties: {
1110
+ "attr.aria-haspopup": "menu ? \"menu\" : null",
1111
+ "attr.aria-expanded": "menuOpen",
1112
+ "attr.aria-controls": "menuOpen ? menu?.panelId : null"
1113
+ },
1114
+ classAttribute: "mat-mdc-menu-trigger"
1115
+ },
1116
+ exportAs: ["matMenuTrigger"],
1117
+ usesInheritance: true,
1118
+ ngImport: i0
1119
+ });
1164
1120
  }
1165
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuTrigger, decorators: [{
1166
- type: Directive,
1167
- args: [{
1168
- selector: '[mat-menu-trigger-for], [matMenuTriggerFor]',
1169
- host: {
1170
- 'class': 'mat-mdc-menu-trigger',
1171
- '[attr.aria-haspopup]': 'menu ? "menu" : null',
1172
- '[attr.aria-expanded]': 'menuOpen',
1173
- '[attr.aria-controls]': 'menuOpen ? menu?.panelId : null',
1174
- '(click)': '_handleClick($event)',
1175
- '(mousedown)': '_handleMousedown($event)',
1176
- '(keydown)': '_handleKeydown($event)',
1177
- },
1178
- exportAs: 'matMenuTrigger',
1179
- }]
1180
- }], ctorParameters: () => [], propDecorators: { _deprecatedMatMenuTriggerFor: [{
1181
- type: Input,
1182
- args: ['mat-menu-trigger-for']
1183
- }], menu: [{
1184
- type: Input,
1185
- args: ['matMenuTriggerFor']
1186
- }], menuData: [{
1187
- type: Input,
1188
- args: ['matMenuTriggerData']
1189
- }], restoreFocus: [{
1190
- type: Input,
1191
- args: ['matMenuTriggerRestoreFocus']
1192
- }], menuOpened: [{
1193
- type: Output
1194
- }], onMenuOpen: [{
1195
- type: Output
1196
- }], menuClosed: [{
1197
- type: Output
1198
- }], onMenuClose: [{
1199
- type: Output
1200
- }] } });
1121
+ i0.ɵɵngDeclareClassMetadata({
1122
+ minVersion: "12.0.0",
1123
+ version: "20.2.0-next.2",
1124
+ ngImport: i0,
1125
+ type: MatMenuTrigger,
1126
+ decorators: [{
1127
+ type: Directive,
1128
+ args: [{
1129
+ selector: '[mat-menu-trigger-for], [matMenuTriggerFor]',
1130
+ host: {
1131
+ 'class': 'mat-mdc-menu-trigger',
1132
+ '[attr.aria-haspopup]': 'menu ? "menu" : null',
1133
+ '[attr.aria-expanded]': 'menuOpen',
1134
+ '[attr.aria-controls]': 'menuOpen ? menu?.panelId : null',
1135
+ '(click)': '_handleClick($event)',
1136
+ '(mousedown)': '_handleMousedown($event)',
1137
+ '(keydown)': '_handleKeydown($event)'
1138
+ },
1139
+ exportAs: 'matMenuTrigger'
1140
+ }]
1141
+ }],
1142
+ ctorParameters: () => [],
1143
+ propDecorators: {
1144
+ _deprecatedMatMenuTriggerFor: [{
1145
+ type: Input,
1146
+ args: ['mat-menu-trigger-for']
1147
+ }],
1148
+ menu: [{
1149
+ type: Input,
1150
+ args: ['matMenuTriggerFor']
1151
+ }],
1152
+ menuData: [{
1153
+ type: Input,
1154
+ args: ['matMenuTriggerData']
1155
+ }],
1156
+ restoreFocus: [{
1157
+ type: Input,
1158
+ args: ['matMenuTriggerRestoreFocus']
1159
+ }],
1160
+ menuOpened: [{
1161
+ type: Output
1162
+ }],
1163
+ onMenuOpen: [{
1164
+ type: Output
1165
+ }],
1166
+ menuClosed: [{
1167
+ type: Output
1168
+ }],
1169
+ onMenuClose: [{
1170
+ type: Output
1171
+ }]
1172
+ }
1173
+ });
1201
1174
 
1202
- /**
1203
- * Trigger that opens a menu whenever the user right-clicks within its host element.
1204
- */
1205
1175
  class MatContextMenuTrigger extends MatMenuTriggerBase {
1206
- _point = { x: 0, y: 0, initialX: 0, initialY: 0, initialScrollX: 0, initialScrollY: 0 };
1207
- _triggerPressedControl = false;
1208
- _rootNode;
1209
- _document = inject(DOCUMENT);
1210
- _viewportRuler = inject(ViewportRuler);
1211
- _scrollDispatcher = inject(ScrollDispatcher);
1212
- _scrollSubscription;
1213
- /** References the menu instance that the trigger is associated with. */
1214
- get menu() {
1215
- return this._menu;
1216
- }
1217
- set menu(menu) {
1218
- this._menu = menu;
1219
- }
1220
- /** Data to be passed along to any lazily-rendered content. */
1221
- menuData;
1222
- /**
1223
- * Whether focus should be restored when the menu is closed.
1224
- * Note that disabling this option can have accessibility implications
1225
- * and it's up to you to manage focus, if you decide to turn it off.
1226
- */
1227
- restoreFocus = true;
1228
- /** Whether the context menu is disabled. */
1229
- disabled = false;
1230
- /** Event emitted when the associated menu is opened. */
1231
- menuOpened = new EventEmitter();
1232
- /** Event emitted when the associated menu is closed. */
1233
- menuClosed = new EventEmitter();
1234
- constructor() {
1235
- super(false);
1236
- }
1237
- ngOnDestroy() {
1238
- super.ngOnDestroy();
1239
- this._scrollSubscription?.unsubscribe();
1240
- }
1241
- /** Handler for `contextmenu` events. */
1242
- _handleContextMenuEvent(event) {
1243
- if (!this.disabled) {
1244
- event.preventDefault();
1245
- // If the menu is already open, only update its position.
1246
- if (this.menuOpen) {
1247
- this._initializePoint(event.clientX, event.clientY);
1248
- this._updatePosition();
1249
- }
1250
- else {
1251
- this._openContextMenu(event);
1252
- }
1253
- }
1254
- }
1255
- _destroyMenu(reason) {
1256
- super._destroyMenu(reason);
1257
- this._scrollSubscription?.unsubscribe();
1258
- }
1259
- _getOverlayOrigin() {
1260
- return this._point;
1261
- }
1262
- _getOutsideClickStream(overlayRef) {
1263
- return overlayRef.outsidePointerEvents().pipe(skipWhile((event, index) => {
1264
- if (event.type === 'contextmenu') {
1265
- // Do not close when attempting to open a context menu within the trigger.
1266
- return this._isWithinMenuOrTrigger(_getEventTarget(event));
1267
- }
1268
- else if (event.type === 'auxclick') {
1269
- // Skip the first `auxclick` since it happens at
1270
- // the same time as the event that opens the menu.
1271
- if (index === 0) {
1272
- return true;
1273
- }
1274
- // Do not close on `auxclick` within the menu since we want to reposition the menu
1275
- // instead. Note that we have to resolve the clicked element using its position,
1276
- // rather than `event.target`, because the `target` is set to the `body`.
1277
- this._rootNode ??= _getShadowRoot(this._element.nativeElement) || this._document;
1278
- return this._isWithinMenuOrTrigger(this._rootNode.elementFromPoint(event.clientX, event.clientY));
1279
- }
1280
- // Using a mouse, the `contextmenu` event can fire either when pressing the right button
1281
- // or left button + control. Most browsers won't dispatch a `click` event right after
1282
- // a `contextmenu` event triggered by left button + control, but Safari will (see #27832).
1283
- // This closes the menu immediately. To work around it, we check that both the triggering
1284
- // event and the current outside click event both had the control key pressed, and that
1285
- // that this is the first outside click event.
1286
- return this._triggerPressedControl && index === 0 && event.ctrlKey;
1287
- }));
1288
- }
1289
- /** Checks whether an element is within the trigger or the opened overlay. */
1290
- _isWithinMenuOrTrigger(target) {
1291
- if (!target) {
1292
- return false;
1293
- }
1294
- const element = this._element.nativeElement;
1295
- if (target === element || element.contains(target)) {
1296
- return true;
1297
- }
1298
- const overlay = this._overlayRef?.hostElement;
1299
- return overlay === target || !!overlay?.contains(target);
1300
- }
1301
- /** Opens the context menu. */
1302
- _openContextMenu(event) {
1303
- // A context menu can be triggered via a mouse right click or a keyboard shortcut.
1304
- if (event.button === 2) {
1305
- this._openedBy = 'mouse';
1306
- }
1307
- else {
1308
- this._openedBy = event.button === 0 ? 'keyboard' : undefined;
1309
- }
1176
+ _point = {
1177
+ x: 0,
1178
+ y: 0,
1179
+ initialX: 0,
1180
+ initialY: 0,
1181
+ initialScrollX: 0,
1182
+ initialScrollY: 0
1183
+ };
1184
+ _triggerPressedControl = false;
1185
+ _rootNode;
1186
+ _document = inject(DOCUMENT);
1187
+ _viewportRuler = inject(ViewportRuler);
1188
+ _scrollDispatcher = inject(ScrollDispatcher);
1189
+ _scrollSubscription;
1190
+ get menu() {
1191
+ return this._menu;
1192
+ }
1193
+ set menu(menu) {
1194
+ this._menu = menu;
1195
+ }
1196
+ menuData;
1197
+ restoreFocus = true;
1198
+ disabled = false;
1199
+ menuOpened = new EventEmitter();
1200
+ menuClosed = new EventEmitter();
1201
+ constructor() {
1202
+ super(false);
1203
+ }
1204
+ ngOnDestroy() {
1205
+ super.ngOnDestroy();
1206
+ this._scrollSubscription?.unsubscribe();
1207
+ }
1208
+ _handleContextMenuEvent(event) {
1209
+ if (!this.disabled) {
1210
+ event.preventDefault();
1211
+ if (this.menuOpen) {
1310
1212
  this._initializePoint(event.clientX, event.clientY);
1311
- this._triggerPressedControl = event.ctrlKey;
1312
- super._openMenu(true);
1313
- this._scrollSubscription?.unsubscribe();
1314
- this._scrollSubscription = this._scrollDispatcher.scrolled(0).subscribe(() => {
1315
- // When passing a point to the connected position strategy, the position
1316
- // won't update as the user is scrolling so we have to do it manually.
1317
- const position = this._viewportRuler.getViewportScrollPosition();
1318
- const point = this._point;
1319
- point.y = point.initialY + (point.initialScrollY - position.top);
1320
- point.x = point.initialX + (point.initialScrollX - position.left);
1321
- this._updatePosition();
1322
- });
1323
- }
1324
- /** Initializes the point representing the origin relative to which the menu will be rendered. */
1325
- _initializePoint(x, y) {
1326
- const scrollPosition = this._viewportRuler.getViewportScrollPosition();
1327
- const point = this._point;
1328
- point.x = point.initialX = x;
1329
- point.y = point.initialY = y;
1330
- point.initialScrollX = scrollPosition.left;
1331
- point.initialScrollY = scrollPosition.top;
1332
- }
1333
- /** Refreshes the position of the overlay. */
1334
- _updatePosition() {
1335
- const overlayRef = this._overlayRef;
1336
- if (overlayRef) {
1337
- const positionStrategy = overlayRef.getConfig()
1338
- .positionStrategy;
1339
- positionStrategy.setOrigin(this._point);
1340
- overlayRef.updatePosition();
1213
+ this._updatePosition();
1214
+ } else {
1215
+ this._openContextMenu(event);
1216
+ }
1217
+ }
1218
+ }
1219
+ _destroyMenu(reason) {
1220
+ super._destroyMenu(reason);
1221
+ this._scrollSubscription?.unsubscribe();
1222
+ }
1223
+ _getOverlayOrigin() {
1224
+ return this._point;
1225
+ }
1226
+ _getOutsideClickStream(overlayRef) {
1227
+ return overlayRef.outsidePointerEvents().pipe(skipWhile((event, index) => {
1228
+ if (event.type === 'contextmenu') {
1229
+ return this._isWithinMenuOrTrigger(_getEventTarget(event));
1230
+ } else if (event.type === 'auxclick') {
1231
+ if (index === 0) {
1232
+ return true;
1341
1233
  }
1342
- }
1343
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatContextMenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1344
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.2.0-next.2", type: MatContextMenuTrigger, isStandalone: true, selector: "[matContextMenuTriggerFor]", inputs: { menu: ["matContextMenuTriggerFor", "menu"], menuData: ["matContextMenuTriggerData", "menuData"], restoreFocus: ["matContextMenuTriggerRestoreFocus", "restoreFocus"], disabled: ["matContextMenuTriggerDisabled", "disabled", booleanAttribute] }, outputs: { menuOpened: "menuOpened", menuClosed: "menuClosed" }, host: { listeners: { "contextmenu": "_handleContextMenuEvent($event)" }, properties: { "class.mat-context-menu-trigger-disabled": "disabled", "attr.aria-controls": "menuOpen ? menu?.panelId : null" }, classAttribute: "mat-context-menu-trigger" }, exportAs: ["matContextMenuTrigger"], usesInheritance: true, ngImport: i0 });
1234
+ this._rootNode ??= _getShadowRoot(this._element.nativeElement) || this._document;
1235
+ return this._isWithinMenuOrTrigger(this._rootNode.elementFromPoint(event.clientX, event.clientY));
1236
+ }
1237
+ return this._triggerPressedControl && index === 0 && event.ctrlKey;
1238
+ }));
1239
+ }
1240
+ _isWithinMenuOrTrigger(target) {
1241
+ if (!target) {
1242
+ return false;
1243
+ }
1244
+ const element = this._element.nativeElement;
1245
+ if (target === element || element.contains(target)) {
1246
+ return true;
1247
+ }
1248
+ const overlay = this._overlayRef?.hostElement;
1249
+ return overlay === target || !!overlay?.contains(target);
1250
+ }
1251
+ _openContextMenu(event) {
1252
+ if (event.button === 2) {
1253
+ this._openedBy = 'mouse';
1254
+ } else {
1255
+ this._openedBy = event.button === 0 ? 'keyboard' : undefined;
1256
+ }
1257
+ this._initializePoint(event.clientX, event.clientY);
1258
+ this._triggerPressedControl = event.ctrlKey;
1259
+ super._openMenu(true);
1260
+ this._scrollSubscription?.unsubscribe();
1261
+ this._scrollSubscription = this._scrollDispatcher.scrolled(0).subscribe(() => {
1262
+ const position = this._viewportRuler.getViewportScrollPosition();
1263
+ const point = this._point;
1264
+ point.y = point.initialY + (point.initialScrollY - position.top);
1265
+ point.x = point.initialX + (point.initialScrollX - position.left);
1266
+ this._updatePosition();
1267
+ });
1268
+ }
1269
+ _initializePoint(x, y) {
1270
+ const scrollPosition = this._viewportRuler.getViewportScrollPosition();
1271
+ const point = this._point;
1272
+ point.x = point.initialX = x;
1273
+ point.y = point.initialY = y;
1274
+ point.initialScrollX = scrollPosition.left;
1275
+ point.initialScrollY = scrollPosition.top;
1276
+ }
1277
+ _updatePosition() {
1278
+ const overlayRef = this._overlayRef;
1279
+ if (overlayRef) {
1280
+ const positionStrategy = overlayRef.getConfig().positionStrategy;
1281
+ positionStrategy.setOrigin(this._point);
1282
+ overlayRef.updatePosition();
1283
+ }
1284
+ }
1285
+ static ɵfac = i0.ɵɵngDeclareFactory({
1286
+ minVersion: "12.0.0",
1287
+ version: "20.2.0-next.2",
1288
+ ngImport: i0,
1289
+ type: MatContextMenuTrigger,
1290
+ deps: [],
1291
+ target: i0.ɵɵFactoryTarget.Directive
1292
+ });
1293
+ static ɵdir = i0.ɵɵngDeclareDirective({
1294
+ minVersion: "16.1.0",
1295
+ version: "20.2.0-next.2",
1296
+ type: MatContextMenuTrigger,
1297
+ isStandalone: true,
1298
+ selector: "[matContextMenuTriggerFor]",
1299
+ inputs: {
1300
+ menu: ["matContextMenuTriggerFor", "menu"],
1301
+ menuData: ["matContextMenuTriggerData", "menuData"],
1302
+ restoreFocus: ["matContextMenuTriggerRestoreFocus", "restoreFocus"],
1303
+ disabled: ["matContextMenuTriggerDisabled", "disabled", booleanAttribute]
1304
+ },
1305
+ outputs: {
1306
+ menuOpened: "menuOpened",
1307
+ menuClosed: "menuClosed"
1308
+ },
1309
+ host: {
1310
+ listeners: {
1311
+ "contextmenu": "_handleContextMenuEvent($event)"
1312
+ },
1313
+ properties: {
1314
+ "class.mat-context-menu-trigger-disabled": "disabled",
1315
+ "attr.aria-controls": "menuOpen ? menu?.panelId : null"
1316
+ },
1317
+ classAttribute: "mat-context-menu-trigger"
1318
+ },
1319
+ exportAs: ["matContextMenuTrigger"],
1320
+ usesInheritance: true,
1321
+ ngImport: i0
1322
+ });
1345
1323
  }
1346
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatContextMenuTrigger, decorators: [{
1347
- type: Directive,
1348
- args: [{
1349
- selector: '[matContextMenuTriggerFor]',
1350
- host: {
1351
- 'class': 'mat-context-menu-trigger',
1352
- '[class.mat-context-menu-trigger-disabled]': 'disabled',
1353
- '[attr.aria-controls]': 'menuOpen ? menu?.panelId : null',
1354
- '(contextmenu)': '_handleContextMenuEvent($event)',
1355
- },
1356
- exportAs: 'matContextMenuTrigger',
1357
- }]
1358
- }], ctorParameters: () => [], propDecorators: { menu: [{
1359
- type: Input,
1360
- args: [{ alias: 'matContextMenuTriggerFor', required: true }]
1361
- }], menuData: [{
1362
- type: Input,
1363
- args: ['matContextMenuTriggerData']
1364
- }], restoreFocus: [{
1365
- type: Input,
1366
- args: ['matContextMenuTriggerRestoreFocus']
1367
- }], disabled: [{
1368
- type: Input,
1369
- args: [{ alias: 'matContextMenuTriggerDisabled', transform: booleanAttribute }]
1370
- }], menuOpened: [{
1371
- type: Output
1372
- }], menuClosed: [{
1373
- type: Output
1374
- }] } });
1324
+ i0.ɵɵngDeclareClassMetadata({
1325
+ minVersion: "12.0.0",
1326
+ version: "20.2.0-next.2",
1327
+ ngImport: i0,
1328
+ type: MatContextMenuTrigger,
1329
+ decorators: [{
1330
+ type: Directive,
1331
+ args: [{
1332
+ selector: '[matContextMenuTriggerFor]',
1333
+ host: {
1334
+ 'class': 'mat-context-menu-trigger',
1335
+ '[class.mat-context-menu-trigger-disabled]': 'disabled',
1336
+ '[attr.aria-controls]': 'menuOpen ? menu?.panelId : null',
1337
+ '(contextmenu)': '_handleContextMenuEvent($event)'
1338
+ },
1339
+ exportAs: 'matContextMenuTrigger'
1340
+ }]
1341
+ }],
1342
+ ctorParameters: () => [],
1343
+ propDecorators: {
1344
+ menu: [{
1345
+ type: Input,
1346
+ args: [{
1347
+ alias: 'matContextMenuTriggerFor',
1348
+ required: true
1349
+ }]
1350
+ }],
1351
+ menuData: [{
1352
+ type: Input,
1353
+ args: ['matContextMenuTriggerData']
1354
+ }],
1355
+ restoreFocus: [{
1356
+ type: Input,
1357
+ args: ['matContextMenuTriggerRestoreFocus']
1358
+ }],
1359
+ disabled: [{
1360
+ type: Input,
1361
+ args: [{
1362
+ alias: 'matContextMenuTriggerDisabled',
1363
+ transform: booleanAttribute
1364
+ }]
1365
+ }],
1366
+ menuOpened: [{
1367
+ type: Output
1368
+ }],
1369
+ menuClosed: [{
1370
+ type: Output
1371
+ }]
1372
+ }
1373
+ });
1375
1374
 
1376
1375
  class MatMenuModule {
1377
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1378
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuModule, imports: [MatRippleModule,
1379
- OverlayModule,
1380
- MatMenu,
1381
- MatMenuItem,
1382
- MatMenuContent,
1383
- MatMenuTrigger,
1384
- MatContextMenuTrigger], exports: [BidiModule,
1385
- CdkScrollableModule,
1386
- MatMenu,
1387
- MatMenuItem,
1388
- MatMenuContent,
1389
- MatMenuTrigger,
1390
- MatContextMenuTrigger] });
1391
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuModule, imports: [MatRippleModule,
1392
- OverlayModule, BidiModule,
1393
- CdkScrollableModule] });
1376
+ static ɵfac = i0.ɵɵngDeclareFactory({
1377
+ minVersion: "12.0.0",
1378
+ version: "20.2.0-next.2",
1379
+ ngImport: i0,
1380
+ type: MatMenuModule,
1381
+ deps: [],
1382
+ target: i0.ɵɵFactoryTarget.NgModule
1383
+ });
1384
+ static ɵmod = i0.ɵɵngDeclareNgModule({
1385
+ minVersion: "14.0.0",
1386
+ version: "20.2.0-next.2",
1387
+ ngImport: i0,
1388
+ type: MatMenuModule,
1389
+ imports: [MatRippleModule, OverlayModule, MatMenu, MatMenuItem, MatMenuContent, MatMenuTrigger, MatContextMenuTrigger],
1390
+ exports: [BidiModule, CdkScrollableModule, MatMenu, MatMenuItem, MatMenuContent, MatMenuTrigger, MatContextMenuTrigger]
1391
+ });
1392
+ static ɵinj = i0.ɵɵngDeclareInjector({
1393
+ minVersion: "12.0.0",
1394
+ version: "20.2.0-next.2",
1395
+ ngImport: i0,
1396
+ type: MatMenuModule,
1397
+ imports: [MatRippleModule, OverlayModule, BidiModule, CdkScrollableModule]
1398
+ });
1394
1399
  }
1395
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatMenuModule, decorators: [{
1396
- type: NgModule,
1397
- args: [{
1398
- imports: [
1399
- MatRippleModule,
1400
- OverlayModule,
1401
- MatMenu,
1402
- MatMenuItem,
1403
- MatMenuContent,
1404
- MatMenuTrigger,
1405
- MatContextMenuTrigger,
1406
- ],
1407
- exports: [
1408
- BidiModule,
1409
- CdkScrollableModule,
1410
- MatMenu,
1411
- MatMenuItem,
1412
- MatMenuContent,
1413
- MatMenuTrigger,
1414
- MatContextMenuTrigger,
1415
- ],
1416
- }]
1417
- }] });
1400
+ i0.ɵɵngDeclareClassMetadata({
1401
+ minVersion: "12.0.0",
1402
+ version: "20.2.0-next.2",
1403
+ ngImport: i0,
1404
+ type: MatMenuModule,
1405
+ decorators: [{
1406
+ type: NgModule,
1407
+ args: [{
1408
+ imports: [MatRippleModule, OverlayModule, MatMenu, MatMenuItem, MatMenuContent, MatMenuTrigger, MatContextMenuTrigger],
1409
+ exports: [BidiModule, CdkScrollableModule, MatMenu, MatMenuItem, MatMenuContent, MatMenuTrigger, MatContextMenuTrigger]
1410
+ }]
1411
+ }]
1412
+ });
1418
1413
 
1419
1414
  export { MAT_MENU_CONTENT, MAT_MENU_DEFAULT_OPTIONS, MAT_MENU_PANEL, MAT_MENU_SCROLL_STRATEGY, MENU_PANEL_TOP_PADDING, MatContextMenuTrigger, MatMenu, MatMenuContent, MatMenuItem, MatMenuModule, MatMenuTrigger };
1420
1415
  //# sourceMappingURL=menu.mjs.map