license import { Subject , Observable } from 'rxjs' ; /** Events to emit as specified by the caller once the MenuStack is empty. */ export const enum FocusNext { nextItem , previousItem , currentItem } /**
 * Interface for the elements tracked in the MenuStack.
 */ export interface MenuStackItem { /** A reference to the previous Menus MenuStack instance. */ _menuStack : MenuStack | null ; } /**
 * MenuStack allows subscribers to listen for close events (when a MenuStackItem is popped off
 * of the stack) in order to perform closing actions. Upon the MenuStack being empty it emits
 * from the `empty` observable specifying the next focus action which the listener should perform
 * as requested by the closer.
 */ export class MenuStack { /** All MenuStackItems tracked by this MenuStack. */ private readonly _elements : MenuStackItem [ ] = [ ] ; /** Emits the element which was popped off of the stack when requested by a closer. */ private readonly _close : Subject < MenuStackItem | undefined > = new Subject ( ) ; /** Emits once the MenuStack has become empty after popping off elements. */ private readonly _empty : Subject < FocusNext | undefined > = new Subject ( ) ; /** Observable which emits the MenuStackItem which has been requested to close. */ readonly closed : Observable < MenuStackItem | undefined > = this . _close ; /**
     * Observable which emits when the MenuStack is empty after popping off the last element. It
     * emits a FocusNext event which specifies the action the closer has requested the listener
     * perform.
     */ readonly emptied : Observable < FocusNext | undefined > = this . _empty ; param menu push ( menu ) { this . _elements . push ( menu ) ; } param lastItem param focusNext close ( lastItem , focusNext ? ) { if ( this . _elements . indexOf ( lastItem ) >= 0 ) { let poppedElement ; do { poppedElement = this . _elements . pop ( ) ; this . _close . next ( poppedElement ) ; } while ( poppedElement !== lastItem ) ; if ( this . isEmpty ( ) ) { this . _empty . next ( focusNext ) ; } } } param lastItem return closeSubMenuOf ( lastItem ) { let removed = false ; if ( this . _elements . indexOf ( lastItem ) >= 0 ) { removed = this . peek ( ) !== lastItem ; while ( this . peek ( ) !== lastItem ) { this . _close . next ( this . _elements . pop ( ) ) ; } } return removed ; } param focusNext closeAll ( focusNext ? ) { if ( ! this . isEmpty ( ) ) { while ( ! this . isEmpty ( ) ) { const menuStackItem = this . _elements . pop ( ) ; if ( menuStackItem ) { this . _close . next ( menuStackItem ) ; } } this . _empty . next ( focusNext ) ; } } /** Return true if this stack is empty. */ isEmpty ( ) { return ! this . _elements . length ; } /** Return the length of the stack. */ length ( ) { return this . _elements . length ; } /** Get the top most element on the stack. */ peek ( ) { return this . _elements [ this . _elements . length - 1 ] ; } } /** NoopMenuStack is a placeholder MenuStack used for inline menus. */ export class NoopMenuStack extends MenuStack { /** Noop push - does not add elements to the MenuStack. */ override push ( _ ) { } }