UNPKG

@angular/material

Version:
959 lines (929 loc) 78.5 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/cdk/a11y'), require('@angular/cdk/coercion'), require('@angular/cdk/keycodes'), require('@angular/core'), require('rxjs'), require('rxjs/operators'), require('@angular/animations'), require('@angular/cdk/portal'), require('@angular/common'), require('@angular/material/core'), require('@angular/cdk/bidi'), require('@angular/cdk/overlay'), require('@angular/cdk/platform')) : typeof define === 'function' && define.amd ? define('@angular/material/menu', ['exports', '@angular/cdk/a11y', '@angular/cdk/coercion', '@angular/cdk/keycodes', '@angular/core', 'rxjs', 'rxjs/operators', '@angular/animations', '@angular/cdk/portal', '@angular/common', '@angular/material/core', '@angular/cdk/bidi', '@angular/cdk/overlay', '@angular/cdk/platform'], factory) : (global = global || self, factory((global.ng = global.ng || {}, global.ng.material = global.ng.material || {}, global.ng.material.menu = {}), global.ng.cdk.a11y, global.ng.cdk.coercion, global.ng.cdk.keycodes, global.ng.core, global.rxjs, global.rxjs.operators, global.ng.animations, global.ng.cdk.portal, global.ng.common, global.ng.material.core, global.ng.cdk.bidi, global.ng.cdk.overlay, global.ng.cdk.platform)); }(this, (function (exports, a11y, coercion, keycodes, core, rxjs, operators, animations, portal, common, core$1, bidi, overlay, platform) { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function __param(paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } } function __metadata(metadataKey, metadataValue) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); } function __awaiter(thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __exportStar(m, exports) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } function __values(o) { var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; if (m) return m.call(o); return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spread() { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; } function __spreadArrays() { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; function __await(v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } function __asyncGenerator(thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var g = generator.apply(thisArg, _arguments || []), i, q = []; return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } function fulfill(value) { resume("next", value); } function reject(value) { resume("throw", value); } function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } } function __asyncDelegator(o) { var i, p; return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } } function __asyncValues(o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } } function __makeTemplateObject(cooked, raw) { if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } return cooked; }; function __importStar(mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result.default = mod; return result; } function __importDefault(mod) { return (mod && mod.__esModule) ? mod : { default: mod }; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Animations used by the mat-menu component. * Animation duration and timing values are based on: * https://material.io/guidelines/components/menus.html#menus-usage * @docs-private */ var matMenuAnimations = { /** * This animation controls the menu panel's entry and exit from the page. * * When the menu panel is added to the DOM, it scales in and fades in its border. * * When the menu panel is removed from the DOM, it simply fades out after a brief * delay to display the ripple. */ transformMenu: animations.trigger('transformMenu', [ animations.state('void', animations.style({ opacity: 0, transform: 'scale(0.8)' })), animations.transition('void => enter', animations.group([ animations.query('.mat-menu-content, .mat-mdc-menu-content', animations.animate('100ms linear', animations.style({ opacity: 1 }))), animations.animate('120ms cubic-bezier(0, 0, 0.2, 1)', animations.style({ transform: 'scale(1)' })), ])), animations.transition('* => void', animations.animate('100ms 25ms linear', animations.style({ opacity: 0 }))) ]), /** * This animation fades in the background color and content of the menu panel * after its containing element is scaled in. */ fadeInItems: animations.trigger('fadeInItems', [ // TODO(crisbeto): this is inside the `transformMenu` // now. Remove next time we do breaking changes. animations.state('showing', animations.style({ opacity: 1 })), animations.transition('void => *', [ animations.style({ opacity: 0 }), animations.animate('400ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)') ]) ]) }; /** * @deprecated * @breaking-change 8.0.0 * @docs-private */ var fadeInItems = matMenuAnimations.fadeInItems; /** * @deprecated * @breaking-change 8.0.0 * @docs-private */ var transformMenu = matMenuAnimations.transformMenu; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Menu content that will be rendered lazily once the menu is opened. */ var MatMenuContent = /** @class */ (function () { function MatMenuContent(_template, _componentFactoryResolver, _appRef, _injector, _viewContainerRef, _document, _changeDetectorRef) { this._template = _template; this._componentFactoryResolver = _componentFactoryResolver; this._appRef = _appRef; this._injector = _injector; this._viewContainerRef = _viewContainerRef; this._document = _document; this._changeDetectorRef = _changeDetectorRef; /** Emits when the menu content has been attached. */ this._attached = new rxjs.Subject(); } /** * Attaches the content with a particular context. * @docs-private */ MatMenuContent.prototype.attach = function (context) { if (context === void 0) { context = {}; } if (!this._portal) { this._portal = new portal.TemplatePortal(this._template, this._viewContainerRef); } this.detach(); if (!this._outlet) { this._outlet = new portal.DomPortalOutlet(this._document.createElement('div'), this._componentFactoryResolver, this._appRef, this._injector); } var element = this._template.elementRef.nativeElement; // Because we support opening the same menu from different triggers (which in turn have their // own `OverlayRef` panel), we have to re-insert the host element every time, otherwise we // risk it staying attached to a pane that's no longer in the DOM. element.parentNode.insertBefore(this._outlet.outletElement, element); // When `MatMenuContent` is used in an `OnPush` component, the insertion of the menu // content via `createEmbeddedView` does not cause the content to be seen as "dirty" // by Angular. This causes the `@ContentChildren` for menu items within the menu to // not be updated by Angular. By explicitly marking for check here, we tell Angular that // it needs to check for new menu items and update the `@ContentChild` in `MatMenu`. // @breaking-change 9.0.0 Make change detector ref required if (this._changeDetectorRef) { this._changeDetectorRef.markForCheck(); } this._portal.attach(this._outlet, context); this._attached.next(); }; /** * Detaches the content. * @docs-private */ MatMenuContent.prototype.detach = function () { if (this._portal.isAttached) { this._portal.detach(); } }; MatMenuContent.prototype.ngOnDestroy = function () { if (this._outlet) { this._outlet.dispose(); } }; MatMenuContent.decorators = [ { type: core.Directive, args: [{ selector: 'ng-template[matMenuContent]' },] } ]; /** @nocollapse */ MatMenuContent.ctorParameters = function () { return [ { type: core.TemplateRef }, { type: core.ComponentFactoryResolver }, { type: core.ApplicationRef }, { type: core.Injector }, { type: core.ViewContainerRef }, { type: undefined, decorators: [{ type: core.Inject, args: [common.DOCUMENT,] }] }, { type: core.ChangeDetectorRef } ]; }; return MatMenuContent; }()); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Throws an exception for the case when menu trigger doesn't have a valid mat-menu instance * @docs-private */ function throwMatMenuMissingError() { throw Error("matMenuTriggerFor: must pass in an mat-menu instance.\n\n Example:\n <mat-menu #menu=\"matMenu\"></mat-menu>\n <button [matMenuTriggerFor]=\"menu\"></button>"); } /** * Throws an exception for the case when menu's x-position value isn't valid. * In other words, it doesn't match 'before' or 'after'. * @docs-private */ function throwMatMenuInvalidPositionX() { throw Error("xPosition value must be either 'before' or after'.\n Example: <mat-menu xPosition=\"before\" #menu=\"matMenu\"></mat-menu>"); } /** * Throws an exception for the case when menu's y-position value isn't valid. * In other words, it doesn't match 'above' or 'below'. * @docs-private */ function throwMatMenuInvalidPositionY() { throw Error("yPosition value must be either 'above' or below'.\n Example: <mat-menu yPosition=\"above\" #menu=\"matMenu\"></mat-menu>"); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Injection token used to provide the parent menu to menu-specific components. * @docs-private */ var MAT_MENU_PANEL = new core.InjectionToken('MAT_MENU_PANEL'); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ // Boilerplate for applying mixins to MatMenuItem. /** @docs-private */ var MatMenuItemBase = /** @class */ (function () { function MatMenuItemBase() { } return MatMenuItemBase; }()); var _MatMenuItemMixinBase = core$1.mixinDisableRipple(core$1.mixinDisabled(MatMenuItemBase)); /** * Single item inside of a `mat-menu`. Provides the menu item styling and accessibility treatment. */ var MatMenuItem = /** @class */ (function (_super) { __extends(MatMenuItem, _super); function MatMenuItem(_elementRef, document, _focusMonitor, _parentMenu) { var _this = // @breaking-change 8.0.0 make `_focusMonitor` and `document` required params. _super.call(this) || this; _this._elementRef = _elementRef; _this._focusMonitor = _focusMonitor; _this._parentMenu = _parentMenu; /** ARIA role for the menu item. */ _this.role = 'menuitem'; /** Stream that emits when the menu item is hovered. */ _this._hovered = new rxjs.Subject(); /** Stream that emits when the menu item is focused. */ _this._focused = new rxjs.Subject(); /** Whether the menu item is highlighted. */ _this._highlighted = false; /** Whether the menu item acts as a trigger for a sub-menu. */ _this._triggersSubmenu = false; if (_focusMonitor) { // Start monitoring the element so it gets the appropriate focused classes. We want // to show the focus style for menu items only when the focus was not caused by a // mouse or touch interaction. _focusMonitor.monitor(_this._elementRef, false); } if (_parentMenu && _parentMenu.addItem) { _parentMenu.addItem(_this); } _this._document = document; return _this; } /** Focuses the menu item. */ MatMenuItem.prototype.focus = function (origin, options) { if (origin === void 0) { origin = 'program'; } if (this._focusMonitor) { this._focusMonitor.focusVia(this._getHostElement(), origin, options); } else { this._getHostElement().focus(options); } this._focused.next(this); }; MatMenuItem.prototype.ngOnDestroy = function () { if (this._focusMonitor) { this._focusMonitor.stopMonitoring(this._elementRef); } if (this._parentMenu && this._parentMenu.removeItem) { this._parentMenu.removeItem(this); } this._hovered.complete(); this._focused.complete(); }; /** Used to set the `tabindex`. */ MatMenuItem.prototype._getTabIndex = function () { return this.disabled ? '-1' : '0'; }; /** Returns the host DOM element. */ MatMenuItem.prototype._getHostElement = function () { return this._elementRef.nativeElement; }; /** Prevents the default element actions if it is disabled. */ // We have to use a `HostListener` here in order to support both Ivy and ViewEngine. // In Ivy the `host` bindings will be merged when this class is extended, whereas in // ViewEngine they're overwritten. // TODO(crisbeto): we move this back into `host` once Ivy is turned on by default. // tslint:disable-next-line:no-host-decorator-in-concrete MatMenuItem.prototype._checkDisabled = function (event) { if (this.disabled) { event.preventDefault(); event.stopPropagation(); } }; /** Emits to the hover stream. */ // We have to use a `HostListener` here in order to support both Ivy and ViewEngine. // In Ivy the `host` bindings will be merged when this class is extended, whereas in // ViewEngine they're overwritten. // TODO(crisbeto): we move this back into `host` once Ivy is turned on by default. // tslint:disable-next-line:no-host-decorator-in-concrete MatMenuItem.prototype._handleMouseEnter = function () { this._hovered.next(this); }; /** Gets the label to be used when determining whether the option should be focused. */ MatMenuItem.prototype.getLabel = function () { var element = this._elementRef.nativeElement; var textNodeType = this._document ? this._document.TEXT_NODE : 3; var output = ''; if (element.childNodes) { var length_1 = element.childNodes.length; // Go through all the top-level text nodes and extract their text. // We skip anything that's not a text node to prevent the text from // being thrown off by something like an icon. for (var i = 0; i < length_1; i++) { if (element.childNodes[i].nodeType === textNodeType) { output += element.childNodes[i].textContent; } } } return output.trim(); }; MatMenuItem.decorators = [ { type: core.Component, args: [{ selector: '[mat-menu-item]', exportAs: 'matMenuItem', inputs: ['disabled', 'disableRipple'], host: { '[attr.role]': 'role', '[class.mat-menu-item]': 'true', '[class.mat-menu-item-highlighted]': '_highlighted', '[class.mat-menu-item-submenu-trigger]': '_triggersSubmenu', '[attr.tabindex]': '_getTabIndex()', '[attr.aria-disabled]': 'disabled.toString()', '[attr.disabled]': 'disabled || null', 'class': 'mat-focus-indicator', }, changeDetection: core.ChangeDetectionStrategy.OnPush, encapsulation: core.ViewEncapsulation.None, template: "<ng-content></ng-content>\n<div class=\"mat-menu-ripple\" matRipple\n [matRippleDisabled]=\"disableRipple || disabled\"\n [matRippleTrigger]=\"_getHostElement()\">\n</div>\n" }] } ]; /** @nocollapse */ MatMenuItem.ctorParameters = function () { return [ { type: core.ElementRef }, { type: undefined, decorators: [{ type: core.Inject, args: [common.DOCUMENT,] }] }, { type: a11y.FocusMonitor }, { type: undefined, decorators: [{ type: core.Inject, args: [MAT_MENU_PANEL,] }, { type: core.Optional }] } ]; }; MatMenuItem.propDecorators = { role: [{ type: core.Input }], _checkDisabled: [{ type: core.HostListener, args: ['click', ['$event'],] }], _handleMouseEnter: [{ type: core.HostListener, args: ['mouseenter',] }] }; return MatMenuItem; }(_MatMenuItemMixinBase)); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** Injection token to be used to override the default options for `mat-menu`. */ var MAT_MENU_DEFAULT_OPTIONS = new core.InjectionToken('mat-menu-default-options', { providedIn: 'root', factory: MAT_MENU_DEFAULT_OPTIONS_FACTORY }); /** @docs-private */ function MAT_MENU_DEFAULT_OPTIONS_FACTORY() { return { overlapTrigger: false, xPosition: 'after', yPosition: 'below', backdropClass: 'cdk-overlay-transparent-backdrop', }; } /** * Start elevation for the menu panel. * @docs-private */ var MAT_MENU_BASE_ELEVATION = 4; var menuPanelUid = 0; /** Base class with all of the `MatMenu` functionality. */ var _MatMenuBase = /** @class */ (function () { function _MatMenuBase(_elementRef, _ngZone, _defaultOptions) { this._elementRef = _elementRef; this._ngZone = _ngZone; this._defaultOptions = _defaultOptions; this._xPosition = this._defaultOptions.xPosition; this._yPosition = this._defaultOptions.yPosition; /** Only the direct descendant menu items. */ this._directDescendantItems = new core.QueryList(); /** Subscription to tab events on the menu panel */ this._tabSubscription = rxjs.Subscription.EMPTY; /** Config object to be passed into the menu's ngClass */ this._classList = {}; /** Current state of the panel animation. */ this._panelAnimationState = 'void'; /** Emits whenever an animation on the menu completes. */ this._animationDone = new rxjs.Subject(); /** Class to be added to the backdrop element. */ this.backdropClass = this._defaultOptions.backdropClass; this._overlapTrigger = this._defaultOptions.overlapTrigger; this._hasBackdrop = this._defaultOptions.hasBackdrop; /** Event emitted when the menu is closed. */ this.closed = new core.EventEmitter(); /** * Event emitted when the menu is closed. * @deprecated Switch to `closed` instead * @breaking-change 8.0.0 */ this.close = this.closed; this.panelId = "mat-menu-panel-" + menuPanelUid++; } Object.defineProperty(_MatMenuBase.prototype, "xPosition", { /** Position of the menu in the X axis. */ get: function () { return this._xPosition; }, set: function (value) { if (value !== 'before' && value !== 'after') { throwMatMenuInvalidPositionX(); } this._xPosition = value; this.setPositionClasses(); }, enumerable: true, configurable: true }); Object.defineProperty(_MatMenuBase.prototype, "yPosition", { /** Position of the menu in the Y axis. */ get: function () { return this._yPosition; }, set: function (value) { if (value !== 'above' && value !== 'below') { throwMatMenuInvalidPositionY(); } this._yPosition = value; this.setPositionClasses(); }, enumerable: true, configurable: true }); Object.defineProperty(_MatMenuBase.prototype, "overlapTrigger", { /** Whether the menu should overlap its trigger. */ get: function () { return this._overlapTrigger; }, set: function (value) { this._overlapTrigger = coercion.coerceBooleanProperty(value); }, enumerable: true, configurable: true }); Object.defineProperty(_MatMenuBase.prototype, "hasBackdrop", { /** Whether the menu has a backdrop. */ get: function () { return this._hasBackdrop; }, set: function (value) { this._hasBackdrop = coercion.coerceBooleanProperty(value); }, enumerable: true, configurable: true }); Object.defineProperty(_MatMenuBase.prototype, "panelClass", { /** * This method takes classes set on the host mat-menu element and applies them on the * menu template that displays in the overlay container. Otherwise, it's difficult * to style the containing menu from outside the component. * @param classes list of class names */ set: function (classes) { var _this = this; var previousPanelClass = this._previousPanelClass; if (previousPanelClass && previousPanelClass.length) { previousPanelClass.split(' ').forEach(function (className) { _this._classList[className] = false; }); } this._previousPanelClass = classes; if (classes && classes.length) { classes.split(' ').forEach(function (className) { _this._classList[className] = true; }); this._elementRef.nativeElement.className = ''; } }, enumerable: true, configurable: true }); Object.defineProperty(_MatMenuBase.prototype, "classList", { /** * This method takes classes set on the host mat-menu element and applies them on the * menu template that displays in the overlay container. Otherwise, it's difficult * to style the containing menu from outside the component. * @deprecated Use `panelClass` instead. * @breaking-change 8.0.0 */ get: function () { return this.panelClass; }, set: function (classes) { this.panelClass = classes; }, enumerable: true, configurable: true }); _MatMenuBase.prototype.ngOnInit = function () { this.setPositionClasses(); }; _MatMenuBase.prototype.ngAfterContentInit = function () { var _this = this; this._updateDirectDescendants(); this._keyManager = new a11y.FocusKeyManager(this._directDescendantItems).withWrap().withTypeAhead(); this._tabSubscription = this._keyManager.tabOut.subscribe(function () { return _this.closed.emit('tab'); }); // If a user manually (programatically) focuses a menu item, we need to reflect that focus // change back to the key manager. Note that we don't need to unsubscribe here because _focused // is internal and we know that it gets completed on destroy. this._directDescendantItems.changes.pipe(operators.startWith(this._directDescendantItems), operators.switchMap(function (items) { return rxjs.merge.apply(void 0, __spread(items.map(function (item) { return item._focused; }))); })).subscribe(function (focusedItem) { return _this._keyManager.updateActiveItem(focusedItem); }); }; _MatMenuBase.prototype.ngOnDestroy = function () { this._directDescendantItems.destroy(); this._tabSubscription.unsubscribe(); this.closed.complete(); }; /** Stream that emits whenever the hovered menu item changes. */ _MatMenuBase.prototype._hovered = function () { // Coerce the `changes` property because Angular types it as `Observable<any>` var itemChanges = this._directDescendantItems.changes; return itemChanges.pipe(operators.startWith(this._directDescendantItems), operators.switchMap(function (items) { return rxjs.merge.apply(void 0, __spread(items.map(function (item) { return item._hovered; }))); })); }; /* * Registers a menu item with the menu. * @docs-private * @deprecated No longer being used. To be removed. * @breaking-change 9.0.0 */ _MatMenuBase.prototype.addItem = function (_item) { }; /** * Removes an item from the menu. * @docs-private * @deprecated No longer being used. To be removed. * @breaking-change 9.0.0 */ _MatMenuBase.prototype.removeItem = function (_item) { }; /** Handle a keyboard event from the menu, delegating to the appropriate action. */ _MatMenuBase.prototype._handleKeydown = function (event) { var keyCode = event.keyCode; var manager = this._keyManager; switch (keyCode) { case keycodes.ESCAPE: if (!keycodes.hasModifierKey(event)) { event.preventDefault(); this.closed.emit('keydown'); } break; case keycodes.LEFT_ARROW: if (this.parentMenu && this.direction === 'ltr') { this.closed.emit('keydown'); } break; case keycodes.RIGHT_ARROW: if (this.parentMenu && this.direction === 'rtl') { this.closed.emit('keydown'); } break; case keycodes.HOME: case keycodes.END: if (!keycodes.hasModifierKey(event)) { keyCode === keycodes.HOME ? manager.setFirstItemActive() : manager.setLastItemActive(); event.preventDefault(); } break; default: if (keyCode === keycodes.UP_ARROW || keyCode === keycodes.DOWN_ARROW) { manager.setFocusOrigin('keyboard'); } manager.onKeydown(event); } }; /** * Focus the first item in the menu. * @param origin Action from which the focus originated. Used to set the correct styling. */ _MatMenuBase.prototype.focusFirstItem = function (origin) { var _this = this; if (origin === void 0) { origin = 'program'; } // When the content is rendered lazily, it takes a bit before the items are inside the DOM. if (this.lazyContent) { this._ngZone.onStable.asObservable() .pipe(operators.take(1)) .subscribe(function () { return _this._focusFirstItem(origin); }); } else { this._focusFirstItem(origin); } }; /** * Actual implementation that focuses the first item. Needs to be separated * out so we don't repeat the same logic in the public `focusFirstItem` method. */ _MatMenuBase.prototype._focusFirstItem = function (origin) { var manager = this._keyManager; manager.setFocusOrigin(origin).setFirstItemActive(); // If there's no active item at this point, it means that all the items are disabled. // Move focus to the menu panel so keyboard events like Escape still work. Also this will // give _some_ feedback to screen readers. if (!manager.activeItem && this._directDescendantItems.length) { var element = this._directDescendantItems.first._getHostElement().parentElement; // Because the `mat-menu` is at the DOM insertion point, not inside the overlay, we don't // have a nice way of getting a hold of the menu panel. We can't use a `ViewChild` either // because the panel is inside an `ng-template`. We work around it by starting from one of // the items and walking up the DOM. while (element) { if (element.getAttribute('role') === 'menu') { element.focus(); break; } else { element = element.parentElement; } } } }; /** * Resets the active item in the menu. This is used when the menu is opened, allowing * the user to start from the first option when pressing the down arrow. */ _MatMenuBase.prototype.resetActiveItem = function () { this._keyManager.setActiveItem(-1); }; /** * Sets the menu panel elevation. * @param depth Number of parent menus that come before the menu. */ _MatMenuBase.prototype.setElevation = function (depth) { // The elevation starts at the base and increases by one for each level. // Capped at 24 because that's the maximum elevation defined in the Material design spec. var elevation = Math.min(MAT_MENU_BASE_ELEVATION + depth, 24); var newElevation = "mat-elevation-z" + elevation; var customElevation = Object.keys(this._classList).find(function (c) { return c.startsWith('mat-elevation-z'); }); if (!customElevation || customElevation === this._previousElevation) { if (this._previousElevation) { this._classList[this._previousElevation] = false; } this._classList[newElevation] = true; this._previousElevation = newElevation; } }; /** * Adds classes to the menu panel based on its position. Can be used by * consumers to add specific styling based on the position. * @param posX Position of the menu along the x axis. * @param posY Position of the menu along the y axis. * @docs-private */ _MatMenuBase.prototype.setPositionClasses = function (posX, posY) { if (posX === void 0) { posX = this.xPosition; } if (posY === void 0) { posY = this.yPosition; } var classes = this._classList; classes['mat-menu-before'] = posX === 'before'; classes['mat-menu-after'] = posX === 'after'; classes['mat-menu-above'] = posY === 'above'; classes['mat-menu-below'] = posY === 'below'; }; /** Starts the enter animation. */ _MatMenuBase.prototype._startAnimation = function () { // @breaking-change 8.0.0 Combine with _resetAnimation. this._panelAnimationState = 'enter'; }; /** Resets the panel animation to its initial state. */ _MatMenuBase.prototype._resetAnimation = function () { // @breaking-change 8.0.0 Combine with _startAnimation. this._panelAnimationState = 'void'; }; /** Callback that is invoked when the panel animation completes. */ _MatMenuBase.prototype._onAnimationDone = function (event) { this._animationDone.next(event); this._isAnimating = false; }; _MatMenuBase.prototype._onAnimationStart = function (event) { this._isAnimating = true; // Scroll the content element to the top as soon as the animation starts. This is necessary, // because we move focus to the first item while it's still being animated, which can throw // the browser off when it determines the scroll position. Alternatively we can move focus // when the animation is done, however moving focus asynchronously will interrupt screen // readers which are in the process of reading out the menu already. We take the `element` // from the `event` since we can't use a `ViewChild` to access the pane. if (event.toState === 'enter' && this._keyManager.activeItemIndex === 0) { event.element.scrollTop = 0; } }; /** * Sets up a stream that will keep track of any newly-added menu items and will update the list * of direct descendants. We collect the descendants this way, because `_allItems` can include * items that are part of child menus, and using a custom way of registering items is unreliable * when it comes to maintaining the item order. */ _MatMenuBase.prototype._updateDirectDescendants = function () { var _this = this; this._allItems.changes .pipe(operators.startWith(this._allItems)) .subscribe(function (items) { _this._directDescendantItems.reset(items.filter(function (item) { return item._parentMenu === _this; })); _this._directDescendantItems.notifyOnChanges(); }); }; _MatMenuBase.decorators = [ { type: core.Directive } ]; /** @nocollapse */ _MatMenuBase.ctorParameters = function () { return [ { type: core.ElementRef }, { type: core.NgZone }, { type: undefined, decorators: [{ type: core.Inject, args: [MAT_MENU_DEFAULT_OPTIONS,] }] } ]; }; _MatMenuBase.propDecorators = { _allItems: [{ type: core.ContentChildren, args: [MatMenuItem, { descendants: true },] }], backdropClass: [{ type: core.Input }], ariaLabel: [{ type: core.Input, args: ['aria-label',] }], ariaLabelledby: [{ type: core.Input, args: ['aria-labelledby',] }], ariaDescribedby: [{ type: core.Input, args: ['aria-describedby',] }], xPosition: [{ type: core.Input }], yPosition: [{ type: core.Input }], templateRef: [{ type: core.ViewChild, args: [core.TemplateRef,] }], items: [{ type: core.ContentChildren, args: [MatMenuItem, { descendants: false },] }], lazyContent: [{ type: core.ContentChild, args: [MatMenuContent,] }], overlapTrigger: [{ type: core.Input }], hasBackdrop: [{ type: core.Input }], panelClass: [{ type: core.Input, args: ['class',] }], classList: [{ type: core.Input }], closed: [{ type: core.Output }], close: [{ type: core.Output }] }; return _MatMenuBase; }()); /** @docs-private We show the "_MatMenu" class as "MatMenu" in the docs. */ var MatMenu = /** @class */ (function (_super) { __extends(MatMenu, _super); function MatMenu() { return _super !== null && _super.apply(this, arguments) || this; } MatMenu.decorators = [ { type: core.Directive } ]; return MatMenu; }(_MatMenuBase)); // Note on the weird inheritance setup: we need three classes, because the MDC-based menu has to // extend `MatMenu`, however keeping a reference to it will cause the inlined template and styles // to be retained as well. The MDC menu also has to provide itself as a `MatMenu` in order for // queries and DI to work correctly, while still not referencing the actual menu class. // Class responsibility is split up as follows: // * _MatMenuBase - provides all the functionality without any of the Angular metadata. // * MatMenu - keeps the same name symbol name as the current menu and // is used as a provider for DI and query purposes. // * _MatMenu - the actual menu component implementation with the Angular metadata that should // be tree shaken away for MDC. /** @docs-public MatMenu */ var _MatMenu = /** @class */ (function (_super) { __extends(_MatMenu, _super); function _MatMenu(elementRef, ngZone, defaultOptions) { return _super.call(this, elementRef, ngZone, defaultOptions) || this; } _MatMenu.decorators = [ { type: core.Component, args: [{ selector: 'mat-menu', template: "<ng-template>\n <div\n class=\"mat-menu-panel\"\n [id]=\"panelId\"\n [ngClass]=\"_classList\"\n (keydown)=\"_handleKeydown($event)\"\n (click)=\"closed.emit('click')\"\n [@transformMenu]=\"_panelAnimationState\"\n (@transformMenu.start)=\"_onAnimationStart($event)\"\n (@transformMenu.done)=\"_onAnimationDone($event)\"\n tabindex=\"-1\"\n role=\"menu\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"ariaLabelledby || null\"\n [attr.aria-describedby]=\"ariaDescribedby || null\">\n <div class=\"mat-menu-content\">\n <ng-content></ng-content>\n </div>\n </div>\n</ng-template>\n", changeDetection: core.ChangeDetectionStrategy.OnPush, encapsulation: core.ViewEncapsulation.None, exportAs: 'matMenu', animations: [ matMenuAnimations.transformMenu, matMenuAnimations.fadeInItems ], providers: [ { provide: MAT_MENU_PANEL, useExisting: MatMenu }, { provide: MatMenu, useExisting: _MatMenu } ], styles: [".mat-menu-panel{min-width:112px;max-width:280px;overflow:auto;-webkit-overflow-scrolling:touch;max-height:calc(100vh - 48px);border-radius:4px;outline:0;min-height:64px}.mat-menu-panel.ng-animating{pointer-events:none}.cdk-high-contrast-active .mat-menu-panel{outline:solid 1px}.mat-menu-content:not(:empty){padding-top:8px;padding-bottom:8px}.mat-menu-item{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:none;border:none;-webkit-tap-highlight-color:transparent;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block;line-height:48px;height:48px;padding:0 16px;text-align:left;text-decoration:none;max-width:100%;position:relative}.mat-menu-item::-moz-focus-inner{border:0}.mat-menu-item[disabled]{cursor:default}[dir=rtl] .mat-menu-item{text-align:right}.mat-menu-item .mat-icon{margin-right:16px;vertical-align:middle}.mat-menu-item .mat-icon svg{vertical-align:top}[dir=rtl] .mat-menu-item .mat-icon{margin-left:16px;margin-right:0}.mat-menu-item[disabled]{pointer-events:none}.cdk-high-contrast-active .mat-menu-item.cdk-program-focused,.cdk-high-contrast-active .mat-menu-item.cdk-keyboard-focused,.cdk-high-contrast-active .mat-menu-item-highlighted{outline:dotted 1px}.mat-menu-item-submenu-trigger{padding-right:32px}.mat-menu-item-submenu-trigger::after{width:0;height:0;border-style:solid;bor