text: /**
   * @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
   */
  import { Directive, TemplateRef, ComponentFactoryResolver, ApplicationRef, Injector, ViewContainerRef, Inject, InjectionToken, ChangeDetectionStrategy, Component, ElementRef, ViewEncapsulation, Optional, ContentChild, ContentChildren, EventEmitter, Input, NgZone, Output, ViewChild, Self, NgModule } from '@angular/core';
  import { TemplatePortal, DomPortalOutlet } from '@angular/cdk/portal';
  import { DOCUMENT, CommonModule } from '@angular/common';
  import { Subject, merge, Subscription, asapScheduler, of } from 'rxjs';
  import { trigger, state, style, animate, transition, query, group } from '@angular/animations';
  import { FocusMonitor, FocusKeyManager, isFakeMousedownFromScreenReader } from '@angular/cdk/a11y';
  import { mixinDisabled, mixinDisableRipple, MatCommonModule, MatRippleModule } from '@angular/material/core';
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
  import { ESCAPE, LEFT_ARROW, RIGHT_ARROW, DOWN_ARROW, UP_ARROW } from '@angular/cdk/keycodes';
  import { startWith, switchMap, take, delay, filter, takeUntil } from 'rxjs/operators';
  import { Directionality } from '@angular/cdk/bidi';
  import { Overlay, OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  /**
   * Menu content that will be rendered lazily once the menu is opened.
   */
  class MatMenuContent {
      /**
       * @param {?} _template
       * @param {?} _componentFactoryResolver
       * @param {?} _appRef
       * @param {?} _injector
       * @param {?} _viewContainerRef
       * @param {?} _document
       */
      constructor(_template, _componentFactoryResolver, _appRef, _injector, _viewContainerRef, _document) {
          this._template = _template;
          this._componentFactoryResolver = _componentFactoryResolver;
          this._appRef = _appRef;
          this._injector = _injector;
          this._viewContainerRef = _viewContainerRef;
          this._document = _document;
          /**
           * Emits when the menu content has been attached.
           */
          this._attached = new Subject();
      }
      /**
       * Attaches the content with a particular context.
       * \@docs-private
       * @param {?=} context
       * @return {?}
       */
      attach(context = {}) {
          if (!this._portal) {
              this._portal = new TemplatePortal(this._template, this._viewContainerRef);
          }
          this.detach();
          if (!this._outlet) {
              this._outlet = new DomPortalOutlet(this._document.createElement('div'), this._componentFactoryResolver, this._appRef, this._injector);
          }
          /** @type {?} */
          const element = this._template.elementRef.nativeElement; /** @type {?} */
          ((
          // 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);
          this._portal.attach(this._outlet, context);
          this._attached.next();
      }
      /**
       * Detaches the content.
       * \@docs-private
       * @return {?}
       */
      detach() {
          if (this._portal.isAttached) {
              this._portal.detach();
          }
      }
      /**
       * @return {?}
       */
      ngOnDestroy() {
          if (this._outlet) {
              this._outlet.dispose();
          }
      }
  }
  MatMenuContent.decorators = [
      { type: Directive, args: [{
                  selector: 'ng-template[matMenuContent]'
              },] },
  ];
  /** @nocollapse */
  MatMenuContent.ctorParameters = () => [
      { type: TemplateRef },
      { type: ComponentFactoryResolver },
      { type: ApplicationRef },
      { type: Injector },
      { type: ViewContainerRef },
      { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  /** *
   * 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
    @type {?} */
  const 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: trigger('transformMenu', [
          state('void', style({
              opacity: 0,
              transform: 'scale(0.8)'
          })),
          transition('void => enter', group([
              query('.mat-menu-content', animate('100ms linear', style({ opacity: 1 }))),
              animate('120ms cubic-bezier(0, 0, 0.2, 1)', style({ transform: 'scale(1)' })),
          ])),
          transition('* => void', animate('100ms 25ms linear', style({ opacity: 0 })))
      ]),
      /**
         * This animation fades in the background color and content of the menu panel
         * after its containing element is scaled in.
         */
      fadeInItems: trigger('fadeInItems', [
          // TODO(crisbeto): this is inside the `transformMenu`
          // now. Remove next time we do breaking changes.
          state('showing', style({ opacity: 1 })),
          transition('void => *', [
              style({ opacity: 0 }),
              animate('400ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)')
          ])
      ])
  };
  /** *
   * @deprecated
   * \@breaking-change 8.0.0
   * \@docs-private
    @type {?} */
  const fadeInItems = matMenuAnimations.fadeInItems;
  /** *
   * @deprecated
   * \@breaking-change 8.0.0
   * \@docs-private
    @type {?} */
  const transformMenu = matMenuAnimations.transformMenu;
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  
  /**
   * Throws an exception for the case when menu trigger doesn't have a valid mat-menu instance
   * \@docs-private
   * @return {?}
   */
  function throwMatMenuMissingError() {
      throw Error(`matMenuTriggerFor: must pass in an mat-menu instance.
  
      Example:
        <mat-menu #menu="matMenu"></mat-menu>
        <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
   * @return {?}
   */
  function throwMatMenuInvalidPositionX() {
      throw Error(`xPosition value must be either 'before' or after'.
        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
   * @return {?}
   */
  function throwMatMenuInvalidPositionY() {
      throw Error(`yPosition value must be either 'above' or below'.
        Example: <mat-menu yPosition="above" #menu="matMenu"></mat-menu>`);
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  /** *
   * Injection token used to provide the parent menu to menu-specific components.
   * \@docs-private
    @type {?} */
  const MAT_MENU_PANEL = new InjectionToken('MAT_MENU_PANEL');
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  /**
   * \@docs-private
   */
  class MatMenuItemBase {
  }
  /** @type {?} */
  const _MatMenuItemMixinBase = mixinDisableRipple(mixinDisabled(MatMenuItemBase));
  /**
   * This directive is intended to be used inside an mat-menu tag.
   * It exists mostly to set the role attribute.
   */
  class MatMenuItem extends _MatMenuItemMixinBase {
      /**
       * @param {?} _elementRef
       * @param {?=} document
       * @param {?=} _focusMonitor
       * @param {?=} _parentMenu
       */
      constructor(_elementRef, document, _focusMonitor, _parentMenu) {
          // @breaking-change 8.0.0 make `_focusMonitor` and `document` required params.
          super();
          this._elementRef = _elementRef;
          this._focusMonitor = _focusMonitor;
          this._parentMenu = _parentMenu;
          /**
           * Stream that emits when the menu item is hovered.
           */
          this._hovered = new 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;
      }
      /**
       * Focuses the menu item.
       * @param {?=} origin
       * @return {?}
       */
      focus(origin = 'program') {
          if (this._focusMonitor) {
              this._focusMonitor.focusVia(this._getHostElement(), origin);
          }
          else {
              this._getHostElement().focus();
          }
      }
      /**
       * @return {?}
       */
      ngOnDestroy() {
          if (this._focusMonitor) {
              this._focusMonitor.stopMonitoring(this._elementRef);
          }
          if (this._parentMenu && this._parentMenu.removeItem) {
              this._parentMenu.removeItem(this);
          }
          this._hovered.complete();
      }
      /**
       * Used to set the `tabindex`.
       * @return {?}
       */
      _getTabIndex() {
          return this.disabled ? '-1' : '0';
      }
      /**
       * Returns the host DOM element.
       * @return {?}
       */
      _getHostElement() {
          return this._elementRef.nativeElement;
      }
      /**
       * Prevents the default element actions if it is disabled.
       * @param {?} event
       * @return {?}
       */
      _checkDisabled(event) {
          if (this.disabled) {
              event.preventDefault();
              event.stopPropagation();
          }
      }
      /**
       * Emits to the hover stream.
       * @return {?}
       */
      _handleMouseEnter() {
          this._hovered.next(this);
      }
      /**
       * Gets the label to be used when determining whether the option should be focused.
       * @return {?}
       */
      getLabel() {
          /** @type {?} */
          const element = this._elementRef.nativeElement;
          /** @type {?} */
          const textNodeType = this._document ? this._document.TEXT_NODE : 3;
          /** @type {?} */
          let output = '';
          if (element.childNodes) {
              /** @type {?} */
              const length = 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 (let i = 0; i < length; i++) {
                  if (element.childNodes[i].nodeType === textNodeType) {
                      output += element.childNodes[i].textContent;
                  }
              }
          }
          return output.trim();
      }
  }
  MatMenuItem.decorators = [
      { type: Component, args: [{selector: '[mat-menu-item]',
                  exportAs: 'matMenuItem',
                  inputs: ['disabled', 'disableRipple'],
                  host: {
                      'role': 'menuitem',
                      'class': 'mat-menu-item',
                      '[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',
                      '(click)': '_checkDisabled($event)',
                      '(mouseenter)': '_handleMouseEnter()',
                  },
                  changeDetection: ChangeDetectionStrategy.OnPush,
                  encapsulation: ViewEncapsulation.None,
                  template: "<ng-content></ng-content><div class=\"mat-menu-ripple\" matRipple [matRippleDisabled]=\"disableRipple || disabled\" [matRippleTrigger]=\"_getHostElement()\"></div>",
              },] },
  ];
  /** @nocollapse */
  MatMenuItem.ctorParameters = () => [
      { type: ElementRef },
      { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
      { type: FocusMonitor },
      { type: undefined, decorators: [{ type: Inject, args: [MAT_MENU_PANEL,] }, { type: Optional }] }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  /** *
   * Injection token to be used to override the default options for `mat-menu`.
    @type {?} */
  const MAT_MENU_DEFAULT_OPTIONS = new InjectionToken('mat-menu-default-options', {
      providedIn: 'root',
      factory: MAT_MENU_DEFAULT_OPTIONS_FACTORY
  });
  /**
   * \@docs-private
   * @return {?}
   */
  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
    @type {?} */
  const MAT_MENU_BASE_ELEVATION = 4;
  class MatMenu {
      /**
       * @param {?} _elementRef
       * @param {?} _ngZone
       * @param {?} _defaultOptions
       */
      constructor(_elementRef, _ngZone, _defaultOptions) {
          this._elementRef = _elementRef;
          this._ngZone = _ngZone;
          this._defaultOptions = _defaultOptions;
          this._xPosition = this._defaultOptions.xPosition;
          this._yPosition = this._defaultOptions.yPosition;
          /**
           * Menu items inside the current menu.
           */
          this._items = [];
          /**
           * Emits whenever the amount of menu items changes.
           */
          this._itemChanges = new Subject();
          /**
           * Subscription to tab events on the menu panel
           */
          this._tabSubscription = 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 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 EventEmitter();
          /**
           * Event emitted when the menu is closed.
           * @deprecated Switch to `closed` instead
           * \@breaking-change 8.0.0
           */
          this.close = this.closed;
      }
      /**
       * Position of the menu in the X axis.
       * @return {?}
       */
      get xPosition() { return this._xPosition; }
      /**
       * @param {?} value
       * @return {?}
       */
      set xPosition(value) {
          if (value !== 'before' && value !== 'after') {
              throwMatMenuInvalidPositionX();
          }
          this._xPosition = value;
          this.setPositionClasses();
      }
      /**
       * Position of the menu in the Y axis.
       * @return {?}
       */
      get yPosition() { return this._yPosition; }
      /**
       * @param {?} value
       * @return {?}
       */
      set yPosition(value) {
          if (value !== 'above' && value !== 'below') {
              throwMatMenuInvalidPositionY();
          }
          this._yPosition = value;
          this.setPositionClasses();
      }
      /**
       * Whether the menu should overlap its trigger.
       * @return {?}
       */
      get overlapTrigger() { return this._overlapTrigger; }
      /**
       * @param {?} value
       * @return {?}
       */
      set overlapTrigger(value) {
          this._overlapTrigger = coerceBooleanProperty(value);
      }
      /**
       * Whether the menu has a backdrop.
       * @return {?}
       */
      get hasBackdrop() { return this._hasBackdrop; }
      /**
       * @param {?} value
       * @return {?}
       */
      set hasBackdrop(value) {
          this._hasBackdrop = coerceBooleanProperty(value);
      }
      /**
       * 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
       * @return {?}
       */
      set panelClass(classes) {
          if (classes && classes.length) {
              this._classList = classes.split(' ').reduce((obj, className) => {
                  obj[className] = true;
                  return obj;
              }, {});
              this._elementRef.nativeElement.className = '';
          }
      }
      /**
       * 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
       * @return {?}
       */
      get classList() { return this.panelClass; }
      /**
       * @param {?} classes
       * @return {?}
       */
      set classList(classes) { this.panelClass = classes; }
      /**
       * @return {?}
       */
      ngOnInit() {
          this.setPositionClasses();
      }
      /**
       * @return {?}
       */
      ngAfterContentInit() {
          this._keyManager = new FocusKeyManager(this._items).withWrap().withTypeAhead();
          this._tabSubscription = this._keyManager.tabOut.subscribe(() => this.closed.emit('tab'));
      }
      /**
       * @return {?}
       */
      ngOnDestroy() {
          this._tabSubscription.unsubscribe();
          this.closed.complete();
      }
      /**
       * Stream that emits whenever the hovered menu item changes.
       * @return {?}
       */
      _hovered() {
          return this._itemChanges.pipe(startWith(this._items), switchMap(items => merge(...items.map(item => item._hovered))));
      }
      /**
       * Handle a keyboard event from the menu, delegating to the appropriate action.
       * @param {?} event
       * @return {?}
       */
      _handleKeydown(event) {
          /** @type {?} */
          const keyCode = event.keyCode;
          switch (keyCode) {
              case ESCAPE:
                  this.closed.emit('keydown');
                  event.stopPropagation();
                  break;
              case LEFT_ARROW:
                  if (this.parentMenu && this.direction === 'ltr') {
                      this.closed.emit('keydown');
                  }
                  break;
              case RIGHT_ARROW:
                  if (this.parentMenu && this.direction === 'rtl') {
                      this.closed.emit('keydown');
                  }
                  break;
              default:
                  if (keyCode === UP_ARROW || keyCode === DOWN_ARROW) {
                      this._keyManager.setFocusOrigin('keyboard');
                  }
                  this._keyManager.onKeydown(event);
          }
      }
      /**
       * Focus the first item in the menu.
       * @param {?=} origin Action from which the focus originated. Used to set the correct styling.
       * @return {?}
       */
      focusFirstItem(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(take(1))
                  .subscribe(() => this._keyManager.setFocusOrigin(origin).setFirstItemActive());
          }
          else {
              this._keyManager.setFocusOrigin(origin).setFirstItemActive();
          }
      }
      /**
       * 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.
       * @return {?}
       */
      resetActiveItem() {
          this._keyManager.setActiveItem(-1);
      }
      /**
       * Sets the menu panel elevation.
       * @param {?} depth Number of parent menus that come before the menu.
       * @return {?}
       */
      setElevation(depth) {
          /** @type {?} */
          const newElevation = `mat-elevation-z${MAT_MENU_BASE_ELEVATION + depth}`;
          /** @type {?} */
          const customElevation = Object.keys(this._classList).find(c => 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;
          }
      }
      /**
       * Registers a menu item with the menu.
       * \@docs-private
       * @param {?} item
       * @return {?}
       */
      addItem(item) {
          // We register the items through this method, rather than picking them up through
          // `ContentChildren`, because we need the items to be picked up by their closest
          // `mat-menu` ancestor. If we used `@ContentChildren(MatMenuItem, {descendants: true})`,
          // all descendant items will bleed into the top-level menu in the case where the consumer
          // has `mat-menu` instances nested inside each other.
          if (this._items.indexOf(item) === -1) {
              this._items.push(item);
              this._itemChanges.next(this._items);
          }
      }
      /**
       * Removes an item from the menu.
       * \@docs-private
       * @param {?} item
       * @return {?}
       */
      removeItem(item) {
          /** @type {?} */
          const index = this._items.indexOf(item);
          if (this._items.indexOf(item) > -1) {
              this._items.splice(index, 1);
              this._itemChanges.next(this._items);
          }
      }
      /**
       * Adds classes to the menu panel based on its position. Can be used by
       * consumers to add specific styling based on the position.
       * \@docs-private
       * @param {?=} posX Position of the menu along the x axis.
       * @param {?=} posY Position of the menu along the y axis.
       * @return {?}
       */
      setPositionClasses(posX = this.xPosition, posY = this.yPosition) {
          /** @type {?} */
          const 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.
       * @return {?}
       */
      _startAnimation() {
          // @breaking-change 8.0.0 Combine with _resetAnimation.
          this._panelAnimationState = 'enter';
      }
      /**
       * Resets the panel animation to its initial state.
       * @return {?}
       */
      _resetAnimation() {
          // @breaking-change 8.0.0 Combine with _startAnimation.
          this._panelAnimationState = 'void';
      }
      /**
       * Callback that is invoked when the panel animation completes.
       * @param {?} event
       * @return {?}
       */
      _onAnimationDone(event) {
          this._animationDone.next(event);
          this._isAnimating = false;
          // Scroll the content element to the top once the animation is done. 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;
          }
      }
  }
  MatMenu.decorators = [
      { type: Component, args: [{selector: 'mat-menu',
                  template: "<ng-template><div class=\"mat-menu-panel\" [ngClass]=\"_classList\" (keydown)=\"_handleKeydown($event)\" (click)=\"closed.emit('click')\" [@transformMenu]=\"_panelAnimationState\" (@transformMenu.start)=\"_isAnimating = true\" (@transformMenu.done)=\"_onAnimationDone($event)\" tabindex=\"-1\" role=\"menu\"><div class=\"mat-menu-content\"><ng-content></ng-content></div></div></ng-template>",
                  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}@media screen and (-ms-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:0;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}@media screen and (-ms-high-contrast:active){.mat-menu-item-highlighted,.mat-menu-item.cdk-keyboard-focused,.mat-menu-item.cdk-program-focused{outline:dotted 1px}}.mat-menu-item-submenu-trigger{padding-right:32px}.mat-menu-item-submenu-trigger::after{width:0;height:0;border-style:solid;border-width:5px 0 5px 5px;border-color:transparent transparent transparent currentColor;content:'';display:inline-block;position:absolute;top:50%;right:16px;transform:translateY(-50%)}[dir=rtl] .mat-menu-item-submenu-trigger{padding-right:16px;padding-left:32px}[dir=rtl] .mat-menu-item-submenu-trigger::after{right:auto;left:16px;transform:rotateY(180deg) translateY(-50%)}.mat-menu-panel.ng-animating .mat-menu-item-submenu-trigger{pointer-events:none}button.mat-menu-item{width:100%}.mat-menu-item .mat-menu-ripple{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none}"],
                  changeDetection: ChangeDetectionStrategy.OnPush,
                  encapsulation: ViewEncapsulation.None,
                  exportAs: 'matMenu',
                  animations: [
                      matMenuAnimations.transformMenu,
                      matMenuAnimations.fadeInItems
                  ],
                  providers: [
                      { provide: MAT_MENU_PANEL, useExisting: MatMenu }
                  ]
              },] },
  ];
  /** @nocollapse */
  MatMenu.ctorParameters = () => [
      { type: ElementRef },
      { type: NgZone },
      { type: undefined, decorators: [{ type: Inject, args: [MAT_MENU_DEFAULT_OPTIONS,] }] }
  ];
  MatMenu.propDecorators = {
      backdropClass: [{ type: Input }],
      xPosition: [{ type: Input }],
      yPosition: [{ type: Input }],
      templateRef: [{ type: ViewChild, args: [TemplateRef,] }],
      items: [{ type: ContentChildren, args: [MatMenuItem,] }],
      lazyContent: [{ type: ContentChild, args: [MatMenuContent,] }],
      overlapTrigger: [{ type: Input }],
      hasBackdrop: [{ type: Input }],
      panelClass: [{ type: Input, args: ['class',] }],
      classList: [{ type: Input }],
      closed: [{ type: Output }],
      close: [{ type: Output }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  /** *
   * Injection token that determines the scroll handling while the menu is open.
    @type {?} */
  const MAT_MENU_SCROLL_STRATEGY = new InjectionToken('mat-menu-scroll-strategy');
  /**
   * \@docs-private
   * @param {?} overlay
   * @return {?}
   */
  function MAT_MENU_SCROLL_STRATEGY_FACTORY(overlay) {
      return () => overlay.scrollStrategies.reposition();
  }
  /** *
   * \@docs-private
    @type {?} */
  const MAT_MENU_SCROLL_STRATEGY_FACTORY_PROVIDER = {
      provide: MAT_MENU_SCROLL_STRATEGY,
      deps: [Overlay],
      useFactory: MAT_MENU_SCROLL_STRATEGY_FACTORY,
  };
  /** *
   * Default top padding of the menu panel.
    @type {?} */
  const MENU_PANEL_TOP_PADDING = 8;
  /**
   * This directive is intended to be used in conjunction with an mat-menu tag.  It is
   * responsible for toggling the display of the provided menu instance.
   */
  class MatMenuTrigger {
      /**
       * @param {?} _overlay
       * @param {?} _element
       * @param {?} _viewContainerRef
       * @param {?} scrollStrategy
       * @param {?} _parentMenu
       * @param {?} _menuItemInstance
       * @param {?} _dir
       * @param {?=} _focusMonitor
       */
      constructor(_overlay, _element, _viewContainerRef, scrollStrategy, _parentMenu, _menuItemInstance, _dir, _focusMonitor) {
          this._overlay = _overlay;
          this._element = _element;
          this._viewContainerRef = _viewContainerRef;
          this._parentMenu = _parentMenu;
          this._menuItemInstance = _menuItemInstance;
          this._dir = _dir;
          this._focusMonitor = _focusMonitor;
          this._overlayRef = null;
          this._menuOpen = false;
          this._closeSubscription = Subscription.EMPTY;
          this._hoverSubscription = Subscription.EMPTY;
          this._openedByMouse = false;
          /**
           * Event emitted when the associated menu is opened.
           */
          this.menuOpened = new EventEmitter();
          /**
           * Event emitted when the associated menu is opened.
           * @deprecated Switch to `menuOpened` instead
           * \@breaking-change 8.0.0
           */
          this.onMenuOpen = this.menuOpened;
          /**
           * Event emitted when the associated menu is closed.
           */
          this.menuClosed = new EventEmitter();
          /**
           * Event emitted when the associated menu is closed.
           * @deprecated Switch to `menuClosed` instead
           * \@breaking-change 8.0.0
           */
          this.onMenuClose = this.menuClosed;
          if (_menuItemInstance) {
              _menuItemInstance._triggersSubmenu = this.triggersSubmenu();
          }
          this._scrollStrategy = scrollStrategy;
      }
      /**
       * @deprecated
       * \@breaking-change 8.0.0
       * @return {?}
       */
      get _deprecatedMatMenuTriggerFor() {
          return this.menu;
      }
      /**
       * @param {?} v
       * @return {?}
       */
      set _deprecatedMatMenuTriggerFor(v) {
          this.menu = v;
      }
      /**
       * @return {?}
       */
      ngAfterContentInit() {
          this._checkMenu();
          this.menu.close.asObservable().subscribe(reason => {
              this._destroyMenu();
              // If a click closed the menu, we should close the entire chain of nested menus.
              if ((reason === 'click' || reason === 'tab') && this._parentMenu) {
                  this._parentMenu.closed.emit(reason);
              }
          });
          this._handleHover();
      }
      /**
       * @return {?}
       */
      ngOnDestroy() {
          if (this._overlayRef) {
              this._overlayRef.dispose();
              this._overlayRef = null;
          }
          this._cleanUpSubscriptions();
      }
      /**
       * Whether the menu is open.
       * @return {?}
       */
      get menuOpen() {
          return this._menuOpen;
      }
      /**
       * The text direction of the containing app.
       * @return {?}
       */
      get dir() {
          return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
      }
      /**
       * Whether the menu triggers a sub-menu or a top-level one.
       * @return {?}
       */
      triggersSubmenu() {
          return !!(this._menuItemInstance && this._parentMenu);
      }
      /**
       * Toggles the menu between the open and closed states.
       * @return {?}
       */
      toggleMenu() {
          return this._menuOpen ? this.closeMenu() : this.openMenu();
      }
      /**
       * Opens the menu.
       * @return {?}
       */
      openMenu() {
          if (this._menuOpen) {
              return;
          }
          this._checkMenu();
          /** @type {?} */
          const overlayRef = this._createOverlay();
          this._setPosition(/** @type {?} */ (overlayRef.getConfig().positionStrategy));
          overlayRef.attach(this._portal);
          if (this.menu.lazyContent) {
              this.menu.lazyContent.attach(this.menuData);
          }
          this._closeSubscription = this._menuClosingActions().subscribe(() => this.closeMenu());
          this._initMenu();
          if (this.menu instanceof MatMenu) {
              this.menu._startAnimation();
          }
      }
      /**
       * Closes the menu.
       * @return {?}
       */
      closeMenu() {
          this.menu.close.emit();
      }
      /**
       * Focuses the menu trigger.
       * @param {?=} origin Source of the menu trigger's focus.
       * @return {?}
       */
      focus(origin = 'program') {
          if (this._focusMonitor) {
              this._focusMonitor.focusVia(this._element, origin);
          }
          else {
              this._element.nativeElement.focus();
          }
      }
      /**
       * Closes the menu and does the necessary cleanup.
       * @return {?}
       */
      _destroyMenu() {
          if (!this._overlayRef || !this.menuOpen) {
              return;
          }
          /** @type {?} */
          const menu = this.menu;
          this._closeSubscription.unsubscribe();
          this._overlayRef.detach();
          if (menu instanceof MatMenu) {
              menu._resetAnimation();
              if (menu.lazyContent) {
                  // Wait for the exit animation to finish before detaching the content.
                  menu._animationDone
                      .pipe(filter(event => event.toState === 'void'), take(1), 
                  // Interrupt if the content got re-attached.
                  takeUntil(menu.lazyContent._attached))
                      .subscribe(() => /** @type {?} */ ((menu.lazyContent)).detach(), undefined, () => {
                      // No matter whether the content got re-attached, reset the menu.
                      this._resetMenu();
                  });
              }
              else {
                  this._resetMenu();
              }
          }
          else {
              this._resetMenu();
              if (menu.lazyContent) {
                  menu.lazyContent.detach();
              }
          }
      }
      /**
       * This method sets the menu state to open and focuses the first item if
       * the menu was opened via the keyboard.
       * @return {?}
       */
      _initMenu() {
          this.menu.parentMenu = this.triggersSubmenu() ? this._parentMenu : undefined;
          this.menu.direction = this.dir;
          this._setMenuElevation();
          this._setIsMenuOpen(true);
          this.menu.focusFirstItem(this._openedByMouse ? 'mouse' : 'program');
      }
      /**
       * Updates the menu elevation based on the amount of parent menus that it has.
       * @return {?}
       */
      _setMenuElevation() {
          if (this.menu.setElevation) {
              /** @type {?} */
              let depth = 0;
              /** @type {?} */
              let parentMenu = this.menu.parentMenu;
              while (parentMenu) {
                  depth++;
                  parentMenu = parentMenu.parentMenu;
              }
              this.menu.setElevation(depth);
          }
      }
      /**
       * This method resets the menu when it's closed, most importantly restoring
       * focus to the menu trigger if the menu was opened via the keyboard.
       * @return {?}
       */
      _resetMenu() {
          this._setIsMenuOpen(false);
          // We should reset focus if the user is navigating using a keyboard or
          // if we have a top-level trigger which might cause focus to be lost
          // when clicking on the backdrop.
          if (!this._openedByMouse) {
              // Note that the focus style will show up both for `program` and
              // `keyboard` so we don't have to specify which one it is.
              this.focus();
          }
          else if (!this.triggersSubmenu()) {
              this.focus('mouse');
          }
          this._openedByMouse = false;
      }
      /**
       * @param {?} isOpen
       * @return {?}
       */
      _setIsMenuOpen(isOpen) {
          this._menuOpen = isOpen;
          this._menuOpen ? this.menuOpened.emit() : this.menuClosed.emit();
          if (this.triggersSubmenu()) {
              this._menuItemInstance._highlighted = isOpen;
          }
      }
      /**
       * This method checks that a valid instance of MatMenu has been passed into
       * matMenuTriggerFor. If not, an exception is thrown.
       * @return {?}
       */
      _checkMenu() {
          if (!this.menu) {
              throwMatMenuMissingError();
          }
      }
      /**
       * This method creates the overlay from the provided menu's template and saves its
       * OverlayRef so that it can be attached to the DOM when openMenu is called.
       * @return {?}
       */
      _createOverlay() {
          if (!this._overlayRef) {
              this._portal = new TemplatePortal(this.menu.templateRef, this._viewContainerRef);
              /** @type {?} */
              const config = this._getOverlayConfig();
              this._subscribeToPositions(/** @type {?} */ (config.positionStrategy));
              this._overlayRef = this._overlay.create(config);
          }
          return this._overlayRef;
      }
      /**
       * This method builds the configuration object needed to create the overlay, the OverlayState.
       * @return {?} OverlayConfig
       */
      _getOverlayConfig() {
          return new OverlayConfig({
              positionStrategy: this._overlay.position()
                  .flexibleConnectedTo(this._element)
                  .withLockedPosition()
                  .withTransformOriginOn('.mat-menu-panel'),
              hasBackdrop: this.menu.hasBackdrop == null ? !this.triggersSubmenu() : this.menu.hasBackdrop,
              backdropClass: this.menu.backdropClass || 'cdk-overlay-transparent-backdrop',
              scrollStrategy: this._scrollStrategy(),
              direction: this._dir
          });
      }
      /**
       * Listens to changes in the position of the overlay and sets the correct classes
       * on the menu based on the new position. This ensures the animation origin is always
       * correct, even if a fallback position is used for the overlay.
       * @param {?} position
       * @return {?}
       */
      _subscribeToPositions(position) {
          if (this.menu.setPositionClasses) {
              position.positionChanges.subscribe(change => {
                  /** @type {?} */
                  const posX = change.connectionPair.overlayX === 'start' ? 'after' : 'before';
                  /** @type {?} */
                  const posY = change.connectionPair.overlayY === 'top' ? 'below' : 'above'; /** @type {?} */
                  ((this.menu.setPositionClasses))(posX, posY);
              });
          }
      }
      /**
       * Sets the appropriate positions on a position strategy
       * so the overlay connects with the trigger correctly.
       * @param {?} positionStrategy Strategy whose position to update.
       * @return {?}
       */
      _setPosition(positionStrategy) {
          let [originX, originFallbackX] = this.menu.xPosition === 'before' ? ['end', 'start'] : ['start', 'end'];
          let [overlayY, overlayFallbackY] = this.menu.yPosition === 'above' ? ['bottom', 'top'] : ['top', 'bottom'];
          let [originY, originFallbackY] = [overlayY, overlayFallbackY];
          let [overlayX, overlayFallbackX] = [originX, originFallbackX];
          /** @type {?} */
          let offsetY = 0;
          if (this.triggersSubmenu()) {
              // When the menu is a sub-menu, it should always align itself
              // to the edges of the trigger, instead of overlapping it.
              overlayFallbackX = originX = this.menu.xPosition === 'before' ? 'start' : 'end';
              originFallbackX = overlayX = originX === 'end' ? 'start' : 'end';
              offsetY = overlayY === 'bottom' ? MENU_PANEL_TOP_PADDING : -MENU_PANEL_TOP_PADDING;
          }
          else if (!this.menu.overlapTrigger) {
              originY = overlayY === 'top' ? 'bottom' : 'top';
              originFallbackY = overlayFallbackY === 'top' ? 'bottom' : 'top';
          }
          positionStrategy.withPositions([
              { originX, originY, overlayX, overlayY, offsetY },
              { originX: originFallbackX, originY, overlayX: overlayFallbackX, overlayY, offsetY },
              {
                  originX,
                  originY: originFallbackY,
                  overlayX,
                  overlayY: overlayFallbackY,
                  offsetY: -offsetY
              },
              {
                  originX: originFallbackX,
                  originY: originFallbackY,
                  overlayX: overlayFallbackX,
                  overlayY: overlayFallbackY,
                  offsetY: -offsetY
              }
          ]);
      }
      /**
       * Cleans up the active subscriptions.
       * @return {?}
       */
      _cleanUpSubscriptions() {
          this._closeSubscription.unsubscribe();
          this._hoverSubscription.unsubscribe();
      }
      /**
       * Returns a stream that emits whenever an action that should close the menu occurs.
       * @return {?}
       */
      _menuClosingActions() {
          /** @type {?} */
          const backdrop = /** @type {?} */ ((this._overlayRef)).backdropClick();
          /** @type {?} */
          const detachments = /** @type {?} */ ((this._overlayRef)).detachments();
          /** @type {?} */
          const parentClose = this._parentMenu ? this._parentMenu.closed : of();
          /** @type {?} */
          const hover = this._parentMenu ? this._parentMenu._hovered().pipe(filter(active => active !== this._menuItemInstance), filter(() => this._menuOpen)) : of();
          return merge(backdrop, parentClose, hover, detachments);
      }
      /**
       * Handles mouse presses on the trigger.
       * @param {?} event
       * @return {?}
       */
      _handleMousedown(event) {
          if (!isFakeMousedownFromScreenReader(event)) {
              // Since right or middle button clicks won't trigger the `click` event,
              // we shouldn't consider the menu as opened by mouse in those cases.
              this._openedByMouse = event.button === 0;
              // Since clicking on the trigger won't close the menu if it opens a sub-menu,
              // we should prevent focus from moving onto it via click to avoid the
              // highlight from lingering on the menu item.
              if (this.triggersSubmenu()) {
                  event.preventDefault();
              }
          }
      }
      /**
       * Handles key presses on the trigger.
       * @param {?} event
       * @return {?}
       */
      _handleKeydown(event) {
          /** @type {?} */
          const keyCode = event.keyCode;
          if (this.triggersSubmenu() && ((keyCode === RIGHT_ARROW && this.dir === 'ltr') ||
              (keyCode === LEFT_ARROW && this.dir === 'rtl'))) {
              this.openMenu();
          }
      }
      /**
       * Handles click events on the trigger.
       * @param {?} event
       * @return {?}
       */
      _handleClick(event) {
          if (this.triggersSubmenu()) {
              // Stop event propagation to avoid closing the parent menu.
              event.stopPropagation();
              this.openMenu();
          }
          else {
              this.toggleMenu();
          }
      }
      /**
       * Handles the cases where the user hovers over the trigger.
       * @return {?}
       */
      _handleHover() {
          // Subscribe to changes in the hovered item in order to toggle the panel.
          if (!this.triggersSubmenu()) {
              return;
          }
          this._hoverSubscription = this._parentMenu._hovered()
              // Since we might have multiple competing triggers for the same menu (e.g. a sub-menu
              // with different data and triggers), we have to delay it by a tick to ensure that
              // it won't be closed immediately after it is opened.
              .pipe(filter(active => active === this._menuItemInstance && !active.disabled), delay(0, asapScheduler))
              .subscribe(() => {
              this._openedByMouse = true;
              // If the same menu is used between multiple triggers, it might still be animating
              // while the new trigger tries to re-open it. Wait for the animation to finish
              // before doing so. Also interrupt if the user moves to another item.
              if (this.menu instanceof MatMenu && this.menu._isAnimating) {
                  // We need the `delay(0)` here in order to avoid
                  // 'changed after checked' errors in some cases. See #12194.
                  this.menu._animationDone
                      .pipe(take(1), delay(0, asapScheduler), takeUntil(this._parentMenu._hovered()))
                      .subscribe(() => this.openMenu());
              }
              else {
                  this.openMenu();
              }
          });
      }
  }
  MatMenuTrigger.decorators = [
      { type: Directive, args: [{
                  selector: `[mat-menu-trigger-for], [matMenuTriggerFor]`,
                  host: {
                      'aria-haspopup': 'true',
                      '[attr.aria-expanded]': 'menuOpen || null',
                      '(mousedown)': '_handleMousedown($event)',
                      '(keydown)': '_handleKeydown($event)',
                      '(click)': '_handleClick($event)',
                  },
                  exportAs: 'matMenuTrigger'
              },] },
  ];
  /** @nocollapse */
  MatMenuTrigger.ctorParameters = () => [
      { type: Overlay },
      { type: ElementRef },
      { type: ViewContainerRef },
      { type: undefined, decorators: [{ type: Inject, args: [MAT_MENU_SCROLL_STRATEGY,] }] },
      { type: MatMenu, decorators: [{ type: Optional }] },
      { type: MatMenuItem, decorators: [{ type: Optional }, { type: Self }] },
      { type: Directionality, decorators: [{ type: Optional }] },
      { type: FocusMonitor }
  ];
  MatMenuTrigger.propDecorators = {
      _deprecatedMatMenuTriggerFor: [{ type: Input, args: ['mat-menu-trigger-for',] }],
      menu: [{ type: Input, args: ['matMenuTriggerFor',] }],
      menuData: [{ type: Input, args: ['matMenuTriggerData',] }],
      menuOpened: [{ type: Output }],
      onMenuOpen: [{ type: Output }],
      menuClosed: [{ type: Output }],
      onMenuClose: [{ type: Output }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  class MatMenuModule {
  }
  MatMenuModule.decorators = [
      { type: NgModule, args: [{
                  imports: [
                      CommonModule,
                      MatCommonModule,
                      MatRippleModule,
                      OverlayModule,
                  ],
                  exports: [MatMenu, MatMenuItem, MatMenuTrigger, MatMenuContent, MatCommonModule],
                  declarations: [MatMenu, MatMenuItem, MatMenuTrigger, MatMenuContent],
                  providers: [MAT_MENU_SCROLL_STRATEGY_FACTORY_PROVIDER]
              },] },
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
   */
  
  export { MAT_MENU_SCROLL_STRATEGY, MatMenuModule, MatMenu, MAT_MENU_DEFAULT_OPTIONS, MatMenuItem, MatMenuTrigger, matMenuAnimations, fadeInItems, transformMenu, MatMenuContent, MAT_MENU_DEFAULT_OPTIONS_FACTORY as ɵa24, MatMenuItemBase as ɵb24, _MatMenuItemMixinBase as ɵc24, MAT_MENU_PANEL as ɵf24, MAT_MENU_SCROLL_STRATEGY_FACTORY as ɵd24, MAT_MENU_SCROLL_STRATEGY_FACTORY_PROVIDER as ɵe24 };
  //# sourceMappingURL=menu.js.map
  