@angular/material 19.0.2 → 19.0.4
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.
- package/autocomplete/index.d.ts +6 -6
- package/button/index.d.ts +2 -0
- package/chips/index.d.ts +1 -1
- package/core/theming/_theming.scss +1 -1
- package/expansion/index.d.ts +11 -8
- package/fesm2022/autocomplete.mjs +41 -37
- package/fesm2022/autocomplete.mjs.map +1 -1
- package/fesm2022/button.mjs +5 -3
- package/fesm2022/button.mjs.map +1 -1
- package/fesm2022/chips.mjs.map +1 -1
- package/fesm2022/core.mjs +1 -1
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/expansion.mjs +91 -82
- package/fesm2022/expansion.mjs.map +1 -1
- package/fesm2022/form-field.mjs +5 -3
- package/fesm2022/form-field.mjs.map +1 -1
- package/fesm2022/input.mjs +19 -25
- package/fesm2022/input.mjs.map +1 -1
- package/fesm2022/list.mjs +9 -6
- package/fesm2022/list.mjs.map +1 -1
- package/fesm2022/menu.mjs +194 -164
- package/fesm2022/menu.mjs.map +1 -1
- package/fesm2022/paginator.mjs +31 -22
- package/fesm2022/paginator.mjs.map +1 -1
- package/fesm2022/progress-bar.mjs +5 -3
- package/fesm2022/progress-bar.mjs.map +1 -1
- package/fesm2022/radio.mjs +5 -4
- package/fesm2022/radio.mjs.map +1 -1
- package/fesm2022/select.mjs +15 -4
- package/fesm2022/select.mjs.map +1 -1
- package/fesm2022/sidenav.mjs +6 -5
- package/fesm2022/sidenav.mjs.map +1 -1
- package/fesm2022/slider.mjs +22 -23
- package/fesm2022/slider.mjs.map +1 -1
- package/fesm2022/sort.mjs +2 -2
- package/fesm2022/sort.mjs.map +1 -1
- package/fesm2022/table.mjs +4 -15
- package/fesm2022/table.mjs.map +1 -1
- package/fesm2022/timepicker.mjs +46 -29
- package/fesm2022/timepicker.mjs.map +1 -1
- package/fesm2022/tooltip.mjs +2 -2
- package/fesm2022/tooltip.mjs.map +1 -1
- package/form-field/index.d.ts +1 -0
- package/input/index.d.ts +8 -5
- package/list/index.d.ts +3 -1
- package/menu/index.d.ts +19 -14
- package/package.json +2 -2
- package/paginator/index.d.ts +8 -0
- package/progress-bar/index.d.ts +2 -0
- package/radio/index.d.ts +2 -0
- package/schematics/ng-add/index.js +1 -1
- package/schematics/ng-add/index.mjs +1 -1
- package/schematics/ng-generate/theme-color/index_bundled.js +2 -2
- package/schematics/ng-update/index_bundled.js +31 -31
- package/select/index.d.ts +16 -3
- package/sidenav/index.d.ts +1 -0
- package/slider/index.d.ts +4 -1
- package/timepicker/index.d.ts +4 -0
package/fesm2022/menu.mjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, ElementRef, ChangeDetectorRef, booleanAttribute, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, TemplateRef, ApplicationRef, Injector, ViewContainerRef, Directive, QueryList, EventEmitter, afterNextRender, ContentChildren, ViewChild, ContentChild, Output, NgZone, NgModule } from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, ElementRef, ChangeDetectorRef, booleanAttribute, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, TemplateRef, ApplicationRef, Injector, ViewContainerRef, Directive, QueryList, EventEmitter, ANIMATION_MODULE_TYPE, afterNextRender, ContentChildren, ViewChild, ContentChild, Output, NgZone, NgModule } from '@angular/core';
|
|
3
3
|
import { FocusMonitor, _IdGenerator, FocusKeyManager, isFakeTouchstartFromScreenReader, isFakeMousedownFromScreenReader } from '@angular/cdk/a11y';
|
|
4
4
|
import { UP_ARROW, DOWN_ARROW, RIGHT_ARROW, LEFT_ARROW, ESCAPE, hasModifierKey, ENTER, SPACE } from '@angular/cdk/keycodes';
|
|
5
|
-
import { Subject, merge, Subscription, of
|
|
6
|
-
import { startWith, switchMap, takeUntil,
|
|
5
|
+
import { Subject, merge, Subscription, of } from 'rxjs';
|
|
6
|
+
import { startWith, switchMap, takeUntil, take, filter } from 'rxjs/operators';
|
|
7
7
|
import { DOCUMENT } from '@angular/common';
|
|
8
8
|
import { _StructuralStylesLoader, MatRipple, MatRippleModule, MatCommonModule } from '@angular/material/core';
|
|
9
9
|
import { _CdkPrivateStyleLoader } from '@angular/cdk/private';
|
|
10
10
|
import { TemplatePortal, DomPortalOutlet } from '@angular/cdk/portal';
|
|
11
|
-
import { trigger, state, style, transition, animate } from '@angular/animations';
|
|
12
11
|
import { Directionality } from '@angular/cdk/bidi';
|
|
13
12
|
import { Overlay, OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
|
|
14
13
|
import { normalizePassiveListenerOptions } from '@angular/cdk/platform';
|
|
15
14
|
import { CdkScrollableModule } from '@angular/cdk/scrolling';
|
|
15
|
+
import { trigger, state, style, transition, animate } from '@angular/animations';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Injection token used to provide the parent menu to menu-specific components.
|
|
@@ -222,14 +222,13 @@ class MatMenuContent {
|
|
|
222
222
|
* @docs-private
|
|
223
223
|
*/
|
|
224
224
|
detach() {
|
|
225
|
-
if (this._portal
|
|
225
|
+
if (this._portal?.isAttached) {
|
|
226
226
|
this._portal.detach();
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
ngOnDestroy() {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
230
|
+
this.detach();
|
|
231
|
+
this._outlet?.dispose();
|
|
233
232
|
}
|
|
234
233
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MatMenuContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
235
234
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.0", type: MatMenuContent, isStandalone: true, selector: "ng-template[matMenuContent]", providers: [{ provide: MAT_MENU_CONTENT, useExisting: MatMenuContent }], ngImport: i0 });
|
|
@@ -242,59 +241,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
|
|
|
242
241
|
}]
|
|
243
242
|
}], ctorParameters: () => [] });
|
|
244
243
|
|
|
245
|
-
/**
|
|
246
|
-
* Animations used by the mat-menu component.
|
|
247
|
-
* Animation duration and timing values are based on:
|
|
248
|
-
* https://material.io/guidelines/components/menus.html#menus-usage
|
|
249
|
-
* @docs-private
|
|
250
|
-
*/
|
|
251
|
-
const matMenuAnimations = {
|
|
252
|
-
/**
|
|
253
|
-
* This animation controls the menu panel's entry and exit from the page.
|
|
254
|
-
*
|
|
255
|
-
* When the menu panel is added to the DOM, it scales in and fades in its border.
|
|
256
|
-
*
|
|
257
|
-
* When the menu panel is removed from the DOM, it simply fades out after a brief
|
|
258
|
-
* delay to display the ripple.
|
|
259
|
-
*/
|
|
260
|
-
transformMenu: trigger('transformMenu', [
|
|
261
|
-
state('void', style({
|
|
262
|
-
opacity: 0,
|
|
263
|
-
transform: 'scale(0.8)',
|
|
264
|
-
})),
|
|
265
|
-
transition('void => enter', animate('120ms cubic-bezier(0, 0, 0.2, 1)', style({
|
|
266
|
-
opacity: 1,
|
|
267
|
-
transform: 'scale(1)',
|
|
268
|
-
}))),
|
|
269
|
-
transition('* => void', animate('100ms 25ms linear', style({ opacity: 0 }))),
|
|
270
|
-
]),
|
|
271
|
-
/**
|
|
272
|
-
* This animation fades in the background color and content of the menu panel
|
|
273
|
-
* after its containing element is scaled in.
|
|
274
|
-
*/
|
|
275
|
-
fadeInItems: trigger('fadeInItems', [
|
|
276
|
-
// TODO(crisbeto): this is inside the `transformMenu`
|
|
277
|
-
// now. Remove next time we do breaking changes.
|
|
278
|
-
state('showing', style({ opacity: 1 })),
|
|
279
|
-
transition('void => *', [
|
|
280
|
-
style({ opacity: 0 }),
|
|
281
|
-
animate('400ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)'),
|
|
282
|
-
]),
|
|
283
|
-
]),
|
|
284
|
-
};
|
|
285
|
-
/**
|
|
286
|
-
* @deprecated
|
|
287
|
-
* @breaking-change 8.0.0
|
|
288
|
-
* @docs-private
|
|
289
|
-
*/
|
|
290
|
-
const fadeInItems = matMenuAnimations.fadeInItems;
|
|
291
|
-
/**
|
|
292
|
-
* @deprecated
|
|
293
|
-
* @breaking-change 8.0.0
|
|
294
|
-
* @docs-private
|
|
295
|
-
*/
|
|
296
|
-
const transformMenu = matMenuAnimations.transformMenu;
|
|
297
|
-
|
|
298
244
|
/** Injection token to be used to override the default options for `mat-menu`. */
|
|
299
245
|
const MAT_MENU_DEFAULT_OPTIONS = new InjectionToken('mat-menu-default-options', {
|
|
300
246
|
providedIn: 'root',
|
|
@@ -309,13 +255,21 @@ function MAT_MENU_DEFAULT_OPTIONS_FACTORY() {
|
|
|
309
255
|
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
310
256
|
};
|
|
311
257
|
}
|
|
258
|
+
/** Name of the enter animation `@keyframes`. */
|
|
259
|
+
const ENTER_ANIMATION = '_mat-menu-enter';
|
|
260
|
+
/** Name of the exit animation `@keyframes`. */
|
|
261
|
+
const EXIT_ANIMATION = '_mat-menu-exit';
|
|
312
262
|
class MatMenu {
|
|
313
263
|
_elementRef = inject(ElementRef);
|
|
314
264
|
_changeDetectorRef = inject(ChangeDetectorRef);
|
|
265
|
+
_injector = inject(Injector);
|
|
315
266
|
_keyManager;
|
|
316
267
|
_xPosition;
|
|
317
268
|
_yPosition;
|
|
318
269
|
_firstItemFocusRef;
|
|
270
|
+
_exitFallbackTimeout;
|
|
271
|
+
/** Whether animations are currently disabled. */
|
|
272
|
+
_animationsDisabled;
|
|
319
273
|
/** All items inside the menu. Includes items nested inside another menu. */
|
|
320
274
|
_allItems;
|
|
321
275
|
/** Only the direct descendant menu items. */
|
|
@@ -327,7 +281,7 @@ class MatMenu {
|
|
|
327
281
|
/** Emits whenever an animation on the menu completes. */
|
|
328
282
|
_animationDone = new Subject();
|
|
329
283
|
/** Whether the menu is animating. */
|
|
330
|
-
_isAnimating;
|
|
284
|
+
_isAnimating = false;
|
|
331
285
|
/** Parent menu of the current menu panel. */
|
|
332
286
|
parentMenu;
|
|
333
287
|
/** Layout direction of the menu. */
|
|
@@ -429,7 +383,6 @@ class MatMenu {
|
|
|
429
383
|
*/
|
|
430
384
|
close = this.closed;
|
|
431
385
|
panelId = inject(_IdGenerator).getId('mat-menu-panel-');
|
|
432
|
-
_injector = inject(Injector);
|
|
433
386
|
constructor() {
|
|
434
387
|
const defaultOptions = inject(MAT_MENU_DEFAULT_OPTIONS);
|
|
435
388
|
this.overlayPanelClass = defaultOptions.overlayPanelClass || '';
|
|
@@ -438,6 +391,7 @@ class MatMenu {
|
|
|
438
391
|
this.backdropClass = defaultOptions.backdropClass;
|
|
439
392
|
this.overlapTrigger = defaultOptions.overlapTrigger;
|
|
440
393
|
this.hasBackdrop = defaultOptions.hasBackdrop;
|
|
394
|
+
this._animationsDisabled = inject(ANIMATION_MODULE_TYPE, { optional: true }) === 'NoopAnimations';
|
|
441
395
|
}
|
|
442
396
|
ngOnInit() {
|
|
443
397
|
this.setPositionClasses();
|
|
@@ -477,6 +431,7 @@ class MatMenu {
|
|
|
477
431
|
this._directDescendantItems.destroy();
|
|
478
432
|
this.closed.complete();
|
|
479
433
|
this._firstItemFocusRef?.destroy();
|
|
434
|
+
clearTimeout(this._exitFallbackTimeout);
|
|
480
435
|
}
|
|
481
436
|
/** Stream that emits whenever the hovered menu item changes. */
|
|
482
437
|
_hovered() {
|
|
@@ -535,14 +490,7 @@ class MatMenu {
|
|
|
535
490
|
// Wait for `afterNextRender` to ensure iOS VoiceOver screen reader focuses the first item (#24735).
|
|
536
491
|
this._firstItemFocusRef?.destroy();
|
|
537
492
|
this._firstItemFocusRef = afterNextRender(() => {
|
|
538
|
-
|
|
539
|
-
if (this._directDescendantItems.length) {
|
|
540
|
-
// Because the `mat-menuPanel` is at the DOM insertion point, not inside the overlay, we don't
|
|
541
|
-
// have a nice way of getting a hold of the menuPanel panel. We can't use a `ViewChild` either
|
|
542
|
-
// because the panel is inside an `ng-template`. We work around it by starting from one of
|
|
543
|
-
// the items and walking up the DOM.
|
|
544
|
-
menuPanel = this._directDescendantItems.first._getHostElement().closest('[role="menu"]');
|
|
545
|
-
}
|
|
493
|
+
const menuPanel = this._resolvePanel();
|
|
546
494
|
// If an item in the menuPanel is already focused, avoid overriding the focus.
|
|
547
495
|
if (!menuPanel || !menuPanel.contains(document.activeElement)) {
|
|
548
496
|
const manager = this._keyManager;
|
|
@@ -585,32 +533,52 @@ class MatMenu {
|
|
|
585
533
|
};
|
|
586
534
|
this._changeDetectorRef.markForCheck();
|
|
587
535
|
}
|
|
588
|
-
/**
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
536
|
+
/** Callback that is invoked when the panel animation completes. */
|
|
537
|
+
_onAnimationDone(state) {
|
|
538
|
+
const isExit = state === EXIT_ANIMATION;
|
|
539
|
+
if (isExit || state === ENTER_ANIMATION) {
|
|
540
|
+
if (isExit) {
|
|
541
|
+
clearTimeout(this._exitFallbackTimeout);
|
|
542
|
+
this._exitFallbackTimeout = undefined;
|
|
543
|
+
}
|
|
544
|
+
this._animationDone.next(isExit ? 'void' : 'enter');
|
|
545
|
+
this._isAnimating = false;
|
|
546
|
+
}
|
|
592
547
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
548
|
+
_onAnimationStart(state) {
|
|
549
|
+
if (state === ENTER_ANIMATION || state === EXIT_ANIMATION) {
|
|
550
|
+
this._isAnimating = true;
|
|
551
|
+
}
|
|
597
552
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
553
|
+
_setIsOpen(isOpen) {
|
|
554
|
+
this._panelAnimationState = isOpen ? 'enter' : 'void';
|
|
555
|
+
if (isOpen) {
|
|
556
|
+
if (this._keyManager.activeItemIndex === 0) {
|
|
557
|
+
// Scroll the content element to the top as soon as the animation starts. This is necessary,
|
|
558
|
+
// because we move focus to the first item while it's still being animated, which can throw
|
|
559
|
+
// the browser off when it determines the scroll position. Alternatively we can move focus
|
|
560
|
+
// when the animation is done, however moving focus asynchronously will interrupt screen
|
|
561
|
+
// readers which are in the process of reading out the menu already. We take the `element`
|
|
562
|
+
// from the `event` since we can't use a `ViewChild` to access the pane.
|
|
563
|
+
const menuPanel = this._resolvePanel();
|
|
564
|
+
if (menuPanel) {
|
|
565
|
+
menuPanel.scrollTop = 0;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
else if (!this._animationsDisabled) {
|
|
570
|
+
// Some apps do `* { animation: none !important; }` in tests which will prevent the
|
|
571
|
+
// `animationend` event from firing. Since the exit animation is loading-bearing for
|
|
572
|
+
// removing the content from the DOM, add a fallback timer.
|
|
573
|
+
this._exitFallbackTimeout = setTimeout(() => this._onAnimationDone(EXIT_ANIMATION), 200);
|
|
613
574
|
}
|
|
575
|
+
// Animation events won't fire when animations are disabled so we simulate them.
|
|
576
|
+
if (this._animationsDisabled) {
|
|
577
|
+
setTimeout(() => {
|
|
578
|
+
this._onAnimationDone(isOpen ? ENTER_ANIMATION : EXIT_ANIMATION);
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
this._changeDetectorRef.markForCheck();
|
|
614
582
|
}
|
|
615
583
|
/**
|
|
616
584
|
* Sets up a stream that will keep track of any newly-added menu items and will update the list
|
|
@@ -626,8 +594,20 @@ class MatMenu {
|
|
|
626
594
|
this._directDescendantItems.notifyOnChanges();
|
|
627
595
|
});
|
|
628
596
|
}
|
|
597
|
+
/** Gets the menu panel DOM node. */
|
|
598
|
+
_resolvePanel() {
|
|
599
|
+
let menuPanel = null;
|
|
600
|
+
if (this._directDescendantItems.length) {
|
|
601
|
+
// Because the `mat-menuPanel` is at the DOM insertion point, not inside the overlay, we don't
|
|
602
|
+
// have a nice way of getting a hold of the menuPanel panel. We can't use a `ViewChild` either
|
|
603
|
+
// because the panel is inside an `ng-template`. We work around it by starting from one of
|
|
604
|
+
// the items and walking up the DOM.
|
|
605
|
+
menuPanel = this._directDescendantItems.first._getHostElement().closest('[role="menu"]');
|
|
606
|
+
}
|
|
607
|
+
return menuPanel;
|
|
608
|
+
}
|
|
629
609
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MatMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
630
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "19.0.0", 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 (click)=\"closed.emit('click')\"\n
|
|
610
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "19.0.0", 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;-webkit-overflow-scrolling:touch;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{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}"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
631
611
|
}
|
|
632
612
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MatMenu, decorators: [{
|
|
633
613
|
type: Component,
|
|
@@ -635,7 +615,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
|
|
|
635
615
|
'[attr.aria-label]': 'null',
|
|
636
616
|
'[attr.aria-labelledby]': 'null',
|
|
637
617
|
'[attr.aria-describedby]': 'null',
|
|
638
|
-
},
|
|
618
|
+
}, 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;-webkit-overflow-scrolling:touch;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{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}"] }]
|
|
639
619
|
}], ctorParameters: () => [], propDecorators: { _allItems: [{
|
|
640
620
|
type: ContentChildren,
|
|
641
621
|
args: [MatMenuItem, { descendants: true }]
|
|
@@ -706,6 +686,8 @@ const passiveEventListenerOptions = normalizePassiveListenerOptions({ passive: t
|
|
|
706
686
|
* @breaking-change 15.0.0
|
|
707
687
|
*/
|
|
708
688
|
const MENU_PANEL_TOP_PADDING = 8;
|
|
689
|
+
/** Mapping between menu panels and the last trigger that opened them. */
|
|
690
|
+
const PANELS_TO_TRIGGERS = new WeakMap();
|
|
709
691
|
/** Directive applied to an element that should trigger a `mat-menu`. */
|
|
710
692
|
class MatMenuTrigger {
|
|
711
693
|
_overlay = inject(Overlay);
|
|
@@ -723,6 +705,7 @@ class MatMenuTrigger {
|
|
|
723
705
|
_closingActionsSubscription = Subscription.EMPTY;
|
|
724
706
|
_hoverSubscription = Subscription.EMPTY;
|
|
725
707
|
_menuCloseSubscription = Subscription.EMPTY;
|
|
708
|
+
_pendingRemoval;
|
|
726
709
|
/**
|
|
727
710
|
* We're specifically looking for a `MatMenu` here since the generic `MatMenuPanel`
|
|
728
711
|
* interface lacks some functionality around nested menus and animations.
|
|
@@ -815,14 +798,18 @@ class MatMenuTrigger {
|
|
|
815
798
|
this._handleHover();
|
|
816
799
|
}
|
|
817
800
|
ngOnDestroy() {
|
|
818
|
-
if (this.
|
|
819
|
-
this.
|
|
820
|
-
this._overlayRef = null;
|
|
801
|
+
if (this.menu && this._ownsMenu(this.menu)) {
|
|
802
|
+
PANELS_TO_TRIGGERS.delete(this.menu);
|
|
821
803
|
}
|
|
822
804
|
this._element.nativeElement.removeEventListener('touchstart', this._handleTouchStart, passiveEventListenerOptions);
|
|
805
|
+
this._pendingRemoval?.unsubscribe();
|
|
823
806
|
this._menuCloseSubscription.unsubscribe();
|
|
824
807
|
this._closingActionsSubscription.unsubscribe();
|
|
825
808
|
this._hoverSubscription.unsubscribe();
|
|
809
|
+
if (this._overlayRef) {
|
|
810
|
+
this._overlayRef.dispose();
|
|
811
|
+
this._overlayRef = null;
|
|
812
|
+
}
|
|
826
813
|
}
|
|
827
814
|
/** Whether the menu is open. */
|
|
828
815
|
get menuOpen() {
|
|
@@ -846,20 +833,33 @@ class MatMenuTrigger {
|
|
|
846
833
|
if (this._menuOpen || !menu) {
|
|
847
834
|
return;
|
|
848
835
|
}
|
|
836
|
+
this._pendingRemoval?.unsubscribe();
|
|
837
|
+
const previousTrigger = PANELS_TO_TRIGGERS.get(menu);
|
|
838
|
+
PANELS_TO_TRIGGERS.set(menu, this);
|
|
839
|
+
// If the same menu is currently attached to another trigger,
|
|
840
|
+
// we need to close it so it doesn't end up in a broken state.
|
|
841
|
+
if (previousTrigger && previousTrigger !== this) {
|
|
842
|
+
previousTrigger.closeMenu();
|
|
843
|
+
}
|
|
849
844
|
const overlayRef = this._createOverlay(menu);
|
|
850
845
|
const overlayConfig = overlayRef.getConfig();
|
|
851
846
|
const positionStrategy = overlayConfig.positionStrategy;
|
|
852
847
|
this._setPosition(menu, positionStrategy);
|
|
853
848
|
overlayConfig.hasBackdrop =
|
|
854
849
|
menu.hasBackdrop == null ? !this.triggersSubmenu() : menu.hasBackdrop;
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
850
|
+
// We need the `hasAttached` check for the case where the user kicked off a removal animation,
|
|
851
|
+
// but re-entered the menu. Re-attaching the same portal will trigger an error otherwise.
|
|
852
|
+
if (!overlayRef.hasAttached()) {
|
|
853
|
+
overlayRef.attach(this._getPortal(menu));
|
|
854
|
+
menu.lazyContent?.attach(this.menuData);
|
|
858
855
|
}
|
|
859
856
|
this._closingActionsSubscription = this._menuClosingActions().subscribe(() => this.closeMenu());
|
|
860
|
-
this.
|
|
857
|
+
menu.parentMenu = this.triggersSubmenu() ? this._parentMaterialMenu : undefined;
|
|
858
|
+
menu.direction = this.dir;
|
|
859
|
+
menu.focusFirstItem(this._openedBy || 'program');
|
|
860
|
+
this._setIsMenuOpen(true);
|
|
861
861
|
if (menu instanceof MatMenu) {
|
|
862
|
-
menu.
|
|
862
|
+
menu._setIsOpen(true);
|
|
863
863
|
menu._directDescendantItems.changes.pipe(takeUntil(menu.close)).subscribe(() => {
|
|
864
864
|
// Re-adjust the position without locking when the amount of items
|
|
865
865
|
// changes so that the overlay is allowed to pick a new optimal position.
|
|
@@ -892,12 +892,25 @@ class MatMenuTrigger {
|
|
|
892
892
|
}
|
|
893
893
|
/** Closes the menu and does the necessary cleanup. */
|
|
894
894
|
_destroyMenu(reason) {
|
|
895
|
-
|
|
895
|
+
const overlayRef = this._overlayRef;
|
|
896
|
+
const menu = this._menu;
|
|
897
|
+
if (!overlayRef || !this.menuOpen) {
|
|
896
898
|
return;
|
|
897
899
|
}
|
|
898
|
-
const menu = this.menu;
|
|
899
900
|
this._closingActionsSubscription.unsubscribe();
|
|
900
|
-
this.
|
|
901
|
+
this._pendingRemoval?.unsubscribe();
|
|
902
|
+
// Note that we don't wait for the animation to finish if another trigger took
|
|
903
|
+
// over the menu, because the panel will end up empty which looks glitchy.
|
|
904
|
+
if (menu instanceof MatMenu && this._ownsMenu(menu)) {
|
|
905
|
+
this._pendingRemoval = menu._animationDone.pipe(take(1)).subscribe(() => overlayRef.detach());
|
|
906
|
+
menu._setIsOpen(false);
|
|
907
|
+
}
|
|
908
|
+
else {
|
|
909
|
+
overlayRef.detach();
|
|
910
|
+
}
|
|
911
|
+
if (menu && this._ownsMenu(menu)) {
|
|
912
|
+
PANELS_TO_TRIGGERS.delete(menu);
|
|
913
|
+
}
|
|
901
914
|
// Always restore focus if the user is navigating using the keyboard or the menu was opened
|
|
902
915
|
// programmatically. We don't restore for non-root triggers, because it can prevent focus
|
|
903
916
|
// from making it back to the root trigger when closing a long chain of menus by clicking
|
|
@@ -906,38 +919,7 @@ class MatMenuTrigger {
|
|
|
906
919
|
this.focus(this._openedBy);
|
|
907
920
|
}
|
|
908
921
|
this._openedBy = undefined;
|
|
909
|
-
|
|
910
|
-
menu._resetAnimation();
|
|
911
|
-
if (menu.lazyContent) {
|
|
912
|
-
// Wait for the exit animation to finish before detaching the content.
|
|
913
|
-
menu._animationDone
|
|
914
|
-
.pipe(filter(event => event.toState === 'void'), take(1),
|
|
915
|
-
// Interrupt if the content got re-attached.
|
|
916
|
-
takeUntil(menu.lazyContent._attached))
|
|
917
|
-
.subscribe({
|
|
918
|
-
next: () => menu.lazyContent.detach(),
|
|
919
|
-
// No matter whether the content got re-attached, reset the menu.
|
|
920
|
-
complete: () => this._setIsMenuOpen(false),
|
|
921
|
-
});
|
|
922
|
-
}
|
|
923
|
-
else {
|
|
924
|
-
this._setIsMenuOpen(false);
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
else {
|
|
928
|
-
this._setIsMenuOpen(false);
|
|
929
|
-
menu?.lazyContent?.detach();
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
/**
|
|
933
|
-
* This method sets the menu state to open and focuses the first item if
|
|
934
|
-
* the menu was opened via the keyboard.
|
|
935
|
-
*/
|
|
936
|
-
_initMenu(menu) {
|
|
937
|
-
menu.parentMenu = this.triggersSubmenu() ? this._parentMaterialMenu : undefined;
|
|
938
|
-
menu.direction = this.dir;
|
|
939
|
-
menu.focusFirstItem(this._openedBy || 'program');
|
|
940
|
-
this._setIsMenuOpen(true);
|
|
922
|
+
this._setIsMenuOpen(false);
|
|
941
923
|
}
|
|
942
924
|
// set state rather than toggle to support triggers sharing a menu
|
|
943
925
|
_setIsMenuOpen(isOpen) {
|
|
@@ -1054,7 +1036,9 @@ class MatMenuTrigger {
|
|
|
1054
1036
|
const detachments = this._overlayRef.detachments();
|
|
1055
1037
|
const parentClose = this._parentMaterialMenu ? this._parentMaterialMenu.closed : of();
|
|
1056
1038
|
const hover = this._parentMaterialMenu
|
|
1057
|
-
? this._parentMaterialMenu
|
|
1039
|
+
? this._parentMaterialMenu
|
|
1040
|
+
._hovered()
|
|
1041
|
+
.pipe(filter(active => this._menuOpen && active !== this._menuItemInstance))
|
|
1058
1042
|
: of();
|
|
1059
1043
|
return merge(backdrop, parentClose, hover, detachments);
|
|
1060
1044
|
}
|
|
@@ -1100,31 +1084,14 @@ class MatMenuTrigger {
|
|
|
1100
1084
|
/** Handles the cases where the user hovers over the trigger. */
|
|
1101
1085
|
_handleHover() {
|
|
1102
1086
|
// Subscribe to changes in the hovered item in order to toggle the panel.
|
|
1103
|
-
if (
|
|
1104
|
-
|
|
1087
|
+
if (this.triggersSubmenu() && this._parentMaterialMenu) {
|
|
1088
|
+
this._hoverSubscription = this._parentMaterialMenu._hovered().subscribe(active => {
|
|
1089
|
+
if (active === this._menuItemInstance && !active.disabled) {
|
|
1090
|
+
this._openedBy = 'mouse';
|
|
1091
|
+
this.openMenu();
|
|
1092
|
+
}
|
|
1093
|
+
});
|
|
1105
1094
|
}
|
|
1106
|
-
this._hoverSubscription = this._parentMaterialMenu
|
|
1107
|
-
._hovered()
|
|
1108
|
-
// Since we might have multiple competing triggers for the same menu (e.g. a sub-menu
|
|
1109
|
-
// with different data and triggers), we have to delay it by a tick to ensure that
|
|
1110
|
-
// it won't be closed immediately after it is opened.
|
|
1111
|
-
.pipe(filter(active => active === this._menuItemInstance && !active.disabled), delay(0, asapScheduler))
|
|
1112
|
-
.subscribe(() => {
|
|
1113
|
-
this._openedBy = 'mouse';
|
|
1114
|
-
// If the same menu is used between multiple triggers, it might still be animating
|
|
1115
|
-
// while the new trigger tries to re-open it. Wait for the animation to finish
|
|
1116
|
-
// before doing so. Also interrupt if the user moves to another item.
|
|
1117
|
-
if (this.menu instanceof MatMenu && this.menu._isAnimating) {
|
|
1118
|
-
// We need the `delay(0)` here in order to avoid
|
|
1119
|
-
// 'changed after checked' errors in some cases. See #12194.
|
|
1120
|
-
this.menu._animationDone
|
|
1121
|
-
.pipe(take(1), delay(0, asapScheduler), takeUntil(this._parentMaterialMenu._hovered()))
|
|
1122
|
-
.subscribe(() => this.openMenu());
|
|
1123
|
-
}
|
|
1124
|
-
else {
|
|
1125
|
-
this.openMenu();
|
|
1126
|
-
}
|
|
1127
|
-
});
|
|
1128
1095
|
}
|
|
1129
1096
|
/** Gets the portal that should be attached to the overlay. */
|
|
1130
1097
|
_getPortal(menu) {
|
|
@@ -1136,6 +1103,14 @@ class MatMenuTrigger {
|
|
|
1136
1103
|
}
|
|
1137
1104
|
return this._portal;
|
|
1138
1105
|
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Determines whether the trigger owns a specific menu panel, at the current point in time.
|
|
1108
|
+
* This allows us to distinguish the case where the same panel is passed into multiple triggers
|
|
1109
|
+
* and multiple are open at a time.
|
|
1110
|
+
*/
|
|
1111
|
+
_ownsMenu(menu) {
|
|
1112
|
+
return PANELS_TO_TRIGGERS.get(menu) === this;
|
|
1113
|
+
}
|
|
1139
1114
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MatMenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1140
1115
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.0", 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"], ngImport: i0 });
|
|
1141
1116
|
}
|
|
@@ -1219,6 +1194,61 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
|
|
|
1219
1194
|
}]
|
|
1220
1195
|
}] });
|
|
1221
1196
|
|
|
1197
|
+
/**
|
|
1198
|
+
* Animations used by the mat-menu component.
|
|
1199
|
+
* Animation duration and timing values are based on:
|
|
1200
|
+
* https://material.io/guidelines/components/menus.html#menus-usage
|
|
1201
|
+
* @docs-private
|
|
1202
|
+
* @deprecated No longer used, will be removed.
|
|
1203
|
+
* @breaking-change 21.0.0
|
|
1204
|
+
*/
|
|
1205
|
+
const matMenuAnimations = {
|
|
1206
|
+
/**
|
|
1207
|
+
* This animation controls the menu panel's entry and exit from the page.
|
|
1208
|
+
*
|
|
1209
|
+
* When the menu panel is added to the DOM, it scales in and fades in its border.
|
|
1210
|
+
*
|
|
1211
|
+
* When the menu panel is removed from the DOM, it simply fades out after a brief
|
|
1212
|
+
* delay to display the ripple.
|
|
1213
|
+
*/
|
|
1214
|
+
transformMenu: trigger('transformMenu', [
|
|
1215
|
+
state('void', style({
|
|
1216
|
+
opacity: 0,
|
|
1217
|
+
transform: 'scale(0.8)',
|
|
1218
|
+
})),
|
|
1219
|
+
transition('void => enter', animate('120ms cubic-bezier(0, 0, 0.2, 1)', style({
|
|
1220
|
+
opacity: 1,
|
|
1221
|
+
transform: 'scale(1)',
|
|
1222
|
+
}))),
|
|
1223
|
+
transition('* => void', animate('100ms 25ms linear', style({ opacity: 0 }))),
|
|
1224
|
+
]),
|
|
1225
|
+
/**
|
|
1226
|
+
* This animation fades in the background color and content of the menu panel
|
|
1227
|
+
* after its containing element is scaled in.
|
|
1228
|
+
*/
|
|
1229
|
+
fadeInItems: trigger('fadeInItems', [
|
|
1230
|
+
// TODO(crisbeto): this is inside the `transformMenu`
|
|
1231
|
+
// now. Remove next time we do breaking changes.
|
|
1232
|
+
state('showing', style({ opacity: 1 })),
|
|
1233
|
+
transition('void => *', [
|
|
1234
|
+
style({ opacity: 0 }),
|
|
1235
|
+
animate('400ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)'),
|
|
1236
|
+
]),
|
|
1237
|
+
]),
|
|
1238
|
+
};
|
|
1239
|
+
/**
|
|
1240
|
+
* @deprecated
|
|
1241
|
+
* @breaking-change 8.0.0
|
|
1242
|
+
* @docs-private
|
|
1243
|
+
*/
|
|
1244
|
+
const fadeInItems = matMenuAnimations.fadeInItems;
|
|
1245
|
+
/**
|
|
1246
|
+
* @deprecated
|
|
1247
|
+
* @breaking-change 8.0.0
|
|
1248
|
+
* @docs-private
|
|
1249
|
+
*/
|
|
1250
|
+
const transformMenu = matMenuAnimations.transformMenu;
|
|
1251
|
+
|
|
1222
1252
|
/**
|
|
1223
1253
|
* Generated bundle index. Do not edit.
|
|
1224
1254
|
*/
|